]> review.fuel-infra Code Review - packages/trusty/mysql-wsrep-5.6.git/commitdiff
New version of mysql-wsrep (5.6.35) 69/30169/5
authorIvan Suzdal <isuzdal@mirantis.com>
Thu, 26 Jan 2017 12:41:08 +0000 (15:41 +0300)
committerIvan Suzdal <isuzdal@mirantis.com>
Wed, 8 Feb 2017 13:06:27 +0000 (13:06 +0000)
Closes-Bug: #1657707

Change-Id: Ib3b160ff533203bd70bb883254568ea3546a7746

314 files changed:
debian/changelog
debian/patches/fix-mysqlhotcopy-test-failure.patch [deleted file]
debian/patches/series
mysql-wsrep-5.6/VERSION
mysql-wsrep-5.6/client/mysqladmin.cc
mysql-wsrep-5.6/cmake/install_layout.cmake
mysql-wsrep-5.6/cmake/os/SunOS.cmake
mysql-wsrep-5.6/cmake/os/WindowsCache.cmake
mysql-wsrep-5.6/cmake/wsrep.cmake
mysql-wsrep-5.6/config.h.cmake
mysql-wsrep-5.6/configure.cmake
mysql-wsrep-5.6/debian/README.Maintainer [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/Docs__Images__Makefile.in [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/Docs__Makefile.in [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/debian-start [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/debian-start.inc.sh [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/debian_create_root_user.sql [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/echo_stderr [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/innotop/changelog.innotop [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/innotop/innotop [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/innotop/innotop.1 [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/my.cnf [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/my5.6.cnf [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/mysql-server.lintian-overrides [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/mysql_config_pic.1 [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/mysql_embedded.1 [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/mysqld_safe_syslog.cnf [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/mysqlreport [new file with mode: 0644]
mysql-wsrep-5.6/debian/additions/mysqlreport.1 [new file with mode: 0644]
mysql-wsrep-5.6/debian/apparmor-profile [new file with mode: 0644]
mysql-wsrep-5.6/debian/changelog [new file with mode: 0644]
mysql-wsrep-5.6/debian/clean [new file with mode: 0644]
mysql-wsrep-5.6/debian/compat [new file with mode: 0644]
mysql-wsrep-5.6/debian/control [new file with mode: 0644]
mysql-wsrep-5.6/debian/copyright [new file with mode: 0644]
mysql-wsrep-5.6/debian/gbp.conf [new file with mode: 0644]
mysql-wsrep-5.6/debian/libmysqld-dev.install [new file with mode: 0644]
mysql-wsrep-5.6/debian/libmysqld-pic.README.Debian [new file with mode: 0644]
mysql-wsrep-5.6/debian/libmysqld-pic.install [new file with mode: 0644]
mysql-wsrep-5.6/debian/libmysqld-pic.manpages [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-server-5.6.py [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.README.Debian [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.dirs [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.docs [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.examples [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.install [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.links [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.lintian-overrides [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.manpages [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-common-5.6.dirs [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-common-5.6.install [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-common-5.6.postrm [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.README.Maintainer [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.dirs [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.examples [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.install [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.manpages [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient18.dirs [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient18.install [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient18.lintian-overrides [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.NEWS [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.README.Debian [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.config [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.dirs [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.examples [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.install [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.lintian-overrides [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.logcheck.ignore.paranoid [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.logcheck.ignore.server [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.logcheck.ignore.workstation [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.manpages [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.mysql-server.logrotate [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.mysql.upstart.disabled [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.postinst [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.postrm [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.preinst [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.prerm [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.templates [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-testsuite-5.6.dirs [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-testsuite-5.6.install [new file with mode: 0644]
mysql-wsrep-5.6/debian/mysql-wsrep-testsuite-5.6.lintian-overrides [new file with mode: 0644]
mysql-wsrep-5.6/debian/patches/fix_standalone_tests.patch [new file with mode: 0644]
mysql-wsrep-5.6/debian/patches/hurd.patch [new file with mode: 0644]
mysql-wsrep-5.6/debian/patches/kfreebsd_tests.patch [new file with mode: 0644]
mysql-wsrep-5.6/debian/patches/scripts__mysqld_safe.sh__signals.patch [new file with mode: 0644]
mysql-wsrep-5.6/debian/patches/series [new file with mode: 0644]
mysql-wsrep-5.6/debian/patches/spelling.patch [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/POTFILES.in [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/ar.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/ca.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/cs.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/da.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/de.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/es.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/eu.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/fr.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/gl.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/it.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/ja.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/nb.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/nl.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/pt.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/pt_BR.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/ro.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/ru.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/sk.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/sv.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/templates.pot [new file with mode: 0644]
mysql-wsrep-5.6/debian/po/tr.po [new file with mode: 0644]
mysql-wsrep-5.6/debian/rules [new file with mode: 0755]
mysql-wsrep-5.6/debian/source.lintian-overrides [new file with mode: 0644]
mysql-wsrep-5.6/debian/source/format [new file with mode: 0644]
mysql-wsrep-5.6/debian/tests/build [new file with mode: 0755]
mysql-wsrep-5.6/debian/tests/control [new file with mode: 0644]
mysql-wsrep-5.6/debian/tests/smoke [new file with mode: 0644]
mysql-wsrep-5.6/debian/tests/upstream [new file with mode: 0755]
mysql-wsrep-5.6/debian/watch [new file with mode: 0644]
mysql-wsrep-5.6/include/lf.h
mysql-wsrep-5.6/include/my_default.h
mysql-wsrep-5.6/include/my_pthread.h
mysql-wsrep-5.6/include/my_sys.h
mysql-wsrep-5.6/mysql-test/extra/rpl_tests/rpl_extra_col_slave.test
mysql-wsrep-5.6/mysql-test/include/mysqlhotcopy.inc
mysql-wsrep-5.6/mysql-test/include/plugin.defs
mysql-wsrep-5.6/mysql-test/include/range.inc
mysql-wsrep-5.6/mysql-test/mysql-test-run.pl
mysql-wsrep-5.6/mysql-test/r/alter_table.result
mysql-wsrep-5.6/mysql-test/r/events_2.result
mysql-wsrep-5.6/mysql-test/r/loaddata.result
mysql-wsrep-5.6/mysql-test/r/mysql_config_editor.result
mysql-wsrep-5.6/mysql-test/r/partition_symlink.result
mysql-wsrep-5.6/mysql-test/r/range_all.result
mysql-wsrep-5.6/mysql-test/r/range_icp.result
mysql-wsrep-5.6/mysql-test/r/range_icp_mrr.result
mysql-wsrep-5.6/mysql-test/r/range_mrr.result
mysql-wsrep-5.6/mysql-test/r/range_mrr_cost.result
mysql-wsrep-5.6/mysql-test/r/range_none.result
mysql-wsrep-5.6/mysql-test/std_data/bug20683959loaddata.txt [deleted file]
mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/check_connection_delay.inc [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/cleanup_proxy_accounts.inc [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/have_connection_control_plugin.inc [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/have_test_plugin.inc [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/install_connection_control_plugin.inc [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/set_after_marker.inc [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/set_before_marker.inc [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/setup_proxy_accounts.inc [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/uninstall_connection_control_plugin.inc [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_anonymous_user.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_info_schema_view.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_invalid_users.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_min_max.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_proxy_users.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_valid_users.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/r/status_variables.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/r/system_variables.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_anonymous_user-master.opt [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_anonymous_user.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_info_schema_view-master.opt [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_info_schema_view.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_invalid_users-master.opt [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_invalid_users.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_min_max-master.opt [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_min_max.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_proxy_users-master.opt [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_proxy_users.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_valid_users-master.opt [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_valid_users.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/status_variables-master.opt [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/status_variables.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/system_variables-master.opt [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/connection_control/t/system_variables.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/r/GAL-480.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328A.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328B.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328C.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328D.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328E.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-329.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db_cc.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/r/galera_wsrep_log_conficts.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/GAL-480.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328-footer.inc [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328-header.inc [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328A.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328B.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328C.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328D.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328E.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-329-master.opt [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-329.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.cnf [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db_cc.cnf [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db_cc.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_autoinc_sst_xtrabackup.cnf
mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_autoinc_sst_xtrabackup.test
mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_wsrep_log_conficts-master.opt [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_wsrep_log_conficts.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/innodb/r/autoinc_debug.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/innodb/r/innodb-log-file-size-1.result
mysql-wsrep-5.6/mysql-test/suite/innodb/r/innodb_mysql.result
mysql-wsrep-5.6/mysql-test/suite/innodb/r/innodb_stats_del_mark.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/innodb/t/autoinc_debug.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/innodb/t/galera.skip
mysql-wsrep-5.6/mysql-test/suite/innodb/t/innodb-log-file-size-1.test
mysql-wsrep-5.6/mysql-test/suite/innodb/t/innodb_stats_del_mark-master.opt [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/innodb/t/innodb_stats_del_mark.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/opt_trace/include/bugs.inc
mysql-wsrep-5.6/mysql-test/suite/opt_trace/r/bugs_no_prot_all.result
mysql-wsrep-5.6/mysql-test/suite/opt_trace/r/bugs_no_prot_none.result
mysql-wsrep-5.6/mysql-test/suite/opt_trace/r/bugs_ps_prot_all.result
mysql-wsrep-5.6/mysql-test/suite/opt_trace/r/bugs_ps_prot_none.result
mysql-wsrep-5.6/mysql-test/suite/parts/inc/partition-dml-1-11.inc
mysql-wsrep-5.6/mysql-test/suite/parts/r/partition-dml-1-11-innodb.result
mysql-wsrep-5.6/mysql-test/suite/parts/r/partition-dml-1-11-myisam.result
mysql-wsrep-5.6/mysql-test/suite/rpl/r/rpl_extra_col_slave_innodb.result
mysql-wsrep-5.6/mysql-test/suite/rpl/r/rpl_extra_col_slave_myisam.result
mysql-wsrep-5.6/mysql-test/suite/sys_vars/r/innodb_stats_include_delete_marked_basic.result [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/suite/sys_vars/t/innodb_stats_include_delete_marked_basic.test [new file with mode: 0644]
mysql-wsrep-5.6/mysql-test/t/alter_table.test
mysql-wsrep-5.6/mysql-test/t/events_2.test
mysql-wsrep-5.6/mysql-test/t/loaddata.test
mysql-wsrep-5.6/mysql-test/t/mysql_config_editor.test
mysql-wsrep-5.6/mysql-test/t/partition_symlink.test
mysql-wsrep-5.6/mysql-test/valgrind.supp
mysql-wsrep-5.6/mysys/CMakeLists.txt
mysql-wsrep-5.6/mysys/lf_alloc-pin.c
mysql-wsrep-5.6/mysys/my_lib.c
mysql-wsrep-5.6/mysys/my_thr_init.c
mysql-wsrep-5.6/mysys/stacktrace.c
mysql-wsrep-5.6/mysys_ssl/my_default.cc
mysql-wsrep-5.6/packaging/deb-jessie/source/include-binaries
mysql-wsrep-5.6/packaging/deb-precise/source/include-binaries
mysql-wsrep-5.6/packaging/deb-trusty/source/include-binaries
mysql-wsrep-5.6/packaging/deb-wheezy/source/include-binaries
mysql-wsrep-5.6/packaging/rpm-docker/mysql.spec.in
mysql-wsrep-5.6/packaging/rpm-fedora/mysql-systemd-start
mysql-wsrep-5.6/packaging/rpm-fedora/mysql.spec.in
mysql-wsrep-5.6/packaging/rpm-fedora/mysql_config.sh
mysql-wsrep-5.6/packaging/rpm-fedora/mysqld.service
mysql-wsrep-5.6/packaging/rpm-oel/mysql-systemd-start
mysql-wsrep-5.6/packaging/rpm-oel/mysql.init
mysql-wsrep-5.6/packaging/rpm-oel/mysql.spec.in
mysql-wsrep-5.6/packaging/rpm-oel/mysql_config.sh
mysql-wsrep-5.6/packaging/rpm-oel/mysqld.service
mysql-wsrep-5.6/packaging/rpm-sles/mysql-systemd-start
mysql-wsrep-5.6/packaging/rpm-sles/mysql.init
mysql-wsrep-5.6/packaging/rpm-sles/mysql.spec.in
mysql-wsrep-5.6/packaging/rpm-sles/mysqld.service
mysql-wsrep-5.6/plugin/connection_control/CMakeLists.txt [new file with mode: 0644]
mysql-wsrep-5.6/plugin/connection_control/connection_control.cc [new file with mode: 0644]
mysql-wsrep-5.6/plugin/connection_control/connection_control.h [new file with mode: 0644]
mysql-wsrep-5.6/plugin/connection_control/connection_control_coordinator.cc [new file with mode: 0644]
mysql-wsrep-5.6/plugin/connection_control/connection_control_coordinator.h [new file with mode: 0644]
mysql-wsrep-5.6/plugin/connection_control/connection_control_data.h [new file with mode: 0644]
mysql-wsrep-5.6/plugin/connection_control/connection_control_interfaces.h [new file with mode: 0644]
mysql-wsrep-5.6/plugin/connection_control/connection_control_memory.h [new file with mode: 0644]
mysql-wsrep-5.6/plugin/connection_control/connection_delay.cc [new file with mode: 0644]
mysql-wsrep-5.6/plugin/connection_control/connection_delay.h [new file with mode: 0644]
mysql-wsrep-5.6/plugin/connection_control/connection_delay_api.h [new file with mode: 0644]
mysql-wsrep-5.6/plugin/connection_control/security_context_wrapper.cc [new file with mode: 0644]
mysql-wsrep-5.6/plugin/connection_control/security_context_wrapper.h [new file with mode: 0644]
mysql-wsrep-5.6/plugin/semisync/semisync_master.cc
mysql-wsrep-5.6/scripts/CMakeLists.txt
mysql-wsrep-5.6/scripts/mysqld_safe.sh
mysql-wsrep-5.6/sql-common/my_time.c
mysql-wsrep-5.6/sql/binlog.cc
mysql-wsrep-5.6/sql/field.cc
mysql-wsrep-5.6/sql/gen_lex_hash.cc
mysql-wsrep-5.6/sql/handler.cc
mysql-wsrep-5.6/sql/mysqld.cc
mysql-wsrep-5.6/sql/partition_info.cc
mysql-wsrep-5.6/sql/partition_info.h
mysql-wsrep-5.6/sql/rpl_record.cc
mysql-wsrep-5.6/sql/sql_class.cc
mysql-wsrep-5.6/sql/sql_class.h
mysql-wsrep-5.6/sql/sql_connect.cc
mysql-wsrep-5.6/sql/sql_load.cc
mysql-wsrep-5.6/sql/sql_optimizer.cc
mysql-wsrep-5.6/sql/sql_parse.cc
mysql-wsrep-5.6/sql/sql_planner.cc
mysql-wsrep-5.6/sql/sql_select.h
mysql-wsrep-5.6/sql/sql_table.cc
mysql-wsrep-5.6/sql/sql_yacc.yy
mysql-wsrep-5.6/sql/table.cc
mysql-wsrep-5.6/sql/transaction.cc
mysql-wsrep-5.6/sql/wsrep_hton.cc
mysql-wsrep-5.6/sql/wsrep_mysqld.cc
mysql-wsrep-5.6/sql/wsrep_mysqld.h
mysql-wsrep-5.6/sql/wsrep_sst.cc
mysql-wsrep-5.6/sql/wsrep_thd.cc
mysql-wsrep-5.6/storage/innobase/dict/dict0stats.cc
mysql-wsrep-5.6/storage/innobase/fts/fts0opt.cc
mysql-wsrep-5.6/storage/innobase/handler/ha_innodb.cc
mysql-wsrep-5.6/storage/innobase/handler/ha_innodb.h
mysql-wsrep-5.6/storage/innobase/handler/handler0alter.cc
mysql-wsrep-5.6/storage/innobase/include/os0thread.h
mysql-wsrep-5.6/storage/innobase/include/srv0srv.h
mysql-wsrep-5.6/storage/innobase/include/trx0trx.h
mysql-wsrep-5.6/storage/innobase/lock/lock0lock.cc
mysql-wsrep-5.6/storage/innobase/mach/mach0data.cc
mysql-wsrep-5.6/storage/innobase/os/os0thread.cc
mysql-wsrep-5.6/storage/innobase/row/row0ftsort.cc
mysql-wsrep-5.6/storage/innobase/row/row0merge.cc
mysql-wsrep-5.6/storage/innobase/row/row0mysql.cc
mysql-wsrep-5.6/storage/innobase/srv/srv0srv.cc
mysql-wsrep-5.6/storage/innobase/trx/trx0trx.cc
mysql-wsrep-5.6/storage/perfschema/pfs.cc
mysql-wsrep-5.6/storage/perfschema/pfs_digest.cc
mysql-wsrep-5.6/storage/perfschema/pfs_digest.h
mysql-wsrep-5.6/storage/perfschema/pfs_lock.h
mysql-wsrep-5.6/storage/perfschema/table_esms_by_digest.cc
mysql-wsrep-5.6/unittest/gunit/CMakeLists.txt

index 05b48a1ba97b45223cfabfda8092c0306c440974..9e5573fa5ddbc50603653a54466830027608c3ac 100644 (file)
@@ -1,3 +1,10 @@
+mysql-wsrep-5.6 (5.6.35-0~u14.04+mos1) mos; urgency=low
+
+  * New release from codership merged with
+    https://github.com/codership/mysql-wsrep/pull/264
+
+ -- Ivan Suzdal <mos-linux@mirantis.com>  Thu, 26 Jan 2017 12:42:43 +0000
+
 mysql-wsrep-5.6 (5.6.34-0~u14.04+mos3) mos; urgency=low
 
   * Add replace for mysql-server-wsrep-core-5.6 package
diff --git a/debian/patches/fix-mysqlhotcopy-test-failure.patch b/debian/patches/fix-mysqlhotcopy-test-failure.patch
deleted file mode 100644 (file)
index 0209176..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-Description: Include return code 255 in list of valid error codes
- Perl 5.20 changed the behaviour of mysqlhotcopy to return 255 on error
- .
- Add this error code to the list of allowable return codes
-Author: James Page <james.page@ubuntu.com>
-Forwarded: no
-
---- a/mysql-test/include/mysqlhotcopy.inc
-+++ b/mysql-test/include/mysqlhotcopy.inc
-@@ -107,7 +107,7 @@ DROP DATABASE hotcopy_save;
- --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
- --list_files $MYSQLD_DATADIR/hotcopy_save
- --replace_result $MASTER_MYSOCK MASTER_MYSOCK
----error 9,11,110,2304
-+--error 9,11,110,255,2304
- --exec $MYSQLHOTCOPY --quiet -S $MASTER_MYSOCK -u root hotcopy_test hotcopy_save
- --replace_result $MASTER_MYSOCK MASTER_MYSOCK
- --exec $MYSQLHOTCOPY --quiet --allowold -S $MASTER_MYSOCK -u root hotcopy_test hotcopy_save
index c92237ffac8888d3283c8ebc30ca0a266628d8de..08ed2f90f446531e42e11465042d704012b851ef 100644 (file)
@@ -2,4 +2,3 @@ hurd.patch
 scripts__mysqld_safe.sh__signals.patch
 fix_standalone_tests.patch
 kfreebsd_tests.patch
-fix-mysqlhotcopy-test-failure.patch
index 86267fad4b8e108639b4b75447981dea3b52c4e7..929bbfc2ed14f37b0f7aa0220bbc5d58b7fbb4fa 100644 (file)
@@ -1,4 +1,4 @@
 MYSQL_VERSION_MAJOR=5
 MYSQL_VERSION_MINOR=6
-MYSQL_VERSION_PATCH=34
+MYSQL_VERSION_PATCH=35
 MYSQL_VERSION_EXTRA=
index 9623014dd9552d6ecdc361025ae54e4e2db1248d..99e9b77471022b3c92a664f590bc4214f83f784a 100644 (file)
@@ -1564,8 +1564,10 @@ static my_bool get_pidfile(MYSQL *mysql, char *pidfile)
 
   if (mysql_query(mysql, "SHOW VARIABLES LIKE 'pid_file'"))
   {
-    my_printf_error(0, "query failed; error: '%s'", error_flags,
-                   mysql_error(mysql));
+    my_printf_error(mysql_errno(mysql),
+                    "The query to get the server's pid file failed,"
+                    " error: '%s'. Continuing.", error_flags,
+                    mysql_error(mysql));
   }
   result = mysql_store_result(mysql);
   if (result)
index 2d5911402ebcf787e797043a05f11cf1ba3997a3..b691bfa1c84d27a72c1025d6effe10c11eadb34d 100644 (file)
@@ -412,7 +412,7 @@ SET(INSTALL_MYSQLTESTDIR_DEB            "mysql-test")
 SET(INSTALL_SQLBENCHDIR_DEB             ".")
 SET(INSTALL_SUPPORTFILESDIR_DEB         "support-files")
 #
-SET(INSTALL_MYSQLDATADIR_DEB            "/var/lib/mysql")
+SET(INSTALL_MYSQLDATADIR_DEB            "data")
 SET(INSTALL_PLUGINTESTDIR_DEB           ${plugin_tests})
 SET(INSTALL_SECURE_FILE_PRIVDIR_DEB     ${secure_file_priv_path})
 SET(INSTALL_SECURE_FILE_PRIV_EMBEDDEDDIR_DEB     ${secure_file_priv_embedded_path})
index 9da409feb361dd563c1ed04d9478d5d35e4293ba..f0b03f239832e3339046274900f132004dcf5308 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
 # 
 # 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
@@ -17,6 +17,33 @@ INCLUDE(CheckSymbolExists)
 INCLUDE(CheckCSourceRuns)
 INCLUDE(CheckCSourceCompiles) 
 
+# We require SunStudio 12u2 (CC 5.11)
+IF(NOT FORCE_UNSUPPORTED_COMPILER)
+  IF(CMAKE_C_COMPILER_ID MATCHES "SunPro")
+    # CC -V yields
+    # CC: Studio 12.5 Sun C++ 5.14 SunOS_sparc Dodona 2016/04/04
+    # CC: Sun C++ 5.13 SunOS_sparc Beta 2014/03/11
+    # CC: Sun C++ 5.11 SunOS_sparc 2010/08/13
+    EXECUTE_PROCESS(
+      COMMAND ${CMAKE_CXX_COMPILER} "-V"
+      OUTPUT_VARIABLE stdout
+      ERROR_VARIABLE  stderr
+      RESULT_VARIABLE result
+    )
+    STRING(REGEX MATCH "CC: Sun C\\+\\+ 5\\.([0-9]+)" VERSION_STRING ${stderr})
+    IF (NOT CMAKE_MATCH_1 OR CMAKE_MATCH_1 STREQUAL "")
+      STRING(REGEX MATCH "CC: Studio 12\\.5 Sun C\\+\\+ 5\\.([0-9]+)"
+        VERSION_STRING ${stderr})
+    ENDIF()
+    SET(CC_MINOR_VERSION ${CMAKE_MATCH_1})
+    IF(${CC_MINOR_VERSION} LESS 11)
+      MESSAGE(FATAL_ERROR "SunStudio 12u2 or newer is required!")
+    ENDIF()
+  ELSE()
+    MESSAGE(FATAL_ERROR "Unsupported compiler!")
+  ENDIF()
+ENDIF()
+
 # Enable 64 bit file offsets
 SET(_FILE_OFFSET_BITS 64)
 
@@ -29,7 +56,7 @@ SET(LIBM m)
 
 # CMake defined -lthread as thread flag. This crashes in dlopen 
 # when trying to load plugins workaround with -lpthread
-SET(CMAKE_THREADS_LIBS_INIT -lpthread CACHE INTERNAL "" FORCE)
+SET(CMAKE_THREAD_LIBS_INIT -lpthread CACHE INTERNAL "" FORCE)
 
 # Solaris specific large page support
 CHECK_SYMBOL_EXISTS(MHA_MAPSIZE_VA sys/mman.h  HAVE_DECL_MHA_MAPSIZE_VA)
index 7b60a268f7e83002832363f06b8b1b64c48f2281..974a50120231ac52d5a4065f96f07686ecc8c1a6 100644 (file)
@@ -34,7 +34,6 @@ SET(HAVE_BACKTRACE_SYMBOLS_FD CACHE  INTERNAL "")
 SET(HAVE_BMOVE CACHE  INTERNAL "")
 SET(HAVE_BSD_SIGNALS CACHE  INTERNAL "")
 SET(HAVE_BSEARCH 1 CACHE  INTERNAL "")
-SET(HAVE_BSS_START CACHE  INTERNAL "")
 SET(HAVE_CHOWN CACHE  INTERNAL "")
 SET(HAVE_CLOCK_GETTIME CACHE  INTERNAL "")
 SET(HAVE_COMPRESS CACHE  INTERNAL "")
@@ -45,7 +44,6 @@ SET(HAVE_CXX_NEW 1 CACHE  INTERNAL "")
 SET(HAVE_CXXABI_H CACHE INTERNAL "")
 SET(HAVE_DECL_MADVISE CACHE  INTERNAL "")
 SET(HAVE_DIRECTIO CACHE  INTERNAL "")
-SET(HAVE_DIRENT_H CACHE  INTERNAL "")
 SET(HAVE_DLERROR CACHE  INTERNAL "")
 SET(HAVE_DLFCN_H CACHE  INTERNAL "")
 SET(HAVE_DLOPEN CACHE  INTERNAL "")
@@ -164,7 +162,6 @@ SET(HAVE_PTHREAD_YIELD_ZERO_ARG CACHE  INTERNAL "")
 SET(HAVE_PUTENV 1 CACHE  INTERNAL "")
 SET(HAVE_PWD_H CACHE  INTERNAL "")
 SET(HAVE_RDTSCLL CACHE  INTERNAL "")
-SET(HAVE_READDIR_R CACHE  INTERNAL "")
 SET(HAVE_READLINK CACHE  INTERNAL "")
 SET(HAVE_READ_REAL_TIME CACHE  INTERNAL "")
 SET(HAVE_REALPATH CACHE  INTERNAL "")
index 71b0dc1390e0dbc9ef4a51960390fc782b6914e2..7c395168f0874701f07d2c855423c1ebe3469c16 100644 (file)
@@ -17,7 +17,7 @@
 # so WSREP_VERSION is produced regardless
 
 # Set the patch version
-SET(WSREP_PATCH_VERSION "18")
+SET(WSREP_PATCH_VERSION "19")
 
 # Obtain patch revision number
 SET(WSREP_REVISION $ENV{WSREP_REV})
index b0e7f78c36d62652c8ce91ba463ea06b501faffa..3309fe3ea0fb6ec5f112657beec20d9d963be387 100644 (file)
@@ -31,7 +31,6 @@
 #cmakedefine HAVE_CXXABI_H 1
 #cmakedefine HAVE_NCURSES_H 1
 #cmakedefine HAVE_NDIR_H 1
-#cmakedefine HAVE_DIRENT_H 1
 #cmakedefine HAVE_DLFCN_H 1
 #cmakedefine HAVE_EXECINFO_H 1
 #cmakedefine HAVE_FCNTL_H 1
 #cmakedefine HAVE_PUTENV 1
 #cmakedefine HAVE_RE_COMP 1
 #cmakedefine HAVE_REGCOMP 1
-#cmakedefine HAVE_READDIR_R 1
 #cmakedefine HAVE_READLINK 1
 #cmakedefine HAVE_REALPATH 1
 #cmakedefine HAVE_RENAME 1
 #cmakedefine HAVE_AIO_READ 1
 /* Symbols we may use */
 /* used by stacktrace functions */
-#cmakedefine HAVE_BSS_START 1
 #cmakedefine HAVE_BACKTRACE 1
 #cmakedefine HAVE_BACKTRACE_SYMBOLS 1
 #cmakedefine HAVE_BACKTRACE_SYMBOLS_FD 1
index 3ecbadf6683937a04a2ef27d98d6565091c99ee6..6559406cfa3a256943eb612e80ef78ebbb6c971e 100644 (file)
@@ -289,10 +289,14 @@ IF(UNIX)
   IF(NOT LIBRT)
     MY_SEARCH_LIBS(clock_gettime rt LIBRT)
   ENDIF()
+  MY_SEARCH_LIBS(backtrace execinfo LIBEXECINFO)
+
   FIND_PACKAGE(Threads)
 
   SET(CMAKE_REQUIRED_LIBRARIES 
-    ${LIBM} ${LIBNSL} ${LIBBIND} ${LIBCRYPT} ${LIBSOCKET} ${LIBDL} ${CMAKE_THREAD_LIBS_INIT} ${LIBRT})
+    ${LIBM} ${LIBNSL} ${LIBBIND} ${LIBCRYPT} ${LIBSOCKET} ${LIBDL}
+    ${CMAKE_THREAD_LIBS_INIT} ${LIBRT} ${LIBEXECINFO}
+  )
   # Need explicit pthread for gcc -fsanitize=address
   IF(CMAKE_USE_PTHREADS_INIT AND CMAKE_C_FLAGS MATCHES "-fsanitize=")
     SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} pthread)
@@ -343,7 +347,6 @@ CHECK_INCLUDE_FILES (aio.h HAVE_AIO_H)
 CHECK_INCLUDE_FILES (arpa/inet.h HAVE_ARPA_INET_H)
 CHECK_INCLUDE_FILES (crypt.h HAVE_CRYPT_H)
 CHECK_INCLUDE_FILES (cxxabi.h HAVE_CXXABI_H)
-CHECK_INCLUDE_FILES (dirent.h HAVE_DIRENT_H)
 CHECK_INCLUDE_FILES (dlfcn.h HAVE_DLFCN_H)
 CHECK_INCLUDE_FILES (execinfo.h HAVE_EXECINFO_H)
 CHECK_INCLUDE_FILES (fcntl.h HAVE_FCNTL_H)
@@ -565,7 +568,6 @@ CHECK_FUNCTION_EXISTS (pthread_sigmask HAVE_PTHREAD_SIGMASK)
 CHECK_FUNCTION_EXISTS (pthread_threadmask HAVE_PTHREAD_THREADMASK)
 CHECK_FUNCTION_EXISTS (pthread_yield_np HAVE_PTHREAD_YIELD_NP)
 CHECK_FUNCTION_EXISTS (putenv HAVE_PUTENV)
-CHECK_FUNCTION_EXISTS (readdir_r HAVE_READDIR_R)
 CHECK_FUNCTION_EXISTS (readlink HAVE_READLINK)
 CHECK_FUNCTION_EXISTS (re_comp HAVE_RE_COMP)
 CHECK_FUNCTION_EXISTS (regcomp HAVE_REGCOMP)
@@ -1078,14 +1080,6 @@ CHECK_CXX_SOURCE_COMPILES("
   HAVE_ABI_CXA_DEMANGLE)
 ENDIF()
 
-CHECK_C_SOURCE_COMPILES("
-  int main(int argc, char **argv) 
-  {
-    extern char *__bss_start;
-    return __bss_start ? 1 : 0;
-  }"
-HAVE_BSS_START)
-
 CHECK_C_SOURCE_COMPILES("
     int main()
     {
diff --git a/mysql-wsrep-5.6/debian/README.Maintainer b/mysql-wsrep-5.6/debian/README.Maintainer
new file mode 100644 (file)
index 0000000..b1e0a60
--- /dev/null
@@ -0,0 +1,114 @@
+
+###########################
+##     FIXME for 5.1    ##
+###########################
+
+* put this trigger-recreation thing into the init scripts -- what?!
+
+###########################################################################
+# Here are some information that are only of interest for the current and #
+# following Debian maintainers of MySQL.                                  #
+###########################################################################
+
+The debian/ directory is under SVN control, see debian/control for URL.
+
+#
+# Preparing a new version
+#
+The new orig.tar.gz (without non-free documentation) is created in /tmp/ when
+running this command:
+debian/rules get-orig-source
+
+#
+# mysqlreport
+#
+The authors e-mail address is <public@codenode.com>.
+
+#
+# Remarks to dependencies
+#
+libwrap0-dev (>= 7.6-8.3)
+       According to bug report 114582 where where build problems on
+       IA-64/sid with at least two prior versions.
+psmisc
+       /usr/bin/killall in the initscript
+
+zlib1g in libmysqlclient-dev:  
+       "mysql_config --libs" ads "-lz"
+
+Build-Dep:
+
+debhelper (>=4.1.16):
+       See po-debconf(7).
+
+autoconf (>= 2.13-20), automake1.7
+       Try to get rid of them.
+
+doxygen, tetex-bin, tetex-extra, gs
+       for ndb/docs/*tex
+
+#
+# Remarks to the start scripts
+#
+
+## initscripts rely on mysqladmin from a different package
+We have the problem that "/etc/init.d/mysql stop" relies on mysqladmin which
+is in another package (mysql-client) and a passwordless access that's maybe
+only available if the user configured his /root/.my.cnf. Can this be a problem?
+* normal mode: not because the user is required to have it. Else:
+* purge/remove: not, same as normal mode
+* upgrade: not, same as normal mode
+* first install: not, it depends on mysql-client which at least is unpacked
+                 so mysqladmin is there (to ping). It is not yet configured
+               passwordles but if there's a server running then there's a
+                /root/.my.cnf. Anyways, we simply kill anything that's mysqld.
+
+## Passwordless access for the maintainer scripts
+Another issue is that the scripts needs passwordless access. To ensure this
+a debian-sys-maint user is configured which has process and shutdown privs.
+The file with the randomly (that's important!) generated password must be
+present as long as the databases remain installed because else a new install
+would have no access. This file should be used like:
+       mysqladmin --defaults-file=/etc/mysql/debian.cnf restart
+to avoid providing the password in plaintext on a commandline where it would 
+be visible to any user via the "ps" command.
+
+## When to start the daemon?
+We aim to give the admin full control on when MySQL is running.
+Issues to be faced here:
+OLD:
+        1. Debconf asks whether MySQL should be started on boot so update-rc.d is
+           only run if the answer has been yes. The admin is likely to forget
+           this decision but update-rc.d checks for an existing line in
+           /etc/runlevel.conf and leaves it intact.
+        2. On initial install, if the answer is yes, the daemon has to be started.
+        3. On upgrades it should only be started if it was already running, everything
+           else is confusing. Especiall relying on an debconf decision made month ago
+           is considered suboptimal. See bug #274264
+        Implementation so far:
+        prerm (called on upgrade before stopping the server): 
+          check for a running server and set flag if necessary
+        preinst (called on initial install and before unpacking when upgrading):
+          check for the debconf variable and set flag if necessary
+        postinst (called on initial install and after each upgrade after unpacking):
+          call update-rc.d if debconf says yes
+          call invoce-rc.d if the flag has been set
+        Problems remaining:
+          dpkg-reconfigure and setting mysql start on boot to yes did not start mysql
+          (ok "start on boot" literally does not mean "start now" so that might have been ok)
+NEW:
+        1. --- no debconf anymore for the sake of simplicity. We have runlevel.conf,
+           the admin should use it
+        2. On initial install the server is started.
+        3. On upgrades the server is started exactly if it was running before so the
+           runlevel configuration is irrelevant. It will be preserved by the mean of
+           update-rc.d's builtin check.
+        Implementation:
+        prerm (called on upgrade before stopping the server):
+          check for a running server and set flag if necessary
+        preinst (called on initial install and before unpacking when upgrading):
+          check for $1 beeing (initial) "install" and set flag
+        postinst (called on initial install and after each upgrade after unpacking):
+          call update-rc.d
+          call invoce-rc.d if the flag has been set
diff --git a/mysql-wsrep-5.6/debian/additions/Docs__Images__Makefile.in b/mysql-wsrep-5.6/debian/additions/Docs__Images__Makefile.in
new file mode 100644 (file)
index 0000000..f7316d4
--- /dev/null
@@ -0,0 +1,6 @@
+all:
+
+distclean:
+       -rm -f Makefile
+
+.PHONY: all distclean clean install check
diff --git a/mysql-wsrep-5.6/debian/additions/Docs__Makefile.in b/mysql-wsrep-5.6/debian/additions/Docs__Makefile.in
new file mode 100644 (file)
index 0000000..f7316d4
--- /dev/null
@@ -0,0 +1,6 @@
+all:
+
+distclean:
+       -rm -f Makefile
+
+.PHONY: all distclean clean install check
diff --git a/mysql-wsrep-5.6/debian/additions/debian-start b/mysql-wsrep-5.6/debian/additions/debian-start
new file mode 100644 (file)
index 0000000..1ea1207
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+#
+# This script is executed by "/etc/init.d/mysql" on every (re)start.
+# 
+# Changes to this file will be preserved when updating the Debian package.
+#
+
+source /usr/share/mysql/debian-start.inc.sh
+
+MYSQL="/usr/bin/mysql --defaults-file=/etc/mysql/debian.cnf"
+MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
+MYUPGRADE="/usr/bin/mysql_upgrade --defaults-extra-file=/etc/mysql/debian.cnf"
+MYCHECK="/usr/bin/mysqlcheck --defaults-file=/etc/mysql/debian.cnf"
+MYCHECK_SUBJECT="WARNING: mysqlcheck has found corrupt tables"
+MYCHECK_PARAMS="--all-databases --fast --silent"
+MYCHECK_RCPT="root"
+
+# The following commands should be run when the server is up but in background
+# where they do not block the server start and in one shell instance so that
+# they run sequentially. They are supposed not to echo anything to stdout.
+# If you want to disable the check for crashed tables comment
+# "check_for_crashed_tables" out.  
+# (There may be no output to stdout inside the background process!)
+echo "Checking for tables which need an upgrade, are corrupt or were "
+echo "not closed cleanly."
+(
+  upgrade_system_tables_if_necessary;
+  check_root_accounts;
+  check_for_crashed_tables;
+) >&2 &
+
+exit 0
diff --git a/mysql-wsrep-5.6/debian/additions/debian-start.inc.sh b/mysql-wsrep-5.6/debian/additions/debian-start.inc.sh
new file mode 100644 (file)
index 0000000..f507128
--- /dev/null
@@ -0,0 +1,72 @@
+#!/bin/bash
+#
+# This file is included by /etc/mysql/debian-start
+#
+
+## Check all unclosed tables.
+# - Requires the server to be up.
+# - Is supposed to run silently in background. 
+function check_for_crashed_tables() {
+  set -e
+  set -u
+
+  # But do it in the background to not stall the boot process.
+  logger -p daemon.info -i -t$0 "Triggering myisam-recover for all MyISAM tables"
+
+  # Checking for $? is unreliable so the size of the output is checked.
+  # Some table handlers like HEAP do not support CHECK TABLE.
+  tempfile=`tempfile`
+  # We have to use xargs in this case, because a for loop barfs on the 
+  # spaces in the thing to be looped over. 
+  LC_ALL=C $MYSQL --skip-column-names --batch -e  '
+      select concat('\''select count(*) into @discard from `'\'',
+                    TABLE_SCHEMA, '\''`.`'\'', TABLE_NAME, '\''`'\'') 
+      from information_schema.TABLES where ENGINE='\''MyISAM'\' | \
+    xargs -i $MYSQL --skip-column-names --silent --batch \
+                    --force -e "{}" >$tempfile 
+  if [ -s $tempfile ]; then
+    (
+      /bin/echo -e "\n" \
+        "Improperly closed tables are also reported if clients are accessing\n" \
+       "the tables *now*. A list of current connections is below.\n";
+       $MYADMIN processlist status
+    ) >> $tempfile
+    # Check for presence as a dependency on mailx would require an MTA.
+    if [ -x /usr/bin/mailx ]; then 
+      mailx -e -s"$MYCHECK_SUBJECT" $MYCHECK_RCPT < $tempfile 
+    fi
+    (echo "$MYCHECK_SUBJECT"; cat $tempfile) | logger -p daemon.warn -i -t$0
+  fi
+  rm $tempfile
+}
+
+## Check for tables needing an upgrade.
+# - Requires the server to be up.
+# - Is supposed to run silently in background. 
+function upgrade_system_tables_if_necessary() {
+  set -e
+  set -u
+
+  logger -p daemon.info -i -t$0 "Upgrading MySQL tables if necessary."
+
+  # Filter all "duplicate column", "duplicate key" and "unknown column"
+  # errors as the script is designed to be idempotent.
+  LC_ALL=C $MYUPGRADE \
+    2>&1 \
+    | egrep -v '^(1|@had|ERROR (1054|1060|1061))' \
+    | logger -p daemon.warn -i -t$0
+}
+
+## Check for the presence of both, root accounts with and without password.
+# This might have been caused by a bug related to mysql_install_db (#418672).
+function check_root_accounts() {
+  set -e
+  set -u
+  
+  logger -p daemon.info -i -t$0 "Checking for insecure root accounts."
+
+  ret=$( echo "SELECT count(*) FROM mysql.user WHERE user='root' and password='';" | $MYSQL --skip-column-names )
+  if [ "$ret" -ne "0" ]; then
+    logger -p daemon.warn -i -t$0 "WARNING: mysql.user contains $ret root accounts without password!"
+  fi
+}
diff --git a/mysql-wsrep-5.6/debian/additions/debian_create_root_user.sql b/mysql-wsrep-5.6/debian/additions/debian_create_root_user.sql
new file mode 100644 (file)
index 0000000..fd45cec
--- /dev/null
@@ -0,0 +1,23 @@
+-- Get the hostname, if the hostname has any wildcard character like "_" or "%"
+-- add escape character in front of wildcard character to convert "_" or "%" to
+-- a plain character
+SET @get_hostname= @@hostname;
+SELECT REPLACE((SELECT REPLACE(@get_hostname,'_','\_')),'%','\%') INTO @current_hostname;
+
+-- Fill "user" table with default users allowing root access
+-- from local machine if "user" table didn't exist before
+CREATE TEMPORARY TABLE tmp_user LIKE user;
+INSERT INTO tmp_user VALUES ('localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N');
+REPLACE INTO tmp_user SELECT @current_hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N' FROM dual WHERE LOWER( @current_hostname) != 'localhost';
+REPLACE INTO tmp_user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N');
+REPLACE INTO tmp_user VALUES ('::1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0,'','','N');
+INSERT INTO user SELECT * FROM tmp_user WHERE @had_user_table=0;
+DROP TABLE tmp_user;
+
+CREATE TEMPORARY TABLE tmp_proxies_priv LIKE proxies_priv;
+INSERT INTO tmp_proxies_priv VALUES ('localhost', 'root', '', '', TRUE, '', now());
+REPLACE INTO tmp_proxies_priv SELECT @current_hostname, 'root', '', '', TRUE, '', now() FROM DUAL WHERE LOWER (@current_hostname) != 'localhost';
+INSERT INTO  proxies_priv SELECT * FROM tmp_proxies_priv WHERE @had_proxies_priv_table=0;
+DROP TABLE tmp_proxies_priv;
+FLUSH PRIVILEGES;
+
diff --git a/mysql-wsrep-5.6/debian/additions/echo_stderr b/mysql-wsrep-5.6/debian/additions/echo_stderr
new file mode 100644 (file)
index 0000000..67b3ed7
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+echo "$*" 1>&2
diff --git a/mysql-wsrep-5.6/debian/additions/innotop/changelog.innotop b/mysql-wsrep-5.6/debian/additions/innotop/changelog.innotop
new file mode 100644 (file)
index 0000000..ab4c154
--- /dev/null
@@ -0,0 +1,357 @@
+Changelog for innotop:
+
+2009-03-09: version 1.7.1
+
+   Changes:
+   * Don't display the CXN column if only one connection is active in 
+     the current view
+
+   Bugs fixed:
+   * fixed bug where trying to aggregate the time column would result 
+     in a crash if the time column had an undef value in it, which is 
+     the case when a thread is in the 'Connect' state
+   * updated innotop.spec file to reflect current version
+
+2009-02-23: version 1.7.0
+
+   Changes:
+   * supports a central config (/etc/innotop/innotop.conf)
+   * changed the default home directory config to ~/.innotop/innotop.conf
+     (away from .ini)
+   * embedded InnoDBParser.pm into innotop so it can be run with no 
+     installation
+   * no longer writes a new config file by default
+   * added --skipcentral (skip reading central config) and --write (write
+     a config if none were loaded at start-up)
+   * if no config file is loaded, connect to a MySQL database on
+     localhost using mysql_read_default_group=client
+   * embedded maatkit's DSNParser.pm and added support for --user,
+     --password, --host, --port
+   * changed default mode from T (InnoDB Transactions) to Q (Query List)
+   * in addition to connected threads, now displays running and cached
+     threads in statusbar
+   * don't load connections from a config file if any DSN information or
+     a username or password is specified on the command-line
+   
+   Bugs fixed:
+   * fixed bug preventing utilization of command-line options that
+     override default config settings if no config file was loaded
+   * fixed a bug where migrating from an old version of the config will
+     delete ~/innotop.ini, if it exists.  Now uses File::Temp::tempfile().
+
+2007-11-09: version 1.6.0
+
+   * S mode crashed on non-numeric values.
+   * New user-defined columns crashed upon restart.
+   * Added --color option to control terminal coloring.
+
+2007-09-18: version 1.5.2
+
+   * Added the ability to monitor InnoDB status from a file.
+   * Changed W mode to L mode; it monitors all locks, not just lock waits.
+
+2007-09-16: version 1.5.1
+
+   * Added C (Command Summary) mode.
+   * Fixed a bug in the 'avg' aggregate function.
+
+2007-09-10: version 1.5.0
+
+   Changes:
+   * Added plugin functionality.
+   * Added group-by functionality.
+   * Moved the configuration file to a directory.
+   * Enhanced filtering and sorting on pivoted tables.
+   * Many small bug fixes.
+
+2007-07-16: version 1.4.3
+
+   Changes:
+   * Added standard --version command-line option
+   * Changed colors to cyan instead of blue; more visible on dark terminals.
+   * Added information to the filter-choosing dialog.
+   * Added column auto-completion when entering a filter expression.
+   * Changed Term::ReadKey from optional to mandatory.
+   * Clarified username in password prompting.
+   * Ten thousand words of documentation!
+
+   Bugs fixed:
+   * innotop crashed in W mode when InnoDB status data was truncated.
+   * innotop didn't display errors in tables if debug was enabled.
+   * The colored() subroutine wasn't being created in non-interactive mode.
+   * Don't prompt to save password except the first time.
+
+2007-05-03: version 1.4.2
+
+   This version contains all changes to the trunk until revision 239; some
+   changes in revisions 240:250 are included.
+
+   MAJOR CHANGES:
+
+   * Quick-filters to easily filter any column in any display
+   * Compatibility with MySQL 3.23 through 6.0
+   * Improved error handling when a server is down, permissions denied, etc
+   * Use additional SHOW INNODB STATUS information in 5.1.x
+   * Make all modes use tables consistently, so they can all be edited,
+     filtered, colored and sorted consistently
+   * Combine V, G and S modes into S mode, with v, g, and s hot-keys
+   * Let DBD driver read MySQL option files; permit connections without
+     user/pass/etc
+   * Compile SQL-like expressions into Perl subroutines; eliminate need to
+     know Perl
+   * Do not save all config data to config file, only save user's customizations
+   * Rewritten and improved command-line option handling
+   * Added --count, --delay, and other command-line options to support
+     run-and-exit operation
+   * Improve built-in variable sets
+   * Improve help screen with three-part balanced-column layout
+   * Simplify table-editor and improve hotkey support
+   * Require Perl to have high-resolution time support (Time::HiRes)
+   * Help the user choose a query to analyze or kill
+   * Enable EXPLAIN, show-full-query in T mode just like Q mode
+   * Let data-extraction access current, previous and incremental data sets
+     all at once
+
+   MINOR CHANGES:
+
+   * Column stabilizing for Q mode
+   * New color rules for T, Q, W modes
+   * Apply slave I/O filter to Q mode
+   * Improve detection of server version and other meta-data
+   * Make connection timeout a config variable
+   * Improve cross-version-compatible SQL syntax
+   * Get some information from the DBD driver instead of asking MySQL for it
+   * Improved error messages
+   * Improve server group creation/editing
+   * Improve connection/thread killing
+   * Fix broken key bindings and restore previously mapped hot-keys for
+     choosing columns
+   * Some documentation updates (but not nearly enough)
+   * Allow the user to specify graphing char in S mode (formerly G mode)
+   * Allow easy switching between variable sets in S mode
+   * Bind 'n' key globally to choose the 'next' server connection
+   * Bind '%' key globally to filter displayed tables
+   * Allow aligning columns on the decimal place for easy readability
+   * Add hide_hdr config variable to hide column headers in tables
+   * Add a feature to smartly run PURGE MASTER LOGS in Replication mode
+   * Enable debug mode as a globally configurable variable
+   * Improve error messages when an expression or filter doesn't compile or has
+     a run-time error; die on error when debug is enabled
+   * Allow user-configurable delays after executing SQL (to let the server
+     settle down before taking another measurement)
+   * Add an expression to show how long until a transaction is finished
+   * Add skip_innodb as a global config variable
+   * Add '%' after percentages to help disambiguate (user-configurable)
+   * Add column to M mode to help see how fast slave is catching up to master
+
+   BUG FIXES:
+
+   * T and W modes had wrong value for wait_status column
+   * Error tracking on connections didn't reset when the connection recovered
+   * wait_timeout on connections couldn't be set before MySQL 4.0.3
+   * There was a crash on 3.23 when wiping deadlocks
+   * Lettercase changes in some result sets (SHOW MASTER/SLAVE STATUS) between
+     MySQL versions crashed innotop
+   * Inactive connections crashed innotop upon access to DBD driver
+   * set_precision did not respect user defaults for number of digits
+   * --inc command-line option could not be negated
+   * InnoDB status parsing was not always parsing all needed information
+   * S mode (formerly G mode) could crash trying to divide non-numeric data
+   * M table didn't show Slave_open_temp_tables variable; incorrect lettercase
+   * DBD drivers with broken AutoCommit would crash innotop
+   * Some key bindings had incorrect labels
+   * Some config-file loading routines could load data for things that didn't
+     exist
+   * Headers printed too often in S mode
+   * High-resolution time was not used even when the user had it
+   * Non-interactive mode printed blank lines sometimes
+   * Q-mode header and statusbar showed different QPS numbers
+   * Formulas for key-cache and query-cache hit ratios were wrong
+   * Mac OS "Darwin" machines were mis-identified as Microsoft Windows
+   * Some multiplications crashed when given undefined input
+   * The commify transformation did not check its input and could crash
+   * Specifying an invalid mode on the command line or config file could crash
+     innotop
+
+2007-03-29: version 1.4.1
+
+   * More tweaks to display of connection errors.
+   * Fixed a problem with skip-innodb in MySQL 5.1.
+   * Fix a bug with dead connections in single-connection mode.
+   * Fix a regex to allow parsing more data from truncated deadlocks.
+   * Don't load active cxns from the config file if the cxn isn't defined.
+
+2007-03-03: version 1.4.0
+
+   * Further tweak error handling and display of connection errors
+   * More centralization of querying
+   * Fix forking so it doesn't kill all database connections
+   * Allow user to run innotop without permissions for GLOBAL variables and status
+
+2007-02-11: version 1.3.6
+
+   * Handle some connection failures so innotop doesn't crash because of one server.
+   * Enable incremental display in more modes.
+   * Tweaks to colorizing, color editor, and default color rules.
+   * Tweaks to default sorting rules.
+   * Use prepared statements for efficiency.
+   * Bug fixes and code cleanups.
+   * Data storage is keyed on clock ticks now.
+
+2007-02-03: version 1.3.5
+
+   * Bug fixes.
+   * More tools for editing configuration from within innotop.
+   * Filters and transformations are constrained to valid values.
+   * Support for colorizing rows.
+   * Sorting by multiple columns.
+   * Compress headers when display is very wide.
+   * Stabilize and limit column widths.
+   * Check config file formats when upgrading so upgrades go smoothly.
+   * Make D mode handle many connections at once.
+   * Extract simple expressions from data sets in column src property.
+     This makes innotop more awk-ish.
+
+2007-01-16: version 1.3
+
+   * Readline support.
+   * Can be used unattended, or in a pipe-and-filter mode
+     where it outputs tab-separated data to standard output.
+   * You can specify a config file on the command line.
+     Config files can be marked read-only.
+   * Monitor multiple servers simultaneously.
+   * Server groups to help manage many servers conveniently.
+   * Monitor master/slave status, and control slaves.
+   * Columns can have user-defined expressions as their data sources.
+   * Better configuration tools.
+   * InnoDB status information is merged into SHOW VARIABLES and
+     SHOW STATUS information, so you can access it all together.
+   * High-precision time support in more places.
+   * Lots of tweaks to make things display more readably and compactly.
+   * Column transformations and filters.
+
+2007-01-16: version 1.0.1
+   * NOTE: innotop is now hosted at Sourceforge, in Subversion not CVS.
+     The new project homepage is http://sourceforge.net/projects/innotop/
+   * Tweak default T/Q mode sort columns to match what people expect.
+   * Fix broken InnoDBParser.pm documentation (and hence man page).
+
+2007-01-06: version 1.0
+   * NOTE: innotop is now hosted at Sourceforge, in Subversion not CVS.
+     The new project homepage is http://sourceforge.net/projects/innotop/
+   * Prevent control characters from freaking terminal out.
+   * Set timeout to keep busy servers from closing connection.
+   * There is only one InnoDB insert buffer.
+   * Make licenses clear and consistent.
+
+2006-11-14: innotop 0.1.160, InnoDBParser version 1.69
+   * Support for ANSI color on Microsoft Windows (more readable, compact
+     display; thanks Gisbert W. Selke).
+   * Better handling of $ENV{HOME} on Windows.
+   * Added a LICENSE file to the package as per Gentoo bug:
+     http://bugs.gentoo.org/show_bug.cgi?id=147600
+
+2006-11-11: innotop 0.1.157, InnoDBParser version 1.69
+   * Add Microsoft Windows support.
+
+2006-10-19: innotop 0.1.154, InnoDBParser version 1.69
+   * Add O (Open Tables) mode
+   * Add some more checks to handle incomplete InnoDB status information
+
+2006-09-30: innotop 0.1.152, InnoDBParser version 1.69
+   * Figured out what was wrong with package $VERSION variable: it wasn't
+     after the package declaration!
+
+2006-09-28: innotop 0.1.152, InnoDBParser version 1.67
+   * Make more efforts towards crash-resistance and tolerance of completely
+     messed-up inputs.  If innotop itself is broken, it is now much harder to
+     tell, because it just keeps on running without complaining.
+   * Fix a small bug parsing out some information and displaying it.
+
+2006-09-05: innotop 0.1.149, InnoDBParser version 1.64
+   * Try to find and eliminate any parsing code that assumes pattern matches
+     will succeed.
+
+2006-09-05: innotop 0.1.149, InnoDBParser version 1.62
+   * Make innotop crash-resistant, so I can declare it STABLE finally.
+   * Instead of using SQL conditional comments, detect MySQL version.
+
+2006-08-22: innotop 0.1.147, InnoDBParser version 1.60
+   * Fix some innotop bugs with undefined values, bad formatting etc.
+
+2006-08-19: innotop 0.1.146, InnoDBParser version 1.60
+   * Make innotop handle some unexpected NULL values in Q mode.
+   * Add OS wait information to W mode, so it is now "everything that waits."
+   * Center section captions better.
+   * Make R mode more readable and compact.
+   * Make InnoDBParser parse lock waits even when they've been waiting 0 secs.
+
+2006-08-12: innotop 0.1.139, InnoDBParser version 1.59
+   * Add more documentation
+   * Tweak V mode to show more info in less space.
+   * Fix a bug in G mode.
+
+2006-08-10: innotop 0.1.132, InnoDBParser version 1.58
+   * Handle yet more types of FK error... it will never end!
+   * Handle some special cases when DEADLOCK info truncated
+   * Add a bit more FK info to F mode in innotop
+   * More tests added to the test suite
+
+2006-08-07: innotop 0.1.131, InnoDBParser version 1.55
+   * Fix another issue with configuration
+   * Handle another type of FK error
+
+2006-08-03: innotop 0.1.130, InnoDBParser version 1.54
+   * Fix an issue loading config file
+   * Add heap_no to 'D' (InnoDB Deadlock) mode to ease deadlock debugging.
+
+2006-08-02: innotop 0.1.128, InnoDBParser version 1.54
+   * Parse lock wait information from the TRANSACTION section.
+   * Even more OS-specific parsing... pain in the butt...
+   * Add 'W' (InnoDB Lock Wait) mode.
+   * Fix some minor display issues with statusbar.
+
+2006-08-02: innotop 0.1.125, InnoDBParser version 1.50
+   * Don't try to get references to Perl built-in functions like time()
+   * Handle more OS-specific variations of InnoDB status text
+   * Add some more information to various places in innotop
+
+2006-08-01: innotop 0.1.123, InnoDBParser version 1.47
+
+   * Enhance S and G modes: clear screen and re-print headers
+   * Don't crash when deadlock data is truncated
+   * Make Analyze mode say how to get back to whatever you came from
+   * Display 'nothing to display' when there is nothing
+   * Add ability to read InnoDB status text from a file (mostly helps test)
+   * Add table of Wait Array Information in Row Op/Semaphore mode
+   * Add table of lock information in InnoDB deadlock mode
+   * Ensure new features in upgrades don't get masked by existing config files
+   * Tweak default column choices for T mode
+   * Enhance foreign key parsing
+   * Enhance physical record and data tuple parsing
+   * Enhance lock parsing (handle old-style and new-style formats)
+
+2006-07-24: innotop 0.1.112, InnoDBParser version 1.36
+
+   * InnoDBParser enhancements for FK error messages.
+   * A fix to innotop to prevent it from crashing while trying to display a FK
+     error message.
+   * Some minor cosmetic changes to number formatting in innotop.
+
+2006-07-22: innotop 0.1.106, InnoDBParser version 1.35
+
+   * InnoDBParser is much more complete and accurate.
+   * Tons of bug fixes.
+   * Add partitions to EXPLAIN mode.
+   * Enhance Q mode header, add T mode header.
+   * Share some configuration variables across modes.
+   * Add formatted time columns to Q, T modes.
+   * Add command-line argument parsing.
+   * Turn off echo when asking for password.
+   * Add option to specify port when connecting.
+   * Let display-optimized-query display multiple notes.
+   * Lots of small improvements, such as showing more info in statusbar.
+
+2006-07-02: innotop 0.1.74, InnoDBParser version 1.24
+
+   * Initial release for public consumption.
diff --git a/mysql-wsrep-5.6/debian/additions/innotop/innotop b/mysql-wsrep-5.6/debian/additions/innotop/innotop
new file mode 100644 (file)
index 0000000..646f0d7
--- /dev/null
@@ -0,0 +1,10946 @@
+#!/usr/bin/perl
+
+# vim: tw=160:nowrap:expandtab:tabstop=3:shiftwidth=3:softtabstop=3
+
+# This program is copyright (c) 2006 Baron Schwartz, baron at xaprb dot com.
+# Feedback and improvements are gratefully received.
+#
+# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+#
+# 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; OR the Perl Artistic License.  On UNIX and similar
+# systems, you can issue `man perlgpl' or `man perlartistic' to read these
+
+# 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., 59 Temple
+# Place, Suite 330, Boston, MA  02111-1307  USA
+
+use strict;
+use warnings FATAL => 'all';
+
+our $VERSION = '1.7.1';
+
+# Find the home directory; it's different on different OSes.
+our $homepath = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.';
+
+# Configuration files
+our $default_home_conf = "$homepath/.innotop/innotop.conf";
+our $default_central_conf = "/etc/innotop/innotop.conf";
+our $conf_file = "";
+
+## Begin packages ##
+
+package DSNParser;
+
+use DBI;
+use Data::Dumper;
+$Data::Dumper::Indent    = 0;
+$Data::Dumper::Quotekeys = 0;
+use English qw(-no_match_vars);
+
+use constant MKDEBUG => $ENV{MKDEBUG};
+
+# Defaults are built-in, but you can add/replace items by passing them as
+# hashrefs of {key, desc, copy, dsn}.  The desc and dsn items are optional.
+# You can set properties with the prop() sub.  Don't set the 'opts' property.
+sub new {
+   my ( $class, @opts ) = @_;
+   my $self = {
+      opts => {
+         A => {
+            desc => 'Default character set',
+            dsn  => 'charset',
+            copy => 1,
+         },
+         D => {
+            desc => 'Database to use',
+            dsn  => 'database',
+            copy => 1,
+         },
+         F => {
+            desc => 'Only read default options from the given file',
+            dsn  => 'mysql_read_default_file',
+            copy => 1,
+         },
+         h => {
+            desc => 'Connect to host',
+            dsn  => 'host',
+            copy => 1,
+         },
+         p => {
+            desc => 'Password to use when connecting',
+            dsn  => 'password',
+            copy => 1,
+         },
+         P => {
+            desc => 'Port number to use for connection',
+            dsn  => 'port',
+            copy => 1,
+         },
+         S => {
+            desc => 'Socket file to use for connection',
+            dsn  => 'mysql_socket',
+            copy => 1,
+         },
+         u => {
+            desc => 'User for login if not current user',
+            dsn  => 'user',
+            copy => 1,
+         },
+      },
+   };
+   foreach my $opt ( @opts ) {
+      MKDEBUG && _d('Adding extra property ' . $opt->{key});
+      $self->{opts}->{$opt->{key}} = { desc => $opt->{desc}, copy => $opt->{copy} };
+   }
+   return bless $self, $class;
+}
+
+# Recognized properties:
+# * autokey:   which key to treat a bareword as (typically h=host).
+# * dbidriver: which DBI driver to use; assumes mysql, supports Pg.
+# * required:  which parts are required (hashref).
+# * setvars:   a list of variables to set after connecting
+sub prop {
+   my ( $self, $prop, $value ) = @_;
+   if ( @_ > 2 ) {
+      MKDEBUG && _d("Setting $prop property");
+      $self->{$prop} = $value;
+   }
+   return $self->{$prop};
+}
+
+sub parse {
+   my ( $self, $dsn, $prev, $defaults ) = @_;
+   if ( !$dsn ) {
+      MKDEBUG && _d('No DSN to parse');
+      return;
+   }
+   MKDEBUG && _d("Parsing $dsn");
+   $prev     ||= {};
+   $defaults ||= {};
+   my %given_props;
+   my %final_props;
+   my %opts = %{$self->{opts}};
+   my $prop_autokey = $self->prop('autokey');
+
+   # Parse given props
+   foreach my $dsn_part ( split(/,/, $dsn) ) {
+      if ( my ($prop_key, $prop_val) = $dsn_part =~  m/^(.)=(.*)$/ ) {
+         # Handle the typical DSN parts like h=host, P=3306, etc.
+         $given_props{$prop_key} = $prop_val;
+      }
+      elsif ( $prop_autokey ) {
+         # Handle barewords
+         MKDEBUG && _d("Interpreting $dsn_part as $prop_autokey=$dsn_part");
+         $given_props{$prop_autokey} = $dsn_part;
+      }
+      else {
+         MKDEBUG && _d("Bad DSN part: $dsn_part");
+      }
+   }
+
+   # Fill in final props from given, previous, and/or default props
+   foreach my $key ( keys %opts ) {
+      MKDEBUG && _d("Finding value for $key");
+      $final_props{$key} = $given_props{$key};
+      if (   !defined $final_props{$key}
+           && defined $prev->{$key} && $opts{$key}->{copy} )
+      {
+         $final_props{$key} = $prev->{$key};
+         MKDEBUG && _d("Copying value for $key from previous DSN");
+      }
+      if ( !defined $final_props{$key} ) {
+         $final_props{$key} = $defaults->{$key};
+         MKDEBUG && _d("Copying value for $key from defaults");
+      }
+   }
+
+   # Sanity check props
+   foreach my $key ( keys %given_props ) {
+      die "Unrecognized DSN part '$key' in '$dsn'\n"
+         unless exists $opts{$key};
+   }
+   if ( (my $required = $self->prop('required')) ) {
+      foreach my $key ( keys %$required ) {
+         die "Missing DSN part '$key' in '$dsn'\n" unless $final_props{$key};
+      }
+   }
+
+   return \%final_props;
+}
+
+sub as_string {
+   my ( $self, $dsn ) = @_;
+   return $dsn unless ref $dsn;
+   return join(',',
+      map  { "$_=" . ($_ eq 'p' ? '...' : $dsn->{$_}) }
+      grep { defined $dsn->{$_} && $self->{opts}->{$_} }
+      sort keys %$dsn );
+}
+
+sub usage {
+   my ( $self ) = @_;
+   my $usage
+      = "DSN syntax is key=value[,key=value...]  Allowable DSN keys:\n"
+      . "  KEY  COPY  MEANING\n"
+      . "  ===  ====  =============================================\n";
+   my %opts = %{$self->{opts}};
+   foreach my $key ( sort keys %opts ) {
+      $usage .= "  $key    "
+             .  ($opts{$key}->{copy} ? 'yes   ' : 'no    ')
+             .  ($opts{$key}->{desc} || '[No description]')
+             . "\n";
+   }
+   if ( (my $key = $self->prop('autokey')) ) {
+      $usage .= "  If the DSN is a bareword, the word is treated as the '$key' key.\n";
+   }
+   return $usage;
+}
+
+# Supports PostgreSQL via the dbidriver element of $info, but assumes MySQL by
+# default.
+sub get_cxn_params {
+   my ( $self, $info ) = @_;
+   my $dsn;
+   my %opts = %{$self->{opts}};
+   my $driver = $self->prop('dbidriver') || '';
+   if ( $driver eq 'Pg' ) {
+      $dsn = 'DBI:Pg:dbname=' . ( $info->{D} || '' ) . ';'
+         . join(';', map  { "$opts{$_}->{dsn}=$info->{$_}" }
+                     grep { defined $info->{$_} }
+                     qw(h P));
+   }
+   else {
+      $dsn = 'DBI:mysql:' . ( $info->{D} || '' ) . ';'
+         . join(';', map  { "$opts{$_}->{dsn}=$info->{$_}" }
+                     grep { defined $info->{$_} }
+                     qw(F h P S A))
+         . ';mysql_read_default_group=client';
+   }
+   MKDEBUG && _d($dsn);
+   return ($dsn, $info->{u}, $info->{p});
+}
+
+
+# Fills in missing info from a DSN after successfully connecting to the server.
+sub fill_in_dsn {
+   my ( $self, $dbh, $dsn ) = @_;
+   my $vars = $dbh->selectall_hashref('SHOW VARIABLES', 'Variable_name');
+   my ($user, $db) = $dbh->selectrow_array('SELECT USER(), DATABASE()');
+   $user =~ s/@.*//;
+   $dsn->{h} ||= $vars->{hostname}->{Value};
+   $dsn->{S} ||= $vars->{'socket'}->{Value};
+   $dsn->{P} ||= $vars->{port}->{Value};
+   $dsn->{u} ||= $user;
+   $dsn->{D} ||= $db;
+}
+
+sub get_dbh {
+   my ( $self, $cxn_string, $user, $pass, $opts ) = @_;
+   $opts ||= {};
+   my $defaults = {
+      AutoCommit        => 0,
+      RaiseError        => 1,
+      PrintError        => 0,
+      mysql_enable_utf8 => ($cxn_string =~ m/charset=utf8/ ? 1 : 0),
+   };
+   @{$defaults}{ keys %$opts } = values %$opts;
+   my $dbh;
+   my $tries = 2;
+   while ( !$dbh && $tries-- ) {
+      eval {
+         MKDEBUG && _d($cxn_string, ' ', $user, ' ', $pass, ' {',
+            join(', ', map { "$_=>$defaults->{$_}" } keys %$defaults ), '}');
+         $dbh = DBI->connect($cxn_string, $user, $pass, $defaults);
+         # Immediately set character set and binmode on STDOUT.
+         if ( my ($charset) = $cxn_string =~ m/charset=(\w+)/ ) {
+            my $sql = "/*!40101 SET NAMES $charset*/";
+            MKDEBUG && _d("$dbh: $sql");
+            $dbh->do($sql);
+            MKDEBUG && _d('Enabling charset for STDOUT');
+            if ( $charset eq 'utf8' ) {
+               binmode(STDOUT, ':utf8')
+                  or die "Can't binmode(STDOUT, ':utf8'): $OS_ERROR";
+            }
+            else {
+               binmode(STDOUT) or die "Can't binmode(STDOUT): $OS_ERROR";
+            }
+         }
+      };
+      if ( !$dbh && $EVAL_ERROR ) {
+         MKDEBUG && _d($EVAL_ERROR);
+         if ( $EVAL_ERROR =~ m/not a compiled character set|character set utf8/ ) {
+            MKDEBUG && _d("Going to try again without utf8 support");
+            delete $defaults->{mysql_enable_utf8};
+         }
+         if ( !$tries ) {
+            die $EVAL_ERROR;
+         }
+      }
+   }
+   # If setvars exists and it's MySQL connection, set them
+   my $setvars = $self->prop('setvars');
+   if ( $cxn_string =~ m/mysql/i && $setvars ) {
+      my $sql = "SET $setvars";
+      MKDEBUG && _d("$dbh: $sql");
+      eval {
+         $dbh->do($sql);
+      };
+      if ( $EVAL_ERROR ) {
+         MKDEBUG && _d($EVAL_ERROR);
+      }
+   }
+   MKDEBUG && _d('DBH info: ',
+      $dbh,
+      Dumper($dbh->selectrow_hashref(
+         'SELECT DATABASE(), CONNECTION_ID(), VERSION()/*!50038 , @@hostname*/')),
+      ' Connection info: ', ($dbh->{mysql_hostinfo} || 'undef'),
+      ' Character set info: ',
+      Dumper($dbh->selectall_arrayref(
+         'SHOW VARIABLES LIKE "character_set%"', { Slice => {}})),
+      ' $DBD::mysql::VERSION: ', $DBD::mysql::VERSION,
+      ' $DBI::VERSION: ', $DBI::VERSION,
+   );
+   return $dbh;
+}
+
+# Tries to figure out a hostname for the connection.
+sub get_hostname {
+   my ( $self, $dbh ) = @_;
+   if ( my ($host) = ($dbh->{mysql_hostinfo} || '') =~ m/^(\w+) via/ ) {
+      return $host;
+   }
+   my ( $hostname, $one ) = $dbh->selectrow_array(
+      'SELECT /*!50038 @@hostname, */ 1');
+   return $hostname;
+}
+
+# Disconnects a database handle, but complains verbosely if there are any active
+# children.  These are usually $sth handles that haven't been finish()ed.
+sub disconnect {
+   my ( $self, $dbh ) = @_;
+   MKDEBUG && $self->print_active_handles($dbh);
+   $dbh->disconnect;
+}
+
+sub print_active_handles {
+   my ( $self, $thing, $level ) = @_;
+   $level ||= 0;
+   printf("# Active %sh: %s %s %s\n", ($thing->{Type} || 'undef'), "\t" x $level,
+      $thing, (($thing->{Type} || '') eq 'st' ? $thing->{Statement} || '' : ''))
+      or die "Cannot print: $OS_ERROR";
+   foreach my $handle ( grep {defined} @{ $thing->{ChildHandles} } ) {
+      $self->print_active_handles( $handle, $level + 1 );
+   }
+}
+
+sub _d {
+   my ($package, undef, $line) = caller 0;
+   @_ = map { (my $temp = $_) =~ s/\n/\n# /g; $temp; }
+        map { defined $_ ? $_ : 'undef' }
+        @_;
+   # Use $$ instead of $PID in case the package
+   # does not use English.
+   print "# $package:$line $$ ", @_, "\n";
+}
+
+1;
+
+package InnoDBParser;
+
+use Data::Dumper;
+$Data::Dumper::Sortkeys = 1;
+use English qw(-no_match_vars);
+use List::Util qw(max);
+
+# Some common patterns
+my $d  = qr/(\d+)/;                    # Digit
+my $f  = qr/(\d+\.\d+)/;               # Float
+my $t  = qr/(\d+ \d+)/;                # Transaction ID
+my $i  = qr/((?:\d{1,3}\.){3}\d+)/;    # IP address
+my $n  = qr/([^`\s]+)/;                # MySQL object name
+my $w  = qr/(\w+)/;                    # Words
+my $fl = qr/([\w\.\/]+) line $d/;      # Filename and line number
+my $h  = qr/((?:0x)?[0-9a-f]*)/;       # Hex
+my $s  = qr/(\d{6} .\d:\d\d:\d\d)/;    # InnoDB timestamp
+
+# If you update this variable, also update the SYNOPSIS in the pod.
+my %innodb_section_headers = (
+   "TRANSACTIONS"                          => "tx",
+   "BUFFER POOL AND MEMORY"                => "bp",
+   "SEMAPHORES"                            => "sm",
+   "LOG"                                   => "lg",
+   "ROW OPERATIONS"                        => "ro",
+   "INSERT BUFFER AND ADAPTIVE HASH INDEX" => "ib",
+   "FILE I/O"                              => "io",
+   "LATEST DETECTED DEADLOCK"              => "dl",
+   "LATEST FOREIGN KEY ERROR"              => "fk",
+);
+
+my %parser_for = (
+   tx => \&parse_tx_section,
+   bp => \&parse_bp_section,
+   sm => \&parse_sm_section,
+   lg => \&parse_lg_section,
+   ro => \&parse_ro_section,
+   ib => \&parse_ib_section,
+   io => \&parse_io_section,
+   dl => \&parse_dl_section,
+   fk => \&parse_fk_section,
+);
+
+my %fk_parser_for = (
+   Transaction => \&parse_fk_transaction_error,
+   Error       => \&parse_fk_bad_constraint_error,
+   Cannot      => \&parse_fk_cant_drop_parent_error,
+);
+
+# A thread's proc_info can be at least 98 different things I've found in the
+# source.  Fortunately, most of them begin with a gerunded verb.  These are
+# the ones that don't.
+my %is_proc_info = (
+   'After create'                 => 1,
+   'Execution of init_command'    => 1,
+   'FULLTEXT initialization'      => 1,
+   'Reopen tables'                => 1,
+   'Repair done'                  => 1,
+   'Repair with keycache'         => 1,
+   'System lock'                  => 1,
+   'Table lock'                   => 1,
+   'Thread initialized'           => 1,
+   'User lock'                    => 1,
+   'copy to tmp table'            => 1,
+   'discard_or_import_tablespace' => 1,
+   'end'                          => 1,
+   'got handler lock'             => 1,
+   'got old table'                => 1,
+   'init'                         => 1,
+   'key cache'                    => 1,
+   'locks'                        => 1,
+   'malloc'                       => 1,
+   'query end'                    => 1,
+   'rename result table'          => 1,
+   'rename'                       => 1,
+   'setup'                        => 1,
+   'statistics'                   => 1,
+   'status'                       => 1,
+   'table cache'                  => 1,
+   'update'                       => 1,
+);
+
+sub new {
+   bless {}, shift;
+}
+
+# Parse the status and return it.
+# See srv_printf_innodb_monitor in innobase/srv/srv0srv.c
+# Pass in the text to parse, whether to be in debugging mode, which sections
+# to parse (hashref; if empty, parse all), and whether to parse full info from
+# locks and such (probably shouldn't unless you need to).
+sub parse_status_text {
+   my ( $self, $fulltext, $debug, $sections, $full ) = @_;
+
+   die "I can't parse undef" unless defined $fulltext;
+   $fulltext =~ s/[\r\n]+/\n/g;
+
+   $sections ||= {};
+   die '$sections must be a hashref' unless ref($sections) eq 'HASH';
+
+   my %innodb_data = (
+      got_all   => 0,         # Whether I was able to get the whole thing
+      ts        => '',        # Timestamp the server put on it
+      last_secs => 0,         # Num seconds the averages are over
+      sections  => {},        # Parsed values from each section
+   );
+
+   if ( $debug ) {
+      $innodb_data{'fulltext'} = $fulltext;
+   }
+
+   # Get the most basic info about the status: beginning and end, and whether
+   # I got the whole thing (if there has been a big deadlock and there are
+   # too many locks to print, the output might be truncated)
+   my ( $time_text ) = $fulltext =~ m/^$s INNODB MONITOR OUTPUT$/m;
+   $innodb_data{'ts'} = [ parse_innodb_timestamp( $time_text ) ];
+   $innodb_data{'timestring'} = ts_to_string($innodb_data{'ts'});
+   ( $innodb_data{'last_secs'} ) = $fulltext
+      =~ m/Per second averages calculated from the last $d seconds/;
+
+   ( my $got_all ) = $fulltext =~ m/END OF INNODB MONITOR OUTPUT/;
+   $innodb_data{'got_all'} = $got_all || 0;
+
+   # Split it into sections.  Each section begins with
+   # -----
+   # LABEL
+   # -----
+   my %innodb_sections;
+   my @matches = $fulltext
+      =~ m#\n(---+)\n([A-Z /]+)\n\1\n(.*?)(?=\n(---+)\n[A-Z /]+\n\4\n|$)#gs;
+   while ( my ( $start, $name, $text, $end ) = splice(@matches, 0, 4) ) {
+      $innodb_sections{$name} = [ $text, $end ? 1 : 0 ];
+   }
+   # The Row Operations section is a special case, because instead of ending
+   # with the beginning of another section, it ends with the end of the file.
+   # So this section is complete if the entire file is complete.
+   $innodb_sections{'ROW OPERATIONS'}->[1] ||= $innodb_data{'got_all'};
+
+   # Just for sanity's sake, make sure I understand what to do with each
+   # section
+   eval {
+      foreach my $section ( keys %innodb_sections ) {
+         my $header = $innodb_section_headers{$section};
+         die "Unknown section $section in $fulltext\n"
+            unless $header;
+         $innodb_data{'sections'}->{ $header }
+            ->{'fulltext'} = $innodb_sections{$section}->[0];
+         $innodb_data{'sections'}->{ $header }
+            ->{'complete'} = $innodb_sections{$section}->[1];
+      }
+   };
+   if ( $EVAL_ERROR ) {
+      _debug( $debug, $EVAL_ERROR);
+   }
+
+   # ################################################################
+   # Parse the detailed data out of the sections.
+   # ################################################################
+   eval {
+      foreach my $section ( keys %parser_for ) {
+         if ( defined $innodb_data{'sections'}->{$section}
+               && (!%$sections || (defined($sections->{$section} && $sections->{$section})) )) {
+            $parser_for{$section}->(
+                  $innodb_data{'sections'}->{$section},
+                  $innodb_data{'sections'}->{$section}->{'complete'},
+                  $debug,
+                  $full )
+               or delete $innodb_data{'sections'}->{$section};
+         }
+         else {
+            delete $innodb_data{'sections'}->{$section};
+         }
+      }
+   };
+   if ( $EVAL_ERROR ) {
+      _debug( $debug, $EVAL_ERROR);
+   }
+
+   return \%innodb_data;
+}
+
+# Parses the status text and returns it flattened out as a single hash.
+sub get_status_hash {
+   my ( $self, $fulltext, $debug, $sections, $full ) = @_;
+
+   # Parse the status text...
+   my $innodb_status
+      = $self->parse_status_text($fulltext, $debug, $sections, $full );
+
+   # Flatten the hierarchical structure into a single list by grabbing desired
+   # sections from it.
+   return
+      (map { 'IB_' . $_ => $innodb_status->{$_} } qw(timestring last_secs got_all)),
+      (map { 'IB_bp_' . $_ => $innodb_status->{'sections'}->{'bp'}->{$_} }
+         qw( writes_pending buf_pool_hit_rate total_mem_alloc buf_pool_reads
+            awe_mem_alloc pages_modified writes_pending_lru page_creates_sec
+            reads_pending pages_total buf_pool_hits writes_pending_single_page
+            page_writes_sec pages_read pages_written page_reads_sec
+            writes_pending_flush_list buf_pool_size add_pool_alloc
+            dict_mem_alloc pages_created buf_free complete )),
+      (map { 'IB_tx_' . $_ => $innodb_status->{'sections'}->{'tx'}->{$_} }
+         qw( num_lock_structs history_list_len purge_done_for transactions
+            purge_undo_for is_truncated trx_id_counter complete )),
+      (map { 'IB_ib_' . $_ => $innodb_status->{'sections'}->{'ib'}->{$_} }
+         qw( hash_table_size hash_searches_s non_hash_searches_s
+            bufs_in_node_heap used_cells size free_list_len seg_size inserts
+            merged_recs merges complete )),
+      (map { 'IB_lg_' . $_ => $innodb_status->{'sections'}->{'lg'}->{$_} }
+         qw( log_ios_done pending_chkp_writes last_chkp log_ios_s
+            log_flushed_to log_seq_no pending_log_writes complete )),
+      (map { 'IB_sm_' . $_ => $innodb_status->{'sections'}->{'sm'}->{$_} }
+         qw( wait_array_size rw_shared_spins rw_excl_os_waits mutex_os_waits
+            mutex_spin_rounds mutex_spin_waits rw_excl_spins rw_shared_os_waits
+            waits signal_count reservation_count complete )),
+      (map { 'IB_ro_' . $_ => $innodb_status->{'sections'}->{'ro'}->{$_} }
+         qw( queries_in_queue n_reserved_extents main_thread_state
+         main_thread_proc_no main_thread_id read_sec del_sec upd_sec ins_sec
+         read_views_open num_rows_upd num_rows_ins num_rows_read
+         queries_inside num_rows_del complete )),
+      (map { 'IB_fk_' . $_ => $innodb_status->{'sections'}->{'fk'}->{$_} }
+         qw( trigger parent_table child_index parent_index attempted_op
+         child_db timestring fk_name records col_name reason txn parent_db
+         type child_table parent_col complete )),
+      (map { 'IB_io_' . $_ => $innodb_status->{'sections'}->{'io'}->{$_} }
+         qw( pending_buffer_pool_flushes pending_pwrites pending_preads
+         pending_normal_aio_reads fsyncs_s os_file_writes pending_sync_ios
+         reads_s flush_type avg_bytes_s pending_ibuf_aio_reads writes_s
+         threads os_file_reads pending_aio_writes pending_log_ios os_fsyncs
+         pending_log_flushes complete )),
+      (map { 'IB_dl_' . $_ => $innodb_status->{'sections'}->{'dl'}->{$_} }
+         qw( timestring rolled_back txns complete ));
+
+}
+
+sub ts_to_string {
+   my $parts = shift;
+   return sprintf('%02d-%02d-%02d %02d:%02d:%02d', @$parts);
+}
+
+sub parse_innodb_timestamp {
+   my $text = shift;
+   my ( $y, $m, $d, $h, $i, $s )
+      = $text =~ m/^(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)$/;
+   die("Can't get timestamp from $text\n") unless $y;
+   $y += 2000;
+   return ( $y, $m, $d, $h, $i, $s );
+}
+
+sub parse_fk_section {
+   my ( $section, $complete, $debug, $full ) = @_;
+   my $fulltext = $section->{'fulltext'};
+
+   return 0 unless $fulltext;
+
+   my ( $ts, $type ) = $fulltext =~ m/^$s\s+(\w+)/m;
+   $section->{'ts'} = [ parse_innodb_timestamp( $ts ) ];
+   $section->{'timestring'} = ts_to_string($section->{'ts'});
+   $section->{'type'} = $type;
+
+   # Decide which type of FK error happened, and dispatch to the right parser.
+   if ( $type && $fk_parser_for{$type} ) {
+      $fk_parser_for{$type}->( $section, $complete, $debug, $fulltext, $full );
+   }
+
+   delete $section->{'fulltext'} unless $debug;
+
+   return 1;
+}
+
+sub parse_fk_cant_drop_parent_error {
+   my ( $section, $complete, $debug, $fulltext, $full ) = @_;
+
+   # Parse the parent/child table info out
+   @{$section}{ qw(attempted_op parent_db parent_table) } = $fulltext
+      =~ m{Cannot $w table `(.*)/(.*)`}m;
+   @{$section}{ qw(child_db child_table) } = $fulltext
+      =~ m{because it is referenced by `(.*)/(.*)`}m;
+
+   ( $section->{'reason'} ) = $fulltext =~ m/(Cannot .*)/s;
+   $section->{'reason'} =~ s/\n(?:InnoDB: )?/ /gm
+      if $section->{'reason'};
+
+   # Certain data may not be present.  Make them '' if not present.
+   map { $section->{$_} ||= "" }
+      qw(child_index fk_name col_name parent_col);
+}
+
+# See dict/dict0dict.c, function dict_foreign_error_report
+# I don't care much about these.  There are lots of different messages, and
+# they come from someone trying to create a foreign key, or similar
+# statements.  They aren't indicative of some transaction trying to insert,
+# delete or update data.  Sometimes it is possible to parse out a lot of
+# information about the tables and indexes involved, but often the message
+# contains the DDL string the user entered, which is way too much for this
+# module to try to handle.
+sub parse_fk_bad_constraint_error {
+   my ( $section, $complete, $debug, $fulltext, $full ) = @_;
+
+   # Parse the parent/child table and index info out
+   @{$section}{ qw(child_db child_table) } = $fulltext
+      =~ m{Error in foreign key constraint of table (.*)/(.*):$}m;
+   $section->{'attempted_op'} = 'DDL';
+
+   # FK name, parent info... if possible.
+   @{$section}{ qw(fk_name col_name parent_db parent_table parent_col) }
+      = $fulltext
+      =~ m/CONSTRAINT `?$n`? FOREIGN KEY \(`?$n`?\) REFERENCES (?:`?$n`?\.)?`?$n`? \(`?$n`?\)/;
+
+   if ( !defined($section->{'fk_name'}) ) {
+      # Try to parse SQL a user might have typed in a CREATE statement or such
+      @{$section}{ qw(col_name parent_db parent_table parent_col) }
+         = $fulltext
+         =~ m/FOREIGN\s+KEY\s*\(`?$n`?\)\s+REFERENCES\s+(?:`?$n`?\.)?`?$n`?\s*\(`?$n`?\)/i;
+   }
+   $section->{'parent_db'} ||= $section->{'child_db'};
+
+   # Name of the child index (index in the same table where the FK is, see
+   # definition of dict_foreign_struct in include/dict0mem.h, where it is
+   # called foreign_index, as opposed to referenced_index which is in the
+   # parent table.  This may not be possible to find.
+   @{$section}{ qw(child_index) } = $fulltext
+      =~ m/^The index in the foreign key in table is $n$/m;
+
+   @{$section}{ qw(reason) } = $fulltext =~ m/:\s*([^:]+)(?= Constraint:|$)/ms;
+   $section->{'reason'} =~ s/\s+/ /g
+      if $section->{'reason'};
+   
+   # Certain data may not be present.  Make them '' if not present.
+   map { $section->{$_} ||= "" }
+      qw(child_index fk_name col_name parent_table parent_col);
+}
+
+# see source file row/row0ins.c
+sub parse_fk_transaction_error {
+   my ( $section, $complete, $debug, $fulltext, $full ) = @_;
+
+   # Parse the txn info out
+   my ( $txn ) = $fulltext
+      =~ m/Transaction:\n(TRANSACTION.*)\nForeign key constraint fails/s;
+   if ( $txn ) {
+      $section->{'txn'} = parse_tx_text( $txn, $complete, $debug, $full );
+   }
+
+   # Parse the parent/child table and index info out.  There are two types: an
+   # update or a delete of a parent record leaves a child orphaned
+   # (row_ins_foreign_report_err), and an insert or update of a child record has
+   # no matching parent record (row_ins_foreign_report_add_err).
+
+   @{$section}{ qw(reason child_db child_table) }
+      = $fulltext =~ m{^(Foreign key constraint fails for table `(.*)/(.*)`:)$}m;
+
+   @{$section}{ qw(fk_name col_name parent_db parent_table parent_col) }
+      = $fulltext
+      =~ m/CONSTRAINT `$n` FOREIGN KEY \(`$n`\) REFERENCES (?:`$n`\.)?`$n` \(`$n`\)/;
+   $section->{'parent_db'} ||= $section->{'child_db'};
+
+   # Special case, which I don't know how to trigger, but see
+   # innobase/row/row0ins.c row_ins_check_foreign_constraint
+   if ( $fulltext =~ m/ibd file does not currently exist!/ ) {
+      my ( $attempted_op, $index, $records )
+         = $fulltext =~ m/^Trying to (add to index) `$n` tuple:\n(.*))?/sm;
+      $section->{'child_index'} = $index;
+      $section->{'attempted_op'} = $attempted_op || '';
+      if ( $records && $full ) {
+         ( $section->{'records'} )
+            = parse_innodb_record_dump( $records, $complete, $debug );
+      }
+      @{$section}{qw(parent_db parent_table)}
+         =~ m/^But the parent table `$n`\.`$n`$/m;
+   }
+   else {
+      my ( $attempted_op, $which, $index )
+         = $fulltext =~ m/^Trying to ([\w ]*) in (child|parent) table, in index `$n` tuple:$/m;
+      if ( $which ) {
+         $section->{$which . '_index'} = $index;
+         $section->{'attempted_op'} = $attempted_op || '';
+
+         # Parse out the related records in the other table.
+         my ( $search_index, $records );
+         if ( $which eq 'child' ) {
+            ( $search_index, $records ) = $fulltext
+               =~ m/^But in parent table [^,]*, in index `$n`,\nthe closest match we can find is record:\n(.*)/ms;
+            $section->{'parent_index'} = $search_index;
+         }
+         else {
+            ( $search_index, $records ) = $fulltext
+               =~ m/^But in child table [^,]*, in index `$n`, (?:the record is not available|there is a record:\n(.*))?/ms;
+            $section->{'child_index'} = $search_index;
+         }
+         if ( $records && $full ) {
+            $section->{'records'}
+               = parse_innodb_record_dump( $records, $complete, $debug );
+         }
+         else {
+            $section->{'records'} = '';
+         }
+      }
+   }
+
+   # Parse out the tuple trying to be updated, deleted or inserted.
+   my ( $trigger ) = $fulltext =~ m/^(DATA TUPLE: \d+ fields;\n.*)$/m;
+   if ( $trigger ) {
+      $section->{'trigger'} = parse_innodb_record_dump( $trigger, $complete, $debug );
+   }
+
+   # Certain data may not be present.  Make them '' if not present.
+   map { $section->{$_} ||= "" }
+      qw(child_index fk_name col_name parent_table parent_col);
+}
+
+# There are new-style and old-style record formats.  See rem/rem0rec.c
+# TODO: write some tests for this
+sub parse_innodb_record_dump {
+   my ( $dump, $complete, $debug ) = @_;
+   return undef unless $dump;
+
+   my $result = {};
+
+   if ( $dump =~ m/PHYSICAL RECORD/ ) {
+      my $style = $dump =~ m/compact format/ ? 'new' : 'old';
+      $result->{'style'} = $style;
+
+      # This is a new-style record.
+      if ( $style eq 'new' ) {
+         @{$result}{qw( heap_no type num_fields info_bits )}
+            = $dump
+            =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; compact format; info bits $d$/m;
+      }
+
+      # OK, it's old-style.  Unfortunately there are variations here too.
+      elsif ( $dump =~ m/-byte offs / ) {
+         # Older-old style.
+         @{$result}{qw( heap_no type num_fields byte_offset info_bits )}
+            = $dump
+            =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; $d-byte offs [A-Z]+; info bits $d$/m;
+            if ( $dump !~ m/-byte offs TRUE/ ) {
+               $result->{'byte_offset'} = 0;
+            }
+      }
+      else {
+         # Newer-old style.
+         @{$result}{qw( heap_no type num_fields byte_offset info_bits )}
+            = $dump
+            =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; $d-byte offsets; info bits $d$/m;
+      }
+
+   }
+   else {
+      $result->{'style'} = 'tuple';
+      @{$result}{qw( type num_fields )}
+         = $dump =~ m/^(DATA TUPLE): $d fields;$/m;
+   }
+
+   # Fill in default values for things that couldn't be parsed.
+   map { $result->{$_} ||= 0 }
+      qw(heap_no num_fields byte_offset info_bits);
+   map { $result->{$_} ||= '' }
+      qw(style type );
+
+   my @fields = $dump =~ m/ (\d+:.*?;?);(?=$| \d+:)/gm;
+   $result->{'fields'} = [ map { parse_field($_, $complete, $debug ) } @fields ];
+
+   return $result;
+}
+
+# New/old-style applies here.  See rem/rem0rec.c
+# $text should not include the leading space or the second trailing semicolon.
+sub parse_field {
+   my ( $text, $complete, $debug ) = @_;
+
+   # Sample fields:
+   # '4: SQL NULL, size 4 '
+   # '1: len 6; hex 000000005601; asc     V ;'
+   # '6: SQL NULL'
+   # '5: len 30; hex 687474703a2f2f7777772e737765657477617465722e636f6d2f73746f72; asc http://www.sweetwater.com/stor;...(truncated)'
+   my ( $id, $nullsize, $len, $hex, $asc, $truncated );
+   ( $id, $nullsize ) = $text =~ m/^$d: SQL NULL, size $d $/;
+   if ( !defined($id) ) {
+      ( $id ) = $text =~ m/^$d: SQL NULL$/;
+   }
+   if ( !defined($id) ) {
+      ( $id, $len, $hex, $asc, $truncated )
+         = $text =~ m/^$d: len $d; hex $h; asc (.*);(\.\.\.\(truncated\))?$/;
+   }
+
+   die "Could not parse this field: '$text'" unless defined $id;
+   return {
+      id    => $id,
+      len   => defined($len) ? $len : defined($nullsize) ? $nullsize : 0,
+      'hex' => defined($hex) ? $hex : '',
+      asc   => defined($asc) ? $asc : '',
+      trunc => $truncated ? 1 : 0,
+   };
+
+}
+
+sub parse_dl_section {
+   my ( $dl, $complete, $debug, $full ) = @_;
+   return unless $dl;
+   my $fulltext = $dl->{'fulltext'};
+   return 0 unless $fulltext;
+
+   my ( $ts ) = $fulltext =~ m/^$s$/m;
+   return 0 unless $ts;
+
+   $dl->{'ts'} = [ parse_innodb_timestamp( $ts ) ];
+   $dl->{'timestring'} = ts_to_string($dl->{'ts'});
+   $dl->{'txns'} = {};
+
+   my @sections
+      = $fulltext
+      =~ m{
+         ^\*{3}\s([^\n]*)  # *** (1) WAITING FOR THIS...
+         (.*?)             # Followed by anything, non-greedy
+         (?=(?:^\*{3})|\z) # Followed by another three stars or EOF
+      }gmsx;
+
+
+   # Loop through each section.  There are no assumptions about how many
+   # there are, who holds and wants what locks, and who gets rolled back.
+   while ( my ($header, $body) = splice(@sections, 0, 2) ) {
+      my ( $txn_id, $what ) = $header =~ m/^\($d\) (.*):$/;
+      next unless $txn_id;
+      $dl->{'txns'}->{$txn_id} ||= {};
+      my $txn = $dl->{'txns'}->{$txn_id};
+
+      if ( $what eq 'TRANSACTION' ) {
+         $txn->{'tx'} = parse_tx_text( $body, $complete, $debug, $full );
+      }
+      else {
+         push @{$txn->{'locks'}}, parse_innodb_record_locks( $body, $complete, $debug, $full );
+      }
+   }
+
+   @{ $dl }{ qw(rolled_back) }
+      = $fulltext =~ m/^\*\*\* WE ROLL BACK TRANSACTION \($d\)$/m;
+
+   # Make sure certain values aren't undef
+   map { $dl->{$_} ||= '' } qw(rolled_back);
+
+   delete $dl->{'fulltext'} unless $debug;
+   return 1;
+}
+
+sub parse_innodb_record_locks {
+   my ( $text, $complete, $debug, $full ) = @_;
+   my @result;
+
+   foreach my $lock ( $text =~ m/(^(?:RECORD|TABLE) LOCKS?.*$)/gm ) {
+      my $hash = {};
+      @{$hash}{ qw(lock_type space_id page_no n_bits index db table txn_id lock_mode) }
+         = $lock
+         =~ m{^(RECORD|TABLE) LOCKS? (?:space id $d page no $d n bits $d index `?$n`? of )?table `$n(?:/|`\.`)$n` trx id $t lock.mode (\S+)}m;
+      ( $hash->{'special'} )
+         = $lock =~ m/^(?:RECORD|TABLE) .*? locks (rec but not gap|gap before rec)/m;
+      $hash->{'insert_intention'}
+         = $lock =~ m/^(?:RECORD|TABLE) .*? insert intention/m ? 1 : 0;
+      $hash->{'waiting'}
+         = $lock =~ m/^(?:RECORD|TABLE) .*? waiting/m ? 1 : 0;
+
+      # Some things may not be in the text, so make sure they are not
+      # undef.
+      map { $hash->{$_} ||= 0 } qw(n_bits page_no space_id);
+      map { $hash->{$_} ||= "" } qw(index special);
+      push @result, $hash;
+   }
+
+   return @result;
+}
+
+sub parse_tx_text {
+   my ( $txn, $complete, $debug, $full ) = @_;
+
+   my ( $txn_id, $txn_status, $active_secs, $proc_no, $os_thread_id )
+      = $txn
+      =~ m/^(?:---)?TRANSACTION $t, (\D*?)(?: $d sec)?, (?:process no $d, )?OS thread id $d/m;
+   my ( $thread_status, $thread_decl_inside )
+      = $txn
+      =~ m/OS thread id \d+(?: ([^,]+?))?(?:, thread declared inside InnoDB $d)?$/m;
+
+   # Parsing the line that begins 'MySQL thread id' is complicated.  The only
+   # thing always in the line is the thread and query id.  See function
+   # innobase_mysql_print_thd in InnoDB source file sql/ha_innodb.cc.
+   my ( $thread_line ) = $txn =~ m/^(MySQL thread id .*)$/m;
+   my ( $mysql_thread_id, $query_id, $hostname, $ip, $user, $query_status );
+
+   if ( $thread_line ) {
+      # These parts can always be gotten.
+      ( $mysql_thread_id, $query_id ) = $thread_line =~ m/^MySQL thread id $d, query id $d/m;
+
+      # If it's a master/slave thread, "Has (read|sent) all" may be the thread's
+      # proc_info.  In these cases, there won't be any host/ip/user info
+      ( $query_status ) = $thread_line =~ m/(Has (?:read|sent) all .*$)/m;
+      if ( defined($query_status) ) {
+         $user = 'system user';
+      }
+
+      # It may be the case that the query id is the last thing in the line.
+      elsif ( $thread_line =~ m/query id \d+ / ) {
+         # The IP address is the only non-word thing left, so it's the most
+         # useful marker for where I have to start guessing.
+         ( $hostname, $ip ) = $thread_line =~ m/query id \d+(?: ([A-Za-z]\S+))? $i/m;
+         if ( defined $ip ) {
+            ( $user, $query_status ) = $thread_line =~ m/$ip $w(?: (.*))?$/;
+         }
+         else { # OK, there wasn't an IP address.
+            # There might not be ANYTHING except the query status.
+            ( $query_status ) = $thread_line =~ m/query id \d+ (.*)$/;
+            if ( $query_status !~ m/^\w+ing/ && !exists($is_proc_info{$query_status}) ) {
+               # The remaining tokens are, in order: hostname, user, query_status.
+               # It's basically impossible to know which is which.
+               ( $hostname, $user, $query_status ) = $thread_line
+                  =~ m/query id \d+(?: ([A-Za-z]\S+))?(?: $w(?: (.*))?)?$/m;
+            }
+            else {
+               $user = 'system user';
+            }
+         }
+      }
+   }
+
+   my ( $lock_wait_status, $lock_structs, $heap_size, $row_locks, $undo_log_entries )
+      = $txn
+      =~ m/^(?:(\D*) )?$d lock struct\(s\), heap size $d(?:, $d row lock\(s\))?(?:, undo log entries $d)?$/m;
+   my ( $lock_wait_time )
+      = $txn
+      =~ m/^------- TRX HAS BEEN WAITING $d SEC/m;
+
+   my $locks;
+   # If the transaction has locks, grab the locks.
+   if ( $txn =~ m/^TABLE LOCK|RECORD LOCKS/ ) {
+      $locks = [parse_innodb_record_locks($txn, $complete, $debug, $full)];
+   }
+   
+   my ( $tables_in_use, $tables_locked )
+      = $txn
+      =~ m/^mysql tables in use $d, locked $d$/m;
+   my ( $txn_doesnt_see_ge, $txn_sees_lt )
+      = $txn
+      =~ m/^Trx read view will not see trx with id >= $t, sees < $t$/m;
+   my $has_read_view = defined($txn_doesnt_see_ge);
+   # Only a certain number of bytes of the query text are included here, at least
+   # under some circumstances.  Some versions include 300, some 600.
+   my ( $query_text )
+      = $txn
+      =~ m{
+         ^MySQL\sthread\sid\s[^\n]+\n           # This comes before the query text
+         (.*?)                                  # The query text
+         (?=                                    # Followed by any of...
+            ^Trx\sread\sview
+            |^-------\sTRX\sHAS\sBEEN\sWAITING
+            |^TABLE\sLOCK
+            |^RECORD\sLOCKS\sspace\sid
+            |^(?:---)?TRANSACTION
+            |^\*\*\*\s\(\d\)
+            |\Z
+         )
+      }xms;
+   if ( $query_text ) {
+      $query_text =~ s/\s+$//;
+   }
+   else {
+      $query_text = '';
+   }
+
+   my %stuff = (
+      active_secs        => $active_secs,
+      has_read_view      => $has_read_view,
+      heap_size          => $heap_size,
+      hostname           => $hostname,
+      ip                 => $ip,
+      lock_structs       => $lock_structs,
+      lock_wait_status   => $lock_wait_status,
+      lock_wait_time     => $lock_wait_time,
+      mysql_thread_id    => $mysql_thread_id,
+      os_thread_id       => $os_thread_id,
+      proc_no            => $proc_no,
+      query_id           => $query_id,
+      query_status       => $query_status,
+      query_text         => $query_text,
+      row_locks          => $row_locks,
+      tables_in_use      => $tables_in_use,
+      tables_locked      => $tables_locked,
+      thread_decl_inside => $thread_decl_inside,
+      thread_status      => $thread_status,
+      txn_doesnt_see_ge  => $txn_doesnt_see_ge,
+      txn_id             => $txn_id,
+      txn_sees_lt        => $txn_sees_lt,
+      txn_status         => $txn_status,
+      undo_log_entries   => $undo_log_entries,
+      user               => $user,
+   );
+   $stuff{'fulltext'} = $txn if $debug;
+   $stuff{'locks'} = $locks if $locks;
+
+   # Some things may not be in the txn text, so make sure they are not
+   # undef.
+   map { $stuff{$_} ||= 0 } qw(active_secs heap_size lock_structs
+         tables_in_use undo_log_entries tables_locked has_read_view
+         thread_decl_inside lock_wait_time proc_no row_locks);
+   map { $stuff{$_} ||= "" } qw(thread_status txn_doesnt_see_ge
+         txn_sees_lt query_status ip query_text lock_wait_status user);
+   $stuff{'hostname'} ||= $stuff{'ip'};
+
+   return \%stuff;
+}
+
+sub parse_tx_section {
+   my ( $section, $complete, $debug, $full ) = @_;
+   return unless $section && $section->{'fulltext'};
+   my $fulltext = $section->{'fulltext'};
+   $section->{'transactions'} = [];
+
+   # Handle the individual transactions
+   my @transactions = $fulltext =~ m/(---TRANSACTION \d.*?)(?=\n---TRANSACTION|$)/gs;
+   foreach my $txn ( @transactions ) {
+      my $stuff = parse_tx_text( $txn, $complete, $debug, $full );
+      delete $stuff->{'fulltext'} unless $debug;
+      push @{$section->{'transactions'}}, $stuff;
+   }
+
+   # Handle the general info
+   @{$section}{ 'trx_id_counter' }
+      = $fulltext =~ m/^Trx id counter $t$/m;
+   @{$section}{ 'purge_done_for', 'purge_undo_for' }
+      = $fulltext =~ m/^Purge done for trx's n:o < $t undo n:o < $t$/m;
+   @{$section}{ 'history_list_len' } # This isn't present in some 4.x versions
+      = $fulltext =~ m/^History list length $d$/m;
+   @{$section}{ 'num_lock_structs' }
+      = $fulltext =~ m/^Total number of lock structs in row lock hash table $d$/m;
+   @{$section}{ 'is_truncated' }
+      = $fulltext =~ m/^\.\.\. truncated\.\.\.$/m ? 1 : 0;
+
+   # Fill in things that might not be present
+   foreach ( qw(history_list_len) ) {
+      $section->{$_} ||= 0;
+   }
+
+   delete $section->{'fulltext'} unless $debug;
+   return 1;
+}
+
+# I've read the source for this section.
+sub parse_ro_section {
+   my ( $section, $complete, $debug, $full ) = @_;
+   return unless $section && $section->{'fulltext'};
+   my $fulltext = $section->{'fulltext'};
+
+   # Grab the info
+   @{$section}{ 'queries_inside', 'queries_in_queue' }
+      = $fulltext =~ m/^$d queries inside InnoDB, $d queries in queue$/m;
+   ( $section->{ 'read_views_open' } )
+      = $fulltext =~ m/^$d read views open inside InnoDB$/m;
+   ( $section->{ 'n_reserved_extents' } )
+      = $fulltext =~ m/^$d tablespace extents now reserved for B-tree/m;
+   @{$section}{ 'main_thread_proc_no', 'main_thread_id', 'main_thread_state' }
+      = $fulltext =~ m/^Main thread (?:process no. $d, )?id $d, state: (.*)$/m;
+   @{$section}{ 'num_rows_ins', 'num_rows_upd', 'num_rows_del', 'num_rows_read' }
+      = $fulltext =~ m/^Number of rows inserted $d, updated $d, deleted $d, read $d$/m;
+   @{$section}{ 'ins_sec', 'upd_sec', 'del_sec', 'read_sec' }
+      = $fulltext =~ m#^$f inserts/s, $f updates/s, $f deletes/s, $f reads/s$#m;
+   $section->{'main_thread_proc_no'} ||= 0;
+
+   map { $section->{$_} ||= 0 } qw(read_views_open n_reserved_extents);
+   delete $section->{'fulltext'} unless $debug;
+   return 1;
+}
+
+sub parse_lg_section {
+   my ( $section, $complete, $debug, $full ) = @_;
+   return unless $section;
+   my $fulltext = $section->{'fulltext'};
+
+   # Grab the info
+   ( $section->{ 'log_seq_no' } )
+      = $fulltext =~ m/Log sequence number \s*(\d.*)$/m;
+   ( $section->{ 'log_flushed_to' } )
+      = $fulltext =~ m/Log flushed up to \s*(\d.*)$/m;
+   ( $section->{ 'last_chkp' } )
+      = $fulltext =~ m/Last checkpoint at \s*(\d.*)$/m;
+   @{$section}{ 'pending_log_writes', 'pending_chkp_writes' }
+      = $fulltext =~ m/$d pending log writes, $d pending chkp writes/;
+   @{$section}{ 'log_ios_done', 'log_ios_s' }
+      = $fulltext =~ m#$d log i/o's done, $f log i/o's/second#;
+
+   delete $section->{'fulltext'} unless $debug;
+   return 1;
+}
+
+sub parse_ib_section {
+   my ( $section, $complete, $debug, $full ) = @_;
+   return unless $section && $section->{'fulltext'};
+   my $fulltext = $section->{'fulltext'};
+
+   # Some servers will output ibuf information for tablespace 0, as though there
+   # might be many tablespaces with insert buffers.  (In practice I believe
+   # the source code shows there will only ever be one).  I have to parse both
+   # cases here, but I assume there will only be one.
+   @{$section}{ 'size', 'free_list_len', 'seg_size' }
+      = $fulltext =~ m/^Ibuf(?: for space 0)?: size $d, free list len $d, seg size $d,$/m;
+   @{$section}{ 'inserts', 'merged_recs', 'merges' }
+      = $fulltext =~ m/^$d inserts, $d merged recs, $d merges$/m;
+
+   @{$section}{ 'hash_table_size', 'used_cells', 'bufs_in_node_heap' }
+      = $fulltext =~ m/^Hash table size $d, used cells $d, node heap has $d buffer\(s\)$/m;
+   @{$section}{ 'hash_searches_s', 'non_hash_searches_s' }
+      = $fulltext =~ m{^$f hash searches/s, $f non-hash searches/s$}m;
+
+   delete $section->{'fulltext'} unless $debug;
+   return 1;
+}
+
+sub parse_wait_array {
+   my ( $text, $complete, $debug, $full ) = @_;
+   my %result;
+
+   @result{ qw(thread waited_at_filename waited_at_line waited_secs) }
+      = $text =~ m/^--Thread $d has waited at $fl for $f seconds/m;
+
+   # Depending on whether it's a SYNC_MUTEX,RW_LOCK_EX,RW_LOCK_SHARED,
+   # there will be different text output
+   if ( $text =~ m/^Mutex at/m ) {
+      $result{'request_type'} = 'M';
+      @result{ qw( lock_mem_addr lock_cfile_name lock_cline lock_var) }
+         = $text =~ m/^Mutex at $h created file $fl, lock var $d$/m;
+      @result{ qw( waiters_flag )}
+         = $text =~ m/^waiters flag $d$/m;
+   }
+   else {
+      @result{ qw( request_type lock_mem_addr lock_cfile_name lock_cline) }
+         = $text =~ m/^(.)-lock on RW-latch at $h created in file $fl$/m;
+      @result{ qw( writer_thread writer_lock_mode ) }
+         = $text =~ m/^a writer \(thread id $d\) has reserved it in mode  (.*)$/m;
+      @result{ qw( num_readers waiters_flag )}
+         = $text =~ m/^number of readers $d, waiters flag $d$/m;
+      @result{ qw(last_s_file_name last_s_line ) }
+         = $text =~ m/Last time read locked in file $fl$/m;
+      @result{ qw(last_x_file_name last_x_line ) }
+         = $text =~ m/Last time write locked in file $fl$/m;
+   }
+
+   $result{'cell_waiting'} = $text =~ m/^wait has ended$/m ? 0 : 1;
+   $result{'cell_event_set'} = $text =~ m/^wait is ending$/m ? 1 : 0;
+
+   # Because there are two code paths, some things won't get set.
+   map { $result{$_} ||= '' }
+      qw(last_s_file_name last_x_file_name writer_lock_mode);
+   map { $result{$_} ||= 0 }
+      qw(num_readers lock_var last_s_line last_x_line writer_thread);
+
+   return \%result;
+}
+
+sub parse_sm_section {
+   my ( $section, $complete, $debug, $full ) = @_;
+   return 0 unless $section && $section->{'fulltext'};
+   my $fulltext = $section->{'fulltext'};
+
+   # Grab the info
+   @{$section}{ 'reservation_count', 'signal_count' }
+      = $fulltext =~ m/^OS WAIT ARRAY INFO: reservation count $d, signal count $d$/m;
+   @{$section}{ 'mutex_spin_waits', 'mutex_spin_rounds', 'mutex_os_waits' }
+      = $fulltext =~ m/^Mutex spin waits $d, rounds $d, OS waits $d$/m;
+   @{$section}{ 'rw_shared_spins', 'rw_shared_os_waits', 'rw_excl_spins', 'rw_excl_os_waits' }
+      = $fulltext =~ m/^RW-shared spins $d, OS waits $d; RW-excl spins $d, OS waits $d$/m;
+
+   # Look for info on waits.
+   my @waits = $fulltext =~ m/^(--Thread.*?)^(?=Mutex spin|--Thread)/gms;
+   $section->{'waits'} = [ map { parse_wait_array($_, $complete, $debug) } @waits ];
+   $section->{'wait_array_size'} = scalar(@waits);
+
+   delete $section->{'fulltext'} unless $debug;
+   return 1;
+}
+
+# I've read the source for this section.
+sub parse_bp_section {
+   my ( $section, $complete, $debug, $full ) = @_;
+   return unless $section && $section->{'fulltext'};
+   my $fulltext = $section->{'fulltext'};
+
+   # Grab the info
+   @{$section}{ 'total_mem_alloc', 'add_pool_alloc' }
+      = $fulltext =~ m/^Total memory allocated $d; in additional pool allocated $d$/m;
+   @{$section}{'dict_mem_alloc'}     = $fulltext =~ m/Dictionary memory allocated $d/;
+   @{$section}{'awe_mem_alloc'}      = $fulltext =~ m/$d MB of AWE memory/;
+   @{$section}{'buf_pool_size'}      = $fulltext =~ m/^Buffer pool size\s*$d$/m;
+   @{$section}{'buf_free'}           = $fulltext =~ m/^Free buffers\s*$d$/m;
+   @{$section}{'pages_total'}        = $fulltext =~ m/^Database pages\s*$d$/m;
+   @{$section}{'pages_modified'}     = $fulltext =~ m/^Modified db pages\s*$d$/m;
+   @{$section}{'pages_read', 'pages_created', 'pages_written'}
+      = $fulltext =~ m/^Pages read $d, created $d, written $d$/m;
+   @{$section}{'page_reads_sec', 'page_creates_sec', 'page_writes_sec'}
+      = $fulltext =~ m{^$f reads/s, $f creates/s, $f writes/s$}m;
+   @{$section}{'buf_pool_hits', 'buf_pool_reads'}
+      = $fulltext =~ m{Buffer pool hit rate $d / $d$}m;
+   if ($fulltext =~ m/^No buffer pool page gets since the last printout$/m) {
+      @{$section}{'buf_pool_hits', 'buf_pool_reads'} = (0, 0);
+      @{$section}{'buf_pool_hit_rate'} = '--';
+   }
+   else {
+      @{$section}{'buf_pool_hit_rate'}
+         = $fulltext =~ m{Buffer pool hit rate (\d+ / \d+)$}m;
+   }
+   @{$section}{'reads_pending'} = $fulltext =~ m/^Pending reads $d/m;
+   @{$section}{'writes_pending_lru', 'writes_pending_flush_list', 'writes_pending_single_page' }
+      = $fulltext =~ m/^Pending writes: LRU $d, flush list $d, single page $d$/m;
+
+   map { $section->{$_} ||= 0 }
+      qw(writes_pending_lru writes_pending_flush_list writes_pending_single_page
+      awe_mem_alloc dict_mem_alloc);
+   @{$section}{'writes_pending'} = List::Util::sum(
+      @{$section}{ qw(writes_pending_lru writes_pending_flush_list writes_pending_single_page) });
+
+   delete $section->{'fulltext'} unless $debug;
+   return 1;
+}
+
+# I've read the source for this.
+sub parse_io_section {
+   my ( $section, $complete, $debug, $full ) = @_;
+   return unless $section && $section->{'fulltext'};
+   my $fulltext = $section->{'fulltext'};
+   $section->{'threads'} = {};
+
+   # Grab the I/O thread info
+   my @threads = $fulltext =~ m<^(I/O thread \d+ .*)$>gm;
+   foreach my $thread (@threads) {
+      my ( $tid, $state, $purpose, $event_set )
+         = $thread =~ m{I/O thread $d state: (.+?) \((.*)\)(?: ev set)?$}m;
+      if ( defined $tid ) {
+         $section->{'threads'}->{$tid} = {
+            thread    => $tid,
+            state     => $state,
+            purpose   => $purpose,
+            event_set => $event_set ? 1 : 0,
+         };
+      }
+   }
+
+   # Grab the reads/writes/flushes info
+   @{$section}{ 'pending_normal_aio_reads', 'pending_aio_writes' }
+      = $fulltext =~ m/^Pending normal aio reads: $d, aio writes: $d,$/m;
+   @{$section}{ 'pending_ibuf_aio_reads', 'pending_log_ios', 'pending_sync_ios' }
+      = $fulltext =~ m{^ ibuf aio reads: $d, log i/o's: $d, sync i/o's: $d$}m;
+   @{$section}{ 'flush_type', 'pending_log_flushes', 'pending_buffer_pool_flushes' }
+      = $fulltext =~ m/^Pending flushes \($w\) log: $d; buffer pool: $d$/m;
+   @{$section}{ 'os_file_reads', 'os_file_writes', 'os_fsyncs' }
+      = $fulltext =~ m/^$d OS file reads, $d OS file writes, $d OS fsyncs$/m;
+   @{$section}{ 'reads_s', 'avg_bytes_s', 'writes_s', 'fsyncs_s' }
+      = $fulltext =~ m{^$f reads/s, $d avg bytes/read, $f writes/s, $f fsyncs/s$}m;
+   @{$section}{ 'pending_preads', 'pending_pwrites' }
+      = $fulltext =~ m/$d pending preads, $d pending pwrites$/m;
+   @{$section}{ 'pending_preads', 'pending_pwrites' } = (0, 0)
+      unless defined($section->{'pending_preads'});
+
+   delete $section->{'fulltext'} unless $debug;
+   return 1;
+}
+
+sub _debug {
+   my ( $debug, $msg ) = @_;
+   if ( $debug ) {
+      die $msg;
+   }
+   else {
+      warn $msg;
+   }
+   return 1;
+}
+
+1;
+
+# end_of_package InnoDBParser
+
+package main;
+
+use sigtrap qw(handler finish untrapped normal-signals);
+
+use Data::Dumper;
+use DBI;
+use English qw(-no_match_vars);
+use File::Basename qw(dirname);
+use File::Temp;
+use Getopt::Long;
+use List::Util qw(max min maxstr sum);
+use POSIX qw(ceil);
+use Time::HiRes qw(time sleep);
+use Term::ReadKey qw(ReadMode ReadKey);
+
+# License and warranty information. {{{1
+# ###########################################################################
+
+my $innotop_license = <<"LICENSE";
+
+This is innotop version $VERSION, a MySQL and InnoDB monitor.
+
+This program is copyright (c) 2006 Baron Schwartz.
+Feedback and improvements are welcome.
+
+THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+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; OR the Perl Artistic License.  On UNIX and similar
+systems, you can issue `man perlgpl' or `man perlartistic' to read these
+licenses.
+
+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., 59 Temple
+Place, Suite 330, Boston, MA  02111-1307  USA.
+LICENSE
+
+# Configuration information and global setup {{{1
+# ###########################################################################
+
+# Really, really, super-global variables.
+my @config_versions = (
+   "000-000-000", "001-003-000", # config file was one big name-value hash.
+   "001-003-000", "001-004-002", # config file contained non-user-defined stuff.
+);
+
+my $clear_screen_sub;
+my $dsn_parser = new DSNParser();
+
+# This defines expected properties and defaults for the column definitions that
+# eventually end up in tbl_meta.
+my %col_props = (
+   hdr     => '',
+   just    => '-',
+   dec     => 0,     # Whether to align the column on the decimal point
+   num     => 0,
+   label   => '',
+   user    => 0,
+   src     => '',
+   tbl     => '',    # Helps when writing/reading custom columns in config files
+   minw    => 0,
+   maxw    => 0,
+   trans   => [],
+   agg     => 'first',  # Aggregate function
+   aggonly => 0,        # Whether to show only when tbl_meta->{aggregate} is true
+);
+
+# Actual DBI connections to MySQL servers.
+my %dbhs;
+
+# Command-line parameters {{{2
+# ###########################################################################
+
+my @opt_spec = (
+   { s => 'help',       d => 'Show this help message' },
+   { s => 'color|C!',   d => 'Use terminal coloring (default)',   c => 'color' },
+   { s => 'config|c=s', d => 'Config file to read' },
+   { s => 'nonint|n',   d => 'Non-interactive, output tab-separated fields' },
+   { s => 'count=i',    d => 'Number of updates before exiting' },
+   { s => 'delay|d=f',  d => 'Delay between updates in seconds',  c => 'interval' },
+   { s => 'mode|m=s',   d => 'Operating mode to start in',        c => 'mode' },
+   { s => 'inc|i!',     d => 'Measure incremental differences',   c => 'status_inc' },
+   { s => 'write|w',    d => 'Write running configuration into home directory if no config files were loaded' },
+   { s => 'skipcentral|s',     d => 'Skip reading the central configuration file' },
+   { s => 'version',    d => 'Output version information and exit' },
+   { s => 'user|u=s',   d => 'User for login if not current user' },
+   { s => 'password|p=s',   d => 'Password to use for connection' },
+   { s => 'host|h=s',   d => 'Connect to host' },
+   { s => 'port|P=i',   d => 'Port number to use for connection' },
+);
+
+# This is the container for the command-line options' values to be stored in
+# after processing.  Initial values are defaults.
+my %opts = (
+   n => !( -t STDIN && -t STDOUT ), # If in/out aren't to terminals, we're interactive
+);
+# Post-process...
+my %opt_seen;
+foreach my $spec ( @opt_spec ) {
+   my ( $long, $short ) = $spec->{s} =~ m/^(\w+)(?:\|([^!+=]*))?/;
+   $spec->{k} = $short || $long;
+   $spec->{l} = $long;
+   $spec->{t} = $short;
+   $spec->{n} = $spec->{s} =~ m/!/;
+   $opts{$spec->{k}} = undef unless defined $opts{$spec->{k}};
+   die "Duplicate option $spec->{k}" if $opt_seen{$spec->{k}}++;
+}
+
+Getopt::Long::Configure('no_ignore_case', 'bundling');
+GetOptions( map { $_->{s} => \$opts{$_->{k}} } @opt_spec) or $opts{help} = 1;
+
+if ( $opts{version} ) {
+   print "innotop  Ver $VERSION\n";
+   exit(0);
+}
+
+if ( $opts{c} and ! -f $opts{c} ) {
+   print $opts{c} . " doesn't exist.  Exiting.\n";
+   exit(1);
+}
+if ( $opts{'help'} ) {
+   print "Usage: innotop <options> <innodb-status-file>\n\n";
+   my $maxw = max(map { length($_->{l}) + ($_->{n} ? 4 : 0)} @opt_spec);
+   foreach my $spec ( sort { $a->{l} cmp $b->{l} } @opt_spec ) {
+      my $long  = $spec->{n} ? "[no]$spec->{l}" : $spec->{l};
+      my $short = $spec->{t} ? "-$spec->{t}" : '';
+      printf("  --%-${maxw}s %-4s %s\n", $long, $short, $spec->{d});
+   }
+   print <<USAGE;
+
+innotop is a MySQL and InnoDB transaction/status monitor, like 'top' for
+MySQL.  It displays queries, InnoDB transactions, lock waits, deadlocks,
+foreign key errors, open tables, replication status, buffer information,
+row operations, logs, I/O operations, load graph, and more.  You can
+monitor many servers at once with innotop. 
+
+USAGE
+   exit(1);
+}
+
+# Meta-data (table definitions etc) {{{2
+# ###########################################################################
+
+# Expressions {{{3
+# Convenience so I can copy/paste these in several places...
+# ###########################################################################
+my %exprs = (
+   Host              => q{my $host = host || hostname || ''; ($host) = $host =~ m/^((?:[\d.]+(?=:))|(?:[a-zA-Z]\w+))/; return $host || ''},
+   Port              => q{my ($p) = host =~ m/:(.*)$/; return $p || 0},
+   OldVersions       => q{dulint_to_int(IB_tx_trx_id_counter) - dulint_to_int(IB_tx_purge_done_for)},
+   MaxTxnTime        => q/max(map{ $_->{active_secs} } @{ IB_tx_transactions }) || 0/,
+   NumTxns           => q{scalar @{ IB_tx_transactions } },
+   DirtyBufs         => q{ $cur->{IB_bp_pages_modified} / ($cur->{IB_bp_buf_pool_size} || 1) },
+   BufPoolFill       => q{ $cur->{IB_bp_pages_total} / ($cur->{IB_bp_buf_pool_size} || 1) },
+   ServerLoad        => q{ $cur->{Threads_connected}/(Questions||1)/Uptime_hires },
+   TxnTimeRemain     => q{ defined undo_log_entries && defined $pre->{undo_log_entries} && undo_log_entries < $pre->{undo_log_entries} ? undo_log_entries / (($pre->{undo_log_entries} - undo_log_entries)/((active_secs-$pre->{active_secs})||1))||1 : 0},
+   SlaveCatchupRate  => ' defined $cur->{seconds_behind_master} && defined $pre->{seconds_behind_master} && $cur->{seconds_behind_master} < $pre->{seconds_behind_master} ? ($pre->{seconds_behind_master}-$cur->{seconds_behind_master})/($cur->{Uptime_hires}-$pre->{Uptime_hires}) : 0',
+   QcacheHitRatio    => q{(Qcache_hits||0)/(((Com_select||0)+(Qcache_hits||0))||1)},
+);
+
+# ###########################################################################
+# Column definitions {{{3
+# Defines every column in every table. A named column has the following
+# properties:
+#    * hdr    Column header/title
+#    * label  Documentation for humans.
+#    * num    Whether it's numeric (for sorting).
+#    * just   Alignment; generated from num, user-overridable in tbl_meta
+#    * minw, maxw Auto-generated, user-overridable.
+# Values from this hash are just copied to tbl_meta, which is where everything
+# else in the program should read from.
+# ###########################################################################
+
+my %columns = (
+   active_secs                 => { hdr => 'SecsActive',          num => 1, label => 'Seconds transaction has been active', },
+   add_pool_alloc              => { hdr => 'Add\'l Pool',         num => 1, label => 'Additonal pool allocated' },
+   attempted_op                => { hdr => 'Action',              num => 0, label => 'The action that caused the error' },
+   awe_mem_alloc               => { hdr => 'AWE Memory',          num => 1, label => '[Windows] AWE memory allocated' },
+   binlog_cache_overflow       => { hdr => 'Binlog Cache',        num => 1, label => 'Transactions too big for binlog cache that went to disk' },
+   binlog_do_db                => { hdr => 'Binlog Do DB',        num => 0, label => 'binlog-do-db setting' },
+   binlog_ignore_db            => { hdr => 'Binlog Ignore DB',    num => 0, label => 'binlog-ignore-db setting' },
+   bps_in                      => { hdr => 'BpsIn',               num => 1, label => 'Bytes per second received by the server', },
+   bps_out                     => { hdr => 'BpsOut',              num => 1, label => 'Bytes per second sent by the server', },
+   buf_free                    => { hdr => 'Free Bufs',           num => 1, label => 'Buffers free in the buffer pool' },
+   buf_pool_hit_rate           => { hdr => 'Hit Rate',            num => 0, label => 'Buffer pool hit rate' },
+   buf_pool_hits               => { hdr => 'Hits',                num => 1, label => 'Buffer pool hits' },
+   buf_pool_reads              => { hdr => 'Reads',               num => 1, label => 'Buffer pool reads' },
+   buf_pool_size               => { hdr => 'Size',                num => 1, label => 'Buffer pool size' },
+   bufs_in_node_heap           => { hdr => 'Node Heap Bufs',      num => 1, label => 'Buffers in buffer pool node heap' },
+   bytes_behind_master         => { hdr => 'ByteLag',             num => 1, label => 'Bytes the slave lags the master in binlog' },
+   cell_event_set              => { hdr => 'Ending?',             num => 1, label => 'Whether the cell event is set' },
+   cell_waiting                => { hdr => 'Waiting?',            num => 1, label => 'Whether the cell is waiting' },
+   child_db                    => { hdr => 'Child DB',            num => 0, label => 'The database of the child table' },
+   child_index                 => { hdr => 'Child Index',         num => 0, label => 'The index in the child table' },
+   child_table                 => { hdr => 'Child Table',         num => 0, label => 'The child table' },
+   cmd                         => { hdr => 'Cmd',                 num => 0, label => 'Type of command being executed', },
+   cnt                         => { hdr => 'Cnt',                 num => 0, label => 'Count', agg => 'count', aggonly => 1 },
+   connect_retry               => { hdr => 'Connect Retry',       num => 1, label => 'Slave connect-retry timeout' },
+   cxn                         => { hdr => 'CXN',                 num => 0, label => 'Connection from which the data came', },
+   db                          => { hdr => 'DB',                  num => 0, label => 'Current database', },
+   dict_mem_alloc              => { hdr => 'Dict Mem',            num => 1, label => 'Dictionary memory allocated' },
+   dirty_bufs                  => { hdr => 'Dirty Buf',           num => 1, label => 'Dirty buffer pool pages' },
+   dl_txn_num                  => { hdr => 'Num',                 num => 0, label => 'Deadlocked transaction number', },
+   event_set                   => { hdr => 'Evt Set?',            num => 1, label => '[Win32] if a wait event is set', },
+   exec_master_log_pos         => { hdr => 'Exec Master Log Pos', num => 1, label => 'Exec Master Log Position' },
+   fk_name                     => { hdr => 'Constraint',          num => 0, label => 'The name of the FK constraint' },
+   free_list_len               => { hdr => 'Free List Len',       num => 1, label => 'Length of the free list' },
+   has_read_view               => { hdr => 'Rd View',             num => 1, label => 'Whether the transaction has a read view' },
+   hash_searches_s             => { hdr => 'Hash/Sec',            num => 1, label => 'Number of hash searches/sec' },
+   hash_table_size             => { hdr => 'Size',                num => 1, label => 'Number of non-hash searches/sec' },
+   heap_no                     => { hdr => 'Heap',                num => 1, label => 'Heap number' },
+   heap_size                   => { hdr => 'Heap',                num => 1, label => 'Heap size' },
+   history_list_len            => { hdr => 'History',             num => 1, label => 'History list length' },
+   host_and_domain             => { hdr => 'Host',                num => 0, label => 'Hostname/IP and domain' },
+   host_and_port               => { hdr => 'Host/IP',             num => 0, label => 'Hostname or IP address, and port number', },
+   hostname                    => { hdr => 'Host',                num => 0, label => 'Hostname' },
+   index                       => { hdr => 'Index',               num => 0, label => 'The index involved' },
+   index_ref                   => { hdr => 'Index Ref',           num => 0, label => 'Index referenced' },
+   info                        => { hdr => 'Query',               num => 0, label => 'Info or the current query', },
+   insert_intention            => { hdr => 'Ins Intent',          num => 1, label => 'Whether the thread was trying to insert' },
+   inserts                     => { hdr => 'Inserts',             num => 1, label => 'Inserts' },
+   io_bytes_s                  => { hdr => 'Bytes/Sec',           num => 1, label => 'Average I/O bytes/sec' },
+   io_flush_type               => { hdr => 'Flush Type',          num => 0, label => 'I/O Flush Type' },
+   io_fsyncs_s                 => { hdr => 'fsyncs/sec',          num => 1, label => 'I/O fsyncs/sec' },
+   io_reads_s                  => { hdr => 'Reads/Sec',           num => 1, label => 'Average I/O reads/sec' },
+   io_writes_s                 => { hdr => 'Writes/Sec',          num => 1, label => 'Average I/O writes/sec' },
+   ip                          => { hdr => 'IP',                  num => 0, label => 'IP address' },
+   is_name_locked              => { hdr => 'Locked',              num => 1, label => 'Whether table is name locked', },
+   key_buffer_hit              => { hdr => 'KCacheHit',           num => 1, label => 'Key cache hit ratio', },
+   key_len                     => { hdr => 'Key Length',          num => 1, label => 'Number of bytes used in the key' },
+   last_chkp                   => { hdr => 'Last Checkpoint',     num => 0, label => 'Last log checkpoint' },
+   last_errno                  => { hdr => 'Last Errno',          num => 1, label => 'Last error number' },
+   last_error                  => { hdr => 'Last Error',          num => 0, label => 'Last error' },
+   last_s_file_name            => { hdr => 'S-File',              num => 0, label => 'Filename where last read locked' },
+   last_s_line                 => { hdr => 'S-Line',              num => 1, label => 'Line where last read locked' },
+   last_x_file_name            => { hdr => 'X-File',              num => 0, label => 'Filename where last write locked' },
+   last_x_line                 => { hdr => 'X-Line',              num => 1, label => 'Line where last write locked' },
+   last_pct                    => { hdr => 'Pct',                 num => 1, label => 'Last Percentage' },
+   last_total                  => { hdr => 'Last Total',          num => 1, label => 'Last Total' },
+   last_value                  => { hdr => 'Last Incr',           num => 1, label => 'Last Value' },
+   load                        => { hdr => 'Load',                num => 1, label => 'Server load' },
+   lock_cfile_name             => { hdr => 'Crtd File',           num => 0, label => 'Filename where lock created' },
+   lock_cline                  => { hdr => 'Crtd Line',           num => 1, label => 'Line where lock created' },
+   lock_mem_addr               => { hdr => 'Addr',                num => 0, label => 'The lock memory address' },
+   lock_mode                   => { hdr => 'Mode',                num => 0, label => 'The lock mode' },
+   lock_structs                => { hdr => 'LStrcts',             num => 1, label => 'Number of lock structs' },
+   lock_type                   => { hdr => 'Type',                num => 0, label => 'The lock type' },
+   lock_var                    => { hdr => 'Lck Var',             num => 1, label => 'The lock variable' },
+   lock_wait_time              => { hdr => 'Wait',                num => 1, label => 'How long txn has waited for a lock' },
+   log_flushed_to              => { hdr => 'Flushed To',          num => 0, label => 'Log position flushed to' },
+   log_ios_done                => { hdr => 'IO Done',             num => 1, label => 'Log I/Os done' },
+   log_ios_s                   => { hdr => 'IO/Sec',              num => 1, label => 'Average log I/Os per sec' },
+   log_seq_no                  => { hdr => 'Sequence No.',        num => 0, label => 'Log sequence number' },
+   main_thread_id              => { hdr => 'Main Thread ID',      num => 1, label => 'Main thread ID' },
+   main_thread_proc_no         => { hdr => 'Main Thread Proc',    num => 1, label => 'Main thread process number' },
+   main_thread_state           => { hdr => 'Main Thread State',   num => 0, label => 'Main thread state' },
+   master_file                 => { hdr => 'File',                num => 0, label => 'Master file' },
+   master_host                 => { hdr => 'Master',              num => 0, label => 'Master server hostname' },
+   master_log_file             => { hdr => 'Master Log File',     num => 0, label => 'Master log file' },
+   master_port                 => { hdr => 'Master Port',         num => 1, label => 'Master port' },
+   master_pos                  => { hdr => 'Position',            num => 1, label => 'Master position' },
+   master_ssl_allowed          => { hdr => 'Master SSL Allowed',  num => 0, label => 'Master SSL Allowed' },
+   master_ssl_ca_file          => { hdr => 'Master SSL CA File',  num => 0, label => 'Master SSL Cert Auth File' },
+   master_ssl_ca_path          => { hdr => 'Master SSL CA Path',  num => 0, label => 'Master SSL Cert Auth Path' },
+   master_ssl_cert             => { hdr => 'Master SSL Cert',     num => 0, label => 'Master SSL Cert' },
+   master_ssl_cipher           => { hdr => 'Master SSL Cipher',   num => 0, label => 'Master SSL Cipher' },
+   master_ssl_key              => { hdr => 'Master SSL Key',      num => 0, label => 'Master SSL Key' },
+   master_user                 => { hdr => 'Master User',         num => 0, label => 'Master username' },
+   max_txn                     => { hdr => 'MaxTxnTime',          num => 1, label => 'MaxTxn' },
+   merged_recs                 => { hdr => 'Merged Recs',         num => 1, label => 'Merged records' },
+   merges                      => { hdr => 'Merges',              num => 1, label => 'Merges' },
+   mutex_os_waits              => { hdr => 'Waits',               num => 1, label => 'Mutex OS Waits' },
+   mutex_spin_rounds           => { hdr => 'Rounds',              num => 1, label => 'Mutex Spin Rounds' },
+   mutex_spin_waits            => { hdr => 'Spins',               num => 1, label => 'Mutex Spin Waits' },
+   mysql_thread_id             => { hdr => 'ID',                  num => 1, label => 'MySQL connection (thread) ID', },
+   name                        => { hdr => 'Name',                num => 0, label => 'Variable Name' },
+   n_bits                      => { hdr => '# Bits',              num => 1, label => 'Number of bits' },
+   non_hash_searches_s         => { hdr => 'Non-Hash/Sec',        num => 1, label => 'Non-hash searches/sec' },
+   num_deletes                 => { hdr => 'Del',                 num => 1, label => 'Number of deletes' },
+   num_deletes_sec             => { hdr => 'Del/Sec',             num => 1, label => 'Number of deletes' },
+   num_inserts                 => { hdr => 'Ins',                 num => 1, label => 'Number of inserts' },
+   num_inserts_sec             => { hdr => 'Ins/Sec',             num => 1, label => 'Number of inserts' },
+   num_readers                 => { hdr => 'Readers',             num => 1, label => 'Number of readers' },
+   num_reads                   => { hdr => 'Read',                num => 1, label => 'Number of reads' },
+   num_reads_sec               => { hdr => 'Read/Sec',            num => 1, label => 'Number of reads' },
+   num_res_ext                 => { hdr => 'BTree Extents',       num => 1, label => 'Number of extents reserved for B-Tree' },
+   num_rows                    => { hdr => 'Row Count',           num => 1, label => 'Number of rows estimated to examine' },
+   num_times_open              => { hdr => 'In Use',              num => 1, label => '# times table is opened', },
+   num_txns                    => { hdr => 'Txns',                num => 1, label => 'Number of transactions' },
+   num_updates                 => { hdr => 'Upd',                 num => 1, label => 'Number of updates' },
+   num_updates_sec             => { hdr => 'Upd/Sec',             num => 1, label => 'Number of updates' },
+   os_file_reads               => { hdr => 'OS Reads',            num => 1, label => 'OS file reads' },
+   os_file_writes              => { hdr => 'OS Writes',           num => 1, label => 'OS file writes' },
+   os_fsyncs                   => { hdr => 'OS fsyncs',           num => 1, label => 'OS fsyncs' },
+   os_thread_id                => { hdr => 'OS Thread',           num => 1, label => 'The operating system thread ID' },
+   p_aio_writes                => { hdr => 'Async Wrt',           num => 1, label => 'Pending asynchronous I/O writes' },
+   p_buf_pool_flushes          => { hdr => 'Buffer Pool Flushes', num => 1, label => 'Pending buffer pool flushes' },
+   p_ibuf_aio_reads            => { hdr => 'IBuf Async Rds',      num => 1, label => 'Pending insert buffer asynch I/O reads' },
+   p_log_flushes               => { hdr => 'Log Flushes',         num => 1, label => 'Pending log flushes' },
+   p_log_ios                   => { hdr => 'Log I/Os',            num => 1, label => 'Pending log I/O operations' },
+   p_normal_aio_reads          => { hdr => 'Async Rds',           num => 1, label => 'Pending asynchronous I/O reads' },
+   p_preads                    => { hdr => 'preads',              num => 1, label => 'Pending p-reads' },
+   p_pwrites                   => { hdr => 'pwrites',             num => 1, label => 'Pending p-writes' },
+   p_sync_ios                  => { hdr => 'Sync I/Os',           num => 1, label => 'Pending synchronous I/O operations' },
+   page_creates_sec            => { hdr => 'Creates/Sec',         num => 1, label => 'Page creates/sec' },
+   page_no                     => { hdr => 'Page',                num => 1, label => 'Page number' },
+   page_reads_sec              => { hdr => 'Reads/Sec',           num => 1, label => 'Page reads per second' },
+   page_writes_sec             => { hdr => 'Writes/Sec',          num => 1, label => 'Page writes per second' },
+   pages_created               => { hdr => 'Created',             num => 1, label => 'Pages created' },
+   pages_modified              => { hdr => 'Dirty Pages',         num => 1, label => 'Pages modified (dirty)' },
+   pages_read                  => { hdr => 'Reads',               num => 1, label => 'Pages read' },
+   pages_total                 => { hdr => 'Pages',               num => 1, label => 'Pages total' },
+   pages_written               => { hdr => 'Writes',              num => 1, label => 'Pages written' },
+   parent_col                  => { hdr => 'Parent Column',       num => 0, label => 'The referred column in the parent table', },
+   parent_db                   => { hdr => 'Parent DB',           num => 0, label => 'The database of the parent table' },
+   parent_index                => { hdr => 'Parent Index',        num => 0, label => 'The referred index in the parent table' },
+   parent_table                => { hdr => 'Parent Table',        num => 0, label => 'The parent table' },
+   part_id                     => { hdr => 'Part ID',             num => 1, label => 'Sub-part ID of the query' },
+   partitions                  => { hdr => 'Partitions',          num => 0, label => 'Query partitions used' },
+   pct                         => { hdr => 'Pct',                 num => 1, label => 'Percentage' },
+   pending_chkp_writes         => { hdr => 'Chkpt Writes',        num => 1, label => 'Pending log checkpoint writes' },
+   pending_log_writes          => { hdr => 'Log Writes',          num => 1, label => 'Pending log writes' },
+   port                        => { hdr => 'Port',                num => 1, label => 'Client port number', },
+   possible_keys               => { hdr => 'Poss. Keys',          num => 0, label => 'Possible keys' },
+   proc_no                     => { hdr => 'Proc',                num => 1, label => 'Process number' },
+   q_cache_hit                 => { hdr => 'QCacheHit',           num => 1, label => 'Query cache hit ratio', },
+   qps                         => { hdr => 'QPS',                 num => 1, label => 'How many queries/sec', },
+   queries_in_queue            => { hdr => 'Queries Queued',      num => 1, label => 'Queries in queue' },
+   queries_inside              => { hdr => 'Queries Inside',      num => 1, label => 'Queries inside InnoDB' },
+   query_id                    => { hdr => 'Query ID',            num => 1, label => 'Query ID' },
+   query_status                => { hdr => 'Query Status',        num => 0, label => 'The query status' },
+   query_text                  => { hdr => 'Query Text',          num => 0, label => 'The query text' },
+   questions                   => { hdr => 'Questions',           num => 1, label => 'How many queries the server has gotten', },
+   read_master_log_pos         => { hdr => 'Read Master Pos',     num => 1, label => 'Read master log position' },
+   read_views_open             => { hdr => 'Rd Views',            num => 1, label => 'Number of read views open' },
+   reads_pending               => { hdr => 'Pending Reads',       num => 1, label => 'Reads pending' },
+   relay_log_file              => { hdr => 'Relay File',          num => 0, label => 'Relay log file' },
+   relay_log_pos               => { hdr => 'Relay Pos',           num => 1, label => 'Relay log position' },
+   relay_log_size              => { hdr => 'Relay Size',          num => 1, label => 'Relay log size' },
+   relay_master_log_file       => { hdr => 'Relay Master File',   num => 0, label => 'Relay master log file' },
+   replicate_do_db             => { hdr => 'Do DB',               num => 0, label => 'Replicate-do-db setting' },
+   replicate_do_table          => { hdr => 'Do Table',            num => 0, label => 'Replicate-do-table setting' },
+   replicate_ignore_db         => { hdr => 'Ignore DB',           num => 0, label => 'Replicate-ignore-db setting' },
+   replicate_ignore_table      => { hdr => 'Ignore Table',        num => 0, label => 'Replicate-do-table setting' },
+   replicate_wild_do_table     => { hdr => 'Wild Do Table',       num => 0, label => 'Replicate-wild-do-table setting' },
+   replicate_wild_ignore_table => { hdr => 'Wild Ignore Table',   num => 0, label => 'Replicate-wild-ignore-table setting' },
+   request_type                => { hdr => 'Type',                num => 0, label => 'Type of lock the thread waits for' },
+   reservation_count           => { hdr => 'ResCnt',              num => 1, label => 'Reservation Count' },
+   row_locks                   => { hdr => 'RLocks',              num => 1, label => 'Number of row locks' },
+   rw_excl_os_waits            => { hdr => 'RW Waits',            num => 1, label => 'R/W Excl. OS Waits' },
+   rw_excl_spins               => { hdr => 'RW Spins',            num => 1, label => 'R/W Excl. Spins' },
+   rw_shared_os_waits          => { hdr => 'Sh Waits',            num => 1, label => 'R/W Shared OS Waits' },
+   rw_shared_spins             => { hdr => 'Sh Spins',            num => 1, label => 'R/W Shared Spins' },
+   scan_type                   => { hdr => 'Type',                num => 0, label => 'Scan type in chosen' },
+   seg_size                    => { hdr => 'Seg. Size',           num => 1, label => 'Segment size' },
+   select_type                 => { hdr => 'Select Type',         num => 0, label => 'Type of select used' },
+   signal_count                => { hdr => 'Signals',             num => 1, label => 'Signal Count' },
+   size                        => { hdr => 'Size',                num => 1, label => 'Size of the tablespace' },
+   skip_counter                => { hdr => 'Skip Counter',        num => 1, label => 'Skip counter' },
+   slave_catchup_rate          => { hdr => 'Catchup',             num => 1, label => 'How fast the slave is catching up in the binlog' },
+   slave_io_running            => { hdr => 'Slave-IO',            num => 0, label => 'Whether the slave I/O thread is running' },
+   slave_io_state              => { hdr => 'Slave IO State',      num => 0, label => 'Slave I/O thread state' },
+   slave_open_temp_tables      => { hdr => 'Temp',                num => 1, label => 'Slave open temp tables' },
+   slave_sql_running           => { hdr => 'Slave-SQL',           num => 0, label => 'Whether the slave SQL thread is running' },
+   slow                        => { hdr => 'Slow',                num => 1, label => 'How many slow queries', },
+   space_id                    => { hdr => 'Space',               num => 1, label => 'Tablespace ID' },
+   special                     => { hdr => 'Special',             num => 0, label => 'Special/Other info' },
+   state                       => { hdr => 'State',               num => 0, label => 'Connection state', maxw => 18, },
+   tables_in_use               => { hdr => 'Tbl Used',            num => 1, label => 'Number of tables in use' },
+   tables_locked               => { hdr => 'Tbl Lck',             num => 1, label => 'Number of tables locked' },
+   tbl                         => { hdr => 'Table',               num => 0, label => 'Table', },
+   thread                      => { hdr => 'Thread',              num => 1, label => 'Thread number' },
+   thread_decl_inside          => { hdr => 'Thread Inside',       num => 0, label => 'What the thread is declared inside' },
+   thread_purpose              => { hdr => 'Purpose',             num => 0, label => "The thread's purpose" },
+   thread_status               => { hdr => 'Thread Status',       num => 0, label => 'The thread status' },
+   time                        => { hdr => 'Time',                num => 1, label => 'Time since the last event', },
+   time_behind_master          => { hdr => 'TimeLag',             num => 1, label => 'Time slave lags master' },
+   timestring                  => { hdr => 'Timestring',          num => 0, label => 'Time the event occurred' },
+   total                       => { hdr => 'Total',               num => 1, label => 'Total' },
+   total_mem_alloc             => { hdr => 'Memory',              num => 1, label => 'Total memory allocated' },
+   truncates                   => { hdr => 'Trunc',               num => 0, label => 'Whether the deadlock is truncating InnoDB status' },
+   txn_doesnt_see_ge           => { hdr => "Txn Won't See",       num => 0, label => 'Where txn read view is limited' },
+   txn_id                      => { hdr => 'ID',                  num => 0, label => 'Transaction ID' },
+   txn_sees_lt                 => { hdr => 'Txn Sees',            num => 1, label => 'Where txn read view is limited' },
+   txn_status                  => { hdr => 'Txn Status',          num => 0, label => 'Transaction status' },
+   txn_time_remain             => { hdr => 'Remaining',           num => 1, label => 'Time until txn rollback/commit completes' },
+   undo_log_entries            => { hdr => 'Undo',                num => 1, label => 'Number of undo log entries' },
+   undo_for                    => { hdr => 'Undo',                num => 0, label => 'Undo for' },
+   until_condition             => { hdr => 'Until Condition',     num => 0, label => 'Slave until condition' },
+   until_log_file              => { hdr => 'Until Log File',      num => 0, label => 'Slave until log file' },
+   until_log_pos               => { hdr => 'Until Log Pos',       num => 1, label => 'Slave until log position' },
+   used_cells                  => { hdr => 'Cells Used',          num => 1, label => 'Number of cells used' },
+   used_bufs                   => { hdr => 'Used Bufs',           num => 1, label => 'Number of buffer pool pages used' },
+   user                        => { hdr => 'User',                num => 0, label => 'Database username', },
+   value                       => { hdr => 'Value',               num => 1, label => 'Value' },
+   versions                    => { hdr => 'Versions',            num => 1, label => 'Number of InnoDB MVCC versions unpurged' },
+   victim                      => { hdr => 'Victim',              num => 0, label => 'Whether this txn was the deadlock victim' },
+   wait_array_size             => { hdr => 'Wait Array Size',     num => 1, label => 'Wait Array Size' },
+   wait_status                 => { hdr => 'Lock Status',         num => 0, label => 'Status of txn locks' },
+   waited_at_filename          => { hdr => 'File',                num => 0, label => 'Filename at which thread waits' },
+   waited_at_line              => { hdr => 'Line',                num => 1, label => 'Line at which thread waits' },
+   waiters_flag                => { hdr => 'Waiters',             num => 1, label => 'Waiters Flag' },
+   waiting                     => { hdr => 'Waiting',             num => 1, label => 'Whether lock is being waited for' },
+   when                        => { hdr => 'When',                num => 0, label => 'Time scale' },
+   writer_lock_mode            => { hdr => 'Wrtr Lck Mode',       num => 0, label => 'Writer lock mode' },
+   writer_thread               => { hdr => 'Wrtr Thread',         num => 1, label => 'Writer thread ID' },
+   writes_pending              => { hdr => 'Writes',              num => 1, label => 'Number of writes pending' },
+   writes_pending_flush_list   => { hdr => 'Flush List Writes',   num => 1, label => 'Number of flush list writes pending' },
+   writes_pending_lru          => { hdr => 'LRU Writes',          num => 1, label => 'Number of LRU writes pending' },
+   writes_pending_single_page  => { hdr => '1-Page Writes',       num => 1, label => 'Number of 1-page writes pending' },
+);
+
+# Apply a default property or three.  By default, columns are not width-constrained,
+# aligned left, and sorted alphabetically, not numerically.
+foreach my $col ( values %columns ) {
+   map { $col->{$_} ||= 0 } qw(num minw maxw);
+   $col->{just} = $col->{num} ? '' : '-';
+}
+
+# Filters {{{3
+# This hash defines every filter that can be applied to a table.  These
+# become part of tbl_meta as well.  Each filter is just an expression that
+# returns true or false.
+# Properties of each entry:
+#  * func:   the subroutine
+#  * name:   the name, repeated
+#  * user:   whether it's a user-defined filter (saved in config)
+#  * text:   text of the subroutine
+#  * note:   explanation
+my %filters = ();
+
+# These are pre-processed to live in %filters above, by compiling them.
+my %builtin_filters = (
+   hide_self => {
+      text => <<'      END',
+         return ( !$set->{info} || $set->{info} ne 'SHOW FULL PROCESSLIST' )
+             && ( !$set->{query_text}    || $set->{query_text} !~ m/INNODB STATUS$/ );
+      END
+      note => 'Removes the innotop processes from the list',
+      tbls => [qw(innodb_transactions processlist)],
+   },
+   hide_inactive => {
+      text => <<'      END',
+         return ( !defined($set->{txn_status}) || $set->{txn_status} ne 'not started' )
+             && ( !defined($set->{cmd})        || $set->{cmd} !~ m/Sleep|Binlog Dump/ )
+             && ( !defined($set->{info})       || $set->{info} =~ m/\S/               );
+      END
+      note => 'Removes processes which are not doing anything',
+      tbls => [qw(innodb_transactions processlist)],
+   },
+   hide_slave_io => {
+      text => <<'      END',
+         return !$set->{state} || $set->{state} !~ m/^(?:Waiting for master|Has read all relay)/;
+      END
+      note => 'Removes slave I/O threads from the list',
+      tbls => [qw(processlist slave_io_status)],
+   },
+   table_is_open => {
+      text => <<'      END',
+         return $set->{num_times_open} + $set->{is_name_locked};
+      END
+      note => 'Removes tables that are not in use or locked',
+      tbls => [qw(open_tables)],
+   },
+   cxn_is_master => {
+      text => <<'      END',
+         return $set->{master_file} ? 1 : 0;
+      END
+      note => 'Removes servers that are not masters',
+      tbls => [qw(master_status)],
+   },
+   cxn_is_slave => {
+      text => <<'      END',
+         return $set->{master_host} ? 1 : 0;
+      END
+      note => 'Removes servers that are not slaves',
+      tbls => [qw(slave_io_status slave_sql_status)],
+   },
+   thd_is_not_waiting => {
+      text => <<'      END',
+         return $set->{thread_status} !~ m#waiting for i/o request#;
+      END
+      note => 'Removes idle I/O threads',
+      tbls => [qw(io_threads)],
+   },
+);
+foreach my $key ( keys %builtin_filters ) {
+   my ( $sub, $err ) = compile_filter($builtin_filters{$key}->{text});
+   $filters{$key} = {
+      func => $sub,
+      text => $builtin_filters{$key}->{text},
+      user => 0,
+      name => $key, # useful for later
+      note => $builtin_filters{$key}->{note},
+      tbls => $builtin_filters{$key}->{tbls},
+   }
+}
+
+# Variable sets {{{3
+# Sets (arrayrefs) of variables that are used in S mode.  They are read/written to
+# the config file.
+my %var_sets = (
+   general => {
+      text => join(
+         ', ',
+         'set_precision(Questions/Uptime_hires) as QPS',
+         'set_precision(Com_commit/Uptime_hires) as Commit_PS',
+         'set_precision((Com_rollback||0)/(Com_commit||1)) as Rollback_Commit',
+         'set_precision(('
+            . join('+', map { "($_||0)" }
+               qw(Com_delete Com_delete_multi Com_insert Com_insert_select Com_replace
+                  Com_replace_select Com_select Com_update Com_update_multi))
+            . ')/(Com_commit||1)) as Write_Commit',
+         'set_precision((Com_select+(Qcache_hits||0))/(('
+            . join('+', map { "($_||0)" }
+               qw(Com_delete Com_delete_multi Com_insert Com_insert_select Com_replace
+                  Com_replace_select Com_select Com_update Com_update_multi))
+            . ')||1)) as R_W_Ratio',
+         'set_precision(Opened_tables/Uptime_hires) as Opens_PS',
+         'percent($cur->{Open_tables}/($cur->{table_cache})) as Table_Cache_Used',
+         'set_precision(Threads_created/Uptime_hires) as Threads_PS',
+         'percent($cur->{Threads_cached}/($cur->{thread_cache_size}||1)) as Thread_Cache_Used',
+         'percent($cur->{Max_used_connections}/($cur->{max_connections}||1)) as CXN_Used_Ever',
+         'percent($cur->{Threads_connected}/($cur->{max_connections}||1)) as CXN_Used_Now',
+      ),
+   },
+   commands => {
+      text => join(
+         ', ',
+         qw(Uptime Questions Com_delete Com_delete_multi Com_insert
+         Com_insert_select Com_replace Com_replace_select Com_select Com_update
+         Com_update_multi)
+      ),
+   },
+   query_status => {
+      text => join(
+         ',',
+         qw( Uptime Select_full_join Select_full_range_join Select_range
+         Select_range_check Select_scan Slow_queries Sort_merge_passes
+         Sort_range Sort_rows Sort_scan)
+      ),
+   },
+   innodb => {
+      text => join(
+         ',',
+         qw( Uptime Innodb_row_lock_current_waits Innodb_row_lock_time
+         Innodb_row_lock_time_avg Innodb_row_lock_time_max Innodb_row_lock_waits
+         Innodb_rows_deleted Innodb_rows_inserted Innodb_rows_read
+         Innodb_rows_updated)
+      ),
+   },
+   txn => {
+      text => join(
+         ',',
+         qw( Uptime Com_begin Com_commit Com_rollback Com_savepoint
+         Com_xa_commit Com_xa_end Com_xa_prepare Com_xa_recover Com_xa_rollback
+         Com_xa_start)
+      ),
+   },
+   key_cache => {
+      text => join(
+         ',',
+         qw( Uptime Key_blocks_not_flushed Key_blocks_unused Key_blocks_used
+         Key_read_requests Key_reads Key_write_requests Key_writes )
+      ),
+   },
+   query_cache => {
+      text => join(
+         ',',
+         "percent($exprs{QcacheHitRatio}) as Hit_Pct",
+         'set_precision((Qcache_hits||0)/(Qcache_inserts||1)) as Hit_Ins',
+         'set_precision((Qcache_lowmem_prunes||0)/Uptime_hires) as Lowmem_Prunes_sec',
+         'percent(1-((Qcache_free_blocks||0)/(Qcache_total_blocks||1))) as Blocks_used',
+         qw( Qcache_free_blocks Qcache_free_memory Qcache_not_cached Qcache_queries_in_cache)
+      ),
+   },
+   handler => {
+      text => join(
+         ',',
+         qw( Uptime Handler_read_key Handler_read_first Handler_read_next
+         Handler_read_prev Handler_read_rnd Handler_read_rnd_next Handler_delete
+         Handler_update Handler_write)
+      ),
+   },
+   cxns_files_threads => {
+      text => join(
+         ',',
+         qw( Uptime Aborted_clients Aborted_connects Bytes_received Bytes_sent
+         Compression Connections Created_tmp_disk_tables Created_tmp_files
+         Created_tmp_tables Max_used_connections Open_files Open_streams
+         Open_tables Opened_tables Table_locks_immediate Table_locks_waited
+         Threads_cached Threads_connected Threads_created Threads_running)
+      ),
+   },
+   prep_stmt => {
+      text => join(
+         ',',
+         qw( Uptime Com_dealloc_sql Com_execute_sql Com_prepare_sql Com_reset
+         Com_stmt_close Com_stmt_execute Com_stmt_fetch Com_stmt_prepare
+         Com_stmt_reset Com_stmt_send_long_data )
+      ),
+   },
+   innodb_health => {
+      text => join(
+         ',',
+         "$exprs{OldVersions} as OldVersions",
+         qw(IB_sm_mutex_spin_waits IB_sm_mutex_spin_rounds IB_sm_mutex_os_waits),
+         "$exprs{NumTxns} as NumTxns",
+         "$exprs{MaxTxnTime} as MaxTxnTime",
+         qw(IB_ro_queries_inside IB_ro_queries_in_queue),
+         "set_precision($exprs{DirtyBufs} * 100) as dirty_bufs",
+         "set_precision($exprs{BufPoolFill} * 100) as buf_fill",
+         qw(IB_bp_pages_total IB_bp_pages_read IB_bp_pages_written IB_bp_pages_created)
+      ),
+   },
+   innodb_health2 => {
+      text => join(
+         ', ',
+         'percent(1-((Innodb_buffer_pool_pages_free||0)/($cur->{Innodb_buffer_pool_pages_total}||1))) as BP_page_cache_usage',
+         'percent(1-((Innodb_buffer_pool_reads||0)/(Innodb_buffer_pool_read_requests||1))) as BP_cache_hit_ratio',
+         'Innodb_buffer_pool_wait_free',
+         'Innodb_log_waits',
+      ),
+   },
+   slow_queries => {
+      text => join(
+         ', ',
+         'set_precision(Slow_queries/Uptime_hires) as Slow_PS',
+         'set_precision(Select_full_join/Uptime_hires) as Full_Join_PS',
+         'percent(Select_full_join/(Com_select||1)) as Full_Join_Ratio',
+      ),
+   },
+);
+
+# Server sets {{{3
+# Defines sets of servers between which the user can quickly switch.
+my %server_groups;
+
+# Connections {{{3
+# This hash defines server connections.  Each connection is a string that can be passed to
+# the DBI connection.  These are saved in the connections section in the config file.
+my %connections;
+# Defines the parts of connections.
+my @conn_parts = qw(user have_user pass have_pass dsn savepass dl_table);
+
+# Graph widths {{{3
+# This hash defines the max values seen for various status/variable values, for graphing.
+# These are stored in their own section in the config file.  These are just initial values:
+my %mvs = (
+   Com_select   => 50,
+   Com_insert   => 50,
+   Com_update   => 50,
+   Com_delete   => 50,
+   Questions    => 100,
+);
+
+# ###########################################################################
+# Valid Term::ANSIColor color strings.
+# ###########################################################################
+my %ansicolors = map { $_ => 1 }
+   qw( black blink blue bold clear concealed cyan dark green magenta on_black
+       on_blue on_cyan on_green on_magenta on_red on_white on_yellow red reset
+       reverse underline underscore white yellow);
+
+# ###########################################################################
+# Valid comparison operators for color rules
+# ###########################################################################
+my %comp_ops = (
+   '==' => 'Numeric equality',
+   '>'  => 'Numeric greater-than',
+   '<'  => 'Numeric less-than',
+   '>=' => 'Numeric greater-than/equal',
+   '<=' => 'Numeric less-than/equal',
+   '!=' => 'Numeric not-equal',
+   'eq' => 'String equality',
+   'gt' => 'String greater-than',
+   'lt' => 'String less-than',
+   'ge' => 'String greater-than/equal',
+   'le' => 'String less-than/equal',
+   'ne' => 'String not-equal',
+   '=~' => 'Pattern match',
+   '!~' => 'Negated pattern match',
+);
+
+# ###########################################################################
+# Valid aggregate functions.
+# ###########################################################################
+my %agg_funcs = (
+   first => sub {
+      return $_[0]
+   },
+   count => sub {
+      return 0 + @_;
+   },
+   avg   => sub {
+      my @args = grep { defined $_ } @_;
+      return (sum(map { m/([\d\.-]+)/g } @args) || 0) / (scalar(@args) || 1);
+   },
+   sum   => sub {
+      my @args = grep { defined $_ } @_;
+      return sum(@args);
+   }
+);
+
+# ###########################################################################
+# Valid functions for transformations.
+# ###########################################################################
+my %trans_funcs = (
+   shorten      => \&shorten,
+   secs_to_time => \&secs_to_time,
+   no_ctrl_char => \&no_ctrl_char,
+   percent      => \&percent,
+   commify      => \&commify,
+   dulint_to_int => \&dulint_to_int,
+   set_precision => \&set_precision,
+);
+
+# Table definitions {{{3
+# This hash defines every table that can get displayed in every mode.  Each
+# table specifies columns and column data sources.  The column is
+# defined by the %columns hash.
+#
+# Example: foo => { src => 'bar' } means the foo column (look at
+# $columns{foo} for its definition) gets its data from the 'bar' element of
+# the current data set, whatever that is.
+#
+# These columns are post-processed after being defined, because they get stuff
+# from %columns.  After all the config is loaded for columns, there's more
+# post-processing too; the subroutines compiled from src get added to
+# the hash elements for extract_values to use.
+# ###########################################################################
+
+my %tbl_meta = (
+   adaptive_hash_index => {
+      capt => 'Adaptive Hash Index',
+      cust => {},
+      cols => {
+         cxn                 => { src => 'cxn' },
+         hash_table_size     => { src => 'IB_ib_hash_table_size', trans => [qw(shorten)], },
+         used_cells          => { src => 'IB_ib_used_cells' },
+         bufs_in_node_heap   => { src => 'IB_ib_bufs_in_node_heap' },
+         hash_searches_s     => { src => 'IB_ib_hash_searches_s' },
+         non_hash_searches_s => { src => 'IB_ib_non_hash_searches_s' },
+      },
+      visible => [ qw(cxn hash_table_size used_cells bufs_in_node_heap hash_searches_s non_hash_searches_s) ],
+      filters => [],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => 'ib',
+      group_by => [],
+      aggregate => 0,
+   },
+   buffer_pool => {
+      capt => 'Buffer Pool',
+      cust => {},
+      cols => {
+         cxn                        => { src => 'cxn' },
+         total_mem_alloc            => { src => 'IB_bp_total_mem_alloc', trans => [qw(shorten)], },
+         awe_mem_alloc              => { src => 'IB_bp_awe_mem_alloc', trans => [qw(shorten)], },
+         add_pool_alloc             => { src => 'IB_bp_add_pool_alloc', trans => [qw(shorten)], },
+         buf_pool_size              => { src => 'IB_bp_buf_pool_size', trans => [qw(shorten)], },
+         buf_free                   => { src => 'IB_bp_buf_free' },
+         buf_pool_hit_rate          => { src => 'IB_bp_buf_pool_hit_rate' },
+         buf_pool_reads             => { src => 'IB_bp_buf_pool_reads' },
+         buf_pool_hits              => { src => 'IB_bp_buf_pool_hits' },
+         dict_mem_alloc             => { src => 'IB_bp_dict_mem_alloc' },
+         pages_total                => { src => 'IB_bp_pages_total' },
+         pages_modified             => { src => 'IB_bp_pages_modified' },
+         reads_pending              => { src => 'IB_bp_reads_pending' },
+         writes_pending             => { src => 'IB_bp_writes_pending' },
+         writes_pending_lru         => { src => 'IB_bp_writes_pending_lru' },
+         writes_pending_flush_list  => { src => 'IB_bp_writes_pending_flush_list' },
+         writes_pending_single_page => { src => 'IB_bp_writes_pending_single_page' },
+         page_creates_sec           => { src => 'IB_bp_page_creates_sec' },
+         page_reads_sec             => { src => 'IB_bp_page_reads_sec' },
+         page_writes_sec            => { src => 'IB_bp_page_writes_sec' },
+         pages_created              => { src => 'IB_bp_pages_created' },
+         pages_read                 => { src => 'IB_bp_pages_read' },
+         pages_written              => { src => 'IB_bp_pages_written' },
+      },
+      visible => [ qw(cxn buf_pool_size buf_free pages_total pages_modified buf_pool_hit_rate total_mem_alloc add_pool_alloc)],
+      filters => [],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => 'bp',
+      group_by => [],
+      aggregate => 0,
+   },
+   # TODO: a new step in set_to_tbl: join result to itself, grouped?
+   # TODO: this would also enable pulling Q and T data together.
+   # TODO: using a SQL-ish language would also allow pivots to be easier -- treat the pivoted data as a view and SELECT from it.
+   cmd_summary => {
+      capt => 'Command Summary',
+      cust => {},
+      cols => {
+         name       => { src => 'name' },
+         total      => { src => 'total' },
+         value      => { src => 'value',                     agg   => 'sum'},
+         pct        => { src => 'value/total',               trans => [qw(percent)] },
+         last_total => { src => 'last_total' },
+         last_value => { src => 'last_value',                agg   => 'sum'},
+         last_pct   => { src => 'last_value/last_total',     trans => [qw(percent)] },
+      },
+      visible   => [qw(name value pct last_value last_pct)],
+      filters   => [qw()],
+      sort_cols => '-value',
+      sort_dir  => '1',
+      innodb    => '',
+      group_by  => [qw(name)],
+      aggregate => 1,
+   },
+   deadlock_locks => {
+      capt => 'Deadlock Locks',
+      cust => {},
+      cols => {
+         cxn              => { src => 'cxn' },
+         mysql_thread_id  => { src => 'mysql_thread_id' },
+         dl_txn_num       => { src => 'dl_txn_num' },
+         lock_type        => { src => 'lock_type' },
+         space_id         => { src => 'space_id' },
+         page_no          => { src => 'page_no' },
+         heap_no          => { src => 'heap_no' },
+         n_bits           => { src => 'n_bits' },
+         index            => { src => 'index' },
+         db               => { src => 'db' },
+         tbl              => { src => 'table' },
+         lock_mode        => { src => 'lock_mode' },
+         special          => { src => 'special' },
+         insert_intention => { src => 'insert_intention' },
+         waiting          => { src => 'waiting' },
+      },
+      visible => [ qw(cxn mysql_thread_id waiting lock_mode db tbl index special insert_intention)],
+      filters => [],
+      sort_cols => 'cxn mysql_thread_id',
+      sort_dir => '1',
+      innodb   => 'dl',
+      group_by => [],
+      aggregate => 0,
+   },
+   deadlock_transactions => {
+      capt => 'Deadlock Transactions',
+      cust => {},
+      cols => {
+         cxn                => { src => 'cxn' },
+         active_secs        => { src => 'active_secs' },
+         dl_txn_num         => { src => 'dl_txn_num' },
+         has_read_view      => { src => 'has_read_view' },
+         heap_size          => { src => 'heap_size' },
+         host_and_domain    => { src => 'hostname' },
+         hostname           => { src => $exprs{Host} },
+         ip                 => { src => 'ip' },
+         lock_structs       => { src => 'lock_structs' },
+         lock_wait_time     => { src => 'lock_wait_time', trans => [ qw(secs_to_time) ] },
+         mysql_thread_id    => { src => 'mysql_thread_id' },
+         os_thread_id       => { src => 'os_thread_id' },
+         proc_no            => { src => 'proc_no' },
+         query_id           => { src => 'query_id' },
+         query_status       => { src => 'query_status' },
+         query_text         => { src => 'query_text', trans => [ qw(no_ctrl_char) ] },
+         row_locks          => { src => 'row_locks' },
+         tables_in_use      => { src => 'tables_in_use' },
+         tables_locked      => { src => 'tables_locked' },
+         thread_decl_inside => { src => 'thread_decl_inside' },
+         thread_status      => { src => 'thread_status' },
+         'time'             => { src => 'active_secs', trans => [ qw(secs_to_time) ] },
+         timestring         => { src => 'timestring' },
+         txn_doesnt_see_ge  => { src => 'txn_doesnt_see_ge' },
+         txn_id             => { src => 'txn_id' },
+         txn_sees_lt        => { src => 'txn_sees_lt' },
+         txn_status         => { src => 'txn_status' },
+         truncates          => { src => 'truncates' },
+         undo_log_entries   => { src => 'undo_log_entries' },
+         user               => { src => 'user' },
+         victim             => { src => 'victim' },
+         wait_status        => { src => 'lock_wait_status' },
+      },
+      visible => [ qw(cxn mysql_thread_id timestring user hostname victim time undo_log_entries lock_structs query_text)],
+      filters => [],
+      sort_cols => 'cxn mysql_thread_id',
+      sort_dir => '1',
+      innodb   => 'dl',
+      group_by => [],
+      aggregate => 0,
+   },
+   explain => {
+      capt => 'EXPLAIN Results',
+      cust => {},
+      cols => {
+         part_id       => { src => 'id' },
+         select_type   => { src => 'select_type' },
+         tbl           => { src => 'table' },
+         partitions    => { src => 'partitions' },
+         scan_type     => { src => 'type' },
+         possible_keys => { src => 'possible_keys' },
+         index         => { src => 'key' },
+         key_len       => { src => 'key_len' },
+         index_ref     => { src => 'ref' },
+         num_rows      => { src => 'rows' },
+         special       => { src => 'extra' },
+      },
+      visible => [ qw(select_type tbl partitions scan_type possible_keys index key_len index_ref num_rows special)],
+      filters => [],
+      sort_cols => '',
+      sort_dir => '1',
+      innodb   => '',
+      group_by => [],
+      aggregate => 0,
+   },
+   file_io_misc => {
+      capt => 'File I/O Misc',
+      cust => {},
+      cols => {
+         cxn            => { src => 'cxn' },
+         io_bytes_s     => { src => 'IB_io_avg_bytes_s' },
+         io_flush_type  => { src => 'IB_io_flush_type' },
+         io_fsyncs_s    => { src => 'IB_io_fsyncs_s' },
+         io_reads_s     => { src => 'IB_io_reads_s' },
+         io_writes_s    => { src => 'IB_io_writes_s' },
+         os_file_reads  => { src => 'IB_io_os_file_reads' },
+         os_file_writes => { src => 'IB_io_os_file_writes' },
+         os_fsyncs      => { src => 'IB_io_os_fsyncs' },
+      },
+      visible => [ qw(cxn os_file_reads os_file_writes os_fsyncs io_reads_s io_writes_s io_bytes_s)],
+      filters => [],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => 'io',
+      group_by => [],
+      aggregate => 0,
+   },
+   fk_error => {
+      capt => 'Foreign Key Error Info',
+      cust => {},
+      cols => {
+         timestring   => { src => 'IB_fk_timestring' },
+         child_db     => { src => 'IB_fk_child_db' },
+         child_table  => { src => 'IB_fk_child_table' },
+         child_index  => { src => 'IB_fk_child_index' },
+         fk_name      => { src => 'IB_fk_fk_name' },
+         parent_db    => { src => 'IB_fk_parent_db' },
+         parent_table => { src => 'IB_fk_parent_table' },
+         parent_col   => { src => 'IB_fk_parent_col' },
+         parent_index => { src => 'IB_fk_parent_index' },
+         attempted_op => { src => 'IB_fk_attempted_op' },
+      },
+      visible => [ qw(timestring child_db child_table child_index parent_db parent_table parent_col parent_index fk_name attempted_op)],
+      filters => [],
+      sort_cols => '',
+      sort_dir => '1',
+      innodb   => 'fk',
+      group_by => [],
+      aggregate => 0,
+   },
+   insert_buffers => {
+      capt => 'Insert Buffers',
+      cust => {},
+      cols => {
+         cxn           => { src => 'cxn' },
+         inserts       => { src => 'IB_ib_inserts' },
+         merged_recs   => { src => 'IB_ib_merged_recs' },
+         merges        => { src => 'IB_ib_merges' },
+         size          => { src => 'IB_ib_size' },
+         free_list_len => { src => 'IB_ib_free_list_len' },
+         seg_size      => { src => 'IB_ib_seg_size' },
+      },
+      visible => [ qw(cxn inserts merged_recs merges size free_list_len seg_size)],
+      filters => [],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => 'ib',
+      group_by => [],
+      aggregate => 0,
+   },
+   innodb_locks  => {
+      capt => 'InnoDB Locks',
+      cust => {},
+      cols => {
+         cxn              => { src => 'cxn' },
+         db               => { src => 'db' },
+         index            => { src => 'index' },
+         insert_intention => { src => 'insert_intention' },
+         lock_mode        => { src => 'lock_mode' },
+         lock_type        => { src => 'lock_type' },
+         lock_wait_time   => { src => 'lock_wait_time', trans => [ qw(secs_to_time) ] },
+         mysql_thread_id  => { src => 'mysql_thread_id' },
+         n_bits           => { src => 'n_bits' },
+         page_no          => { src => 'page_no' },
+         space_id         => { src => 'space_id' },
+         special          => { src => 'special' },
+         tbl              => { src => 'table' },
+         'time'           => { src => 'active_secs', hdr => 'Active', trans => [ qw(secs_to_time) ] },
+         txn_id           => { src => 'txn_id' },
+         waiting          => { src => 'waiting' },
+      },
+      visible => [ qw(cxn mysql_thread_id lock_type waiting lock_wait_time time lock_mode db tbl index insert_intention special)],
+      filters => [],
+      sort_cols => 'cxn -lock_wait_time',
+      sort_dir => '1',
+      innodb   => 'tx',
+      colors   => [
+         { col => 'lock_wait_time', op => '>',  arg => 60, color => 'red' },
+         { col => 'lock_wait_time', op => '>',  arg => 30, color => 'yellow' },
+         { col => 'lock_wait_time', op => '>',  arg => 10, color => 'green' },
+      ],
+      group_by => [],
+      aggregate => 0,
+   },
+   innodb_transactions => {
+      capt => 'InnoDB Transactions',
+      cust => {},
+      cols => {
+         cxn                => { src => 'cxn' },
+         active_secs        => { src => 'active_secs' },
+         has_read_view      => { src => 'has_read_view' },
+         heap_size          => { src => 'heap_size' },
+         hostname           => { src => $exprs{Host} },
+         ip                 => { src => 'ip' },
+         wait_status        => { src => 'lock_wait_status' },
+         lock_wait_time     => { src => 'lock_wait_time',      trans => [ qw(secs_to_time) ] },
+         lock_structs       => { src => 'lock_structs' },
+         mysql_thread_id    => { src => 'mysql_thread_id' },
+         os_thread_id       => { src => 'os_thread_id' },
+         proc_no            => { src => 'proc_no' },
+         query_id           => { src => 'query_id' },
+         query_status       => { src => 'query_status' },
+         query_text         => { src => 'query_text',          trans => [ qw(no_ctrl_char) ] },
+         txn_time_remain    => { src => $exprs{TxnTimeRemain}, trans => [ qw(secs_to_time) ] },
+         row_locks          => { src => 'row_locks' },
+         tables_in_use      => { src => 'tables_in_use' },
+         tables_locked      => { src => 'tables_locked' },
+         thread_decl_inside => { src => 'thread_decl_inside' },
+         thread_status      => { src => 'thread_status' },
+         'time'             => { src => 'active_secs',         trans => [ qw(secs_to_time) ], agg => 'sum' },
+         txn_doesnt_see_ge  => { src => 'txn_doesnt_see_ge' },
+         txn_id             => { src => 'txn_id' },
+         txn_sees_lt        => { src => 'txn_sees_lt' },
+         txn_status         => { src => 'txn_status',          minw => 10, maxw => 10 },
+         undo_log_entries   => { src => 'undo_log_entries' },
+         user               => { src => 'user',                maxw => 10 },
+         cnt                => { src => 'mysql_thread_id',     minw => 0 },
+      },
+      visible => [ qw(cxn cnt mysql_thread_id user hostname txn_status time undo_log_entries query_text)],
+      filters => [ qw( hide_self hide_inactive ) ],
+      sort_cols => '-active_secs txn_status cxn mysql_thread_id',
+      sort_dir => '1',
+      innodb   => 'tx',
+      hide_caption => 1,
+      colors   => [
+         { col => 'wait_status', op => 'eq', arg => 'LOCK WAIT',   color => 'black on_red' },
+         { col => 'time',        op => '>',  arg => 600,           color => 'red' },
+         { col => 'time',        op => '>',  arg => 300,           color => 'yellow' },
+         { col => 'time',        op => '>',  arg => 60,            color => 'green' },
+         { col => 'time',        op => '>',  arg => 30,            color => 'cyan' },
+         { col => 'txn_status',  op => 'eq', arg => 'not started', color => 'white' },
+      ],
+      group_by => [ qw(cxn txn_status) ],
+      aggregate => 0,
+   },
+   io_threads => {
+      capt => 'I/O Threads',
+      cust => {},
+      cols => {
+         cxn            => { src => 'cxn' },
+         thread         => { src => 'thread' },
+         thread_purpose => { src => 'purpose' },
+         event_set      => { src => 'event_set' },
+         thread_status  => { src => 'state' },
+      },
+      visible => [ qw(cxn thread thread_purpose thread_status)],
+      filters => [ qw() ],
+      sort_cols => 'cxn thread',
+      sort_dir => '1',
+      innodb   => 'io',
+      group_by => [],
+      aggregate => 0,
+   },
+   log_statistics => {
+      capt => 'Log Statistics',
+      cust => {},
+      cols => {
+         cxn                 => { src => 'cxn' },
+         last_chkp           => { src => 'IB_lg_last_chkp' },
+         log_flushed_to      => { src => 'IB_lg_log_flushed_to' },
+         log_ios_done        => { src => 'IB_lg_log_ios_done' },
+         log_ios_s           => { src => 'IB_lg_log_ios_s' },
+         log_seq_no          => { src => 'IB_lg_log_seq_no' },
+         pending_chkp_writes => { src => 'IB_lg_pending_chkp_writes' },
+         pending_log_writes  => { src => 'IB_lg_pending_log_writes' },
+      },
+      visible => [ qw(cxn log_seq_no log_flushed_to last_chkp log_ios_done log_ios_s)],
+      filters => [],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => 'lg',
+      group_by => [],
+      aggregate => 0,
+   },
+   master_status => {
+      capt => 'Master Status',
+      cust => {},
+      cols => {
+         cxn                         => { src => 'cxn' },
+         binlog_do_db                => { src => 'binlog_do_db' },
+         binlog_ignore_db            => { src => 'binlog_ignore_db' },
+         master_file                 => { src => 'file' },
+         master_pos                  => { src => 'position' },
+         binlog_cache_overflow       => { src => '(Binlog_cache_disk_use||0)/(Binlog_cache_use||1)', trans => [ qw(percent) ] },
+      },
+      visible => [ qw(cxn master_file master_pos binlog_cache_overflow)],
+      filters => [ qw(cxn_is_master) ],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => '',
+      group_by => [],
+      aggregate => 0,
+   },
+   pending_io => {
+      capt => 'Pending I/O',
+      cust => {},
+      cols => {
+         cxn                => { src => 'cxn' },
+         p_normal_aio_reads => { src => 'IB_io_pending_normal_aio_reads' },
+         p_aio_writes       => { src => 'IB_io_pending_aio_writes' },
+         p_ibuf_aio_reads   => { src => 'IB_io_pending_ibuf_aio_reads' },
+         p_sync_ios         => { src => 'IB_io_pending_sync_ios' },
+         p_buf_pool_flushes => { src => 'IB_io_pending_buffer_pool_flushes' },
+         p_log_flushes      => { src => 'IB_io_pending_log_flushes' },
+         p_log_ios          => { src => 'IB_io_pending_log_ios' },
+         p_preads           => { src => 'IB_io_pending_preads' },
+         p_pwrites          => { src => 'IB_io_pending_pwrites' },
+      },
+      visible => [ qw(cxn p_normal_aio_reads p_aio_writes p_ibuf_aio_reads p_sync_ios p_log_flushes p_log_ios)],
+      filters => [],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => 'io',
+      group_by => [],
+      aggregate => 0,
+   },
+   open_tables => {
+      capt => 'Open Tables',
+      cust => {},
+      cols => {
+         cxn            => { src => 'cxn' },
+         db             => { src => 'database' },
+         tbl            => { src => 'table' },
+         num_times_open => { src => 'in_use' },
+         is_name_locked => { src => 'name_locked' },
+      },
+      visible => [ qw(cxn db tbl num_times_open is_name_locked)],
+      filters => [ qw(table_is_open) ],
+      sort_cols => '-num_times_open cxn db tbl',
+      sort_dir => '1',
+      innodb   => '',
+      group_by => [],
+      aggregate => 0,
+   },
+   page_statistics => {
+      capt => 'Page Statistics',
+      cust => {},
+      cols => {
+         cxn              => { src => 'cxn' },
+         pages_read       => { src => 'IB_bp_pages_read' },
+         pages_written    => { src => 'IB_bp_pages_written' },
+         pages_created    => { src => 'IB_bp_pages_created' },
+         page_reads_sec   => { src => 'IB_bp_page_reads_sec' },
+         page_writes_sec  => { src => 'IB_bp_page_writes_sec' },
+         page_creates_sec => { src => 'IB_bp_page_creates_sec' },
+      },
+      visible => [ qw(cxn pages_read pages_written pages_created page_reads_sec page_writes_sec page_creates_sec)],
+      filters => [],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => 'bp',
+      group_by => [],
+      aggregate => 0,
+   },
+   processlist => {
+      capt => 'MySQL Process List',
+      cust => {},
+      cols => {
+         cxn             => { src => 'cxn',        minw => 6,  maxw => 10 },
+         mysql_thread_id => { src => 'id',         minw => 6,  maxw => 0 },
+         user            => { src => 'user',       minw => 5,  maxw => 8 },
+         hostname        => { src => $exprs{Host}, minw => 13, maxw => 8, },
+         port            => { src => $exprs{Port}, minw => 0,  maxw => 0, },
+         host_and_port   => { src => 'host',       minw => 0,  maxw => 0 },
+         db              => { src => 'db',         minw => 6,  maxw => 12 },
+         cmd             => { src => 'command',    minw => 5,  maxw => 0 },
+         time            => { src => 'time',       minw => 5,  maxw => 0, trans => [ qw(secs_to_time) ], agg => 'sum' },
+         state           => { src => 'state',      minw => 0,  maxw => 0 },
+         info            => { src => 'info',       minw => 0,  maxw => 0, trans => [ qw(no_ctrl_char) ] },
+         cnt             => { src => 'id',         minw => 0,  maxw => 0 },
+      },
+      visible => [ qw(cxn cmd cnt mysql_thread_id state user hostname db time info)],
+      filters => [ qw(hide_self hide_inactive hide_slave_io) ],
+      sort_cols => '-time cxn hostname mysql_thread_id',
+      sort_dir => '1',
+      innodb   => '',
+      hide_caption => 1,
+      colors   => [
+         { col => 'state',       op => 'eq', arg => 'Locked',      color => 'black on_red' },
+         { col => 'cmd',         op => 'eq', arg => 'Sleep',       color => 'white' },
+         { col => 'user',        op => 'eq', arg => 'system user', color => 'white' },
+         { col => 'cmd',         op => 'eq', arg => 'Connect',     color => 'white' },
+         { col => 'cmd',         op => 'eq', arg => 'Binlog Dump', color => 'white' },
+         { col => 'time',        op => '>',  arg => 600,           color => 'red' },
+         { col => 'time',        op => '>',  arg => 120,           color => 'yellow' },
+         { col => 'time',        op => '>',  arg => 60,            color => 'green' },
+         { col => 'time',        op => '>',  arg => 30,            color => 'cyan' },
+      ],
+      group_by => [qw(cxn cmd)],
+      aggregate => 0,
+   },
+
+   # TODO: some more columns:
+   # kb_used=hdr='BufUsed' minw='0' num='0' src='percent(1 - ((Key_blocks_unused * key_cache_block_size) / (key_buffer_size||1)))' dec='0' trans='' tbl='q_header' just='-' user='1' maxw='0' label='User-defined'
+   # retries=hdr='Retries' minw='0' num='0' src='Slave_retried_transactions' dec='0' trans='' tbl='slave_sql_status' just='-' user='1' maxw='0' label='User-defined'
+   # thd=hdr='Thd' minw='0' num='0' src='Threads_connected' dec='0' trans='' tbl='slave_sql_status' just='-' user='1' maxw='0' label='User-defined'
+
+   q_header => {
+      capt => 'Q-mode Header',
+      cust => {},
+      cols => {
+         cxn            => { src => 'cxn' },
+         questions      => { src => 'Questions' },
+         qps            => { src => 'Questions/Uptime_hires',               dec => 1, trans => [qw(shorten)] },
+         load           => { src => $exprs{ServerLoad},                     dec => 1, trans => [qw(shorten)] },
+         slow           => { src => 'Slow_queries',                         dec => 1, trans => [qw(shorten)] },
+         q_cache_hit    => { src => $exprs{QcacheHitRatio},                 dec => 1, trans => [qw(percent)] },
+         key_buffer_hit => { src => '1-(Key_reads/(Key_read_requests||1))', dec => 1, trans => [qw(percent)] },
+         bps_in         => { src => 'Bytes_received/Uptime_hires',          dec => 1, trans => [qw(shorten)] },
+         bps_out        => { src => 'Bytes_sent/Uptime_hires',              dec => 1, trans => [qw(shorten)] },
+         when           => { src => 'when' },
+      },
+      visible => [ qw(cxn when load qps slow q_cache_hit key_buffer_hit bps_in bps_out)],
+      filters => [],
+      sort_cols => 'when cxn',
+      sort_dir => '1',
+      innodb   => '',
+      hide_caption => 1,
+      group_by => [],
+      aggregate => 0,
+   },
+   row_operations => {
+      capt => 'InnoDB Row Operations',
+      cust => {},
+      cols => {
+         cxn         => { src => 'cxn' },
+         num_inserts => { src => 'IB_ro_num_rows_ins' },
+         num_updates => { src => 'IB_ro_num_rows_upd' },
+         num_reads   => { src => 'IB_ro_num_rows_read' },
+         num_deletes => { src => 'IB_ro_num_rows_del' },
+         num_inserts_sec => { src => 'IB_ro_ins_sec' },
+         num_updates_sec => { src => 'IB_ro_upd_sec' },
+         num_reads_sec   => { src => 'IB_ro_read_sec' },
+         num_deletes_sec => { src => 'IB_ro_del_sec' },
+      },
+      visible => [ qw(cxn num_inserts num_updates num_reads num_deletes num_inserts_sec
+                       num_updates_sec num_reads_sec num_deletes_sec)],
+      filters => [],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => 'ro',
+      group_by => [],
+      aggregate => 0,
+   },
+   row_operation_misc => {
+      capt => 'Row Operation Misc',
+      cust => {},
+      cols => {
+         cxn                 => { src => 'cxn' },
+         queries_in_queue    => { src => 'IB_ro_queries_in_queue' },
+         queries_inside      => { src => 'IB_ro_queries_inside' },
+         read_views_open     => { src => 'IB_ro_read_views_open' },
+         main_thread_id      => { src => 'IB_ro_main_thread_id' },
+         main_thread_proc_no => { src => 'IB_ro_main_thread_proc_no' },
+         main_thread_state   => { src => 'IB_ro_main_thread_state' },
+         num_res_ext         => { src => 'IB_ro_n_reserved_extents' },
+      },
+      visible => [ qw(cxn queries_in_queue queries_inside read_views_open main_thread_state)],
+      filters => [],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => 'ro',
+      group_by => [],
+      aggregate => 0,
+   },
+   semaphores => {
+      capt => 'InnoDB Semaphores',
+      cust => {},
+      cols => {
+         cxn                => { src => 'cxn' },
+         mutex_os_waits     => { src => 'IB_sm_mutex_os_waits' },
+         mutex_spin_rounds  => { src => 'IB_sm_mutex_spin_rounds' },
+         mutex_spin_waits   => { src => 'IB_sm_mutex_spin_waits' },
+         reservation_count  => { src => 'IB_sm_reservation_count' },
+         rw_excl_os_waits   => { src => 'IB_sm_rw_excl_os_waits' },
+         rw_excl_spins      => { src => 'IB_sm_rw_excl_spins' },
+         rw_shared_os_waits => { src => 'IB_sm_rw_shared_os_waits' },
+         rw_shared_spins    => { src => 'IB_sm_rw_shared_spins' },
+         signal_count       => { src => 'IB_sm_signal_count' },
+         wait_array_size    => { src => 'IB_sm_wait_array_size' },
+      },
+      visible => [ qw(cxn mutex_os_waits mutex_spin_waits mutex_spin_rounds
+         rw_excl_os_waits rw_excl_spins rw_shared_os_waits rw_shared_spins
+         signal_count reservation_count )],
+      filters => [],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => 'sm',
+      group_by => [],
+      aggregate => 0,
+   },
+   slave_io_status => {
+      capt => 'Slave I/O Status',
+      cust => {},
+      cols => {
+         cxn                         => { src => 'cxn' },
+         connect_retry               => { src => 'connect_retry' },
+         master_host                 => { src => 'master_host', hdr => 'Master'},
+         master_log_file             => { src => 'master_log_file', hdr => 'File' },
+         master_port                 => { src => 'master_port' },
+         master_ssl_allowed          => { src => 'master_ssl_allowed' },
+         master_ssl_ca_file          => { src => 'master_ssl_ca_file' },
+         master_ssl_ca_path          => { src => 'master_ssl_ca_path' },
+         master_ssl_cert             => { src => 'master_ssl_cert' },
+         master_ssl_cipher           => { src => 'master_ssl_cipher' },
+         master_ssl_key              => { src => 'master_ssl_key' },
+         master_user                 => { src => 'master_user' },
+         read_master_log_pos         => { src => 'read_master_log_pos', hdr => 'Pos' },
+         relay_log_size              => { src => 'relay_log_space', trans => [qw(shorten)] },
+         slave_io_running            => { src => 'slave_io_running', hdr => 'On?' },
+         slave_io_state              => { src => 'slave_io_state', hdr => 'State' },
+      },
+      visible => [ qw(cxn master_host slave_io_running master_log_file relay_log_size read_master_log_pos slave_io_state)],
+      filters => [ qw( cxn_is_slave ) ],
+      sort_cols => 'slave_io_running cxn',
+      colors   => [
+         { col => 'slave_io_running',  op => 'ne', arg => 'Yes', color => 'black on_red' },
+      ],
+      sort_dir => '1',
+      innodb   => '',
+      group_by => [],
+      aggregate => 0,
+   },
+   slave_sql_status => {
+      capt => 'Slave SQL Status',
+      cust => {},
+      cols => {
+         cxn                         => { src => 'cxn' },
+         exec_master_log_pos         => { src => 'exec_master_log_pos', hdr => 'Master Pos' },
+         last_errno                  => { src => 'last_errno' },
+         last_error                  => { src => 'last_error' },
+         master_host                 => { src => 'master_host', hdr => 'Master' },
+         relay_log_file              => { src => 'relay_log_file' },
+         relay_log_pos               => { src => 'relay_log_pos' },
+         relay_log_size              => { src => 'relay_log_space', trans => [qw(shorten)] },
+         relay_master_log_file       => { src => 'relay_master_log_file', hdr => 'Master File' },
+         replicate_do_db             => { src => 'replicate_do_db' },
+         replicate_do_table          => { src => 'replicate_do_table' },
+         replicate_ignore_db         => { src => 'replicate_ignore_db' },
+         replicate_ignore_table      => { src => 'replicate_ignore_table' },
+         replicate_wild_do_table     => { src => 'replicate_wild_do_table' },
+         replicate_wild_ignore_table => { src => 'replicate_wild_ignore_table' },
+         skip_counter                => { src => 'skip_counter' },
+         slave_sql_running           => { src => 'slave_sql_running', hdr => 'On?' },
+         until_condition             => { src => 'until_condition' },
+         until_log_file              => { src => 'until_log_file' },
+         until_log_pos               => { src => 'until_log_pos' },
+         time_behind_master          => { src => 'seconds_behind_master', trans => [ qw(secs_to_time) ] },
+         bytes_behind_master         => { src => 'master_log_file && master_log_file eq relay_master_log_file ? read_master_log_pos - exec_master_log_pos : 0', trans => [qw(shorten)] },
+         slave_catchup_rate          => { src => $exprs{SlaveCatchupRate}, trans => [ qw(set_precision) ] },
+         slave_open_temp_tables      => { src => 'Slave_open_temp_tables' },
+      },
+      visible => [ qw(cxn master_host slave_sql_running time_behind_master slave_catchup_rate slave_open_temp_tables relay_log_pos last_error)],
+      filters => [ qw( cxn_is_slave ) ],
+      sort_cols => 'slave_sql_running cxn',
+      sort_dir => '1',
+      innodb   => '',
+      colors   => [
+         { col => 'slave_sql_running',  op => 'ne', arg => 'Yes', color => 'black on_red' },
+         { col => 'time_behind_master', op => '>',  arg => 600,   color => 'red' },
+         { col => 'time_behind_master', op => '>',  arg => 60,    color => 'yellow' },
+         { col => 'time_behind_master', op => '==', arg => 0,     color => 'white' },
+      ],
+      group_by => [],
+      aggregate => 0,
+   },
+   t_header => {
+      capt => 'T-Mode Header',
+      cust => {},
+      cols => {
+         cxn                         => { src => 'cxn' },
+         dirty_bufs                  => { src => $exprs{DirtyBufs},           trans => [qw(percent)] },
+         history_list_len            => { src => 'IB_tx_history_list_len' },
+         lock_structs                => { src => 'IB_tx_num_lock_structs' },
+         num_txns                    => { src => $exprs{NumTxns} },
+         max_txn                     => { src => $exprs{MaxTxnTime},          trans => [qw(secs_to_time)] },
+         undo_for                    => { src => 'IB_tx_purge_undo_for' },
+         used_bufs                   => { src => $exprs{BufPoolFill},         trans => [qw(percent)]},
+         versions                    => { src => $exprs{OldVersions} },
+      },
+      visible => [ qw(cxn history_list_len versions undo_for dirty_bufs used_bufs num_txns max_txn lock_structs)],
+      filters => [ ],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => '',
+      colors   => [],
+      hide_caption => 1,
+      group_by => [],
+      aggregate => 0,
+   },
+   var_status => {
+      capt      => 'Variables & Status',
+      cust      => {},
+      cols      => {}, # Generated from current varset
+      visible   => [], # Generated from current varset
+      filters   => [],
+      sort_cols => '',
+      sort_dir  => 1,
+      innodb    => '',
+      temp      => 1, # Do not persist to config file.
+      hide_caption  => 1,
+      pivot     => 0,
+      group_by => [],
+      aggregate => 0,
+   },
+   wait_array => {
+      capt => 'InnoDB Wait Array',
+      cust => {},
+      cols => {
+         cxn                => { src => 'cxn' },
+         thread             => { src => 'thread' },
+         waited_at_filename => { src => 'waited_at_filename' },
+         waited_at_line     => { src => 'waited_at_line' },
+         'time'             => { src => 'waited_secs', trans => [ qw(secs_to_time) ] },
+         request_type       => { src => 'request_type' },
+         lock_mem_addr      => { src => 'lock_mem_addr' },
+         lock_cfile_name    => { src => 'lock_cfile_name' },
+         lock_cline         => { src => 'lock_cline' },
+         writer_thread      => { src => 'writer_thread' },
+         writer_lock_mode   => { src => 'writer_lock_mode' },
+         num_readers        => { src => 'num_readers' },
+         lock_var           => { src => 'lock_var' },
+         waiters_flag       => { src => 'waiters_flag' },
+         last_s_file_name   => { src => 'last_s_file_name' },
+         last_s_line        => { src => 'last_s_line' },
+         last_x_file_name   => { src => 'last_x_file_name' },
+         last_x_line        => { src => 'last_x_line' },
+         cell_waiting       => { src => 'cell_waiting' },
+         cell_event_set     => { src => 'cell_event_set' },
+      },
+      visible => [ qw(cxn thread time waited_at_filename waited_at_line request_type num_readers lock_var waiters_flag cell_waiting cell_event_set)],
+      filters => [],
+      sort_cols => 'cxn -time',
+      sort_dir => '1',
+      innodb   => 'sm',
+      group_by => [],
+      aggregate => 0,
+   },
+);
+
+# Initialize %tbl_meta from %columns and do some checks.
+foreach my $table_name ( keys %tbl_meta ) {
+   my $table = $tbl_meta{$table_name};
+   my $cols  = $table->{cols};
+
+   foreach my $col_name ( keys %$cols ) {
+      my $col_def = $table->{cols}->{$col_name};
+      die "I can't find a column named '$col_name' for '$table_name'" unless $columns{$col_name};
+      $columns{$col_name}->{referenced} = 1;
+
+      foreach my $prop ( keys %col_props ) {
+         # Each column gets non-existing values set from %columns or defaults from %col_props.
+         if ( !$col_def->{$prop} ) {
+            $col_def->{$prop}
+               = defined($columns{$col_name}->{$prop})
+               ? $columns{$col_name}->{$prop}
+               : $col_props{$prop};
+         }
+      }
+
+      # Ensure transformations and aggregate functions are valid
+      die "Unknown aggregate function '$col_def->{agg}' "
+         . "for column '$col_name' in table '$table_name'"
+         unless exists $agg_funcs{$col_def->{agg}};
+      foreach my $trans ( @{$col_def->{trans}} ) {
+         die "Unknown transformation '$trans' "
+            . "for column '$col_name' in table '$table_name'"
+            unless exists $trans_funcs{$trans};
+      }
+   }
+
+   # Ensure each column in visible and group_by exists in cols
+   foreach my $place ( qw(visible group_by) ) {
+      foreach my $col_name ( @{$table->{$place}} ) {
+         if ( !exists $cols->{$col_name} ) {
+            die "Column '$col_name' is listed in '$place' for '$table_name', but doesn't exist";
+         }
+      }
+   }
+
+   # Compile sort and color subroutines
+   $table->{sort_func}  = make_sort_func($table);
+   $table->{color_func} = make_color_func($table);
+}
+
+# This is for code cleanup:
+{
+   my @unused_cols = grep { !$columns{$_}->{referenced} } sort keys %columns;
+   if ( @unused_cols ) {
+      die "The following columns are not used: "
+         . join(' ', @unused_cols);
+   }
+}
+
+# ###########################################################################
+# Operating modes {{{3
+# ###########################################################################
+my %modes = (
+   B => {
+      hdr               => 'InnoDB Buffers',
+      cust              => {},
+      note              => 'Shows buffer info from InnoDB',
+      action_for        => {
+         i => {
+            action => sub { toggle_config('status_inc') },
+            label  => 'Toggle incremental status display',
+         },
+      },
+      display_sub       => \&display_B,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 0,
+      tables            => [qw(buffer_pool page_statistics insert_buffers adaptive_hash_index)],
+      visible_tables    => [qw(buffer_pool page_statistics insert_buffers adaptive_hash_index)],
+   },
+   C => {
+      hdr               => 'Command Summary',
+      cust              => {},
+      note              => 'Shows relative magnitude of variables',
+      action_for        => {
+         s => {
+            action => sub { get_config_interactive('cmd_filter') },
+            label  => 'Choose variable prefix',
+         },
+      },
+      display_sub       => \&display_C,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 0,
+      tables            => [qw(cmd_summary)],
+      visible_tables    => [qw(cmd_summary)],
+   },
+   D => {
+      hdr               => 'InnoDB Deadlocks',
+      cust              => {},
+      note              => 'View InnoDB deadlock information',
+      action_for        => {
+         c => {
+            action => sub { edit_table('deadlock_transactions') },
+            label  => 'Choose visible columns',
+         },
+         w => {
+            action => \&create_deadlock,
+            label  => 'Wipe deadlock status info by creating a deadlock',
+         },
+      },
+      display_sub       => \&display_D,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 0,
+      tables            => [qw(deadlock_transactions deadlock_locks)],
+      visible_tables    => [qw(deadlock_transactions deadlock_locks)],
+   },
+   F => {
+      hdr               => 'InnoDB FK Err',
+      cust              => {},
+      note              => 'View the latest InnoDB foreign key error',
+      action_for        => {},
+      display_sub       => \&display_F,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 1,
+      tables            => [qw(fk_error)],
+      visible_tables    => [qw(fk_error)],
+   },
+   I => {
+      hdr               => 'InnoDB I/O Info',
+      cust              => {},
+      note              => 'Shows I/O info (i/o, log...) from InnoDB',
+      action_for        => {
+         i => {
+            action => sub { toggle_config('status_inc') },
+            label  => 'Toggle incremental status display',
+         },
+      },
+      display_sub       => \&display_I,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 0,
+      tables            => [qw(io_threads pending_io file_io_misc log_statistics)],
+      visible_tables    => [qw(io_threads pending_io file_io_misc log_statistics)],
+   },
+   L => {
+      hdr             => 'Locks',
+      cust            => {},
+      note            => 'Shows transaction locks',
+      action_for      => {
+         a => {
+            action => sub { send_cmd_to_servers('CREATE TABLE IF NOT EXISTS test.innodb_lock_monitor(a int) ENGINE=InnoDB', 0, '', []); },
+            label  => 'Start the InnoDB Lock Monitor',
+         },
+         o => {
+            action => sub { send_cmd_to_servers('DROP TABLE IF EXISTS test.innodb_lock_monitor', 0, '', []); },
+            label  => 'Stop the InnoDB Lock Monitor',
+         },
+      },
+      display_sub     => \&display_L,
+      connections     => [],
+      server_group    => '',
+      one_connection  => 0,
+      tables            => [qw(innodb_locks)],
+      visible_tables    => [qw(innodb_locks)],
+   },
+   M => {
+      hdr               => 'Replication Status',
+      cust              => {},
+      note              => 'Shows replication (master and slave) status',
+      action_for        => {
+         a => {
+            action => sub { send_cmd_to_servers('START SLAVE', 0, 'START SLAVE SQL_THREAD UNTIL MASTER_LOG_FILE = ?, MASTER_LOG_POS = ?', []); },
+            label  => 'Start slave(s)',
+         },
+         i => {
+            action => sub { toggle_config('status_inc') },
+            label  => 'Toggle incremental status display',
+         },
+         o => {
+            action => sub { send_cmd_to_servers('STOP SLAVE', 0, '', []); },
+            label  => 'Stop slave(s)',
+         },
+         b => {
+            action => sub { purge_master_logs() },
+            label  => 'Purge unused master logs',
+         },
+      },
+      display_sub       => \&display_M,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 0,
+      tables            => [qw(slave_sql_status slave_io_status master_status)],
+      visible_tables    => [qw(slave_sql_status slave_io_status master_status)],
+   },
+   O => {
+      hdr               => 'Open Tables',
+      cust              => {},
+      note              => 'Shows open tables in MySQL',
+      action_for        => {
+         r => {
+            action => sub { reverse_sort('open_tables'); },
+            label  => 'Reverse sort order',
+         },
+         s => {
+            action => sub { choose_sort_cols('open_tables'); },
+            label => "Choose sort column",
+         },
+      },
+      display_sub       => \&display_O,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 0,
+      tables            => [qw(open_tables)],
+      visible_tables    => [qw(open_tables)],
+   },
+   Q => {
+      hdr        => 'Query List',
+      cust       => {},
+      note       => 'Shows queries from SHOW FULL PROCESSLIST',
+      action_for => {
+         a => {
+            action => sub { toggle_filter('processlist', 'hide_self') },
+            label  => 'Toggle the innotop process',
+         },
+         c => {
+            action => sub { edit_table('processlist') },
+            label  => 'Choose visible columns',
+         },
+         e => {
+            action => sub { analyze_query('e'); },
+            label  => "Explain a thread's query",
+         },
+         f => {
+            action => sub { analyze_query('f'); },
+            label  => "Show a thread's full query",
+         },
+         h => {
+            action => sub { toggle_visible_table('Q', 'q_header') },
+            label  => 'Toggle the header on and off',
+         },
+         i => {
+            action => sub { toggle_filter('processlist', 'hide_inactive') },
+            label  => 'Toggle idle processes',
+         },
+         k => {
+            action => sub { kill_query('CONNECTION') },
+            label => "Kill a query's connection",
+         },
+         r => {
+            action => sub { reverse_sort('processlist'); },
+            label  => 'Reverse sort order',
+         },
+         s => {
+            action => sub { choose_sort_cols('processlist'); },
+            label => "Change the display's sort column",
+         },
+         x => {
+            action => sub { kill_query('QUERY') },
+            label => "Kill a query",
+         },
+      },
+      display_sub       => \&display_Q,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 0,
+      tables            => [qw(q_header processlist)],
+      visible_tables    => [qw(q_header processlist)],
+   },
+   R => {
+      hdr               => 'InnoDB Row Ops',
+      cust              => {},
+      note              => 'Shows InnoDB row operation and semaphore info',
+      action_for        => {
+         i => {
+            action => sub { toggle_config('status_inc') },
+            label  => 'Toggle incremental status display',
+         },
+      },
+      display_sub       => \&display_R,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 0,
+      tables            => [qw(row_operations row_operation_misc semaphores wait_array)],
+      visible_tables    => [qw(row_operations row_operation_misc semaphores wait_array)],
+   },
+   S => {
+      hdr               => 'Variables & Status',
+      cust              => {},
+      note              => 'Shows query load statistics a la vmstat',
+      action_for        => {
+         '>' => {
+            action => sub { switch_var_set('S_set', 1) },
+            label  => 'Switch to next variable set',
+         },
+         '<' => {
+            action => sub { switch_var_set('S_set', -1) },
+            label  => 'Switch to prev variable set',
+         },
+         c => {
+            action => sub {
+               choose_var_set('S_set');
+               start_S_mode();
+            },
+            label => "Choose which set to display",
+         },
+         e => {
+            action => \&edit_current_var_set,
+            label  => 'Edit the current set of variables',
+         },
+         i => {
+            action => sub { $clear_screen_sub->(); toggle_config('status_inc') },
+            label  => 'Toggle incremental status display',
+         },
+         '-' => {
+            action => sub { set_display_precision(-1) },
+            label  => 'Decrease fractional display precision',
+         },
+         '+' => {
+            action => sub { set_display_precision(1) },
+            label  => 'Increase fractional display precision',
+         },
+         g => {
+            action => sub { set_s_mode('g') },
+            label  => 'Switch to graph (tload) view',
+         },
+         s => {
+            action => sub { set_s_mode('s') },
+            label  => 'Switch to standard (vmstat) view',
+         },
+         v => {
+            action => sub { set_s_mode('v') },
+            label  => 'Switch to pivoted view',
+         },
+      },
+      display_sub       => \&display_S,
+      no_clear_screen   => 1,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 0,
+      tables            => [qw(var_status)],
+      visible_tables    => [qw(var_status)],
+   },
+   T => {
+      hdr        => 'InnoDB Txns',
+      cust       => {},
+      note       => 'Shows InnoDB transactions in top-like format',
+      action_for => {
+         a => {
+            action => sub { toggle_filter('innodb_transactions', 'hide_self') },
+            label  => 'Toggle the innotop process',
+         },
+         c => {
+            action => sub { edit_table('innodb_transactions') },
+            label  => 'Choose visible columns',
+         },
+         e => {
+            action => sub { analyze_query('e'); },
+            label  => "Explain a thread's query",
+         },
+         f => {
+            action => sub { analyze_query('f'); },
+            label  => "Show a thread's full query",
+         },
+         h => {
+            action => sub { toggle_visible_table('T', 't_header') },
+            label  => 'Toggle the header on and off',
+         },
+         i => {
+            action => sub { toggle_filter('innodb_transactions', 'hide_inactive') },
+            label  => 'Toggle inactive transactions',
+         },
+         k => {
+            action => sub { kill_query('CONNECTION') },
+            label  => "Kill a transaction's connection",
+         },
+         r => {
+            action => sub { reverse_sort('innodb_transactions'); },
+            label  => 'Reverse sort order',
+         },
+         s => {
+            action => sub { choose_sort_cols('innodb_transactions'); },
+            label  => "Change the display's sort column",
+         },
+         x => {
+            action => sub { kill_query('QUERY') },
+            label  => "Kill a query",
+         },
+      },
+      display_sub       => \&display_T,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 0,
+      tables            => [qw(t_header innodb_transactions)],
+      visible_tables    => [qw(t_header innodb_transactions)],
+   },
+);
+
+# ###########################################################################
+# Global key mappings {{{3
+# Keyed on a single character, which is read from the keyboard.  Uppercase
+# letters switch modes.  Lowercase letters access commands when in a mode.
+# These can be overridden by action_for in %modes.
+# ###########################################################################
+my %action_for = (
+   '$' => {
+      action => \&edit_configuration,
+      label  => 'Edit configuration settings',
+   },
+   '?' => {
+      action => \&display_help,
+      label  => 'Show help',
+   },
+   '!' => {
+      action => \&display_license,
+      label  => 'Show license and warranty',
+   },
+   '^' => {
+      action => \&edit_table,
+      label  => "Edit the displayed table(s)",
+   },
+   '#' => {
+      action => \&choose_server_groups,
+      label  => 'Select/create server groups',
+   },
+   '@' => {
+      action => \&choose_servers,
+      label  => 'Select/create server connections',
+   },
+   '/' => {
+      action => \&add_quick_filter,
+      label  => 'Quickly filter what you see',
+   },
+   '\\' => {
+      action => \&clear_quick_filters,
+      label  => 'Clear quick-filters',
+   },
+   '%' => {
+      action => \&choose_filters,
+      label  => 'Choose and edit table filters',
+   },
+   "\t" => {
+      action => \&next_server_group,
+      label  => 'Switch to the next server group',
+      key    => 'TAB',
+   },
+   '=' => {
+      action => \&toggle_aggregate,
+      label  => 'Toggle aggregation',
+   },
+   # TODO: can these be auto-generated from %modes?
+   B => {
+      action => sub { switch_mode('B') },
+      label  => '',
+   },
+   C => {
+      action => sub { switch_mode('C') },
+      label  => '',
+   },
+   D => {
+      action => sub { switch_mode('D') },
+      label  => '',
+   },
+   F => {
+      action => sub { switch_mode('F') },
+      label  => '',
+   },
+   I => {
+      action => sub { switch_mode('I') },
+      label  => '',
+   },
+   L => {
+      action => sub { switch_mode('L') },
+      label  => '',
+   },
+   M => {
+      action => sub { switch_mode('M') },
+      label  => '',
+   },
+   O => {
+      action => sub { switch_mode('O') },
+      label  => '',
+   },
+   Q => {
+      action => sub { switch_mode('Q') },
+      label  => '',
+   },
+   R => {
+      action => sub { switch_mode('R') },
+      label  => '',
+   },
+   S => {
+      action => \&start_S_mode,
+      label  => '',
+   },
+   T => {
+      action => sub { switch_mode('T') },
+      label  => '',
+   },
+   d => {
+      action => sub { get_config_interactive('interval') },
+      label  => 'Change refresh interval',
+   },
+   n => { action => \&next_server,       label => 'Switch to the next connection' },
+   p => { action => \&pause,             label => 'Pause innotop', },
+   q => { action => \&finish,            label => 'Quit innotop', },
+);
+
+# ###########################################################################
+# Sleep times after certain statements {{{3
+# ###########################################################################
+my %stmt_sleep_time_for = ();
+
+# ###########################################################################
+# Config editor key mappings {{{3
+# ###########################################################################
+my %cfg_editor_action = (
+   c => {
+      note => 'Edit columns, etc in the displayed table(s)',
+      func => \&edit_table,
+   },
+   g => {
+      note => 'Edit general configuration',
+      func => \&edit_configuration_variables,
+   },
+   k => {
+      note => 'Edit row-coloring rules',
+      func => \&edit_color_rules,
+   },
+   p => {
+      note => 'Manage plugins',
+      func => \&edit_plugins,
+   },
+   s => {
+      note => 'Edit server groups',
+      func => \&edit_server_groups,
+   },
+   S => {
+      note => 'Edit SQL statement sleep delays',
+      func => \&edit_stmt_sleep_times,
+   },
+   t => {
+      note => 'Choose which table(s) to display in this mode',
+      func => \&choose_mode_tables,
+   },
+);
+
+# ###########################################################################
+# Color editor key mappings {{{3
+# ###########################################################################
+my %color_editor_action = (
+   n => {
+      note => 'Create a new color rule',
+      func => sub {
+         my ( $tbl, $idx ) = @_;
+         my $meta = $tbl_meta{$tbl};
+
+         $clear_screen_sub->();
+         my $col;
+         do {
+            $col = prompt_list(
+               'Choose the target column for the rule',
+               '',
+               sub { return keys %{$meta->{cols}} },
+               { map { $_ => $meta->{cols}->{$_}->{label} } keys %{$meta->{cols}} });
+         } while ( !$col );
+         ( $col ) = grep { $_ } split(/\W+/, $col);
+         return $idx unless $col && exists $meta->{cols}->{$col};
+
+         $clear_screen_sub->();
+         my $op;
+         do {
+            $op = prompt_list(
+               'Choose the comparison operator for the rule',
+               '',
+               sub { return keys %comp_ops },
+               { map { $_ => $comp_ops{$_} } keys %comp_ops } );
+         } until ( $op );
+         $op =~ s/\s+//g;
+         return $idx unless $op && exists $comp_ops{$op};
+
+         my $arg;
+         do {
+            $arg = prompt('Specify an argument for the comparison');
+         } until defined $arg;
+
+         my $color;
+         do {
+            $color = prompt_list(
+               'Choose the color(s) the row should be when the rule matches',
+               '',
+               sub { return keys %ansicolors },
+               { map { $_ => $_ } keys %ansicolors } );
+         } until defined $color;
+         $color = join(' ', unique(grep { exists $ansicolors{$_} } split(/\W+/, $color)));
+         return $idx unless $color;
+
+         push @{$tbl_meta{$tbl}->{colors}}, {
+            col   => $col,
+            op    => $op,
+            arg   => $arg,
+            color => $color
+         };
+         $tbl_meta{$tbl}->{cust}->{colors} = 1;
+
+         return $idx;
+      },
+   },
+   d => {
+      note => 'Remove the selected rule',
+      func => sub {
+         my ( $tbl, $idx ) = @_;
+         my @rules = @{ $tbl_meta{$tbl}->{colors} };
+         return 0 unless @rules > 0 && $idx < @rules && $idx >= 0;
+         splice(@{$tbl_meta{$tbl}->{colors}}, $idx, 1);
+         $tbl_meta{$tbl}->{cust}->{colors} = 1;
+         return $idx == @rules ? $#rules : $idx;
+      },
+   },
+   j => {
+      note => 'Move highlight down one',
+      func => sub {
+         my ( $tbl, $idx ) = @_;
+         my $num_rules = scalar @{$tbl_meta{$tbl}->{colors}};
+         return ($idx + 1) % $num_rules;
+      },
+   },
+   k => {
+      note => 'Move highlight up one',
+      func => sub {
+         my ( $tbl, $idx ) = @_;
+         my $num_rules = scalar @{$tbl_meta{$tbl}->{colors}};
+         return ($idx - 1) % $num_rules;
+      },
+   },
+   '+' => {
+      note => 'Move selected rule up one',
+      func => sub {
+         my ( $tbl, $idx ) = @_;
+         my $meta = $tbl_meta{$tbl};
+         my $dest = $idx == 0 ? scalar(@{$meta->{colors}} - 1) : $idx - 1;
+         my $temp = $meta->{colors}->[$idx];
+         $meta->{colors}->[$idx]  = $meta->{colors}->[$dest];
+         $meta->{colors}->[$dest] = $temp;
+         $meta->{cust}->{colors} = 1;
+         return $dest;
+      },
+   },
+   '-' => {
+      note => 'Move selected rule down one',
+      func => sub {
+         my ( $tbl, $idx ) = @_;
+         my $meta = $tbl_meta{$tbl};
+         my $dest = $idx == scalar(@{$meta->{colors}} - 1) ? 0 : $idx + 1;
+         my $temp = $meta->{colors}->[$idx];
+         $meta->{colors}->[$idx]  = $meta->{colors}->[$dest];
+         $meta->{colors}->[$dest] = $temp;
+         $meta->{cust}->{colors} = 1;
+         return $dest;
+      },
+   },
+);
+
+# ###########################################################################
+# Plugin editor key mappings {{{3
+# ###########################################################################
+my %plugin_editor_action = (
+   '*' => {
+      note => 'Toggle selected plugin active/inactive',
+      func => sub {
+         my ( $plugins, $idx ) = @_;
+         my $plugin = $plugins->[$idx];
+         $plugin->{active} = $plugin->{active} ? 0 : 1;
+         return $idx;
+      },
+   },
+   j => {
+      note => 'Move highlight down one',
+      func => sub {
+         my ( $plugins, $idx ) = @_;
+         return ($idx + 1) % scalar(@$plugins);
+      },
+   },
+   k => {
+      note => 'Move highlight up one',
+      func => sub {
+         my ( $plugins, $idx ) = @_;
+         return $idx == 0 ? @$plugins - 1 : $idx - 1;
+      },
+   },
+);
+
+# ###########################################################################
+# Table editor key mappings {{{3
+# ###########################################################################
+my %tbl_editor_action = (
+   a => {
+      note => 'Add a column to the table',
+      func => sub {
+         my ( $tbl, $col ) = @_;
+         my @visible_cols = @{ $tbl_meta{$tbl}->{visible} };
+         my %all_cols     = %{ $tbl_meta{$tbl}->{cols} };
+         delete @all_cols{@visible_cols};
+         my $choice = prompt_list(
+            'Choose a column',
+            '',
+            sub { return keys %all_cols; },
+            { map { $_ => $all_cols{$_}->{label} || $all_cols{$_}->{hdr} } keys %all_cols });
+         if ( $all_cols{$choice} ) {
+            push @{$tbl_meta{$tbl}->{visible}}, $choice;
+            $tbl_meta{$tbl}->{cust}->{visible} = 1;
+            return $choice;
+         }
+         return $col;
+      },
+   },
+   n => {
+      note => 'Create a new column and add it to the table',
+      func => sub {
+         my ( $tbl, $col ) = @_;
+
+         $clear_screen_sub->();
+         print word_wrap("Choose a name for the column.  This name is not displayed, and is used only "
+               . "for internal reference.  It can contain only lowercase letters, numbers, "
+               . "and underscores.");
+         print "\n\n";
+         do {
+            $col = prompt("Enter column name");
+            $col = '' if $col =~ m/[^a-z0-9_]/;
+         } while ( !$col );
+
+         $clear_screen_sub->();
+         my $hdr;
+         do {
+            $hdr = prompt("Enter column header");
+         } while ( !$hdr );
+
+         $clear_screen_sub->();
+         print "Choose a source for the column's data\n\n";
+         my ( $src, $sub, $err );
+         do {
+            if ( $err ) {
+               print "Error: $err\n\n";
+            }
+            $src = prompt("Enter column source");
+            if ( $src ) {
+               ( $sub, $err ) = compile_expr($src);
+            }
+         } until ( !$err);
+
+         # TODO: this duplicates %col_props.
+         $tbl_meta{$tbl}->{cols}->{$col} = {
+            hdr   => $hdr,
+            src   => $src,
+            just  => '-',
+            num   => 0,
+            label => 'User-defined',
+            user  => 1,
+            tbl   => $tbl,
+            minw  => 0,
+            maxw  => 0,
+            trans => [],
+            func  => $sub,
+            dec   => 0,
+            agg   => 0,
+            aggonly => 0,
+         };
+
+         $tbl_meta{$tbl}->{visible} = [ unique(@{$tbl_meta{$tbl}->{visible}}, $col) ];
+         $tbl_meta{$tbl}->{cust}->{visible} = 1;
+         return $col;
+      },
+   },
+   d => {
+      note => 'Remove selected column',
+      func => sub {
+         my ( $tbl, $col ) = @_;
+         my @visible_cols = @{ $tbl_meta{$tbl}->{visible} };
+         my $idx          = 0;
+         return $col unless @visible_cols > 1;
+         while ( $visible_cols[$idx] ne $col ) {
+            $idx++;
+         }
+         $tbl_meta{$tbl}->{visible} = [ grep { $_ ne $col } @visible_cols ];
+         $tbl_meta{$tbl}->{cust}->{visible} = 1;
+         return $idx == $#visible_cols ? $visible_cols[$idx - 1] : $visible_cols[$idx + 1];
+      },
+   },
+   e => {
+      note => 'Edit selected column',
+      func => sub {
+         # TODO: make this editor hotkey-driven and give readline support.
+         my ( $tbl, $col ) = @_;
+         $clear_screen_sub->();
+         my $meta = $tbl_meta{$tbl}->{cols}->{$col};
+         my @prop = qw(hdr label src just num minw maxw trans agg); # TODO redundant
+
+         my $answer;
+         do {
+            # Do what the user asked...
+            if ( $answer && grep { $_ eq $answer } @prop ) {
+               # Some properties are arrays, others scalars.
+               my $ini = ref $col_props{$answer} ? join(' ', @{$meta->{$answer}}) : $meta->{$answer};
+               my $val = prompt("New value for $answer", undef, $ini);
+               $val = [ split(' ', $val) ] if ref($col_props{$answer});
+               if ( $answer eq 'trans' ) {
+                  $val = [ unique(grep{ exists $trans_funcs{$_} } @$val) ];
+               }
+               @{$meta}{$answer, 'user', 'tbl' } = ( $val, 1, $tbl );
+            }
+
+            my @display_lines = (
+               '',
+               "You are editing column $tbl.$col.\n",
+            );
+
+            push @display_lines, create_table2(
+               \@prop,
+               { map { $_ => $_ } @prop },
+               { map { $_ => ref $meta->{$_} eq 'ARRAY' ? join(' ', @{$meta->{$_}})
+                           : ref $meta->{$_}            ? '[expression code]'
+                           :                              $meta->{$_}
+                     } @prop
+               },
+               { sep => '  ' });
+            draw_screen(\@display_lines, { raw => 1 });
+            print "\n\n"; # One to add space, one to clear readline artifacts
+            $answer = prompt('Edit what? (q to quit)');
+         } while ( $answer ne 'q' );
+
+         return $col;
+      },
+   },
+   j => {
+      note => 'Move highlight down one',
+      func => sub {
+         my ( $tbl, $col ) = @_;
+         my @visible_cols = @{ $tbl_meta{$tbl}->{visible} };
+         my $idx          = 0;
+         while ( $visible_cols[$idx] ne $col ) {
+            $idx++;
+         }
+         return $visible_cols[ ($idx + 1) % @visible_cols ];
+      },
+   },
+   k => {
+      note => 'Move highlight up one',
+      func => sub {
+         my ( $tbl, $col ) = @_;
+         my @visible_cols = @{ $tbl_meta{$tbl}->{visible} };
+         my $idx          = 0;
+         while ( $visible_cols[$idx] ne $col ) {
+            $idx++;
+         }
+         return $visible_cols[ $idx - 1 ];
+      },
+   },
+   '+' => {
+      note => 'Move selected column up one',
+      func => sub {
+         my ( $tbl, $col ) = @_;
+         my $meta         = $tbl_meta{$tbl};
+         my @visible_cols = @{$meta->{visible}};
+         my $idx          = 0;
+         while ( $visible_cols[$idx] ne $col ) {
+            $idx++;
+         }
+         if ( $idx ) {
+            $visible_cols[$idx]     = $visible_cols[$idx - 1];
+            $visible_cols[$idx - 1] = $col;
+            $meta->{visible}        = \@visible_cols;
+         }
+         else {
+            shift @{$meta->{visible}};
+            push @{$meta->{visible}}, $col;
+         }
+         $meta->{cust}->{visible} = 1;
+         return $col;
+      },
+   },
+   '-' => {
+      note => 'Move selected column down one',
+      func => sub {
+         my ( $tbl, $col ) = @_;
+         my $meta         = $tbl_meta{$tbl};
+         my @visible_cols = @{$meta->{visible}};
+         my $idx          = 0;
+         while ( $visible_cols[$idx] ne $col ) {
+            $idx++;
+         }
+         if ( $idx == $#visible_cols ) {
+            unshift @{$meta->{visible}}, $col;
+            pop @{$meta->{visible}};
+         }
+         else {
+            $visible_cols[$idx]     = $visible_cols[$idx + 1];
+            $visible_cols[$idx + 1] = $col;
+            $meta->{visible}        = \@visible_cols;
+         }
+         $meta->{cust}->{visible} = 1;
+         return $col;
+      },
+   },
+   f => {
+      note => 'Choose filters',
+      func => sub {
+         my ( $tbl, $col ) = @_;
+         choose_filters($tbl);
+         return $col;
+      },
+   },
+   o => {
+      note => 'Edit color rules',
+      func => sub {
+         my ( $tbl, $col ) = @_;
+         edit_color_rules($tbl);
+         return $col;
+      },
+   },
+   s => {
+      note => 'Choose sort columns',
+      func => sub {
+         my ( $tbl, $col ) = @_;
+         choose_sort_cols($tbl);
+         return $col;
+      },
+   },
+   g => {
+      note => 'Choose group-by (aggregate) columns',
+      func => sub {
+         my ( $tbl, $col ) = @_;
+         choose_group_cols($tbl);
+         return $col;
+      },
+   },
+);
+
+# ###########################################################################
+# Global variables and environment {{{2
+# ###########################################################################
+
+my @this_term_size; # w_chars, h_chars, w_pix, h_pix
+my @last_term_size; # w_chars, h_chars, w_pix, h_pix
+my $char;
+my $windows       = $OSNAME =~ m/MSWin/;
+my $have_color    = 0;
+my $MAX_ULONG     = 4294967295; # 2^32-1
+my $num_regex     = qr/^[+-]?(?=\d|\.)\d*(?:\.\d+)?(?:E[+-]?\d+|)$/i;
+my $int_regex     = qr/^\d+$/;
+my $bool_regex    = qr/^[01]$/;
+my $term          = undef;
+my $file          = undef; # File to watch for InnoDB monitor output
+my $file_mtime    = undef; # Status of watched file
+my $file_data     = undef; # Last chunk of text read from file
+my $innodb_parser = InnoDBParser->new;
+
+my $nonfatal_errs = join('|',
+   'Access denied for user',
+   'Unknown MySQL server host',
+   'Unknown database',
+   'Can\'t connect to local MySQL server through socket',
+   'Can\'t connect to MySQL server on',
+   'MySQL server has gone away',
+   'Cannot call SHOW INNODB STATUS',
+   'Access denied',
+   'AutoCommit',
+);
+
+if ( !$opts{n} ) {
+   require Term::ReadLine;
+   $term = Term::ReadLine->new('innotop');
+}
+
+# Stores status, variables, innodb status, master/slave status etc.
+# Keyed on connection name.  Each entry is a hashref of current and past data sets,
+# keyed on clock tick.
+my %vars;
+my %info_gotten = (); # Which things have been retrieved for the current clock tick.
+
+# Stores info on currently displayed queries: cxn, connection ID, query text.
+my @current_queries;
+
+my $lines_printed       = 0;
+my $clock               = 0;   # Incremented with every wake-sleep cycle
+my $clearing_deadlocks  = 0;
+
+# If terminal coloring is available, use it.  The only function I want from
+# the module is the colored() function.
+eval {
+   if ( !$opts{n} ) {
+      if ( $windows ) {
+         require Win32::Console::ANSI;
+      }
+      require Term::ANSIColor;
+      import Term::ANSIColor qw(colored);
+      $have_color = 1;
+   }
+};
+if ( $EVAL_ERROR || $opts{n} ) {
+   # If there was an error, manufacture my own colored() function that does no
+   # coloring.
+   *colored = sub { pop @_; @_; };
+}
+
+if ( $opts{n} ) {
+   $clear_screen_sub = sub {};
+}
+elsif ( $windows ) {
+   $clear_screen_sub = sub { $lines_printed = 0; system("cls") };
+}
+else {
+   my $clear = `clear`;
+   $clear_screen_sub = sub { $lines_printed = 0; print $clear };
+}
+
+# ###########################################################################
+# Config storage. {{{2
+# ###########################################################################
+my %config = (
+   color => {
+      val  => $have_color,
+      note => 'Whether to use terminal coloring',
+      conf => 'ALL',
+      pat  => $bool_regex,
+   },
+   cmd_filter => {
+      val  => 'Com_',
+      note => 'Prefix for values in C mode',
+      conf => [qw(C)],
+   },
+   plugin_dir => {
+      val  => "$homepath/.innotop/plugins",
+      note => 'Directory where plugins can be found',
+      conf => 'ALL',
+   },
+   show_percent => {
+      val  => 1,
+      note => 'Show the % symbol after percentages',
+      conf => 'ALL',
+      pat  => $bool_regex,
+   },
+   skip_innodb => {
+      val  => 0,
+      note => 'Disable SHOW INNODB STATUS',
+      conf => 'ALL',
+      pat  => $bool_regex,
+   },
+   S_func => {
+      val  => 's',
+      note => 'What to display in S mode: graph, status, pivoted status',
+      conf => [qw(S)],
+      pat  => qr/^[gsv]$/,
+   },
+   cxn_timeout => {
+      val  => 28800,
+      note => 'Connection timeout for keeping unused connections alive',
+      conf => 'ALL',
+      pat  => $int_regex,
+   },
+   graph_char => {
+      val  => '*',
+      note => 'Character for drawing graphs',
+      conf => [ qw(S) ],
+      pat  => qr/^.$/,
+   },
+   show_cxn_errors_in_tbl => {
+      val  => 1,
+      note => 'Whether to display connection errors as rows in the table',
+      conf => 'ALL',
+      pat  => $bool_regex,
+   },
+   hide_hdr => {
+      val  => 0,
+      note => 'Whether to show column headers',
+      conf => 'ALL',
+      pat  => $bool_regex,
+   },
+   show_cxn_errors => {
+      val  => 1,
+      note => 'Whether to print connection errors to STDOUT',
+      conf => 'ALL',
+      pat  => $bool_regex,
+   },
+   readonly => {
+      val  => 1,
+      note => 'Whether the config file is read-only',
+      conf => [ qw() ],
+      pat  => $bool_regex,
+   },
+   global => {
+      val  => 1,
+      note => 'Whether to show GLOBAL variables and status',
+      conf => 'ALL',
+      pat  => $bool_regex,
+   },
+   header_highlight => {
+      val  => 'bold',
+      note => 'How to highlight table column headers',
+      conf => 'ALL',
+      pat  => qr/^(?:bold|underline)$/,
+   },
+   display_table_captions => {
+      val  => 1,
+      note => 'Whether to put captions on tables',
+      conf => 'ALL',
+      pat  => $bool_regex,
+   },
+   charset => {
+      val  => 'ascii',
+      note => 'What type of characters should be displayed in queries (ascii, unicode, none)',
+      conf => 'ALL',
+      pat  => qr/^(?:ascii|unicode|none)$/,
+   },
+   auto_wipe_dl => {
+      val  => 0,
+      note => 'Whether to auto-wipe InnoDB deadlocks',
+      conf => 'ALL',
+      pat  => $bool_regex,
+   },
+   max_height => {
+      val  => 30,
+      note => '[Win32] Max window height',
+      conf => 'ALL',
+   },
+   debug => {
+      val  => 0,
+      pat  => $bool_regex,
+      note => 'Debug mode (more verbose errors, uses more memory)',
+      conf => 'ALL',
+   },
+   num_digits => {
+      val  => 2,
+      pat  => $int_regex,
+      note => 'How many digits to show in fractional numbers and percents',
+      conf => 'ALL',
+   },
+   debugfile => {
+      val  => "$homepath/.innotop/core_dump",
+      note => 'A debug file in case you are interested in error output',
+   },
+   show_statusbar => {
+      val  => 1,
+      pat  => $bool_regex,
+      note => 'Whether to show the status bar in the display',
+      conf => 'ALL',
+   },
+   mode => {
+      val  => "Q",
+      note => "Which mode to start in",
+      cmdline => 1,
+   },
+   status_inc => {
+      val  => 0,
+      note => 'Whether to show raw or incremental values for status variables',
+      pat  => $bool_regex,
+   },
+   interval => {
+      val  => 10,
+      pat  => qr/^(?:(?:\d*?[1-9]\d*(?:\.\d*)?)|(?:\d*\.\d*?[1-9]\d*))$/,
+      note => "The interval at which the display will be refreshed.  Fractional values allowed.",
+   },
+   num_status_sets => {
+      val  => 9,
+      pat  => $int_regex,
+      note => 'How many sets of STATUS and VARIABLES values to show',
+      conf => [ qw(S) ],
+   },
+   S_set => {
+      val  => 'general',
+      pat  => qr/^\w+$/,
+      note => 'Which set of variables to display in S (Variables & Status) mode',
+      conf => [ qw(S) ],
+   },
+);
+
+# ###########################################################################
+# Config file sections {{{2
+# The configuration file is broken up into sections like a .ini file.  This
+# variable defines those sections and the subroutines responsible for reading
+# and writing them.
+# ###########################################################################
+my %config_file_sections = (
+   plugins => {
+      reader => \&load_config_plugins,
+      writer => \&save_config_plugins,
+   },
+   group_by => {
+      reader => \&load_config_group_by,
+      writer => \&save_config_group_by,
+   },
+   filters => {
+      reader => \&load_config_filters,
+      writer => \&save_config_filters,
+   },
+   active_filters => {
+      reader => \&load_config_active_filters,
+      writer => \&save_config_active_filters,
+   },
+   visible_tables => {
+      reader => \&load_config_visible_tables,
+      writer => \&save_config_visible_tables,
+   },
+   sort_cols => {
+      reader => \&load_config_sort_cols,
+      writer => \&save_config_sort_cols,
+   },
+   active_columns => {
+      reader => \&load_config_active_columns,
+      writer => \&save_config_active_columns,
+   },
+   tbl_meta => {
+      reader => \&load_config_tbl_meta,
+      writer => \&save_config_tbl_meta,
+   },
+   general => {
+      reader => \&load_config_config,
+      writer => \&save_config_config,
+   },
+   connections => {
+      reader => \&load_config_connections,
+      writer => \&save_config_connections,
+   },
+   active_connections => {
+      reader => \&load_config_active_connections,
+      writer => \&save_config_active_connections,
+   },
+   server_groups => {
+      reader => \&load_config_server_groups,
+      writer => \&save_config_server_groups,
+   },
+   active_server_groups => {
+      reader => \&load_config_active_server_groups,
+      writer => \&save_config_active_server_groups,
+   },
+   max_values_seen => {
+      reader => \&load_config_mvs,
+      writer => \&save_config_mvs,
+   },
+   varsets => {
+      reader => \&load_config_varsets,
+      writer => \&save_config_varsets,
+   },
+   colors => {
+      reader => \&load_config_colors,
+      writer => \&save_config_colors,
+   },
+   stmt_sleep_times => {
+      reader => \&load_config_stmt_sleep_times,
+      writer => \&save_config_stmt_sleep_times,
+   },
+);
+
+# Config file sections have some dependencies, so they have to be read/written in order.
+my @ordered_config_file_sections = qw(general plugins filters active_filters tbl_meta
+   connections active_connections server_groups active_server_groups max_values_seen
+   active_columns sort_cols visible_tables varsets colors stmt_sleep_times
+   group_by);
+
+# All events for which plugins may register themselves.  Entries are arrayrefs.
+my %event_listener_for = map { $_ => [] }
+   qw(
+      extract_values
+      set_to_tbl_pre_filter set_to_tbl_pre_sort set_to_tbl_pre_group
+      set_to_tbl_pre_colorize set_to_tbl_pre_transform set_to_tbl_pre_pivot
+      set_to_tbl_pre_create set_to_tbl_post_create
+      draw_screen
+   );
+
+# All variables to which plugins have access.
+my %pluggable_vars = (
+   action_for    => \%action_for,
+   agg_funcs     => \%agg_funcs,
+   config        => \%config,
+   connections   => \%connections,
+   dbhs          => \%dbhs,
+   filters       => \%filters,
+   modes         => \%modes,
+   server_groups => \%server_groups,
+   tbl_meta      => \%tbl_meta,
+   trans_funcs   => \%trans_funcs,
+   var_sets      => \%var_sets,
+);
+
+# ###########################################################################
+# Contains logic to generate prepared statements for a given function for a
+# given DB connection.  Returns a $sth.
+# ###########################################################################
+my %stmt_maker_for = (
+   INNODB_STATUS => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare(version_ge( $dbh, '5.0.0' )
+             ? 'SHOW ENGINE INNODB STATUS'
+             : 'SHOW INNODB STATUS');
+   },
+   SHOW_VARIABLES => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare($config{global}->{val} && version_ge( $dbh, '4.0.3' )
+             ? 'SHOW GLOBAL VARIABLES'
+             : 'SHOW VARIABLES');
+   },
+   SHOW_STATUS => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare($config{global}->{val} && version_ge( $dbh, '5.0.2' )
+             ? 'SHOW GLOBAL STATUS'
+             : 'SHOW STATUS');
+   },
+   KILL_QUERY => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare(version_ge( $dbh, '5.0.0' )
+             ? 'KILL QUERY ?'
+             : 'KILL ?');
+   },
+   SHOW_MASTER_LOGS => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare('SHOW MASTER LOGS');
+   },
+   SHOW_MASTER_STATUS => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare('SHOW MASTER STATUS');
+   },
+   SHOW_SLAVE_STATUS => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare('SHOW SLAVE STATUS');
+   },
+   KILL_CONNECTION => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare(version_ge( $dbh, '5.0.0' )
+             ? 'KILL CONNECTION ?'
+             : 'KILL ?');
+   },
+   OPEN_TABLES => sub {
+      my ( $dbh ) = @_;
+      return version_ge($dbh, '4.0.0')
+         ? $dbh->prepare('SHOW OPEN TABLES')
+         : undef;
+   },
+   PROCESSLIST => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare('SHOW FULL PROCESSLIST');
+   },
+);
+
+# Plugins!
+my %plugins = (
+);
+
+# ###########################################################################
+# Run the program {{{1
+# ###########################################################################
+
+# This config variable is only useful for MS Windows because its terminal
+# can't tell how tall it is.
+if ( !$windows ) {
+   delete $config{max_height};
+}
+
+# Try to lower my priority.
+eval { setpriority(0, 0, getpriority(0, 0) + 10); };
+
+# Print stuff to the screen immediately, don't wait for a newline.
+$OUTPUT_AUTOFLUSH = 1;
+
+# Clear the screen and load the configuration.
+$clear_screen_sub->();
+load_config();
+
+# Override config variables with command-line options
+my %cmdline =
+   map  { $_->{c} => $opts{$_->{k}} }
+   grep { exists $_->{c} && exists $opts{$_->{k}} }
+   @opt_spec;
+
+foreach my $name (keys %cmdline) {
+   next if not defined $cmdline{$name};
+   my $val = $cmdline{$name};
+   if ( exists($config{$name}) and (!$config{$name}->{pat} or $val =~ m/$config{$name}->{pat}/ )) {
+      $config{$name}->{val} = $val;
+   }
+}
+
+post_process_tbl_meta();
+
+# Make sure no changes are written to config file in non-interactive mode.
+if ( $opts{n} ) {
+   $config{readonly}->{val} = 1;
+}
+
+eval {
+
+   # Open the file for InnoDB status
+   if ( @ARGV ) {
+      my $filename = shift @ARGV;
+      open $file, "<", $filename
+         or die "Cannot open '$filename': $OS_ERROR";
+   }
+
+   # In certain modes we might have to collect data for two cycles
+   # before printing anything out, so we need to bump up the count one.
+   if ( $opts{n} && $opts{count} && $config{status_inc}->{val}
+      && $config{mode}->{val} =~ m/[S]/ )
+   {
+      $opts{count}++;
+   }
+
+   while (++$clock) {
+
+      my $mode = $config{mode}->{val} || 'Q';
+      if ( !$modes{$mode} ) {
+         die "Mode '$mode' doesn't exist; try one of these:\n"
+            . join("\n", map { "  $_ $modes{$_}->{hdr}" }  sort keys %modes)
+            . "\n";
+      }
+
+      if ( !$opts{n} ) {
+         @last_term_size = @this_term_size;
+         @this_term_size = Term::ReadKey::GetTerminalSize(\*STDOUT);
+         if ( $windows ) {
+            $this_term_size[0]--;
+            $this_term_size[1]
+               = min($this_term_size[1], $config{max_height}->{val});
+         }
+         die("Can't read terminal size") unless @this_term_size;
+      }
+
+      # If there's no connection to a database server, we need to fix that...
+      if ( !%connections ) {
+         print "You have not defined any database connections.\n\n";
+         add_new_dsn();
+      }
+
+      # See whether there are any connections defined for this mode.  If there's only one
+      # connection total, assume the user wants to just use innotop for a single server
+      # and don't ask which server to connect to.  Also, if we're monitoring from a file,
+      # we just use the first connection.
+      if ( !get_connections() ) {
+         if ( $file || 1 == scalar keys %connections ) {
+            $modes{$config{mode}->{val}}->{connections} = [ keys %connections ];
+         }
+         else {
+            choose_connections();
+         }
+      }
+
+      # Term::ReadLine might have re-set $OUTPUT_AUTOFLUSH.
+      $OUTPUT_AUTOFLUSH = 1;
+
+      # Prune old data
+      my $sets = $config{num_status_sets}->{val};
+      foreach my $store ( values %vars ) {
+         delete @{$store}{ grep { $_ < $clock - $sets } keys %$store };
+      }
+      %info_gotten = ();
+
+      # Call the subroutine to display this mode.
+      $modes{$mode}->{display_sub}->();
+
+      # It may be time to quit now.
+      if ( $opts{count} && $clock >= $opts{count} ) {
+         finish();
+      }
+
+      # Wait for a bit.
+      if ( $opts{n} ) {
+         sleep($config{interval}->{val});
+      }
+      else {
+         ReadMode('cbreak');
+         $char = ReadKey($config{interval}->{val});
+         ReadMode('normal');
+      }
+
+      # Handle whatever action the key indicates.
+      do_key_action();
+
+   }
+};
+if ( $EVAL_ERROR ) {
+   core_dump( $EVAL_ERROR );
+}
+finish();
+
+# Subroutines {{{1
+# Mode functions{{{2
+# switch_mode {{{3
+sub switch_mode {
+   my $mode = shift;
+   $config{mode}->{val} = $mode;
+}
+
+# Prompting functions {{{2
+# prompt_list {{{3
+# Prompts the user for a value, given a question, initial value,
+# a completion function and a hashref of hints.
+sub prompt_list {
+   die "Can't call in non-interactive mode" if $opts{n};
+   my ( $question, $init, $completion, $hints ) = @_;
+   if ( $hints ) {
+      # Figure out how wide the table will be
+      my $max_name = max(map { length($_) } keys %$hints );
+      $max_name ||= 0;
+      $max_name +=  3;
+      my @meta_rows = create_table2(
+               [ sort keys %$hints ],
+               { map { $_ => $_ } keys %$hints },
+               { map { $_ => trunc($hints->{$_}, $this_term_size[0] - $max_name) } keys %$hints },
+               { sep => '  ' });
+      if (@meta_rows > 10) {
+         # Try to split and stack the meta rows next to each other
+         my $split = int(@meta_rows / 2);
+         @meta_rows = stack_next(
+            [@meta_rows[0..$split - 1]],
+            [@meta_rows[$split..$#meta_rows]],
+            { pad => ' | '},
+         );
+      }
+      print join( "\n",
+         '',
+         map { ref $_ ? colored(@$_) : $_ } create_caption('Choose from', @meta_rows), ''),
+         "\n";
+   }
+   $term->Attribs->{completion_function} = $completion;
+   my $answer = $term->readline("$question: ", $init);
+   $OUTPUT_AUTOFLUSH = 1;
+   $answer = '' if !defined($answer);
+   $answer =~ s/\s+$//;
+   return $answer;
+}
+
+# prompt {{{3
+# Prints out a prompt and reads from the keyboard, then validates with the
+# validation regex until the input is correct.
+sub prompt {
+   die "Can't call in non-interactive mode" if $opts{n};
+   my ( $prompt, $regex, $init, $completion ) = @_;
+   my $response;
+   my $success = 0;
+   do {
+      if ( $completion ) {
+         $term->Attribs->{completion_function} = $completion;
+      }
+      $response = $term->readline("$prompt: ", $init);
+      if ( $regex && $response !~ m/$regex/ ) {
+         print "Invalid response.\n\n";
+      }
+      else {
+         $success = 1;
+      }
+   } while ( !$success );
+   $OUTPUT_AUTOFLUSH = 1;
+   $response =~ s/\s+$//;
+   return $response;
+}
+
+# prompt_noecho {{{3
+# Unfortunately, suppressing echo with Term::ReadLine isn't reliable; the user might not
+# have that library, or it might not support that feature.
+sub prompt_noecho {
+   my ( $prompt ) = @_;
+   print colored("$prompt: ", 'underline');
+   my $response;
+   ReadMode('noecho');
+   $response = <STDIN>;
+   chomp($response);
+   ReadMode('normal');
+   return $response;
+}
+
+# do_key_action {{{3
+# Depending on whether a key was read, do something.  Keys have certain
+# actions defined in lookup tables.  Each mode may have its own lookup table,
+# which trumps the global table -- so keys can be context-sensitive.  The key
+# may be read and written in a subroutine, so it's a global.
+sub do_key_action {
+   if ( defined $char ) {
+      my $mode = $config{mode}->{val};
+      my $action
+         = defined($modes{$mode}->{action_for}->{$char})
+         ? $modes{$mode}->{action_for}->{$char}->{action}
+         : defined($action_for{$char})
+         ? $action_for{$char}->{action}
+         : sub{};
+      $action->();
+   }
+}
+
+# pause {{{3
+sub pause {
+   die "Can't call in non-interactive mode" if $opts{n};
+   my $msg = shift;
+   print defined($msg) ? "\n$msg" : "\nPress any key to continue";
+   ReadMode('cbreak');
+   my $char = ReadKey(0);
+   ReadMode('normal');
+   return $char;
+}
+
+# reverse_sort {{{3
+sub reverse_sort {
+   my $tbl = shift;
+   $tbl_meta{$tbl}->{sort_dir} *= -1;
+}
+
+# select_cxn {{{3
+# Selects connection(s).  If the mode (or argument list) has only one, returns
+# it without prompt.
+sub select_cxn {
+   my ( $prompt, @cxns ) = @_;
+   if ( !@cxns ) {
+      @cxns = get_connections();
+   }
+   if ( @cxns == 1 ) {
+      return $cxns[0];
+   }
+   my $choices = prompt_list(
+         $prompt,
+         $cxns[0],
+         sub{ return @cxns },
+         { map { $_ => $connections{$_}->{dsn} } @cxns });
+   my @result = unique(grep { my $a = $_; grep { $_ eq $a } @cxns } split(/\s+/, $choices));
+   return @result;
+}
+
+# kill_query {{{3
+# Kills a connection, or on new versions, optionally a query but not connection.
+sub kill_query {
+   my ( $q_or_c ) = @_;
+
+   my $info = choose_thread(
+      sub { 1 },
+      'Select a thread to kill the ' . $q_or_c,
+   );
+   return unless $info;
+   return unless pause("Kill $info->{id}?") =~ m/y/i;
+
+   eval {
+      do_stmt($info->{cxn}, $q_or_c eq 'QUERY' ? 'KILL_QUERY' : 'KILL_CONNECTION', $info->{id} );
+   };
+
+   if ( $EVAL_ERROR ) {
+      print "\nError: $EVAL_ERROR";
+      pause();
+   }
+}
+
+# set_display_precision {{{3
+sub set_display_precision {
+   my $dir = shift;
+   $config{num_digits}->{val} = min(9, max(0, $config{num_digits}->{val} + $dir));
+}
+
+sub toggle_visible_table {
+   my ( $mode, $table ) = @_;
+   my $visible = $modes{$mode}->{visible_tables};
+   if ( grep { $_ eq $table } @$visible ) {
+      $modes{$mode}->{visible_tables} = [ grep { $_ ne $table } @$visible ];
+   }
+   else {
+      unshift @$visible, $table;
+   }
+   $modes{$mode}->{cust}->{visible_tables} = 1;
+}
+
+# toggle_filter{{{3
+sub toggle_filter {
+   my ( $tbl, $filter ) = @_;
+   my $filters = $tbl_meta{$tbl}->{filters};
+   if ( grep { $_ eq $filter } @$filters ) {
+      $tbl_meta{$tbl}->{filters} = [ grep { $_ ne $filter } @$filters ];
+   }
+   else {
+      push @$filters, $filter;
+   }
+   $tbl_meta{$tbl}->{cust}->{filters} = 1;
+}
+
+# toggle_config {{{3
+sub toggle_config {
+   my ( $key ) = @_;
+   $config{$key}->{val} ^= 1;
+}
+
+# create_deadlock {{{3
+sub create_deadlock {
+   $clear_screen_sub->();
+
+   print "This function will deliberately cause a small deadlock, "
+      . "clearing deadlock information from the InnoDB monitor.\n\n";
+
+   my $answer = prompt("Are you sure you want to proceed?  Say 'y' if you do");
+   return 0 unless $answer eq 'y';
+
+   my ( $cxn ) = select_cxn('Clear on which server? ');
+   return unless $cxn && exists($connections{$cxn});
+
+   clear_deadlock($cxn);
+}
+
+# deadlock_thread {{{3
+sub deadlock_thread {
+   my ( $id, $tbl, $cxn ) = @_;
+
+   eval {
+      my $dbh = get_new_db_connection($cxn, 1);
+      my @stmts = (
+         "set transaction isolation level serializable",
+         (version_ge($dbh, '4.0.11') ? "start transaction" : 'begin'),
+         "select * from $tbl where a = $id",
+         "update $tbl set a = $id where a <> $id",
+      );
+
+      foreach my $stmt (@stmts[0..2]) {
+         $dbh->do($stmt);
+      }
+      sleep(1 + $id);
+      $dbh->do($stmts[-1]);
+   };
+   if ( $EVAL_ERROR ) {
+      if ( $EVAL_ERROR !~ m/Deadlock found/ ) {
+         die $EVAL_ERROR;
+      }
+   }
+   exit(0);
+}
+
+# Purges unused binlogs on the master, up to but not including the latest log.
+# TODO: guess which connections are slaves of a given master.
+sub purge_master_logs {
+   my @cxns = get_connections();
+
+   get_master_slave_status(@cxns);
+
+   # Toss out the rows that don't have master/slave status...
+   my @vars =
+      grep { $_ && ($_->{file} || $_->{master_host}) }
+      map  { $vars{$_}->{$clock} } @cxns;
+   @cxns = map { $_->{cxn} } @vars;
+
+   # Figure out which master to purge ons.
+   my @masters = map { $_->{cxn} } grep { $_->{file} } @vars;
+   my ( $master ) = select_cxn('Which master?', @masters );
+   return unless $master;
+   my ($master_status) = grep { $_->{cxn} eq $master } @vars;
+
+   # Figure out the result order (not lexical order) of master logs.
+   my @master_logs = get_master_logs($master);
+   my $i = 0;
+   my %master_logs = map { $_->{log_name} => $i++ } @master_logs;
+
+   # Ask which slave(s) are reading from this master.
+   my @slave_status = grep { $_->{master_host} } @vars;
+   my @slaves = map { $_->{cxn} } @slave_status;
+   @slaves = select_cxn("Which slaves are reading from $master?", @slaves);
+   @slave_status = grep { my $item = $_; grep { $item->{cxn} eq $_ } @slaves } @slave_status;
+   return unless @slave_status;
+
+   # Find the minimum binary log in use.
+   my $min_log = min(map { $master_logs{$_->{master_log_file}} } @slave_status);
+   my $log_name = $master_logs[$min_log]->{log_name};
+
+   my $stmt = "PURGE MASTER LOGS TO '$log_name'";
+   send_cmd_to_servers($stmt, 0, 'PURGE {MASTER | BINARY} LOGS {TO "log_name" | BEFORE "date"}', [$master]);
+}
+
+sub send_cmd_to_servers {
+   my ( $cmd, $all, $hint, $cxns ) = @_;
+   if ( $all ) {
+      @$cxns = get_connections();
+   }
+   elsif ( !@$cxns ) {
+      @$cxns = select_cxn('Which servers?', @$cxns);
+   }
+   if ( $hint ) {
+      print "\nHint: $hint\n";
+   }
+   $cmd = prompt('Command to send', undef, $cmd);
+   foreach my $cxn ( @$cxns ) {
+      eval {
+         my $sth = do_query($cxn, $cmd);
+      };
+      if ( $EVAL_ERROR ) {
+         print "Error from $cxn: $EVAL_ERROR\n";
+      }
+      else {
+         print "Success on $cxn\n";
+      }
+   }
+   pause();
+}
+
+# Display functions {{{2
+
+sub set_s_mode {
+   my ( $func ) = @_;
+   $clear_screen_sub->();
+   $config{S_func}->{val} = $func;
+}
+
+# start_S_mode {{{3
+sub start_S_mode {
+   $clear_screen_sub->();
+   switch_mode('S');
+}
+
+# display_B {{{3
+sub display_B {
+   my @display_lines;
+   my @cxns = get_connections();
+   get_innodb_status(\@cxns);
+
+   my @buffer_pool;
+   my @page_statistics;
+   my @insert_buffers;
+   my @adaptive_hash_index;
+   my %rows_for = (
+      buffer_pool         => \@buffer_pool,
+      page_statistics     => \@page_statistics,
+      insert_buffers      => \@insert_buffers,
+      adaptive_hash_index => \@adaptive_hash_index,
+   );
+
+   my @visible = get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+
+   foreach my $cxn ( @cxns ) {
+      my $set = $vars{$cxn}->{$clock};
+      my $pre = $vars{$cxn}->{$clock-1} || $set;
+
+      if ( $set->{IB_bp_complete} ) {
+         if ( $wanted{buffer_pool} ) {
+            push @buffer_pool, extract_values($set, $set, $pre, 'buffer_pool');
+         }
+         if ( $wanted{page_statistics} ) {
+            push @page_statistics, extract_values($set, $set, $pre, 'page_statistics');
+         }
+      }
+      if ( $set->{IB_ib_complete} ) {
+         if ( $wanted{insert_buffers} ) {
+            push @insert_buffers, extract_values(
+               $config{status_inc}->{val} ? inc(0, $cxn) : $set, $set, $pre,
+               'insert_buffers');
+         }
+         if ( $wanted{adaptive_hash_index} ) {
+            push @adaptive_hash_index, extract_values($set, $set, $pre, 'adaptive_hash_index');
+         }
+      }
+   }
+
+   my $first_table = 0;
+   foreach my $tbl ( @visible ) {
+      push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl);
+      push @display_lines, get_cxn_errors(@cxns)
+         if ( $config{debug}->{val} || !$first_table++ );
+   }
+
+   draw_screen(\@display_lines);
+}
+
+# display_C {{{3
+sub display_C {
+   my @display_lines;
+   my @cxns = get_connections();
+   get_status_info(@cxns);
+
+   my @cmd_summary;
+   my %rows_for = (
+      cmd_summary => \@cmd_summary,
+   );
+
+   my @visible = get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+
+   # For now, I'm manually pulling these variables out and pivoting.  Eventually a SQL-ish
+   # dialect should let me join a table to a grouped and pivoted table and do this more easily.
+   # TODO: make it so.
+   my $prefix = qr/^$config{cmd_filter}->{val}/; # TODO: this is a total hack
+   my @values;
+   my ($total, $last_total) = (0, 0);
+   foreach my $cxn ( @cxns ) {
+      my $set = $vars{$cxn}->{$clock};
+      my $pre = $vars{$cxn}->{$clock-1} || $set;
+      foreach my $key ( keys %$set ) {
+         next unless $key =~ m/$prefix/i;
+         my $val = $set->{$key};
+         next unless defined $val && $val =~ m/^\d+$/;
+         my $last_val = $val - ($pre->{$key} || 0);
+         $total      += $val;
+         $last_total += $last_val;
+         push @values, {
+            name       => $key,
+            value      => $val,
+            last_value => $last_val,
+         };
+      }
+   }
+
+   # Add aggregation and turn into a real set TODO: total hack
+   if ( $wanted{cmd_summary} ) {
+      foreach my $value ( @values ) {
+         @{$value}{qw(total last_total)} = ($total, $last_total);
+         push @cmd_summary, extract_values($value, $value, $value, 'cmd_summary');
+      }
+   }
+
+   my $first_table = 0;
+   foreach my $tbl ( @visible ) {
+      push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl);
+      push @display_lines, get_cxn_errors(@cxns)
+         if ( $config{debug}->{val} || !$first_table++ );
+   }
+
+   draw_screen(\@display_lines);
+}
+
+# display_D {{{3
+sub display_D {
+   my @display_lines;
+   my @cxns = get_connections();
+   get_innodb_status(\@cxns);
+
+   my @deadlock_transactions;
+   my @deadlock_locks;
+   my %rows_for = (
+      deadlock_transactions => \@deadlock_transactions,
+      deadlock_locks        => \@deadlock_locks,
+   );
+
+   my @visible = get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+
+   foreach my $cxn ( @cxns ) {
+      my $innodb_status = $vars{$cxn}->{$clock};
+      my $prev_status   = $vars{$cxn}->{$clock-1} || $innodb_status;
+
+      if ( $innodb_status->{IB_dl_timestring} ) {
+
+         my $victim = $innodb_status->{IB_dl_rolled_back} || 0;
+
+         if ( %wanted ) {
+            foreach my $txn_id ( keys %{$innodb_status->{IB_dl_txns}} ) {
+               my $txn = $innodb_status->{IB_dl_txns}->{$txn_id};
+               my $pre = $prev_status->{IB_dl_txns}->{$txn_id} || $txn;
+
+               if ( $wanted{deadlock_transactions} ) {
+                  my $hash = extract_values($txn->{tx}, $txn->{tx}, $pre->{tx}, 'deadlock_transactions');
+                  $hash->{cxn}        = $cxn;
+                  $hash->{dl_txn_num} = $txn_id;
+                  $hash->{victim}     = $txn_id == $victim ? 'Yes' : 'No';
+                  $hash->{timestring} = $innodb_status->{IB_dl_timestring};
+                  $hash->{truncates}  = $innodb_status->{IB_dl_complete} ? 'No' : 'Yes';
+                  push @deadlock_transactions, $hash;
+               }
+
+               if ( $wanted{deadlock_locks} ) {
+                  foreach my $lock ( @{$txn->{locks}} ) {
+                     my $hash = extract_values($lock, $lock, $lock, 'deadlock_locks');
+                     $hash->{dl_txn_num}      = $txn_id;
+                     $hash->{cxn}             = $cxn;
+                     $hash->{mysql_thread_id} = $txn->{tx}->{mysql_thread_id};
+                     push @deadlock_locks, $hash;
+                  }
+               }
+
+            }
+         }
+      }
+   }
+
+   my $first_table = 0;
+   foreach my $tbl ( @visible ) {
+      push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl);
+      push @display_lines, get_cxn_errors(@cxns)
+         if ( $config{debug}->{val} || !$first_table++ );
+   }
+
+   draw_screen(\@display_lines);
+}
+
+# display_F {{{3
+sub display_F {
+   my @display_lines;
+   my ( $cxn ) = get_connections();
+   get_innodb_status([$cxn]);
+   my $innodb_status = $vars{$cxn}->{$clock};
+
+   if ( $innodb_status->{IB_fk_timestring} ) {
+
+      push @display_lines, 'Reason: ' . $innodb_status->{IB_fk_reason};
+
+      # Display FK errors caused by invalid DML.
+      if ( $innodb_status->{IB_fk_txn} ) {
+         my $txn = $innodb_status->{IB_fk_txn};
+         push @display_lines,
+            '',
+            "User $txn->{user} from $txn->{hostname}, thread $txn->{mysql_thread_id} was executing:",
+            '', no_ctrl_char($txn->{query_text});
+      }
+
+      my @fk_table = create_table2(
+         $tbl_meta{fk_error}->{visible},
+         meta_to_hdr('fk_error'),
+         extract_values($innodb_status, $innodb_status, $innodb_status, 'fk_error'),
+         { just => '-', sep => '  '});
+      push @display_lines, '', @fk_table;
+
+   }
+   else {
+      push @display_lines, '', 'No foreign key error data.';
+   }
+   draw_screen(\@display_lines, { raw => 1 } );
+}
+
+# display_I {{{3
+sub display_I {
+   my @display_lines;
+   my @cxns = get_connections();
+   get_innodb_status(\@cxns);
+
+   my @io_threads;
+   my @pending_io;
+   my @file_io_misc;
+   my @log_statistics;
+   my %rows_for = (
+      io_threads     => \@io_threads,
+      pending_io     => \@pending_io,
+      file_io_misc   => \@file_io_misc,
+      log_statistics => \@log_statistics,
+   );
+
+   my @visible = get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+
+   foreach my $cxn ( @cxns ) {
+      my $set = $vars{$cxn}->{$clock};
+      my $pre = $vars{$cxn}->{$clock-1} || $set;
+
+      if ( $set->{IB_io_complete} ) {
+         if ( $wanted{io_threads} ) {
+            my $cur_threads = $set->{IB_io_threads};
+            my $pre_threads = $pre->{IB_io_threads} || $cur_threads;
+            foreach my $key ( sort keys %$cur_threads ) {
+               my $cur_thd = $cur_threads->{$key};
+               my $pre_thd = $pre_threads->{$key} || $cur_thd;
+               my $hash = extract_values($cur_thd, $cur_thd, $pre_thd, 'io_threads');
+               $hash->{cxn} = $cxn;
+               push @io_threads, $hash;
+            }
+         }
+         if ( $wanted{pending_io} ) {
+            push @pending_io, extract_values($set, $set, $pre, 'pending_io');
+         }
+         if ( $wanted{file_io_misc} ) {
+            push @file_io_misc, extract_values(
+               $config{status_inc}->{val} ? inc(0, $cxn) : $set,
+               $set, $pre, 'file_io_misc');
+         }
+      }
+      if ( $set->{IB_lg_complete} && $wanted{log_statistics} ) {
+         push @log_statistics, extract_values($set, $set, $pre, 'log_statistics');
+      }
+   }
+
+   my $first_table = 0;
+   foreach my $tbl ( @visible ) {
+      push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl);
+      push @display_lines, get_cxn_errors(@cxns)
+         if ( $config{debug}->{val} || !$first_table++ );
+   }
+
+   draw_screen(\@display_lines);
+}
+
+# display_L {{{3
+sub display_L {
+   my @display_lines;
+   my @cxns = get_connections();
+   get_innodb_status(\@cxns);
+
+   my @innodb_locks;
+   my %rows_for = (
+      innodb_locks => \@innodb_locks,
+   );
+
+   my @visible = get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+
+   # Get info on locks
+   foreach my $cxn ( @cxns ) {
+      my $set = $vars{$cxn}->{$clock} or next;
+      my $pre = $vars{$cxn}->{$clock-1} || $set;
+
+      if ( $wanted{innodb_locks} && defined $set->{IB_tx_transactions} && @{$set->{IB_tx_transactions}} ) {
+
+         my $cur_txns = $set->{IB_tx_transactions};
+         my $pre_txns = $pre->{IB_tx_transactions} || $cur_txns;
+         my %cur_txns = map { $_->{mysql_thread_id} => $_ } @$cur_txns;
+         my %pre_txns = map { $_->{mysql_thread_id} => $_ } @$pre_txns;
+         foreach my $txn ( @$cur_txns ) {
+            foreach my $lock ( @{$txn->{locks}} ) {
+               my %hash = map { $_ => $txn->{$_} } qw(txn_id mysql_thread_id lock_wait_time active_secs);
+               map { $hash{$_} = $lock->{$_} } qw(lock_type space_id page_no n_bits index db table txn_id lock_mode special insert_intention waiting);
+               $hash{cxn} = $cxn;
+               push @innodb_locks, extract_values(\%hash, \%hash, \%hash, 'innodb_locks');
+            }
+         }
+      }
+   }
+
+   my $first_table = 0;
+   foreach my $tbl ( @visible ) {
+      push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl);
+      push @display_lines, get_cxn_errors(@cxns)
+         if ( $config{debug}->{val} || !$first_table++ );
+   }
+
+   draw_screen(\@display_lines);
+}
+
+# display_M {{{3
+sub display_M {
+   my @display_lines;
+   my @cxns = get_connections();
+   get_master_slave_status(@cxns);
+   get_status_info(@cxns);
+
+   my @slave_sql_status;
+   my @slave_io_status;
+   my @master_status;
+   my %rows_for = (
+      slave_sql_status => \@slave_sql_status,
+      slave_io_status  => \@slave_io_status,
+      master_status    => \@master_status,
+   );
+
+   my @visible = get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+
+   foreach my $cxn ( @cxns ) {
+      my $set  = $config{status_inc}->{val} ? inc(0, $cxn) : $vars{$cxn}->{$clock};
+      my $pre  = $vars{$cxn}->{$clock - 1} || $set;
+      if ( $wanted{slave_sql_status} ) {
+         push @slave_sql_status, extract_values($set, $set, $pre, 'slave_sql_status');
+      }
+      if ( $wanted{slave_io_status} ) {
+         push @slave_io_status, extract_values($set, $set, $pre, 'slave_io_status');
+      }
+      if ( $wanted{master_status} ) {
+         push @master_status, extract_values($set, $set, $pre, 'master_status');
+      }
+   }
+
+   my $first_table = 0;
+   foreach my $tbl ( @visible ) {
+      push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl);
+      push @display_lines, get_cxn_errors(@cxns)
+         if ( $config{debug}->{val} || !$first_table++ );
+   }
+
+   draw_screen(\@display_lines);
+}
+
+# display_O {{{3
+sub display_O {
+   my @display_lines = ('');
+   my @cxns          = get_connections();
+   my @open_tables   = get_open_tables(@cxns);
+   my @tables = map { extract_values($_, $_, $_, 'open_tables') } @open_tables;
+   push @display_lines, set_to_tbl(\@tables, 'open_tables'), get_cxn_errors(@cxns);
+   draw_screen(\@display_lines);
+}
+
+# display_Q {{{3
+sub display_Q {
+   my @display_lines;
+
+   my @q_header;
+   my @processlist;
+   my %rows_for = (
+      q_header    => \@q_header,
+      processlist => \@processlist,
+   );
+
+   my @visible = $opts{n} ? 'processlist' : get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+
+   # Get the data
+   my @cxns             = get_connections();
+   my @full_processlist = get_full_processlist(@cxns);
+
+   # Create header
+   if ( $wanted{q_header} ) {
+      get_status_info(@cxns);
+      foreach my $cxn ( @cxns ) {
+         my $set = $vars{$cxn}->{$clock};
+         my $pre = $vars{$cxn}->{$clock-1} || $set;
+         my $hash = extract_values($set, $set, $pre, 'q_header');
+         $hash->{cxn} = $cxn;
+         $hash->{when} = 'Total';
+         push @q_header, $hash;
+
+         if ( exists $vars{$cxn}->{$clock - 1} ) {
+            my $inc = inc(0, $cxn);
+            my $hash = extract_values($inc, $set, $pre, 'q_header');
+            $hash->{cxn} = $cxn;
+            $hash->{when} = 'Now';
+            push @q_header, $hash;
+         }
+      }
+   }
+
+   if ( $wanted{processlist} ) {
+      # TODO: save prev values
+      push @processlist, map { extract_values($_, $_, $_, 'processlist') } @full_processlist;
+   }
+
+   my $first_table = 0;
+   foreach my $tbl ( @visible ) {
+      next unless $wanted{$tbl};
+      push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl);
+      push @display_lines, get_cxn_errors(@cxns)
+         if ( $config{debug}->{val} || !$first_table++ );
+   }
+
+   # Save queries in global variable for analysis.  The rows in %rows_for have been
+   # filtered, etc as a side effect of set_to_tbl(), so they are the same as the rows
+   # that get pushed to the screen.
+   @current_queries = map {
+      my %hash;
+      @hash{ qw(cxn id db query secs) } = @{$_}{ qw(cxn mysql_thread_id db info secs) };
+      \%hash;
+   } @{$rows_for{processlist}};
+
+   draw_screen(\@display_lines);
+}
+
+# display_R {{{3
+sub display_R {
+   my @display_lines;
+   my @cxns = get_connections();
+   get_innodb_status(\@cxns);
+
+   my @row_operations;
+   my @row_operation_misc;
+   my @semaphores;
+   my @wait_array;
+   my %rows_for = (
+      row_operations     => \@row_operations,
+      row_operation_misc => \@row_operation_misc,
+      semaphores         => \@semaphores,
+      wait_array         => \@wait_array,
+   );
+
+   my @visible = get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+   my $incvar  = $config{status_inc}->{val};
+
+   foreach my $cxn ( @cxns ) {
+      my $set = $vars{$cxn}->{$clock};
+      my $pre = $vars{$cxn}->{$clock-1} || $set;
+      my $inc; # Only assigned to if wanted
+
+      if ( $set->{IB_ro_complete} ) {
+         if ( $wanted{row_operations} ) {
+            $inc ||= $incvar ? inc(0, $cxn) : $set;
+            push @row_operations, extract_values($inc, $set, $pre, 'row_operations');
+         }
+         if ( $wanted{row_operation_misc} ) {
+            push @row_operation_misc, extract_values($set, $set, $pre, 'row_operation_misc'),
+         }
+      }
+
+      if ( $set->{IB_sm_complete} && $wanted{semaphores} ) {
+         $inc ||= $incvar ? inc(0, $cxn) : $set;
+         push @semaphores, extract_values($inc, $set, $pre, 'semaphores');
+      }
+
+      if ( $set->{IB_sm_wait_array_size} && $wanted{wait_array} ) {
+         foreach my $wait ( @{$set->{IB_sm_waits}} ) {
+            my $hash = extract_values($wait, $wait, $wait, 'wait_array');
+            $hash->{cxn} = $cxn;
+            push @wait_array, $hash;
+         }
+      }
+   }
+
+   my $first_table = 0;
+   foreach my $tbl ( @visible ) {
+      push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl);
+      push @display_lines, get_cxn_errors(@cxns)
+         if ( $config{debug}->{val} || !$first_table++ );
+   }
+
+   draw_screen(\@display_lines);
+}
+
+# display_T {{{3
+sub display_T {
+   my @display_lines;
+
+   my @t_header;
+   my @innodb_transactions;
+   my %rows_for = (
+      t_header            => \@t_header,
+      innodb_transactions => \@innodb_transactions,
+   );
+
+   my @visible = $opts{n} ? 'innodb_transactions' : get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+
+   my @cxns = get_connections();
+
+   # If the header is to be shown, buffer pool data is required.
+   get_innodb_status( \@cxns, [ $wanted{t_header} ? qw(bp) : () ] );
+
+   foreach my $cxn ( get_connections() ) {
+      my $set = $vars{$cxn}->{$clock};
+      my $pre = $vars{$cxn}->{$clock-1} || $set;
+
+      next unless $set->{IB_tx_transactions};
+
+      if ( $wanted{t_header} ) {
+         my $hash = extract_values($set, $set, $pre, 't_header');
+         push @t_header, $hash;
+      }
+
+      if ( $wanted{innodb_transactions} ) {
+         my $cur_txns = $set->{IB_tx_transactions};
+         my $pre_txns = $pre->{IB_tx_transactions} || $cur_txns;
+         my %cur_txns = map { $_->{mysql_thread_id} => $_ } @$cur_txns;
+         my %pre_txns = map { $_->{mysql_thread_id} => $_ } @$pre_txns;
+         foreach my $thd_id ( sort keys %cur_txns ) {
+            my $cur_txn = $cur_txns{$thd_id};
+            my $pre_txn = $pre_txns{$thd_id} || $cur_txn;
+            my $hash    = extract_values($cur_txn, $cur_txn, $pre_txn, 'innodb_transactions');
+            $hash->{cxn} = $cxn;
+            push @innodb_transactions, $hash;
+         }
+      }
+
+   }
+
+   my $first_table = 0;
+   foreach my $tbl ( @visible ) {
+      push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl);
+      push @display_lines, get_cxn_errors(@cxns)
+         if ( $config{debug}->{val} || !$first_table++ );
+   }
+
+   # Save queries in global variable for analysis.  The rows in %rows_for have been
+   # filtered, etc as a side effect of set_to_tbl(), so they are the same as the rows
+   # that get pushed to the screen.
+   @current_queries = map {
+      my %hash;
+      @hash{ qw(cxn id db query secs) } = @{$_}{ qw(cxn mysql_thread_id db query_text active_secs) };
+      \%hash;
+   } @{$rows_for{innodb_transactions}};
+
+   draw_screen(\@display_lines);
+}
+
+# display_S {{{3
+sub display_S {
+   my $fmt  = get_var_set('S_set');
+   my $func = $config{S_func}->{val};
+   my $inc  = $func eq 'g' || $config{status_inc}->{val};
+
+   # The table's meta-data is generated from the compiled var_set.
+   my ( $cols, $visible );
+   if ( $tbl_meta{var_status}->{fmt} && $fmt eq $tbl_meta{var_status}->{fmt} ) {
+      ( $cols, $visible ) = @{$tbl_meta{var_status}}{qw(cols visible)};
+   }
+   else {
+      ( $cols, $visible ) = compile_select_stmt($fmt);
+
+      # Apply missing values to columns.  Always apply averages across all connections.
+      map {
+         $_->{agg}   = 'avg';
+         $_->{label} = $_->{hdr};
+      } values %$cols;
+
+      $tbl_meta{var_status}->{cols}    = $cols;
+      $tbl_meta{var_status}->{visible} = $visible;
+      $tbl_meta{var_status}->{fmt}     = $fmt;
+      map { $tbl_meta{var_status}->{cols}->{$_}->{just} = ''} @$visible;
+   }
+
+   my @var_status;
+   my %rows_for = (
+      var_status => \@var_status,
+   );
+
+   my @visible = get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+   my @cxns    = get_connections();
+
+   get_status_info(@cxns);
+   get_innodb_status(\@cxns);
+
+   # Set up whether to pivot and how many sets to extract.
+   $tbl_meta{var_status}->{pivot} = $func eq 'v';
+
+   my $num_sets
+      = $func eq 'v'
+      ? $config{num_status_sets}->{val}
+      : 0;
+   foreach my $set ( 0 .. $num_sets ) {
+      my @rows;
+      foreach my $cxn ( @cxns ) {
+         my $vars = $inc ? inc($set, $cxn) : $vars{$cxn}->{$clock - $set};
+         my $cur  = $vars{$cxn}->{$clock-$set};
+         my $pre  = $vars{$cxn}->{$clock-$set-1} || $cur;
+         next unless $vars && %$vars;
+         my $hash = extract_values($vars, $cur, $pre, 'var_status');
+         push @rows, $hash;
+      }
+      @rows = apply_group_by('var_status', [], @rows);
+      push @var_status, @rows;
+   }
+
+   # Recompile the sort func. TODO: avoid recompiling at every refresh.
+   # Figure out whether the data is all numeric and decide on a sort type.
+   # my $cmp
+   #   = scalar(
+   #      grep { !defined $_ || $_ !~ m/^\d+$/ }
+   #      map  { my $col = $_; map { $_->{$col} } @var_status }
+   #           $tbl_meta{var_status}->{sort_cols} =~ m/(\w+)/g)
+   #   ? 'cmp'
+   #   : '<=>';
+   $tbl_meta{var_status}->{sort_func} = make_sort_func($tbl_meta{var_status});
+
+   # ################################################################
+   # Now there is specific display code based on $config{S_func}
+   # ################################################################
+   if ( $func =~ m/s|g/ ) {
+      my $min_width = 4;
+
+      # Clear the screen if the display width changed.
+      if ( @last_term_size && $this_term_size[0] != $last_term_size[0] ) {
+         $lines_printed = 0;
+         $clear_screen_sub->();
+      }
+
+      if ( $func eq 's' ) {
+         # Decide how wide columns should be.
+         my $num_cols = scalar(@$visible);
+         my $width    = $opts{n} ? 0 : max($min_width, int(($this_term_size[0] - $num_cols + 1) / $num_cols));
+         my $g_format = $opts{n} ? ( "%s\t" x $num_cols ) : ( "%-${width}s " x $num_cols );
+
+         # Print headers every now and then.  Headers can get really long, so compact them.
+         my @hdr = @$visible;
+         if ( $opts{n} ) {
+            if ( $lines_printed == 0 ) {
+               print join("\t", @hdr), "\n";
+               $lines_printed++;
+            }
+         }
+         elsif ( $lines_printed == 0 || $lines_printed > $this_term_size[1] - 2 ) {
+            @hdr = map { donut(crunch($_, $width), $width) } @hdr;
+            print join(' ', map { sprintf( "%${width}s", donut($_, $width)) } @hdr) . "\n";
+            $lines_printed = 1;
+         }
+
+         # Design a column format for the values.
+         my $format
+            = $opts{n}
+            ? join("\t", map { '%s' } @$visible) . "\n"
+            : join(' ',  map { "%${width}s" } @hdr) . "\n";
+
+         foreach my $row ( @var_status ) {
+            printf($format, map { defined $_ ? $_ : '' } @{$row}{ @$visible });
+            $lines_printed++;
+         }
+      }
+      else { # 'g' mode
+         # Design a column format for the values.
+         my $num_cols = scalar(@$visible);
+         my $width    = $opts{n} ? 0 : int(($this_term_size[0] - $num_cols + 1) / $num_cols);
+         my $format   = $opts{n} ? ( "%s\t" x $num_cols ) : ( "%-${width}s " x $num_cols );
+         $format      =~ s/\s$/\n/;
+
+         # Print headers every now and then.
+         if ( $opts{n} ) {
+            if ( $lines_printed == 0 ) {
+               print join("\t", @$visible), "\n";
+               print join("\t", map { shorten($mvs{$_}) } @$visible), "\n";
+            }
+         }
+         elsif ( $lines_printed == 0 || $lines_printed > $this_term_size[1] - 2 ) {
+            printf($format, map { donut(crunch($_, $width), $width) } @$visible);
+            printf($format, map { shorten($mvs{$_} || 0) } @$visible);
+            $lines_printed = 2;
+         }
+
+         # Update the max ever seen, and scale by the max ever seen.
+         my $set = $var_status[0];
+         foreach my $col ( @$visible ) {
+            $set->{$col}  = 1 unless defined $set->{$col} && $set->{$col} =~ m/$num_regex/;
+            $set->{$col}  = ($set->{$col} || 1) / ($set->{Uptime_hires} || 1);
+            $mvs{$col}    = max($mvs{$col} || 1, $set->{$col});
+            $set->{$col} /= $mvs{$col};
+         }
+         printf($format, map { ( $config{graph_char}->{val} x int( $width * $set->{$_} )) || '.' } @$visible );
+         $lines_printed++;
+
+      }
+   }
+   else { # 'v'
+      my $first_table = 0;
+      my @display_lines;
+      foreach my $tbl ( @visible ) {
+         push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl);
+         push @display_lines, get_cxn_errors(@cxns)
+            if ( $config{debug}->{val} || !$first_table++ );
+      }
+      $clear_screen_sub->();
+      draw_screen( \@display_lines );
+   }
+}
+
+# display_explain {{{3
+sub display_explain {
+   my $info = shift;
+   my $cxn   = $info->{cxn};
+   my $db    = $info->{db};
+
+   my ( $mods, $query ) = rewrite_for_explain($info->{query});
+
+   my @display_lines;
+
+   if ( $query ) {
+
+      my $part = version_ge($dbhs{$cxn}->{dbh}, '5.1.5') ? 'PARTITIONS' : '';
+      $query = "EXPLAIN $part\n" . $query;
+
+      eval {
+         if ( $db ) {
+            do_query($cxn, "use $db");
+         }
+         my $sth = do_query($cxn, $query);
+
+         my $res;
+         while ( $res = $sth->fetchrow_hashref() ) {
+            map { $res->{$_} ||= '' } ( 'partitions', keys %$res);
+            my @this_table = create_caption("Sub-Part $res->{id}",
+               create_table2(
+                  $tbl_meta{explain}->{visible},
+                  meta_to_hdr('explain'),
+                  extract_values($res, $res, $res, 'explain')));
+            @display_lines = stack_next(\@display_lines, \@this_table, { pad => '  ', vsep => 2 });
+         }
+      };
+
+      if ( $EVAL_ERROR ) {
+         push @display_lines,
+            '',
+            "The query could not be explained.  Only SELECT queries can be "
+            . "explained; innotop tries to rewrite certain REPLACE and INSERT queries "
+            . "into SELECT, but this doesn't always succeed.";
+      }
+
+   }
+   else {
+      push @display_lines, '', 'The query could not be explained.';
+   }
+
+   if ( $mods ) {
+      push @display_lines, '', '[This query has been re-written to be explainable]';
+   }
+
+   unshift @display_lines, no_ctrl_char($query);
+   draw_screen(\@display_lines, { raw => 1 } );
+}
+
+# rewrite_for_explain {{{3
+sub rewrite_for_explain {
+   my $query = shift;
+
+   my $mods = 0;
+   my $orig = $query;
+   $mods += $query =~ s/^\s*(?:replace|insert).*?select/select/is;
+   $mods += $query =~ s/^
+      \s*create\s+(?:temporary\s+)?table
+      \s+(?:\S+\s+)as\s+select/select/xis;
+   $mods += $query =~ s/\s+on\s+duplicate\s+key\s+update.*$//is;
+   return ( $mods, $query );
+}
+
+# show_optimized_query {{{3
+sub show_optimized_query {
+   my $info = shift;
+   my $cxn   = $info->{cxn};
+   my $db    = $info->{db};
+   my $meta  = $dbhs{$cxn};
+
+   my @display_lines;
+
+   my ( $mods, $query ) = rewrite_for_explain($info->{query});
+
+   if ( $mods ) {
+      push @display_lines, '[This query has been re-written to be explainable]';
+   }
+
+   if ( $query ) {
+      push @display_lines, no_ctrl_char($info->{query});
+
+      eval {
+         if ( $db ) {
+            do_query($cxn, "use $db");
+         }
+         do_query( $cxn, 'EXPLAIN EXTENDED ' . $query ) or die "Can't explain query";
+         my $sth = do_query($cxn, 'SHOW WARNINGS');
+         my $res = $sth->fetchall_arrayref({});
+
+         if ( $res ) {
+            foreach my $result ( @$res ) {
+               push @display_lines, 'Note:', no_ctrl_char($result->{message});
+            }
+         }
+         else {
+            push @display_lines, '', 'The query optimization could not be generated.';
+         }
+      };
+
+      if ( $EVAL_ERROR ) {
+         push @display_lines, '', "The optimization could not be generated: $EVAL_ERROR";
+      }
+
+   }
+   else {
+      push @display_lines, '', 'The query optimization could not be generated.';
+   }
+
+   draw_screen(\@display_lines, { raw => 1 } );
+}
+
+# display_help {{{3
+sub display_help {
+   my $mode = $config{mode}->{val};
+
+   # Get globally mapped keys, then overwrite them with mode-specific ones.
+   my %keys = map {
+         $_ => $action_for{$_}->{label}
+      } keys %action_for;
+   foreach my $key ( keys %{$modes{$mode}->{action_for}} ) {
+      $keys{$key} = $modes{$mode}->{action_for}->{$key}->{label};
+   }
+   delete $keys{'?'};
+
+   # Split them into three kinds of keys: MODE keys, action keys, and
+   # magic (special character) keys.
+   my @modes   = sort grep { m/[A-Z]/   } keys %keys;
+   my @actions = sort grep { m/[a-z]/   } keys %keys;
+   my @magic   = sort grep { m/[^A-Z]/i } keys %keys;
+
+   my @display_lines = ( '', 'Switch to a different mode:' );
+
+   # Mode keys
+   my @all_modes = map { "$_  $modes{$_}->{hdr}" } @modes;
+   my @col1 = splice(@all_modes, 0, ceil(@all_modes/3));
+   my @col2 = splice(@all_modes, 0, ceil(@all_modes/2));
+   my $max1 = max(map {length($_)} @col1);
+   my $max2 = max(map {length($_)} @col2);
+   while ( @col1 ) {
+      push @display_lines, sprintf("   %-${max1}s  %-${max2}s  %s",
+         (shift @col1      || ''),
+         (shift @col2      || ''),
+         (shift @all_modes || ''));
+   }
+
+   # Action keys
+   my @all_actions = map { "$_  $keys{$_}" } @actions;
+   @col1 = splice(@all_actions, 0, ceil(@all_actions/2));
+   $max1 = max(map {length($_)} @col1);
+   push @display_lines, '', 'Actions:';
+   while ( @col1 ) {
+      push @display_lines, sprintf("   %-${max1}s  %s",
+         (shift @col1        || ''),
+         (shift @all_actions || ''));
+   }
+
+   # Magic keys
+   my @all_magic = map { sprintf('%4s', $action_for{$_}->{key} || $_) . "  $keys{$_}" } @magic;
+   @col1 = splice(@all_magic, 0, ceil(@all_magic/2));
+   $max1 = max(map {length($_)} @col1);
+   push @display_lines, '', 'Other:';
+   while ( @col1 ) {
+      push @display_lines, sprintf("%-${max1}s%s",
+         (shift @col1      || ''),
+         (shift @all_magic || ''));
+   }
+
+   $clear_screen_sub->();
+   draw_screen(\@display_lines, { show_all => 1 } );
+   pause();
+   $clear_screen_sub->();
+}
+
+# show_full_query {{{3
+sub show_full_query {
+   my $info = shift;
+   my @display_lines = no_ctrl_char($info->{query});
+   draw_screen(\@display_lines, { raw => 1 });
+}
+
+# Formatting functions {{{2
+
+# create_table2 {{{3
+# Makes a two-column table, labels on left, data on right.
+# Takes refs of @cols, %labels and %data, %user_prefs
+sub create_table2 {
+   my ( $cols, $labels, $data, $user_prefs ) = @_;
+   my @rows;
+
+   if ( @$cols && %$data ) {
+
+      # Override defaults
+      my $p = {
+         just  => '',
+         sep   => ':',
+         just1 => '-',
+      };
+      if ( $user_prefs ) {
+         map { $p->{$_} = $user_prefs->{$_} } keys %$user_prefs;
+      }
+
+      # Fix undef values
+      map { $data->{$_} = '' unless defined $data->{$_} } @$cols;
+
+      # Format the table
+      my $max_l = max(map{ length($labels->{$_}) } @$cols);
+      my $max_v = max(map{ length($data->{$_}) } @$cols);
+      my $format    = "%$p->{just}${max_l}s$p->{sep} %$p->{just1}${max_v}s";
+      foreach my $col ( @$cols ) {
+         push @rows, sprintf($format, $labels->{$col}, $data->{$col});
+      }
+   }
+   return @rows;
+}
+
+# stack_next {{{3
+# Stacks one display section next to the other.  Accepts left-hand arrayref,
+# right-hand arrayref, and options hashref.  Tries to stack as high as
+# possible, so
+# aaaaaa
+# bbb
+# can stack ccc next to the bbb.
+# NOTE: this DOES modify its arguments, even though it returns a new array.
+sub stack_next {
+   my ( $left, $right, $user_prefs ) = @_;
+   my @result;
+
+   my $p = {
+      pad   => ' ',
+      vsep  => 0,
+   };
+   if ( $user_prefs ) {
+      map { $p->{$_} = $user_prefs->{$_} } keys %$user_prefs;
+   }
+
+   # Find out how wide the LHS can be and still let the RHS fit next to it.
+   my $pad   = $p->{pad};
+   my $max_r = max( map { length($_) } @$right) || 0;
+   my $max_l = $this_term_size[0] - $max_r - length($pad);
+
+   # Find the minimum row on the LHS that the RHS will fit next to.
+   my $i = scalar(@$left) - 1;
+   while ( $i >= 0 && length($left->[$i]) <= $max_l ) {
+      $i--;
+   }
+   $i++;
+   my $offset = $i;
+
+   if ( $i < scalar(@$left) ) {
+      # Find the max width of the section of the LHS against which the RHS
+      # will sit.
+      my $max_i_in_common = min($i + scalar(@$right) - 1, scalar(@$left) - 1);
+      my $max_width = max( map { length($_) } @{$left}[$i..$max_i_in_common]);
+
+      # Append the RHS onto the LHS until one runs out.
+      while ( $i < @$left && $i - $offset < @$right ) {
+         my $format = "%-${max_width}s$pad%${max_r}s";
+         $left->[$i] = sprintf($format, $left->[$i], $right->[$i - $offset]);
+         $i++;
+      }
+      while ( $i - $offset < @$right ) {
+         # There is more RHS to push on the end of the array
+         push @$left,
+            sprintf("%${max_width}s$pad%${max_r}s", ' ', $right->[$i - $offset]);
+         $i++;
+      }
+      push @result, @$left;
+   }
+   else {
+      # There is no room to put them side by side.  Add them below, with
+      # a blank line above them if specified.
+      push @result, @$left;
+      push @result, (' ' x $this_term_size[0]) if $p->{vsep} && @$left;
+      push @result, @$right;
+   }
+   return @result;
+}
+
+# create_caption {{{3
+sub create_caption {
+   my ( $caption, @rows ) = @_;
+   if ( @rows ) {
+
+      # Calculate the width of what will be displayed, so it can be centered
+      # in that space.  When the thing is wider than the display, center the
+      # caption in the display.
+      my $width = min($this_term_size[0], max(map { length(ref($_) ? $_->[0] : $_) } @rows));
+
+      my $cap_len = length($caption);
+
+      # It may be narrow enough to pad the sides with underscores and save a
+      # line on the screen.
+      if ( $cap_len <= $width - 6 ) {
+         my $left = int(($width - 2 - $cap_len) / 2);
+         unshift @rows,
+            ("_" x $left) . " $caption " . ("_" x ($width - $left - $cap_len - 2));
+      }
+
+      # The caption is too wide to add underscores on each side.
+      else {
+
+         # Color is supported, so we can use terminal underlining.
+         if ( $config{color}->{val} ) {
+            my $left = int(($width - $cap_len) / 2);
+            unshift @rows, [
+               (" " x $left) . $caption . (" " x ($width - $left - $cap_len)),
+               'underline',
+            ];
+         }
+
+         # Color is not supported, so we have to add a line underneath to separate the
+         # caption from whatever it's captioning.
+         else {
+            my $left = int(($width - $cap_len) / 2);
+            unshift @rows, ('-' x $width);
+            unshift @rows, (" " x $left) . $caption . (" " x ($width - $left - $cap_len));
+         }
+
+         # The caption is wider than the thing it labels, so we have to pad the
+         # thing it labels to a consistent width.
+         if ( $cap_len > $width ) {
+            @rows = map {
+               ref($_)
+                  ? [ sprintf('%-' . $cap_len . 's', $_->[0]), $_->[1] ]
+                  : sprintf('%-' . $cap_len . 's', $_);
+            } @rows;
+         }
+
+      }
+   }
+   return @rows;
+}
+
+# create_table {{{3
+# Input: an arrayref of columns, hashref of col info, and an arrayref of hashes
+# Example: [ 'a', 'b' ]
+#          { a => spec, b => spec }
+#          [ { a => 1, b => 2}, { a => 3, b => 4 } ]
+# The 'spec' is a hashref of hdr => label, just => ('-' or '').  It also supports min and max-widths
+# vi the minw and maxw params.
+# Output: an array of strings, one per row.
+# Example:
+# Column One Column Two
+# ---------- ----------
+# 1          2
+# 3          4
+sub create_table {
+   my ( $cols, $info, $data, $prefs ) = @_;
+   $prefs ||= {};
+   $prefs->{no_hdr} ||= ($opts{n} && $clock != 1);
+
+   # Truncate rows that will surely be off screen even if this is the only table.
+   if ( !$opts{n} && !$prefs->{raw} && !$prefs->{show_all} && $this_term_size[1] < @$data-1 ) {
+      $data = [ @$data[0..$this_term_size[1] - 1] ];
+   }
+
+   my @rows = ();
+
+   if ( @$cols && %$info ) {
+
+      # Fix undef values, collapse whitespace.
+      foreach my $row ( @$data ) {
+         map { $row->{$_} = collapse_ws($row->{$_}) } @$cols;
+      }
+
+      my $col_sep = $opts{n} ? "\t" : '  ';
+
+      # Find each column's max width.
+      my %width_for;
+      if ( !$opts{n} ) {
+         %width_for = map {
+            my $col_name  = $_;
+            if ( $info->{$_}->{dec} ) {
+               # Align along the decimal point
+               my $max_rodp = max(0, map { $_->{$col_name} =~ m/([^\s\d-].*)$/ ? length($1) : 0 } @$data);
+               foreach my $row ( @$data ) {
+                  my $col = $row->{$col_name};
+                  my ( $l, $r ) = $col =~ m/^([\s\d]*)(.*)$/;
+                  $row->{$col_name} = sprintf("%s%-${max_rodp}s", $l, $r);
+               }
+            }
+            my $max_width = max( length($info->{$_}->{hdr}), map { length($_->{$col_name}) } @$data);
+            if ( $info->{$col_name}->{maxw} ) {
+               $max_width = min( $max_width, $info->{$col_name}->{maxw} );
+            }
+            if ( $info->{$col_name}->{minw} ) {
+               $max_width = max( $max_width, $info->{$col_name}->{minw} );
+            }
+            $col_name => $max_width;
+         } @$cols;
+      }
+
+      # The table header.
+      if ( !$config{hide_hdr}->{val} && !$prefs->{no_hdr} ) {
+         push @rows, $opts{n}
+            ? join( $col_sep, @$cols )
+            : join( $col_sep, map { sprintf( "%-$width_for{$_}s", trunc($info->{$_}->{hdr}, $width_for{$_}) ) } @$cols );
+         if ( $config{color}->{val} && $config{header_highlight}->{val} ) {
+            push @rows, [ pop @rows, $config{header_highlight}->{val} ];
+         }
+         elsif ( !$opts{n} ) {
+            push @rows, join( $col_sep, map { "-" x $width_for{$_} } @$cols );
+         }
+      }
+
+      # The table data.
+      if ( $opts{n} ) {
+         foreach my $item ( @$data ) {
+            push @rows, join($col_sep, map { $item->{$_} } @$cols );
+         }
+      }
+      else {
+         my $format = join( $col_sep,
+            map { "%$info->{$_}->{just}$width_for{$_}s" } @$cols );
+         foreach my $item ( @$data ) {
+            my $row = sprintf($format, map { trunc($item->{$_}, $width_for{$_}) } @$cols );
+            if ( $config{color}->{val} && $item->{_color} ) {
+               push @rows, [ $row, $item->{_color} ];
+            }
+            else {
+               push @rows, $row;
+            }
+         }
+      }
+   }
+
+   return @rows;
+}
+
+# Aggregates a table.  If $group_by is an arrayref of columns, the grouping key
+# is the specified columns; otherwise it's just the empty string (e.g.
+# everything is grouped as one group).
+sub apply_group_by {
+   my ( $tbl, $group_by, @rows ) = @_;
+   my $meta = $tbl_meta{$tbl};
+   my %is_group = map { $_ => 1 } @$group_by;
+   my @non_grp  = grep { !$is_group{$_} } keys %{$meta->{cols}};
+
+   my %temp_table;
+   foreach my $row ( @rows ) {
+      my $group_key
+         = @$group_by
+         ? '{' . join('}{', map { defined $_ ? $_ : '' } @{$row}{@$group_by}) . '}'
+         : '';
+      $temp_table{$group_key} ||= [];
+      push @{$temp_table{$group_key}}, $row;
+   }
+
+   # Crush the rows together...
+   my @new_rows;
+   foreach my $key ( sort keys %temp_table ) {
+      my $group = $temp_table{$key};
+      my %new_row;
+      @new_row{@$group_by} = @{$group->[0]}{@$group_by};
+      foreach my $col ( @non_grp ) {
+         my $agg = $meta->{cols}->{$col}->{agg} || 'first';
+         $new_row{$col} = $agg_funcs{$agg}->( map { $_->{$col} } @$group );
+      }
+      push @new_rows, \%new_row;
+   }
+   return @new_rows;
+}
+
+# set_to_tbl {{{3
+# Unifies all the work of filtering, sorting etc.  Alters the input.
+# TODO: pull all the little pieces out into subroutines and stick events in each of them.
+sub set_to_tbl {
+   my ( $rows, $tbl ) = @_;
+   my $meta = $tbl_meta{$tbl} or die "No such table $tbl in tbl_meta";
+
+   # don't show cxn if there's only one connection being displayed
+   my @visible;
+   if (scalar @{$modes{$config{mode}->{val}}->{connections}} == 1) {
+      map { push @visible, $_ if $_ !~ /^cxn$/ } @{$meta->{visible}};
+      delete $$rows[0]{cxn} if defined $$rows[0]{cxn};
+   }
+   else {
+      @visible = @{$meta->{visible}};
+   }
+
+   if ( !$meta->{pivot} ) {
+
+      # Hook in event listeners
+      foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_filter}} ) {
+         $listener->set_to_tbl_pre_filter($rows, $tbl);
+      }
+
+      # Apply filters.  Note that if the table is pivoted, filtering and sorting
+      # are applied later.
+      foreach my $filter ( @{$meta->{filters}} ) {
+         eval {
+            @$rows = grep { $filters{$filter}->{func}->($_) } @$rows;
+         };
+         if ( $EVAL_ERROR && $config{debug}->{val} ) {
+            die $EVAL_ERROR;
+         }
+      }
+
+      foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_sort}} ) {
+         $listener->set_to_tbl_pre_sort($rows, $tbl);
+      }
+
+      # Sort.  Note that if the table is pivoted, sorting might have the wrong
+      # columns and it could crash.  This will only be an issue if it's possible
+      # to toggle pivoting on and off, which it's not at the moment.
+      if ( @$rows && $meta->{sort_func} && !$meta->{aggregate} ) {
+         if ( $meta->{sort_dir} > 0 ) {
+            @$rows = $meta->{sort_func}->( @$rows );
+         }
+         else {
+            @$rows = reverse $meta->{sort_func}->( @$rows );
+         }
+      }
+
+   }
+
+   # Stop altering arguments now.
+   my @rows = @$rows;
+
+   foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_group}} ) {
+      $listener->set_to_tbl_pre_group(\@rows, $tbl);
+   }
+
+   # Apply group-by.
+   if ( $meta->{aggregate} ) {
+      @rows = apply_group_by($tbl, $meta->{group_by}, @rows);
+
+      # Sort.  Note that if the table is pivoted, sorting might have the wrong
+      # columns and it could crash.  This will only be an issue if it's possible
+      # to toggle pivoting on and off, which it's not at the moment.
+      if ( @rows && $meta->{sort_func} ) {
+         if ( $meta->{sort_dir} > 0 ) {
+            @rows = $meta->{sort_func}->( @rows );
+         }
+         else {
+            @rows = reverse $meta->{sort_func}->( @rows );
+         }
+      }
+
+   }
+
+   foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_colorize}} ) {
+      $listener->set_to_tbl_pre_colorize(\@rows, $tbl);
+   }
+
+   if ( !$meta->{pivot} ) {
+      # Colorize.  Adds a _color column to rows.
+      if ( @rows && $meta->{color_func} ) {
+         eval {
+            foreach my $row ( @rows ) {
+               $row->{_color} = $meta->{color_func}->($row);
+            }
+         };
+         if ( $EVAL_ERROR ) {
+            pause($EVAL_ERROR);
+         }
+      }
+   }
+
+   foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_transform}} ) {
+      $listener->set_to_tbl_pre_transform(\@rows, $tbl);
+   }
+
+   # Apply_transformations.
+   if ( @rows ) {
+      my $cols = $meta->{cols};
+      foreach my $col ( keys %{$rows->[0]} ) {
+         # Don't auto-vivify $tbl_meta{tbl}-{cols}->{_color}->{trans}
+         next if $col eq '_color';
+         foreach my $trans ( @{$cols->{$col}->{trans}} ) {
+            map { $_->{$col} = $trans_funcs{$trans}->($_->{$col}) } @rows;
+         }
+      }
+   }
+
+   my ($fmt_cols, $fmt_meta);
+
+   # Pivot.
+   if ( $meta->{pivot} ) {
+
+      foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_pivot}} ) {
+         $listener->set_to_tbl_pre_pivot(\@rows, $tbl);
+      }
+
+      my @vars = @{$meta->{visible}};
+      my @tmp  = map { { name => $_ } } @vars;
+      my @cols = 'name';
+      foreach my $i ( 0..@$rows-1 ) {
+         my $col = "set_$i";
+         push @cols, $col;
+         foreach my $j ( 0..@vars-1 ) {
+            $tmp[$j]->{$col} = $rows[$i]->{$vars[$j]};
+         }
+      }
+      $fmt_meta = { map { $_ => { hdr => $_, just => '-' } } @cols };
+      $fmt_cols = \@cols;
+      @rows = @tmp;
+
+      # Hook in event listeners
+      foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_filter}} ) {
+         $listener->set_to_tbl_pre_filter($rows, $tbl);
+      }
+
+      # Apply filters.
+      foreach my $filter ( @{$meta->{filters}} ) {
+         eval {
+            @rows = grep { $filters{$filter}->{func}->($_) } @rows;
+         };
+         if ( $EVAL_ERROR && $config{debug}->{val} ) {
+            die $EVAL_ERROR;
+         }
+      }
+
+      foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_sort}} ) {
+         $listener->set_to_tbl_pre_sort($rows, $tbl);
+      }
+
+      # Sort.
+      if ( @rows && $meta->{sort_func} ) {
+         if ( $meta->{sort_dir} > 0 ) {
+            @rows = $meta->{sort_func}->( @rows );
+         }
+         else {
+            @rows = reverse $meta->{sort_func}->( @rows );
+         }
+      }
+
+   }
+   else {
+      # If the table isn't pivoted, just show all columns that are supposed to
+      # be shown; but eliminate aggonly columns if the table isn't aggregated.
+      my $aggregated = $meta->{aggregate};
+      $fmt_cols = [ grep { $aggregated || !$meta->{cols}->{$_}->{aggonly} } @visible ];
+      $fmt_meta = { map  { $_ => $meta->{cols}->{$_}                      } @$fmt_cols };
+
+      # If the table is aggregated, re-order the group_by columns to the left of
+      # the display.
+      if ( $aggregated ) {
+         my %is_group = map { $_ => 1 } @{$meta->{group_by}};
+         $fmt_cols = [ @{$meta->{group_by}}, grep { !$is_group{$_} } @$fmt_cols ];
+      }
+   }
+
+   foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_create}} ) {
+      $listener->set_to_tbl_pre_create(\@rows, $tbl);
+   }
+
+   @rows = create_table( $fmt_cols, $fmt_meta, \@rows);
+   if ( !$meta->{hide_caption} && !$opts{n} && $config{display_table_captions}->{val} ) {
+      @rows = create_caption($meta->{capt}, @rows)
+   }
+
+   foreach my $listener ( @{$event_listener_for{set_to_tbl_post_create}} ) {
+      $listener->set_to_tbl_post_create(\@rows, $tbl);
+   }
+
+   return @rows;
+}
+
+# meta_to_hdr {{{3
+sub meta_to_hdr {
+   my $tbl = shift;
+   my $meta = $tbl_meta{$tbl};
+   my %labels = map { $_ => $meta->{cols}->{$_}->{hdr} } @{$meta->{visible}};
+   return \%labels;
+}
+
+# commify {{{3
+# From perlfaq5: add commas.
+sub commify {
+   my ( $num ) = @_;
+   $num = 0 unless defined $num;
+   $num =~ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g;
+   return $num;
+}
+
+# set_precision {{{3
+# Trim to desired precision.
+sub set_precision {
+   my ( $num, $precision ) = @_;
+   $precision = $config{num_digits}->{val} if !defined $precision;
+   sprintf("%.${precision}f", $num);
+}
+
+# percent {{{3
+# Convert to percent
+sub percent {
+   my ( $num ) = @_;
+   $num = 0 unless defined $num;
+   my $digits = $config{num_digits}->{val};
+   return sprintf("%.${digits}f", $num * 100)
+      . ($config{show_percent}->{val} ? '%' : '');
+}
+
+# shorten {{{3
+sub shorten {
+   my ( $num, $opts ) = @_;
+
+   return $num if !defined($num) || $opts{n} || $num !~ m/$num_regex/;
+
+   $opts ||= {};
+   my $pad = defined $opts->{pad} ? $opts->{pad} : '';
+   my $num_digits = defined $opts->{num_digits}
+      ? $opts->{num_digits}
+      : $config{num_digits}->{val};
+   my $force = defined $opts->{force};
+
+   my $n = 0;
+   while ( $num >= 1_024 ) {
+      $num /= 1_024;
+      ++$n;
+   }
+   return sprintf(
+      $num =~ m/\./ || $n || $force
+         ? "%.${num_digits}f%s"
+         : '%d',
+      $num, ($pad,'k','M','G', 'T')[$n]);
+
+}
+
+# Utility functions {{{2
+# unique {{{3
+sub unique {
+   my %seen;
+   return grep { !$seen{$_}++ } @_;
+}
+
+# make_color_func {{{3
+sub make_color_func {
+   my ( $tbl ) = @_;
+   my @criteria;
+   foreach my $spec ( @{$tbl->{colors}} ) {
+      next unless exists $comp_ops{$spec->{op}};
+      my $val = $spec->{op} =~ m/^(?:eq|ne|le|ge|lt|gt)$/ ? "'$spec->{arg}'"
+              : $spec->{op} =~ m/^(?:=~|!~)$/             ? "m/" . quotemeta($spec->{arg}) . "/"
+              :                                             $spec->{arg};
+      push @criteria,
+         "( defined \$set->{$spec->{col}} && \$set->{$spec->{col}} $spec->{op} $val ) { return '$spec->{color}'; }";
+   }
+   return undef unless @criteria;
+   my $sub = eval 'sub { my ( $set ) = @_; if ' . join(" elsif ", @criteria) . '}';
+   die if $EVAL_ERROR;
+   return $sub;
+}
+
+# make_sort_func {{{3
+# Gets a list of sort columns from the table, like "+cxn -time" and returns a
+# subroutine that will sort that way.
+sub make_sort_func {
+   my ( $tbl ) = @_;
+   my @criteria;
+
+   # Pivoted tables can be sorted by 'name' and set_x columns; others must be
+   # sorted by existing columns.  TODO: this will crash if you toggle between
+   # pivoted and nonpivoted.  I have several other 'crash' notes about this if
+   # this ever becomes possible.
+
+   if ( $tbl->{pivot} ) {
+      # Sort type is not really possible on pivoted columns, because a 'column'
+      # contains data from an entire non-pivoted row, so there could be a mix of
+      # numeric and non-numeric data.  Thus everything has to be 'cmp' type.
+      foreach my $col ( split(/\s+/, $tbl->{sort_cols} ) ) {
+         next unless $col;
+         my ( $dir, $name ) = $col =~ m/([+-])?(\w+)$/;
+         next unless $name && $name =~ m/^(?:name|set_\d+)$/;
+         $dir ||= '+';
+         my $op = 'cmp';
+         my $df = "''";
+         push @criteria,
+            $dir eq '+'
+            ? "(\$a->{$name} || $df) $op (\$b->{$name} || $df)"
+            : "(\$b->{$name} || $df) $op (\$a->{$name} || $df)";
+      }
+   }
+   else {
+      foreach my $col ( split(/\s+/, $tbl->{sort_cols} ) ) {
+         next unless $col;
+         my ( $dir, $name ) = $col =~ m/([+-])?(\w+)$/;
+         next unless $name && $tbl->{cols}->{$name};
+         $dir ||= '+';
+         my $op = $tbl->{cols}->{$name}->{num} ? "<=>" : "cmp";
+         my $df = $tbl->{cols}->{$name}->{num} ? "0"   : "''";
+         push @criteria,
+            $dir eq '+'
+            ? "(\$a->{$name} || $df) $op (\$b->{$name} || $df)"
+            : "(\$b->{$name} || $df) $op (\$a->{$name} || $df)";
+      }
+   }
+   return sub { return @_ } unless @criteria;
+   my $sub = eval 'sub { sort {' . join("||", @criteria) . '} @_; }';
+   die if $EVAL_ERROR;
+   return $sub;
+}
+
+# trunc {{{3
+# Shortens text to specified length.
+sub trunc {
+   my ( $text, $len ) = @_;
+   if ( length($text) <= $len ) {
+      return $text;
+   }
+   return substr($text, 0, $len);
+}
+
+# donut {{{3
+# Takes out the middle of text to shorten it.
+sub donut {
+   my ( $text, $len ) = @_;
+   return $text if length($text) <= $len;
+   my $max = length($text) - $len;
+   my $min = $max - 1;
+
+   # Try to remove a single "word" from somewhere in the center
+   if ( $text =~ s/_[^_]{$min,$max}_/_/ ) {
+      return $text;
+   }
+
+   # Prefer removing the end of a "word"
+   if ( $text =~ s/([^_]+)[^_]{$max}_/$1_/ ) {
+      return $text;
+   }
+
+   $text = substr($text, 0, int($len/2))
+         . "_"
+         . substr($text, int($len/2) + $max + 1);
+   return $text;
+}
+
+# crunch {{{3
+# Removes vowels and compacts repeated letters to shorten text.
+sub crunch {
+   my ( $text, $len ) = @_;
+   return $text if $len && length($text) <= $len;
+   $text =~ s/^IB_\w\w_//;
+   $text =~ s/(?<![_ ])[aeiou]//g;
+   $text =~ s/(.)\1+/$1/g;
+   return $text;
+}
+
+# collapse_ws {{{3
+# Collapses all whitespace to a single space.
+sub collapse_ws {
+   my ( $text ) = @_;
+   return '' unless defined $text;
+   $text =~ s/\s+/ /g;
+   return $text;
+}
+
+# Strips out non-printable characters within fields, which freak terminals out.
+sub no_ctrl_char {
+   my ( $text ) = @_;
+   return '' unless defined $text;
+   my $charset = $config{charset}->{val};
+   if ( $charset && $charset eq 'unicode' ) {
+      $text =~ s/
+         ("(?:(?!(?<!\\)").)*"  # Double-quoted string
+         |'(?:(?!(?<!\\)').)*') # Or single-quoted string
+         /$1 =~ m#\p{IsC}# ? "[BINARY]" : $1/egx;
+   }
+   elsif ( $charset && $charset eq 'none' ) {
+      $text =~ s/
+         ("(?:(?!(?<!\\)").)*"
+         |'(?:(?!(?<!\\)').)*')
+         /[TEXT]/gx;
+   }
+   else { # The default is 'ascii'
+      $text =~ s/
+         ("(?:(?!(?<!\\)").)*"
+         |'(?:(?!(?<!\\)').)*')
+         /$1 =~ m#[^\040-\176]# ? "[BINARY]" : $1/egx;
+   }
+   return $text;
+}
+
+# word_wrap {{{3
+# Wraps text at word boundaries so it fits the screen.
+sub word_wrap {
+   my ( $text, $width) = @_;
+   $width ||= $this_term_size[0];
+   $text =~ s/(.{0,$width})(?:\s+|$)/$1\n/g;
+   $text =~ s/ +$//mg;
+   return $text;
+}
+
+# draw_screen {{{3
+# Prints lines to the screen.  The first argument is an arrayref.  Each
+# element of the array is either a string or an arrayref.  If it's a string it
+# just gets printed.  If it's an arrayref, the first element is the string to
+# print, and the second is args to colored().
+sub draw_screen {
+   my ( $display_lines, $prefs ) = @_;
+   if ( !$opts{n} && $config{show_statusbar}->{val} ) {
+      unshift @$display_lines, create_statusbar();
+   }
+
+   foreach my $listener ( @{$event_listener_for{draw_screen}} ) {
+      $listener->draw_screen($display_lines);
+   }
+
+   $clear_screen_sub->()
+      if $prefs->{clear} || !$modes{$config{mode}->{val}}->{no_clear_screen};
+   if ( $opts{n} || $prefs->{raw} ) {
+      my $num_lines = 0;
+      print join("\n",
+         map {
+            $num_lines++;
+            ref $_
+               ? colored($_->[0], $_->[1])
+               : $_;
+         }
+         grep { !$opts{n} || $_ } # Suppress empty lines
+         @$display_lines);
+      if ( $opts{n} && $num_lines ) {
+         print "\n";
+      }
+   }
+   else {
+      my $max_lines = $prefs->{show_all}
+         ? scalar(@$display_lines)- 1
+         : min(scalar(@$display_lines), $this_term_size[1]);
+      print join("\n",
+         map {
+            ref $_
+               ? colored(substr($_->[0], 0, $this_term_size[0]), $_->[1])
+               : substr($_, 0, $this_term_size[0]);
+         } @$display_lines[0..$max_lines - 1]);
+   }
+}
+
+# secs_to_time {{{3
+sub secs_to_time {
+   my ( $secs, $fmt ) = @_;
+   $secs ||= 0;
+   return '00:00' unless $secs;
+
+   # Decide what format to use, if not given
+   $fmt ||= $secs >= 86_400 ? 'd'
+          : $secs >= 3_600  ? 'h'
+          :                   'm';
+
+   return
+      $fmt eq 'd' ? sprintf(
+         "%d+%02d:%02d:%02d",
+         int($secs / 86_400),
+         int(($secs % 86_400) / 3_600),
+         int(($secs % 3_600) / 60),
+         $secs % 60)
+      : $fmt eq 'h' ? sprintf(
+         "%02d:%02d:%02d",
+         int(($secs % 86_400) / 3_600),
+         int(($secs % 3_600) / 60),
+         $secs % 60)
+      : sprintf(
+         "%02d:%02d",
+         int(($secs % 3_600) / 60),
+         $secs % 60);
+}
+
+# dulint_to_int {{{3
+# Takes a number that InnoDB formats as two ulint integers, like transaction IDs
+# and such, and turns it into a single integer
+sub dulint_to_int {
+   my $num = shift;
+   return 0 unless $num;
+   my ( $high, $low ) = $num =~ m/^(\d+) (\d+)$/;
+   return $low unless $high;
+   return $low + ( $high * $MAX_ULONG );
+}
+
+# create_statusbar {{{3
+sub create_statusbar {
+   my $mode = $config{mode}->{val};
+   my @cxns = sort { $a cmp $b } get_connections();
+
+   my $modeline        = ( $config{readonly}->{val} ? '[RO] ' : '' )
+                         . $modes{$mode}->{hdr} . " (? for help)";
+   my $mode_width      = length($modeline);
+   my $remaining_width = $this_term_size[0] - $mode_width - 1;
+   my $result;
+
+   # The thingie in top-right that says what we're monitoring.
+   my $cxn = '';
+
+   if ( 1 == @cxns && $dbhs{$cxns[0]} && $dbhs{$cxns[0]}->{dbh} ) {
+      $cxn = $dbhs{$cxns[0]}->{dbh}->{mysql_serverinfo} || '';
+   }
+   else {
+      if ( $modes{$mode}->{server_group} ) {
+         $cxn = "Servers: " . $modes{$mode}->{server_group};
+         my $err_count = grep { $dbhs{$_} && $dbhs{$_}->{err_count} } @cxns;
+         if ( $err_count ) {
+            $cxn .= "(" . ( scalar(@cxns) - $err_count ) . "/" . scalar(@cxns) . ")";
+         }
+      }
+      else {
+         $cxn = join(' ', map { ($dbhs{$_}->{err_count} ? '!' : '') . $_ }
+            grep { $dbhs{$_} } @cxns);
+      }
+   }
+
+   if ( 1 == @cxns ) {
+      get_driver_status(@cxns);
+      my $vars = $vars{$cxns[0]}->{$clock};
+      my $inc  = inc(0, $cxns[0]);
+
+      # Format server uptime human-readably, calculate QPS...
+      my $uptime = secs_to_time( $vars->{Uptime_hires} );
+      my $qps    = ($inc->{Questions}||0) / ($inc->{Uptime_hires}||1);
+      my $ibinfo = '';
+
+      if ( exists $vars->{IB_last_secs} ) {
+         $ibinfo .= "InnoDB $vars->{IB_last_secs}s ";
+         if ( $vars->{IB_got_all} ) {
+            if ( ($mode eq 'T' || $mode eq 'W')
+                  && $vars->{IB_tx_is_truncated} ) {
+               $ibinfo .= ':^|';
+            }
+            else {
+               $ibinfo .= ':-)';
+            }
+         }
+         else {
+            $ibinfo .= ':-(';
+         }
+      }
+      $result = sprintf(
+         "%-${mode_width}s %${remaining_width}s",
+         $modeline,
+         join(', ', grep { $_ } (
+            $cxns[0],
+            $uptime,
+            $ibinfo,
+            shorten($qps) . " QPS",
+            ($vars->{Threads} || 0) . "/" . ($vars->{Threads_running} || 0) . "/" . ($vars->{Threads_cached} || 0) . " con/run/cac thds",
+            $cxn)));
+   }
+   else {
+      $result = sprintf(
+         "%-${mode_width}s %${remaining_width}s",
+         $modeline,
+         $cxn);
+   }
+
+   return $config{color}->{val} ? [ $result, 'bold reverse' ] : $result;
+}
+
+# Database connections {{{3
+sub add_new_dsn {
+   my ( $name, $dsn, $dl_table, $have_user, $user, $have_pass, $pass, $savepass ) = @_;
+
+   if ( defined $name ) {
+      $name =~ s/[\s:;]//g;
+   }
+
+   if ( !$name ) {
+      print word_wrap("Choose a name for the connection.  It cannot contain "
+         . "whitespace, colons or semicolons."), "\n\n";
+      do {
+         $name = prompt("Enter a name");
+         $name =~ s/[\s:;]//g;
+      } until ( $name );
+   }
+
+   if ( !$dsn ) {
+      do {
+         $clear_screen_sub->();
+         print "Typical DSN strings look like\n   DBI:mysql:;host=hostname;port=port\n"
+            . "The db and port are optional and can usually be omitted.\n"
+            . "If you specify 'mysql_read_default_group=mysql' many options can be read\n"
+            . "from your mysql options files (~/.my.cnf, /etc/my.cnf).\n\n";
+         $dsn = prompt("Enter a DSN string", undef, "DBI:mysql:;mysql_read_default_group=mysql;host=$name");
+      } until ( $dsn );
+   }
+   if ( !$dl_table ) {
+      $clear_screen_sub->();
+      my $dl_table = prompt("Optional: enter a table (must not exist) to use when resetting InnoDB deadlock information",
+         undef, 'test.innotop_dl');
+   }
+
+   $connections{$name} = {
+      dsn       => $dsn,
+      dl_table  => $dl_table,
+      have_user => $have_user,
+      user      => $user,
+      have_pass => $have_pass,
+      pass      => $pass,
+      savepass  => $savepass
+   };
+}
+
+sub add_new_server_group {
+   my ( $name ) = @_;
+
+   if ( defined $name ) {
+      $name =~ s/[\s:;]//g;
+   }
+
+   if ( !$name ) {
+      print word_wrap("Choose a name for the group.  It cannot contain "
+         . "whitespace, colons or semicolons."), "\n\n";
+      do {
+         $name = prompt("Enter a name");
+         $name =~ s/[\s:;]//g;
+      } until ( $name );
+   }
+
+   my @cxns;
+   do {
+      $clear_screen_sub->();
+      @cxns = select_cxn("Choose servers for $name", keys %connections);
+   } until ( @cxns );
+
+   $server_groups{$name} = \@cxns;
+   return $name;
+}
+
+sub get_var_set {
+   my ( $name ) = @_;
+   while ( !$name || !exists($var_sets{$config{$name}->{val}}) ) {
+      $name = choose_var_set($name);
+   }
+   return $var_sets{$config{$name}->{val}}->{text};
+}
+
+sub add_new_var_set {
+   my ( $name ) = @_;
+
+   if ( defined $name ) {
+      $name =~ s/\W//g;
+   }
+
+   if ( !$name ) {
+      do {
+         $name = prompt("Enter a name");
+         $name =~ s/\W//g;
+      } until ( $name );
+   }
+
+   my $variables;
+   do {
+      $clear_screen_sub->();
+      $variables = prompt("Enter variables for $name", undef );
+   } until ( $variables );
+
+   $var_sets{$name} = { text => $variables, user => 1 };
+}
+
+sub next_server {
+   my $mode     = $config{mode}->{val};
+   my @cxns     = sort keys %connections;
+   my ($cur)    = get_connections($mode);
+   $cur         ||= $cxns[0];
+   my $pos      = grep { $_ lt $cur } @cxns;
+   my $newpos   = ($pos + 1) % @cxns;
+   $modes{$mode}->{server_group} = '';
+   $modes{$mode}->{connections} = [ $cxns[$newpos] ];
+   $clear_screen_sub->();
+}
+
+sub next_server_group {
+   my $mode = shift || $config{mode}->{val};
+   my @grps = sort keys %server_groups;
+   my $curr = $modes{$mode}->{server_group};
+
+   return unless @grps;
+
+   if ( $curr ) {
+      # Find the current group's position.
+      my $pos = 0;
+      while ( $curr ne $grps[$pos] ) {
+         $pos++;
+      }
+      $modes{$mode}->{server_group} = $grps[ ($pos + 1) % @grps ];
+   }
+   else {
+      $modes{$mode}->{server_group} = $grps[0];
+   }
+}
+
+# Get a list of connection names used in this mode.
+sub get_connections {
+   if ( $file ) {
+      return qw(file);
+   }
+   my $mode = shift || $config{mode}->{val};
+   my @connections = $modes{$mode}->{server_group}
+      ? @{$server_groups{$modes{$mode}->{server_group}}}
+      : @{$modes{$mode}->{connections}};
+   if ( $modes{$mode}->{one_connection} ) {
+      @connections = @connections ? $connections[0] : ();
+   }
+   return unique(@connections);
+}
+
+# Get a list of tables used in this mode.  If innotop is running non-interactively, just use the first.
+sub get_visible_tables {
+   my $mode = shift || $config{mode}->{val};
+   my @tbls = @{$modes{$mode}->{visible_tables}};
+   if ( $opts{n} ) {
+      return $tbls[0];
+   }
+   else {
+      return @tbls;
+   }
+}
+
+# Choose from among available connections or server groups.
+# If the mode has a server set in use, prefers that instead.
+sub choose_connections {
+   $clear_screen_sub->();
+   my $mode    = $config{mode}->{val};
+   my $meta    =  { map { $_ => $connections{$_}->{dsn} } keys %connections };
+   foreach my $group ( keys %server_groups ) {
+      $meta->{"#$group"} = join(' ', @{$server_groups{$group}});
+   }
+
+   my $choices = prompt_list("Choose connections or a group for $mode mode",
+      undef, sub { return keys %$meta }, $meta);
+
+   my @choices = unique(grep { $_ } split(/\s+/, $choices));
+   if ( @choices ) {
+      if ( $choices[0] =~ s/^#// && exists $server_groups{$choices[0]} ) {
+         $modes{$mode}->{server_group} = $choices[0];
+      }
+      else {
+         $modes{$mode}->{connections} = [ grep { exists $connections{$_} } @choices ];
+      }
+   }
+}
+
+# Accepts a DB connection name and the name of a prepared query (e.g. status, kill).
+# Also a list of params for the prepared query.  This allows not storing prepared
+# statements globally.  Returns a $sth that's been executed.
+# ERROR-HANDLING SEMANTICS: if the statement throws an error, propagate, but if the
+# connection has gone away or can't connect, DO NOT.  Just return undef.
+sub do_stmt {
+   my ( $cxn, $stmt_name, @args ) = @_;
+
+   return undef if $file;
+
+   # Test if the cxn should not even be tried
+   return undef if $dbhs{$cxn}
+      && $dbhs{$cxn}->{err_count} 
+      && ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} )
+      && $dbhs{$cxn}->{wake_up} > $clock;
+
+   my $sth;
+   my $retries = 1;
+   my $success = 0;
+   TRY:
+   while ( $retries-- >= 0 && !$success ) {
+
+      eval {
+         my $dbh = connect_to_db($cxn);
+
+         # If the prepared query doesn't exist, make it.
+         if ( !exists $dbhs{$cxn}->{stmts}->{$stmt_name} ) {
+            $dbhs{$cxn}->{stmts}->{$stmt_name} = $stmt_maker_for{$stmt_name}->($dbh);
+         }
+
+         $sth = $dbhs{$cxn}->{stmts}->{$stmt_name};
+         if ( $sth ) {
+            $sth->execute(@args);
+         }
+         $success = 1;
+      };
+      if ( $EVAL_ERROR ) {
+         if ( $EVAL_ERROR =~ m/$nonfatal_errs/ ) {
+            handle_cxn_error($cxn, $EVAL_ERROR);
+         }
+         else {
+            die "$cxn $stmt_name: $EVAL_ERROR";
+         }
+         if ( $retries < 0 ) {
+            $sth = undef;
+         }
+      }
+   }
+
+   if ( $sth && $sth->{NUM_OF_FIELDS} ) {
+      sleep($stmt_sleep_time_for{$stmt_name}) if $stmt_sleep_time_for{$stmt_name};
+      return $sth;
+   }
+}
+
+# Keeps track of error count, sleep times till retries, etc etc.
+# When there's an error we retry the connection every so often, increasing in
+# Fibonacci series to prevent too much banging on the server.
+sub handle_cxn_error {
+   my ( $cxn, $err ) = @_;
+   my $meta = $dbhs{$cxn};
+   $meta->{err_count}++;
+
+   # This is used so errors that have to do with permissions needed by the current
+   # mode will get displayed as long as we're in this mode, but get ignored if the
+   # mode changes.
+   $meta->{mode} = $config{mode}->{val};
+
+   # Strip garbage from the error text if possible.
+   $err =~ s/\s+/ /g;
+   if ( $err =~ m/failed: (.*?) at \S*innotop line/ ) {
+      $err = $1;
+   }
+
+   $meta->{last_err}   = $err;
+   my $sleep_time      = $meta->{this_sleep} + $meta->{prev_sleep};
+   $meta->{prev_sleep} = $meta->{this_sleep};
+   $meta->{this_sleep} = $sleep_time;
+   $meta->{wake_up}    = $clock + $sleep_time;
+   if ( $config{show_cxn_errors}->{val} ) {
+      print STDERR "Error at tick $clock $cxn $err" if $config{debug}->{val};
+   }
+}
+
+# Accepts a DB connection name and a (string) query.  Returns a $sth that's been
+# executed.
+sub do_query {
+   my ( $cxn, $query ) = @_;
+
+   return undef if $file;
+
+   # Test if the cxn should not even be tried
+   return undef if $dbhs{$cxn}
+      && $dbhs{$cxn}->{err_count} 
+      && ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} )
+      && $dbhs{$cxn}->{wake_up} > $clock;
+
+   my $sth;
+   my $retries = 1;
+   my $success = 0;
+   TRY:
+   while ( $retries-- >= 0 && !$success ) {
+
+      eval {
+         my $dbh = connect_to_db($cxn);
+
+         $sth = $dbh->prepare($query);
+         $sth->execute();
+         $success = 1;
+      };
+      if ( $EVAL_ERROR ) {
+         if ( $EVAL_ERROR =~ m/$nonfatal_errs/ ) {
+            handle_cxn_error($cxn, $EVAL_ERROR);
+         }
+         else {
+            die $EVAL_ERROR;
+         }
+         if ( $retries < 0 ) {
+            $sth = undef;
+         }
+      }
+   }
+   return $sth;
+}
+
+sub get_uptime {
+   my ( $cxn ) = @_;
+   $dbhs{$cxn}->{start_time} ||= time();
+   # Avoid dividing by zero
+   return (time() - $dbhs{$cxn}->{start_time}) || .001;
+}
+
+sub connect_to_db {
+   my ( $cxn ) = @_;
+
+   $dbhs{$cxn} ||= {
+      stmts      => {},  # bucket for prepared statements.
+      prev_sleep => 0,
+      this_sleep => 1,
+      wake_up    => 0,
+      start_time => 0,
+      dbh        => undef,
+   };
+   my $href = $dbhs{$cxn};
+
+   if ( !$href->{dbh} || ref($href->{dbh}) !~ m/DBI/ || !$href->{dbh}->ping ) {
+      my $dbh = get_new_db_connection($cxn);
+      @{$href}{qw(dbh err_count wake_up this_sleep start_time prev_sleep)}
+               = ($dbh, 0, 0, 1, 0, 0);
+
+      # Derive and store the server's start time in hi-res
+      my $uptime = $dbh->selectrow_hashref("show status like 'Uptime'")->{value};
+      $href->{start_time} = time() - $uptime;
+
+      # Set timeouts so an unused connection stays alive.
+      # For example, a connection might be used in Q mode but idle in T mode.
+      if ( version_ge($dbh, '4.0.3')) {
+         my $timeout = $config{cxn_timeout}->{val};
+         $dbh->do("set session wait_timeout=$timeout, interactive_timeout=$timeout");
+      }
+   }
+   return $href->{dbh};
+}
+
+# Compares versions like 5.0.27 and 4.1.15-standard-log
+sub version_ge {
+   my ( $dbh, $target ) = @_;
+   my $version = sprintf('%03d%03d%03d', $dbh->{mysql_serverinfo} =~ m/(\d+)/g);
+   return $version ge sprintf('%03d%03d%03d', $target =~ m/(\d+)/g);
+}
+
+# Extracts status values that can be gleaned from the DBD driver without doing a whole query.
+sub get_driver_status {
+   my @cxns = @_;
+   if ( !$info_gotten{driver_status}++ ) {
+      foreach my $cxn ( @cxns ) {
+         next unless $dbhs{$cxn} && $dbhs{$cxn}->{dbh} && $dbhs{$cxn}->{dbh}->{Active};
+         $vars{$cxn}->{$clock} ||= {};
+         my $vars = $vars{$cxn}->{$clock};
+         my %res = map {  $_ =~ s/ +/_/g; $_ } $dbhs{$cxn}->{dbh}->{mysql_stat} =~ m/(\w[^:]+): ([\d\.]+)/g;
+         map { $vars->{$_} ||= $res{$_} } keys %res;
+         $vars->{Uptime_hires} ||= get_uptime($cxn);
+         $vars->{cxn} = $cxn;
+      }
+   }
+}
+
+sub get_new_db_connection {
+   my ( $connection, $destroy ) = @_;
+   if ( $file ) {
+      die "You can't connect to a MySQL server while monitoring a file.  This is probably a bug.";
+   }
+
+   my $dsn = $connections{$connection}
+      or die "No connection named '$connection' is defined in your configuration";
+
+   # don't ask for a username if mysql_read_default_group=client is in the DSN
+   if ( !defined $dsn->{have_user} and $dsn->{dsn} !~ /mysql_read_default_group=client/ ) {
+      my $answer = prompt("Do you want to specify a username for $connection?", undef, 'n');
+      $dsn->{have_user} = $answer && $answer =~ m/1|y/i;
+   }
+
+   # don't ask for a password if mysql_read_default_group=client is in the DSN
+   if ( !defined $dsn->{have_pass} and $dsn->{dsn} !~ /mysql_read_default_group=client/ ) {
+      my $answer = prompt("Do you want to specify a password for $connection?", undef, 'n');
+      $dsn->{have_pass} = $answer && $answer =~ m/1|y/i;
+   }
+
+   if ( !$dsn->{user} && $dsn->{have_user} ) {
+      my $user = $ENV{USERNAME} || $ENV{USER} || getlogin() || getpwuid($REAL_USER_ID) || undef;
+      $dsn->{user} = prompt("Enter username for $connection", undef, $user);
+   }
+
+   if ( !defined $dsn->{user} ) {
+      $dsn->{user} = '';
+   }
+
+   if ( !$dsn->{pass} && !$dsn->{savepass} && $dsn->{have_pass} ) {
+      $dsn->{pass} = prompt_noecho("Enter password for '$dsn->{user}' on $connection");
+      print "\n";
+      if ( !defined($dsn->{savepass}) ) {
+         my $answer = prompt("Save password in plain text in the config file?", undef, 'y');
+         $dsn->{savepass} = $answer && $answer =~ m/1|y/i;
+      }
+   }
+
+   my $dbh = DBI->connect(
+      $dsn->{dsn}, $dsn->{user}, $dsn->{pass},
+      { RaiseError => 1, PrintError => 0, AutoCommit => 1 });
+   $dbh->{InactiveDestroy} = 1 unless $destroy; # Can't be set in $db_options
+   $dbh->{FetchHashKeyName} = 'NAME_lc'; # Lowercases all column names for fetchrow_hashref
+   return $dbh;
+}
+
+sub get_cxn_errors {
+   my @cxns = @_;
+   return () unless $config{show_cxn_errors_in_tbl}->{val};
+   return
+      map  { [ $_ . ': ' . $dbhs{$_}->{last_err}, 'red' ] }
+      grep { $dbhs{$_} && $dbhs{$_}->{err_count} && $dbhs{$_}->{mode} eq $config{mode}->{val} }
+      @cxns;
+}
+
+# Setup and tear-down functions {{{2
+
+# Takes a string and turns it into a hashref you can apply to %tbl_meta tables.  The string
+# can be in the form 'foo, bar, foo/bar, foo as bar' much like a SQL SELECT statement.
+sub compile_select_stmt {
+   my ($str) = @_;
+   my @exps = $str =~ m/\s*([^,]+(?i:\s+as\s+[^,\s]+)?)\s*(?=,|$)/g;
+   my %cols;
+   my @visible;
+   foreach my $exp ( @exps ) {
+      my ( $text, $colname );
+      if ( $exp =~ m/as\s+(\w+)\s*/ ) {
+         $colname = $1;
+         $exp =~ s/as\s+(\w+)\s*//;
+         $text    = $exp;
+      }
+      else {
+         $text = $colname = $exp;
+      }
+      my ($func, $err) = compile_expr($text);
+      $cols{$colname} = {
+         src  => $text,
+         hdr  => $colname,
+         num  => 0,
+         func => $func,
+      };
+      push @visible, $colname;
+   }
+   return (\%cols, \@visible);
+}
+
+# compile_filter {{{3
+sub compile_filter {
+   my ( $text ) = @_;
+   my ( $sub, $err );
+   eval "\$sub = sub { my \$set = shift; $text }";
+   if ( $EVAL_ERROR ) {
+      $EVAL_ERROR =~ s/at \(eval.*$//;
+      $sub = sub { return $EVAL_ERROR };
+      $err = $EVAL_ERROR;
+   }
+   return ( $sub, $err );
+}
+
+# compile_expr {{{3
+sub compile_expr {
+   my ( $expr ) = @_;
+   # Leave built-in functions alone so they get called as Perl functions, unless
+   # they are the only word in $expr, in which case treat them as hash keys.
+   if ( $expr =~ m/\W/ ) {
+      $expr =~ s/(?<!\{|\$)\b([A-Za-z]\w{2,})\b/is_func($1) ? $1 : "\$set->{$1}"/eg;
+   }
+   else {
+      $expr = "\$set->{$expr}";
+   }
+   my ( $sub, $err );
+   my $quoted = quotemeta($expr);
+   eval qq{
+      \$sub = sub {
+         my (\$set, \$cur, \$pre) = \@_;
+         my \$val = eval { $expr };
+         if ( \$EVAL_ERROR && \$config{debug}->{val} ) {
+            \$EVAL_ERROR =~ s/ at \\(eval.*//s;
+            die "\$EVAL_ERROR in expression $quoted";
+         }
+         return \$val;
+      }
+   };
+   if ( $EVAL_ERROR ) {
+      if ( $config{debug}->{val} ) {
+         die $EVAL_ERROR;
+      }
+      $EVAL_ERROR =~ s/ at \(eval.*$//;
+      $sub = sub { return $EVAL_ERROR };
+      $err = $EVAL_ERROR;
+   }
+   return ( $sub, $err );
+}
+
+# finish {{{3
+# This is a subroutine because it's called from a key to quit the program.
+sub finish {
+   save_config();
+   ReadMode('normal') unless $opts{n};
+   print "\n";
+   exit(0);
+}
+
+# core_dump {{{3
+sub core_dump {
+   my $msg = shift;
+   if ($config{debugfile}->{val} && $config{debug}->{val}) {
+      eval {
+         open my $file, '>>', $config{debugfile}->{val};
+         if ( %vars ) {
+            print $file "Current variables:\n" . Dumper(\%vars);
+         }
+         close $file;
+      };
+   }
+   print $msg;
+}
+
+# migrate_config {{{3
+sub migrate_config {
+
+   my ($old_filename, $new_filename) = @_;
+
+   # don't proceed if old file doesn't exist
+   if ( ! -f $old_filename ) {
+      die "Error migrating '$old_filename': file doesn't exist.\n";
+   }
+   # don't migrate files if new file exists
+   elsif ( -f $new_filename ) {
+      die "Error migrating '$old_filename' to '$new_filename': new file already exists.\n";
+   }
+   # if migrating from one file to another in the same directory, just rename them
+   if (dirname($old_filename) eq dirname($new_filename)) {
+      rename($old_filename, $new_filename)
+         or die "Can't rename '$old_filename' to '$new_filename': $OS_ERROR";
+   }
+   # otherwise, move the existing conf file to a temp file, make the necessary directory structure,
+   # and move the temp conf file to its new home
+   else {
+      my $tmp = File::Temp->new( TEMPLATE => 'innotopXXXXX', DIR => $homepath, SUFFIX => '.conf');
+      my $tmp_filename = $tmp->filename;
+      my $dirname = dirname($new_filename);
+      rename($old_filename, $tmp_filename)
+         or die "Can't rename '$old_filename' to '$tmp_filename': $OS_ERROR";
+      mkdir($dirname) or die "Can't create directory '$dirname': $OS_ERROR";
+      mkdir("$dirname/plugins") or die "Can't create directory '$dirname/plugins': $OS_ERROR";
+      rename($tmp_filename, $new_filename)
+         or die "Can't rename '$tmp_filename' to '$new_filename': $OS_ERROR";
+   }
+}
+
+# load_config {{{3
+sub load_config {
+    
+   my ($old_filename, $answer);
+
+   if ( $opts{u} or $opts{p} or $opts{h} or $opts{P} ) {
+     my @params = $dsn_parser->get_cxn_params(\%opts); # dsn=$params[0]
+     add_new_dsn($opts{h} || 'localhost', $params[0], 'test.innotop_dl', 
+                 $opts{u} ? 1 : 0, $opts{u}, $opts{p} ? 1 : 0, $opts{p});
+   }
+   if ($opts{c}) {
+      $conf_file = $opts{c};
+   }  
+   # innotop got upgraded and this is an old config file.
+   elsif ( -f "$homepath/.innotop" or -f "$homepath/.innotop/innotop.ini" ) {
+      $conf_file = $default_home_conf;
+      if ( -f  "$homepath/.innotop") {
+         $old_filename = "$homepath/.innotop";
+      }
+      elsif ( -f "$homepath/.innotop/innotop.ini" ) {
+         $old_filename = "$homepath/.innotop/innotop.ini";
+      }
+      $answer = pause("Innotop's default config location has moved to '$conf_file'.  Move old config file '$old_filename' there now? y/n");
+      if ( lc $answer eq 'y' ) {
+         migrate_config($old_filename, $conf_file);
+      }
+      else {
+         print "\nInnotop will now exit so you can fix the config file.\n";
+         exit(0);
+      }
+   }
+   elsif ( -f $default_home_conf ) {
+      $conf_file = $default_home_conf;
+   }
+   elsif ( -f $default_central_conf and not $opts{s} ) {
+      $conf_file = $default_central_conf;
+   }
+   else {
+      # If no config file was loaded, set readonly to 0 if the user wants to 
+      # write a config
+      $config{readonly}->{val} = 0 if $opts{w};
+      # If no connections have been defined, connect to a MySQL database 
+      # on localhost using mysql_read_default_group=client
+      if (!%connections) {
+         add_new_dsn('localhost', 
+                     'DBI:mysql:;host=localhost;mysql_read_default_group=client', 
+                     'test.innotop_dl');
+      }
+   }
+
+   if ( -f "$conf_file" ) {
+      open my $file, "<", $conf_file or die("Can't open '$conf_file': $OS_ERROR");
+
+      # Check config file version.  Just ignore if either innotop or the file has
+      # garbage in the version number.
+      if ( defined(my $line = <$file>) && $VERSION =~ m/\d/ ) {
+         chomp $line;
+         if ( my ($maj, $min, $rev) = $line =~ m/^version=(\d+)\.(\d+)(?:\.(\d+))?$/ ) {
+            $rev ||= 0;
+            my $cfg_ver          = sprintf('%03d-%03d-%03d', $maj, $min, $rev);
+            ( $maj, $min, $rev ) = $VERSION =~ m/^(\d+)\.(\d+)(?:\.(\d+))?$/;
+            $rev ||= 0;
+            my $innotop_ver      = sprintf('%03d-%03d-%03d', $maj, $min, $rev);
+
+            if ( $cfg_ver gt $innotop_ver ) {
+               pause("The config file is for a newer version of innotop and may not be read correctly.");
+            }
+            else {
+               my @ver_history = @config_versions;
+               while ( my ($start, $end) = splice(@ver_history, 0, 2) ) {
+                  # If the config file is between the endpoints and innotop is greater than
+                  # the endpoint, innotop has a newer config file format than the file.
+                  if ( $cfg_ver ge $start && $cfg_ver lt $end && $innotop_ver ge $end ) {
+                     my $msg = "innotop's config file format has changed.  Overwrite $conf_file?  y or n";
+                     if ( pause($msg) eq 'n' ) {
+                        $config{readonly}->{val} = 1;
+                        print "\ninnotop will not save any configuration changes you make.";
+                        pause();
+                        print "\n";
+                     }
+                     close $file;
+                     return;
+                  }
+               }
+            }
+         }
+      }
+
+      while ( my $line = <$file> ) {
+         chomp $line;
+         next unless $line =~ m/^\[([a-z_]+)\]$/;
+         if ( exists $config_file_sections{$1} ) {
+            $config_file_sections{$1}->{reader}->($file);
+         }
+         else {
+            warn "Unknown config file section '$1'";
+         }
+      }
+      close $file or die("Can't close $conf_file: $OS_ERROR");
+   }
+
+}
+
+# Do some post-processing on %tbl_meta: compile src properties into func etc.
+sub post_process_tbl_meta {
+   foreach my $table ( values %tbl_meta ) {
+      foreach my $col_name ( keys %{$table->{cols}} ) {
+         my $col_def = $table->{cols}->{$col_name};
+         my ( $sub, $err ) = compile_expr($col_def->{src});
+         $col_def->{func} = $sub;
+      }
+   }
+}
+
+# load_config_plugins {{{3
+sub load_config_plugins {
+   my ( $file ) = @_;
+
+   # First, find a list of all plugins that exist on disk, and get information about them.
+   my $dir = $config{plugin_dir}->{val};
+   foreach my $p_file ( <$dir/*.pm> ) {
+      my ($package, $desc);
+      eval {
+         open my $p_in, "<", $p_file or die $OS_ERROR;
+         while ( my $line = <$p_in> ) {
+            chomp $line;
+            if ( $line =~ m/^package\s+(.*?);/ ) {
+               $package = $1;
+            }
+            elsif ( $line =~ m/^# description: (.*)/ ) {
+               $desc = $1;
+            }
+            last if $package && $desc;
+         }
+         close $p_in;
+      };
+      if ( $package ) {
+         $plugins{$package} = {
+            file   => $p_file,
+            desc   => $desc,
+            class  => $package,
+            active => 0,
+         };
+         if ( $config{debug}->{val} && $EVAL_ERROR ) {
+            die $EVAL_ERROR;
+         }
+      }
+   }
+
+   # Now read which ones the user has activated.  Each line simply represents an active plugin.
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+      next unless $line && $plugins{$line};
+
+      my $obj;
+      eval {
+         require $plugins{$line}->{file};
+         $obj = $line->new(%pluggable_vars);
+         foreach my $event ( $obj->register_for_events() ) {
+            my $queue = $event_listener_for{$event};
+            if ( $queue ) {
+               push @$queue, $obj;
+            }
+         }
+      };
+      if ( $config{debug}->{val} && $EVAL_ERROR ) {
+         die $EVAL_ERROR;
+      }
+      if ( $obj ) {
+         $plugins{$line}->{active} = 1;
+         $plugins{$line}->{object} = $obj;
+      }
+   }
+}
+
+# save_config_plugins {{{3
+sub save_config_plugins {
+   my $file = shift;
+   foreach my $class ( sort keys %plugins ) {
+      next unless $plugins{$class}->{active};
+      print $file "$class\n";
+   }
+}
+
+# load_config_active_server_groups {{{3
+sub load_config_active_server_groups {
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $mode, $group ) = $line =~ m/^(.*?)=(.*)$/;
+      next unless $mode && $group
+         && exists $modes{$mode} && exists $server_groups{$group};
+      $modes{$mode}->{server_group} = $group;
+   }
+}
+
+# save_config_active_server_groups {{{3
+sub save_config_active_server_groups {
+   my $file = shift;
+   foreach my $mode ( sort keys %modes ) {
+      print $file "$mode=$modes{$mode}->{server_group}\n";
+   }
+}
+
+# load_config_server_groups {{{3
+sub load_config_server_groups {
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $name, $rest ) = $line =~ m/^(.*?)=(.*)$/;
+      next unless $name && $rest;
+      my @vars = unique(grep { $_ && exists $connections{$_} } split(/\s+/, $rest));
+      next unless @vars;
+      $server_groups{$name} = \@vars;
+   }
+}
+
+# save_config_server_groups {{{3
+sub save_config_server_groups {
+   my $file = shift;
+   foreach my $set ( sort keys %server_groups ) {
+      print $file "$set=", join(' ', @{$server_groups{$set}}), "\n";
+   }
+}
+
+# load_config_varsets {{{3
+sub load_config_varsets {
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $name, $rest ) = $line =~ m/^(.*?)=(.*)$/;
+      next unless $name && $rest;
+      $var_sets{$name} = {
+         text => $rest,
+         user => 1,
+      };
+   }
+}
+
+# save_config_varsets {{{3
+sub save_config_varsets {
+   my $file = shift;
+   foreach my $varset ( sort keys %var_sets ) {
+      next unless $var_sets{$varset}->{user};
+      print $file "$varset=$var_sets{$varset}->{text}\n";
+   }
+}
+
+# load_config_group_by {{{3
+sub load_config_group_by {
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $tbl , $rest ) = $line =~ m/^(.*?)=(.*)$/;
+      next unless $tbl && exists $tbl_meta{$tbl};
+      my @parts = unique(grep { exists($tbl_meta{$tbl}->{cols}->{$_}) } split(/\s+/, $rest));
+      $tbl_meta{$tbl}->{group_by} = [ @parts ];
+      $tbl_meta{$tbl}->{cust}->{group_by} = 1;
+   }
+}
+
+# save_config_group_by {{{3
+sub save_config_group_by {
+   my $file = shift;
+   foreach my $tbl ( sort keys %tbl_meta ) {
+      next if $tbl_meta{$tbl}->{temp};
+      next unless $tbl_meta{$tbl}->{cust}->{group_by};
+      my $aref = $tbl_meta{$tbl}->{group_by};
+      print $file "$tbl=", join(' ', @$aref), "\n";
+   }
+}
+
+# load_config_filters {{{3
+sub load_config_filters {
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $key, $rest ) = $line =~ m/^(.+?)=(.*)$/;
+      next unless $key && $rest;
+
+      my %parts = $rest =~ m/(\w+)='((?:(?!(?<!\\)').)*)'/g; # Properties are single-quoted
+      next unless $parts{text} && $parts{tbls};
+
+      foreach my $prop ( keys %parts ) {
+         # Un-escape escaping
+         $parts{$prop} =~ s/\\\\/\\/g;
+         $parts{$prop} =~ s/\\'/'/g;
+      }
+
+      my ( $sub, $err ) = compile_filter($parts{text});
+      my @tbls = unique(split(/\s+/, $parts{tbls}));
+      @tbls = grep { exists $tbl_meta{$_} } @tbls;
+      $filters{$key} = {
+         func => $sub,
+         text => $parts{text},
+         user => 1,
+         name => $key,
+         note => 'User-defined filter',
+         tbls => \@tbls,
+      }
+   }
+}
+
+# save_config_filters {{{3
+sub save_config_filters {
+   my $file = shift;
+   foreach my $key ( sort keys %filters ) {
+      next if !$filters{$key}->{user} || $filters{$key}->{quick};
+      my $text = $filters{$key}->{text};
+      $text =~ s/([\\'])/\\$1/g;
+      my $tbls = join(" ", @{$filters{$key}->{tbls}});
+      print $file "$key=text='$text' tbls='$tbls'\n";
+   }
+}
+
+# load_config_visible_tables {{{3
+sub load_config_visible_tables {
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $mode, $rest ) = $line =~ m/^(.*?)=(.*)$/;
+      next unless $mode && exists $modes{$mode};
+      $modes{$mode}->{visible_tables} =
+         [ unique(grep { $_ && exists $tbl_meta{$_} } split(/\s+/, $rest)) ];
+      $modes{$mode}->{cust}->{visible_tables} = 1;
+   }
+}
+
+# save_config_visible_tables {{{3
+sub save_config_visible_tables {
+   my $file = shift;
+   foreach my $mode ( sort keys %modes ) {
+      next unless $modes{$mode}->{cust}->{visible_tables};
+      my $tables = $modes{$mode}->{visible_tables};
+      print $file "$mode=", join(' ', @$tables), "\n";
+   }
+}
+
+# load_config_sort_cols {{{3
+sub load_config_sort_cols {
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $key , $rest ) = $line =~ m/^(.*?)=(.*)$/;
+      next unless $key && exists $tbl_meta{$key};
+      $tbl_meta{$key}->{sort_cols} = $rest;
+      $tbl_meta{$key}->{cust}->{sort_cols} = 1;
+      $tbl_meta{$key}->{sort_func} = make_sort_func($tbl_meta{$key});
+   }
+}
+
+# save_config_sort_cols {{{3
+sub save_config_sort_cols {
+   my $file = shift;
+   foreach my $tbl ( sort keys %tbl_meta ) {
+      next unless $tbl_meta{$tbl}->{cust}->{sort_cols};
+      my $col = $tbl_meta{$tbl}->{sort_cols};
+      print $file "$tbl=$col\n";
+   }
+}
+
+# load_config_active_filters {{{3
+sub load_config_active_filters {
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $tbl , $rest ) = $line =~ m/^(.*?)=(.*)$/;
+      next unless $tbl && exists $tbl_meta{$tbl};
+      my @parts = unique(grep { exists($filters{$_}) } split(/\s+/, $rest));
+      @parts = grep { grep { $tbl eq $_ } @{$filters{$_}->{tbls}} } @parts;
+      $tbl_meta{$tbl}->{filters} = [ @parts ];
+      $tbl_meta{$tbl}->{cust}->{filters} = 1;
+   }
+}
+
+# save_config_active_filters {{{3
+sub save_config_active_filters {
+   my $file = shift;
+   foreach my $tbl ( sort keys %tbl_meta ) {
+      next if $tbl_meta{$tbl}->{temp};
+      next unless $tbl_meta{$tbl}->{cust}->{filters};
+      my $aref = $tbl_meta{$tbl}->{filters};
+      print $file "$tbl=", join(' ', @$aref), "\n";
+   }
+}
+
+# load_config_active_columns {{{3
+sub load_config_active_columns {
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $key , $rest ) = $line =~ m/^(.*?)=(.*)$/;
+      next unless $key && exists $tbl_meta{$key};
+      my @parts = grep { exists($tbl_meta{$key}->{cols}->{$_}) } unique split(/ /, $rest);
+      $tbl_meta{$key}->{visible} = [ @parts ];
+      $tbl_meta{$key}->{cust}->{visible} = 1;
+   }
+}
+
+# save_config_active_columns {{{3
+sub save_config_active_columns {
+   my $file = shift;
+   foreach my $tbl ( sort keys %tbl_meta ) {
+      next unless $tbl_meta{$tbl}->{cust}->{visible};
+      my $aref = $tbl_meta{$tbl}->{visible};
+      print $file "$tbl=", join(' ', @$aref), "\n";
+   }
+}
+
+# save_config_tbl_meta {{{3
+sub save_config_tbl_meta {
+   my $file = shift;
+   foreach my $tbl ( sort keys %tbl_meta ) {
+      foreach my $col ( keys %{$tbl_meta{$tbl}->{cols}} ) {
+         my $meta = $tbl_meta{$tbl}->{cols}->{$col};
+         next unless $meta->{user};
+         print $file "$col=", join(
+            " ",
+            map {
+               # Some properties (trans) are arrays, others scalars
+               my $val = ref($meta->{$_}) ? join(',', @{$meta->{$_}}) : $meta->{$_};
+               $val =~ s/([\\'])/\\$1/g;  # Escape backslashes and single quotes
+               "$_='$val'";               # Enclose in single quotes
+            }
+            grep { $_ ne 'func' }
+            keys %$meta
+         ), "\n";
+      }
+   }
+}
+
+# save_config_config {{{3
+sub save_config_config {
+   my $file = shift;
+   foreach my $key ( sort keys %config ) {
+      eval {
+      if ( $key ne 'password' || $config{savepass}->{val} ) {
+         print $file "# $config{$key}->{note}\n"
+            or die "Cannot print to file: $OS_ERROR";
+         my $val = $config{$key}->{val};
+         $val = '' unless defined($val);
+         if ( ref( $val ) eq 'ARRAY' ) {
+            print $file "$key="
+               . join( " ", @$val ) . "\n"
+               or die "Cannot print to file: $OS_ERROR";
+         }
+         elsif ( ref( $val ) eq 'HASH' ) {
+            print $file "$key="
+               . join( " ",
+                  map { "$_:$val->{$_}" } keys %$val
+               ) . "\n";
+         }
+         else {
+            print $file "$key=$val\n";
+         }
+      }
+      };
+      if ( $EVAL_ERROR ) { print "$EVAL_ERROR in $key"; };
+   }
+
+}
+
+# load_config_config {{{3
+sub load_config_config {
+   my ( $file ) = @_;
+
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $name, $val ) = $line =~ m/^(.+?)=(.*)$/;
+      next unless defined $name && defined $val;
+
+      # Validate the incoming values...
+      if ( $name && exists( $config{$name} ) ) {
+         if ( !$config{$name}->{pat} || $val =~ m/$config{$name}->{pat}/ ) {
+            $config{$name}->{val} = $val;
+            $config{$name}->{read} = 1;
+         }
+      }
+   }
+}
+
+# load_config_tbl_meta {{{3
+sub load_config_tbl_meta {
+   my ( $file ) = @_;
+
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      # Each tbl_meta section has all the properties defined in %col_props.
+      my ( $col , $rest ) = $line =~ m/^(.*?)=(.*)$/;
+      next unless $col;
+      my %parts = $rest =~ m/(\w+)='((?:(?!(?<!\\)').)*)'/g; # Properties are single-quoted
+
+      # Each section read from the config file has one extra property: which table it
+      # goes in.
+      my $tbl  = $parts{tbl}     or die "There's no table for tbl_meta $col";
+      my $meta = $tbl_meta{$tbl} or die "There's no table in tbl_meta named $tbl";
+
+      # The section is user-defined by definition (if that makes sense).
+      $parts{user} = 1;
+
+      # The column may already exist in the table, in which case this is just a
+      # customization.
+      $meta->{cols}->{$col} ||= {};
+
+      foreach my $prop ( keys %col_props ) {
+         if ( !defined($parts{$prop}) ) {
+            die "Undefined property $prop for column $col in table $tbl";
+         }
+
+         # Un-escape escaping
+         $parts{$prop} =~ s/\\\\/\\/g;
+         $parts{$prop} =~ s/\\'/'/g;
+
+         if ( ref $col_props{$prop} ) {
+            if ( $prop eq 'trans' ) {
+               $meta->{cols}->{$col}->{trans}
+                  = [ unique(grep { exists $trans_funcs{$_} } split(',', $parts{$prop})) ];
+            }
+            else {
+               $meta->{cols}->{$col}->{$prop} = [ split(',', $parts{$prop}) ];
+            }
+         }
+         else {
+            $meta->{cols}->{$col}->{$prop} = $parts{$prop};
+         }
+      }
+
+   }
+}
+
+# save_config {{{3
+sub save_config {
+   print "\n";
+   return if $config{readonly}->{val};
+   # return if no config file was loaded and -w wasn't specified
+   if (not $conf_file) {
+      if (not $opts{w}) {
+         return;
+      }
+      else {
+         # if no config was loaded but -w was specified,
+         # write to $default_home_conf
+         $conf_file = $default_home_conf;
+      }
+   }
+   elsif ($conf_file and $opts{w}) {
+     print "Loaded config file on start-up, so ignoring -w (see --help)\n"
+   }
+   
+   my $dirname  = dirname($conf_file);
+
+   # if directories don't exist, create them.  This could cause errors
+   # or warnings if a central config doesn't have readonly=1, but being
+   # flexible requires giving the user enough rope to hang themselves with.
+   if ( ! -d $dirname ) {
+      mkdir $dirname
+         or die "Can't create directory '$dirname': $OS_ERROR";
+   }
+   if ( ! -d "$dirname/plugins" ) {
+      mkdir "$dirname/plugins"
+         or warn "Can't create directory '$dirname/plugins': $OS_ERROR\n";
+   }
+
+   # Save to a temp file first, so a crash doesn't destroy the main config file
+   my $tmpfile = File::Temp->new( TEMPLATE => 'innotopXXXXX', DIR => $dirname, SUFFIX => '.conf.tmp');
+   open my $file, "+>", $tmpfile
+      or die("Can't write to $tmpfile: $OS_ERROR");
+   print $file "version=$VERSION\n";
+
+   foreach my $section ( @ordered_config_file_sections ) {
+      die "No such config file section $section" unless $config_file_sections{$section};
+      print $file "\n[$section]\n\n";
+      $config_file_sections{$section}->{writer}->($file);
+      print $file "\n[/$section]\n";
+   }
+
+   # Now clobber the main config file with the temp.
+   close $file or die("Can't close $tmpfile: $OS_ERROR");
+   rename($tmpfile, $conf_file) or die("Can't rename $tmpfile to $conf_file: $OS_ERROR");
+}
+
+# load_config_connections {{{3
+sub load_config_connections {
+   return if $opts{u} or $opts{p} or $opts{h} or $opts{P}; # don't load connections if DSN or user/pass options used
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $key , $rest ) = $line =~ m/^(.*?)=(.*)$/;
+      next unless $key;
+      my %parts = $rest =~ m/(\S+?)=(\S*)/g;
+      my %conn  = map { $_ => $parts{$_} || '' } @conn_parts;
+      $connections{$key} = \%conn;
+   }
+}
+
+# save_config_connections {{{3
+sub save_config_connections {
+   my $file = shift;
+   foreach my $conn ( sort keys %connections ) {
+      my $href = $connections{$conn};
+      my @keys = $href->{savepass} ? @conn_parts : grep { $_ ne 'pass' } @conn_parts;
+      print $file "$conn=", join(' ', map { "$_=$href->{$_}" } grep { defined $href->{$_} } @keys), "\n";
+   }
+}
+
+sub load_config_colors {
+   my ( $file ) = @_;
+   my %rule_set_for;
+
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $tbl, $rule ) = $line =~ m/^(.*?)=(.*)$/;
+      next unless $tbl && $rule;
+      next unless exists $tbl_meta{$tbl};
+      my %parts = $rule =~ m/(\w+)='((?:(?!(?<!\\)').)*)'/g; # Properties are single-quoted
+      next unless $parts{col} && exists $tbl_meta{$tbl}->{cols}->{$parts{col}};
+      next unless $parts{op}  && exists $comp_ops{$parts{op}};
+      next unless defined $parts{arg};
+      next unless defined $parts{color};
+      my @colors = unique(grep { exists $ansicolors{$_} } split(/\W+/, $parts{color}));
+      next unless @colors;
+
+      # Finally!  Enough validation...
+      $rule_set_for{$tbl} ||= [];
+      push @{$rule_set_for{$tbl}}, \%parts;
+   }
+
+   foreach my $tbl ( keys %rule_set_for ) {
+      $tbl_meta{$tbl}->{colors} = $rule_set_for{$tbl};
+      $tbl_meta{$tbl}->{color_func} = make_color_func($tbl_meta{$tbl});
+      $tbl_meta{$tbl}->{cust}->{colors} = 1;
+   }
+}
+
+# save_config_colors {{{3
+sub save_config_colors {
+   my $file = shift;
+   foreach my $tbl ( sort keys %tbl_meta ) {
+      my $meta = $tbl_meta{$tbl};
+      next unless $meta->{cust}->{colors};
+      foreach my $rule ( @{$meta->{colors}} ) {
+         print $file "$tbl=", join(
+            ' ',
+            map {
+               my $val = $rule->{$_};
+               $val =~ s/([\\'])/\\$1/g;  # Escape backslashes and single quotes
+               "$_='$val'";               # Enclose in single quotes
+            }
+            qw(col op arg color)
+         ), "\n";
+      }
+   }
+}
+
+# load_config_active_connections {{{3
+sub load_config_active_connections {
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $key , $rest ) = $line =~ m/^(.*?)=(.*)$/;
+      next unless $key && exists $modes{$key};
+      my @parts = grep { exists $connections{$_} } split(/ /, $rest);
+      $modes{$key}->{connections} = [ @parts ] if exists $modes{$key};
+   }
+}
+
+# save_config_active_connections {{{3
+sub save_config_active_connections {
+   my $file = shift;
+   foreach my $mode ( sort keys %modes ) {
+      my @connections = get_connections($mode);
+      print $file "$mode=", join(' ', @connections), "\n";
+   }
+}
+
+# load_config_stmt_sleep_times {{{3
+sub load_config_stmt_sleep_times {
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $key , $val ) = split('=', $line);
+      next unless $key && defined $val && $val =~ m/$num_regex/;
+      $stmt_sleep_time_for{$key} = $val;
+   }
+}
+
+# save_config_stmt_sleep_times {{{3
+sub save_config_stmt_sleep_times {
+   my $file = shift;
+   foreach my $key ( sort keys %stmt_sleep_time_for ) {
+      print $file "$key=$stmt_sleep_time_for{$key}\n";
+   }
+}
+
+# load_config_mvs {{{3
+sub load_config_mvs {
+   my ( $file ) = @_;
+   while ( my $line = <$file> ) {
+      chomp $line;
+      next if $line =~ m/^#/;
+      last if $line =~ m/^\[/;
+
+      my ( $key , $val ) = split('=', $line);
+      next unless $key && defined $val && $val =~ m/$num_regex/;
+      $mvs{$key} = $val;
+   }
+}
+
+# save_config_mvs {{{3
+sub save_config_mvs {
+   my $file = shift;
+   foreach my $key ( sort keys %mvs ) {
+      print $file "$key=$mvs{$key}\n";
+   }
+}
+
+# edit_configuration {{{3
+sub edit_configuration {
+   my $key = '';
+   while ( $key ne 'q' ) {
+      $clear_screen_sub->();
+      my @display_lines = '';
+
+      if ( $key && $cfg_editor_action{$key} ) {
+         $cfg_editor_action{$key}->{func}->();
+      }
+
+      # Show help
+      push @display_lines, create_caption('What configuration do you want to edit?',
+      create_table2(
+         [ sort keys %cfg_editor_action ],
+         { map { $_ => $_ } keys %cfg_editor_action },
+         { map { $_ => $cfg_editor_action{$_}->{note} } keys %cfg_editor_action },
+         { sep => '  ' }));
+
+      draw_screen(\@display_lines);
+      $key = pause('');
+   }
+}
+
+# edit_configuration_variables {{{3
+sub edit_configuration_variables {
+   $clear_screen_sub->();
+   my $mode = $config{mode}->{val};
+
+   my %config_choices
+      = map  { $_ => $config{$_}->{note} || '' }
+        # Only config values that are marked as applying to this mode.
+        grep {
+           my $key = $_;
+           $config{$key}->{conf} &&
+              ( $config{$key}->{conf} eq 'ALL'
+              || grep { $mode eq $_ } @{$config{$key}->{conf}} )
+        } keys %config;
+
+   my $key = prompt_list(
+      "Enter the name of the variable you wish to configure",
+      '',
+      sub{ return keys %config_choices },
+      \%config_choices);
+
+   if ( exists($config_choices{$key}) ) {
+      get_config_interactive($key);
+   }
+}
+
+# edit_color_rules {{{3
+sub edit_color_rules {
+   my ( $tbl ) = @_;
+   $clear_screen_sub->();
+   $tbl ||= choose_visible_table();
+   if ( $tbl && exists($tbl_meta{$tbl}) ) {
+      my $meta = $tbl_meta{$tbl};
+      my @cols = ('', qw(col op arg color));
+      my $info = { map { $_ => { hdr => $_, just => '-', } }  @cols };
+      $info->{label}->{maxw} = 30;
+      my $key;
+      my $selected_rule;
+
+      # This loop builds a tabular view of the rules.
+      do {
+
+         # Show help
+         if ( $key && $key eq '?' ) {
+            my @display_lines = '';
+            push @display_lines, create_caption('Editor key mappings',
+            create_table2(
+               [ sort keys %color_editor_action ],
+               { map { $_ => $_ } keys %color_editor_action },
+               { map { $_ => $color_editor_action{$_}->{note} } keys %color_editor_action },
+               { sep => '  ' }));
+            draw_screen(\@display_lines);
+            pause();
+            $key = '';
+         }
+         else {
+
+            # Do the action specified
+            $selected_rule ||= 0;
+            if ( $key && $color_editor_action{$key} ) {
+               $selected_rule = $color_editor_action{$key}->{func}->($tbl, $selected_rule);
+               $selected_rule ||= 0;
+            }
+
+            # Build the table of rules.  If the terminal has color, the selected rule
+            # will be highlighted; otherwise a > at the left will indicate.
+            my $data = $meta->{colors} || [];
+            foreach my $i ( 0..@$data - 1  ) {
+               $data->[$i]->{''} = $i == $selected_rule ? '>' : '';
+            }
+            my @display_lines = create_table(\@cols, $info, $data);
+
+            # Highlight selected entry
+            for my $i ( 0 .. $#display_lines ) {
+               if ( $display_lines[$i] =~ m/^>/ ) {
+                  $display_lines[$i] = [ $display_lines[$i], 'reverse' ];
+               }
+            }
+
+            # Draw the screen and wait for a command.
+            unshift @display_lines, '',
+               "Editing color rules for $meta->{capt}.  Press ? for help, q to "
+               . "quit.", '';
+            draw_screen(\@display_lines);
+            print "\n\n", word_wrap('Rules are applied in order from top to '
+               . 'bottom.  The first matching rule wins and prevents the '
+               . 'rest of the rules from being applied.');
+            $key = pause('');
+         }
+      } while ( $key ne 'q' );
+      $meta->{color_func} = make_color_func($meta);
+   }
+}
+
+# add_quick_filter {{{3
+sub add_quick_filter {
+   my $tbl = choose_visible_table();
+   if ( $tbl && exists($tbl_meta{$tbl}) ) {
+      print "\n";
+      my $response = prompt_list(
+         "Enter column name and filter text",
+         '',
+         sub { return keys %{$tbl_meta{$tbl}->{cols}} },
+         ()
+      );
+      my ( $col, $text ) = split(/\s+/, $response, 2);
+
+      # You can't filter on a nonexistent column.  But if you filter on a pivoted
+      # table, the columns are different, so on a pivoted table, allow filtering
+      # on the 'name' column.
+      # NOTE: if a table is pivoted and un-pivoted, this will likely cause crashes.
+      # Currently not an issue since there's no way to toggle pivot/nopivot.
+      return unless $col && $text &&
+         (exists($tbl_meta{$tbl}->{cols}->{$col})
+            || ($tbl_meta{$tbl}->{pivot} && $col eq 'name'));
+
+      my ( $sub, $err ) = compile_filter( "defined \$set->{$col} && \$set->{$col} =~ m/$text/" );
+      return if !$sub || $err;
+      my $name = "quick_$tbl.$col";
+      $filters{$name} = {
+         func  => $sub,
+         text  => $text,
+         user  => 1,
+         quick => 1,
+         name  => $name,
+         note  => 'Quick-filter',
+         tbls  => [$tbl],
+      };
+      push @{$tbl_meta{$tbl}->{filters}}, $name;
+   }
+}
+
+# clear_quick_filters {{{3
+sub clear_quick_filters {
+   my $tbl = choose_visible_table(
+      # Only tables that have quick-filters
+      sub {
+         my ( $tbl ) = @_;
+         return scalar grep { $filters{$_}->{quick} } @{ $tbl_meta{$tbl}->{filters} };
+      }
+   );
+   if ( $tbl && exists($tbl_meta{$tbl}) ) {
+      my @current = @{$tbl_meta{$tbl}->{filters}};
+      @current = grep { !$filters{$_}->{quick} } @current;
+      $tbl_meta{$tbl}->{filters} = \@current;
+   }
+}
+
+sub edit_plugins {
+   $clear_screen_sub->();
+
+   my @cols = ('', qw(class desc active));
+   my $info = { map { $_ => { hdr => $_, just => '-', } }  @cols };
+   my @rows = map { $plugins{$_} } sort keys %plugins;
+   my $key;
+   my $selected;
+
+   # This loop builds a tabular view of the plugins.
+   do {
+
+      # Show help
+      if ( $key && $key eq '?' ) {
+         my @display_lines = '';
+         push @display_lines, create_caption('Editor key mappings',
+         create_table2(
+            [ sort keys %plugin_editor_action ],
+            { map { $_ => $_ } keys %plugin_editor_action },
+            { map { $_ => $plugin_editor_action{$_}->{note} } keys %plugin_editor_action },
+            { sep => '  ' }));
+         draw_screen(\@display_lines);
+         pause();
+         $key = '';
+      }
+
+      # Do the action specified
+      else {
+         $selected ||= 0;
+         if ( $key && $plugin_editor_action{$key} ) {
+            $selected = $plugin_editor_action{$key}->{func}->(\@rows, $selected);
+            $selected ||= 0;
+         }
+
+         # Build the table of plugins.
+         foreach my $row ( 0.. $#rows ) {
+            $rows[$row]->{''} = $row eq $selected ? '>' : ' ';
+         }
+         my @display_lines = create_table(\@cols, $info, \@rows);
+
+         # Highlight selected entry
+         for my $i ( 0 .. $#display_lines ) {
+            if ( $display_lines[$i] =~ m/^>/ ) {
+               $display_lines[$i] = [ $display_lines[$i], 'reverse' ];
+            }
+         }
+
+         # Draw the screen and wait for a command.
+         unshift @display_lines, '',
+            "Plugin Management.  Press ? for help, q to quit.", '';
+         draw_screen(\@display_lines);
+         $key = pause('');
+      }
+   } while ( $key ne 'q' );
+}
+
+# edit_table {{{3
+sub edit_table {
+   $clear_screen_sub->();
+   my ( $tbl ) = @_;
+   $tbl ||= choose_visible_table();
+   if ( $tbl && exists($tbl_meta{$tbl}) ) {
+      my $meta = $tbl_meta{$tbl};
+      my @cols = ('', qw(name hdr label src));
+      my $info = { map { $_ => { hdr => $_, just => '-', } }  @cols };
+      $info->{label}->{maxw} = 30;
+      my $key;
+      my $selected_column;
+
+      # This loop builds a tabular view of the tbl_meta's structure, showing each column
+      # in the entry as a row.
+      do {
+
+         # Show help
+         if ( $key && $key eq '?' ) {
+            my @display_lines = '';
+            push @display_lines, create_caption('Editor key mappings',
+            create_table2(
+               [ sort keys %tbl_editor_action ],
+               { map { $_ => $_ } keys %tbl_editor_action },
+               { map { $_ => $tbl_editor_action{$_}->{note} } keys %tbl_editor_action },
+               { sep => '  ' }));
+            draw_screen(\@display_lines);
+            pause();
+            $key = '';
+         }
+         else {
+
+            # Do the action specified
+            $selected_column ||= $meta->{visible}->[0];
+            if ( $key && $tbl_editor_action{$key} ) {
+               $selected_column = $tbl_editor_action{$key}->{func}->($tbl, $selected_column);
+               $selected_column ||= $meta->{visible}->[0];
+            }
+
+            # Build the pivoted view of the table's meta-data.  If the terminal has color,
+            # The selected row will be highlighted; otherwise a > at the left will indicate.
+            my $data = [];
+            foreach my $row ( @{$meta->{visible}} ) {
+               my %hash;
+               @hash{ @cols } = @{$meta->{cols}->{$row}}{@cols};
+               $hash{src}  = '' if ref $hash{src};
+               $hash{name} = $row;
+               $hash{''}   = $row eq $selected_column ? '>' : ' ';
+               push @$data, \%hash;
+            }
+            my @display_lines = create_table(\@cols, $info, $data);
+
+            # Highlight selected entry
+            for my $i ( 0 .. $#display_lines ) {
+               if ( $display_lines[$i] =~ m/^>/ ) {
+                  $display_lines[$i] = [ $display_lines[$i], 'reverse' ];
+               }
+            }
+
+            # Draw the screen and wait for a command.
+            unshift @display_lines, '',
+               "Editing table definition for $meta->{capt}.  Press ? for help, q to quit.", '';
+            draw_screen(\@display_lines, { clear => 1 });
+            $key = pause('');
+         }
+      } while ( $key ne 'q' );
+   }
+}
+
+# choose_mode_tables {{{3
+# Choose which table(s), and in what order, to display in a given mode.
+sub choose_mode_tables {
+   my $mode = $config{mode}->{val};
+   my @tbls = @{$modes{$mode}->{visible_tables}};
+   my $new  = prompt_list(
+      "Choose tables to display",
+      join(' ', @tbls),
+      sub { return @{$modes{$mode}->{tables}} },
+      { map { $_ => $tbl_meta{$_}->{capt} } @{$modes{$mode}->{tables}} }
+   );
+   $modes{$mode}->{visible_tables} =
+      [ unique(grep { $_ && exists $tbl_meta{$_} } split(/\s+/, $new)) ];
+   $modes{$mode}->{cust}->{visible_tables} = 1;
+}
+
+# choose_visible_table {{{3
+sub choose_visible_table {
+   my ( $grep_cond ) = @_;
+   my $mode = $config{mode}->{val};
+   my @tbls
+      = grep { $grep_cond ? $grep_cond->($_) : 1 }
+        @{$modes{$mode}->{visible_tables}};
+   my $tbl = $tbls[0];
+   if ( @tbls > 1 ) {
+      $tbl = prompt_list(
+         "Choose a table",
+         '',
+         sub { return @tbls },
+         { map { $_ => $tbl_meta{$_}->{capt} } @tbls }
+      );
+   }
+   return $tbl;
+}
+
+sub toggle_aggregate {
+   my ( $tbl ) = @_;
+   $tbl ||= choose_visible_table();
+   return unless $tbl && exists $tbl_meta{$tbl};
+   my $meta = $tbl_meta{$tbl};
+   $meta->{aggregate} ^= 1;
+}
+
+sub choose_filters {
+   my ( $tbl ) = @_;
+   $tbl ||= choose_visible_table();
+   return unless $tbl && exists $tbl_meta{$tbl};
+   my $meta = $tbl_meta{$tbl};
+   $clear_screen_sub->();
+
+   print "Choose filters for $meta->{capt}:\n";
+
+   my $ini = join(' ', @{$meta->{filters}});
+   my $val = prompt_list(
+      'Choose filters',
+      $ini,
+      sub { return keys %filters },
+      {
+         map  { $_ => $filters{$_}->{note} }
+         grep { grep { $tbl eq $_ } @{$filters{$_}->{tbls}} }
+         keys %filters
+      }
+   );
+
+   my @choices = unique(split(/\s+/, $val));
+   foreach my $new ( grep { !exists($filters{$_}) } @choices ) {
+      my $answer = prompt("There is no filter called '$new'.  Create it?", undef, 'y');
+      if ( $answer eq 'y' ) {
+         create_new_filter($new, $tbl);
+      }
+   }
+   @choices = grep { exists $filters{$_} } @choices;
+   @choices = grep { grep { $tbl eq $_ } @{$filters{$_}->{tbls}} } @choices;
+   $meta->{filters} = [ @choices ];
+   $meta->{cust}->{filters} = 1;
+}
+
+sub choose_group_cols {
+   my ( $tbl ) = @_;
+   $tbl ||= choose_visible_table();
+   return unless $tbl && exists $tbl_meta{$tbl};
+   $clear_screen_sub->();
+   my $meta = $tbl_meta{$tbl};
+   my $curr = join(', ', @{$meta->{group_by}});
+   my $val = prompt_list(
+      'Group-by columns',
+      $curr,
+      sub { return keys %{$meta->{cols}} },
+      { map { $_ => $meta->{cols}->{$_}->{label} } keys %{$meta->{cols}} });
+   if ( $curr ne $val ) {
+      $meta->{group_by} = [ grep { exists $meta->{cols}->{$_} } $val =~ m/(\w+)/g ];
+      $meta->{cust}->{group_by} = 1;
+   }
+}
+
+sub choose_sort_cols {
+   my ( $tbl ) = @_;
+   $tbl ||= choose_visible_table();
+   return unless $tbl && exists $tbl_meta{$tbl};
+   $clear_screen_sub->();
+   my $meta = $tbl_meta{$tbl};
+
+   my ( $cols, $hints );
+   if ( $meta->{pivot} ) {
+      $cols  = sub { qw(name set_0) };
+      $hints = { name => 'name', set_0 => 'set_0' };
+   }
+   else {
+      $cols  = sub { return keys %{$meta->{cols}} };
+      $hints = { map { $_ => $meta->{cols}->{$_}->{label} } keys %{$meta->{cols}} };
+   }
+
+   my $val = prompt_list(
+      'Sort columns (reverse sort with -col)',
+      $meta->{sort_cols},
+      $cols,
+      $hints );
+   if ( $meta->{sort_cols} ne $val ) {
+      $meta->{sort_cols} = $val;
+      $meta->{cust}->{sort_cols} = 1;
+      $tbl_meta{$tbl}->{sort_func} = make_sort_func($tbl_meta{$tbl});
+   }
+}
+
+# create_new_filter {{{3
+sub create_new_filter {
+   my ( $filter, $tbl ) = @_;
+   $clear_screen_sub->();
+
+   if ( !$filter || $filter =~ m/\W/ ) {
+      print word_wrap("Choose a name for the filter.  This name is not displayed, and is only used "
+            . "for internal reference.  It can only contain lowercase letters, numbers, and underscores.");
+      print "\n\n";
+      do {
+         $filter = prompt("Enter filter name");
+      } while ( !$filter || $filter =~ m/\W/ );
+   }
+
+   my $completion = sub { keys %{$tbl_meta{$tbl}->{cols}} };
+   my ( $err, $sub, $body );
+   do {
+      $clear_screen_sub->();
+      print word_wrap("A filter is a Perl subroutine that accepts a hashref of columns "
+         . "called \$set, and returns a true value if the filter accepts the row.  Example:\n"
+         . "   \$set->{active_secs} > 5\n"
+         . "will only allow rows if their active_secs column is greater than 5.");
+      print "\n\n";
+      if ( $err ) {
+         print "There's an error in your filter expression: $err\n\n";
+      }
+      $body = prompt("Enter subroutine body", undef, undef, $completion);
+      ( $sub, $err ) = compile_filter($body);
+   } while ( $err );
+
+   $filters{$filter} = {
+      func => $sub,
+      text => $body,
+      user => 1,
+      name => $filter,
+      note => 'User-defined filter',
+      tbls => [$tbl],
+   };
+}
+
+# get_config_interactive {{{3
+sub get_config_interactive {
+   my $key = shift;
+   $clear_screen_sub->();
+
+   # Print help first.
+   print "Enter a new value for '$key' ($config{$key}->{note}).\n";
+
+   my $current = ref($config{$key}->{val}) ? join(" ", @{$config{$key}->{val}}) : $config{$key}->{val};
+
+   my $new_value = prompt('Enter a value', $config{$key}->{pat}, $current);
+   $config{$key}->{val} = $new_value;
+}
+
+sub edit_current_var_set {
+   my $mode = $config{mode}->{val};
+   my $name = $config{"${mode}_set"}->{val};
+   my $variables = $var_sets{$name}->{text};
+
+   my $new = $variables;
+   do {
+      $clear_screen_sub->();
+      $new = prompt("Enter variables for $name", undef, $variables);
+   } until ( $new );
+
+   if ( $new ne $variables ) {
+      @{$var_sets{$name}}{qw(text user)} = ( $new, 1);
+   }
+}
+
+
+sub choose_var_set {
+   my ( $key ) = @_;
+   $clear_screen_sub->();
+
+   my $new_value = prompt_list(
+      'Choose a set of values to display, or enter the name of a new one',
+      $config{$key}->{val},
+      sub { return keys %var_sets },
+      { map { $_ => $var_sets{$_}->{text} } keys %var_sets });
+
+   if ( !exists $var_sets{$new_value} ) {
+      add_new_var_set($new_value);
+   }
+
+   $config{$key}->{val} = $new_value if exists $var_sets{$new_value};
+}
+
+sub switch_var_set {
+   my ( $cfg_var, $dir ) = @_;
+   my @var_sets = sort keys %var_sets;
+   my $cur      = $config{$cfg_var}->{val};
+   my $pos      = grep { $_ lt $cur } @var_sets;
+   my $newpos   = ($pos + $dir) % @var_sets;
+   $config{$cfg_var}->{val} = $var_sets[$newpos];
+   $clear_screen_sub->();
+}
+
+# Online configuration and prompting functions {{{2
+
+# edit_stmt_sleep_times {{{3
+sub edit_stmt_sleep_times {
+   $clear_screen_sub->();
+   my $stmt = prompt_list('Specify a statement', '', sub { return sort keys %stmt_maker_for });
+   return unless $stmt && exists $stmt_maker_for{$stmt};
+   $clear_screen_sub->();
+   my $curr_val = $stmt_sleep_time_for{$stmt} || 0;
+   my $new_val  = prompt('Specify a sleep delay after calling this SQL', $num_regex, $curr_val);
+   if ( $new_val ) {
+      $stmt_sleep_time_for{$stmt} = $new_val;
+   }
+   else {
+      delete $stmt_sleep_time_for{$stmt};
+   }
+}
+
+# edit_server_groups {{{3
+# Choose which server connections are in a server group.  First choose a group,
+# then choose which connections are in it.
+sub edit_server_groups {
+   $clear_screen_sub->();
+   my $mode  = $config{mode}->{val};
+   my $group = $modes{$mode}->{server_group};
+   my %curr  = %server_groups;
+   my $new   = choose_or_create_server_group($group, 'to edit');
+   $clear_screen_sub->();
+   if ( exists $curr{$new} ) {
+      # Don't do this step if the user just created a new server group,
+      # because part of that process was to choose connections.
+      my $cxns  = join(' ', @{$server_groups{$new}});
+      my @conns = choose_or_create_connection($cxns, 'for this group');
+      $server_groups{$new} = \@conns;
+   }
+}
+
+# choose_server_groups {{{3
+sub choose_server_groups {
+   $clear_screen_sub->();
+   my $mode  = $config{mode}->{val};
+   my $group = $modes{$mode}->{server_group};
+   my $new   = choose_or_create_server_group($group, 'for this mode');
+   $modes{$mode}->{server_group} = $new if exists $server_groups{$new};
+}
+
+sub choose_or_create_server_group {
+   my ( $group, $prompt ) = @_;
+   my $new   = '';
+
+   my @available = sort keys %server_groups;
+
+   if ( @available ) {
+      print "You can enter the name of a new group to create it.\n";
+
+      $new = prompt_list(
+         "Choose a server group $prompt",
+         $group,
+         sub { return @available },
+         { map { $_ => join(' ', @{$server_groups{$_}}) } @available });
+
+      $new =~ s/\s.*//;
+
+      if ( !exists $server_groups{$new} ) {
+         my $answer = prompt("There is no server group called '$new'.  Create it?", undef, "y");
+         if ( $answer eq 'y' ) {
+            add_new_server_group($new);
+         }
+      }
+   }
+   else {
+      $new = add_new_server_group();
+   }
+   return $new;
+}
+
+sub choose_or_create_connection {
+   my ( $cxns, $prompt ) = @_;
+   print "You can enter the name of a new connection to create it.\n";
+
+   my @available = sort keys %connections;
+   my $new_cxns = prompt_list(
+      "Choose connections $prompt",
+      $cxns,
+      sub { return @available },
+      { map { $_ => $connections{$_}->{dsn} } @available });
+
+   my @new = unique(grep { !exists $connections{$_} } split(/\s+/, $new_cxns));
+   foreach my $new ( @new ) {
+      my $answer = prompt("There is no connection called '$new'.  Create it?", undef, "y");
+      if ( $answer eq 'y' ) {
+         add_new_dsn($new);
+      }
+   }
+
+   return unique(grep { exists $connections{$_} } split(/\s+/, $new_cxns));
+}
+
+# choose_servers {{{3
+sub choose_servers {
+   $clear_screen_sub->();
+   my $mode = $config{mode}->{val};
+   my $cxns = join(' ', get_connections());
+   my @chosen = choose_or_create_connection($cxns, 'for this mode');
+   $modes{$mode}->{connections} = \@chosen;
+   $modes{$mode}->{server_group} = ''; # Clear this because it overrides {connections}
+}
+
+# display_license {{{3
+sub display_license {
+   $clear_screen_sub->();
+
+   print $innotop_license;
+
+   pause();
+}
+
+# Data-retrieval functions {{{2
+# get_status_info {{{3
+# Get SHOW STATUS and SHOW VARIABLES together.
+sub get_status_info {
+   my @cxns = @_;
+   if ( !$info_gotten{status}++ ) {
+      foreach my $cxn ( @cxns ) {
+         $vars{$cxn}->{$clock} ||= {};
+         my $vars = $vars{$cxn}->{$clock};
+
+         my $sth = do_stmt($cxn, 'SHOW_STATUS') or next;
+         my $res = $sth->fetchall_arrayref();
+         map { $vars->{$_->[0]} = $_->[1] || 0 } @$res;
+
+         # Calculate hi-res uptime and add cxn to the hash.  This duplicates get_driver_status,
+         # but it's most important to have consistency.
+         $vars->{Uptime_hires} ||= get_uptime($cxn);
+         $vars->{cxn} = $cxn;
+
+         # Add SHOW VARIABLES to the hash
+         $sth = do_stmt($cxn, 'SHOW_VARIABLES') or next;
+         $res = $sth->fetchall_arrayref();
+         map { $vars->{$_->[0]} = $_->[1] || 0 } @$res;
+      }
+   }
+}
+
+# Chooses a thread for explaining, killing, etc...
+# First arg is a func that can be called in grep.
+sub choose_thread {
+   my ( $grep_cond, $prompt ) = @_;
+
+   # Narrow the list to queries that can be explained.
+   my %thread_for = map {
+      # Eliminate innotop's own threads.
+      $_ => $dbhs{$_}->{dbh} ? $dbhs{$_}->{dbh}->{mysql_thread_id} : 0
+   } keys %connections;
+
+   my @candidates = grep {
+      $_->{id} != $thread_for{$_->{cxn}} && $grep_cond->($_)
+   } @current_queries;
+   return unless @candidates;
+
+   # Find out which server.
+   my @cxns = unique map { $_->{cxn} } @candidates;
+   my ( $cxn ) = select_cxn('On which server', @cxns);
+   return unless $cxn && exists($connections{$cxn});
+
+   # Re-filter the list of candidates to only those on this server
+   @candidates = grep { $_->{cxn} eq $cxn } @candidates;
+
+   # Find out which thread to do.
+   my $info;
+   if ( @candidates > 1 ) {
+
+      # Sort longest-active first, then longest-idle.
+      my $sort_func = sub {
+         my ( $a, $b ) = @_;
+         return  $a->{query} && !$b->{query} ? 1
+               : $b->{query} && !$a->{query} ? -1
+               : ($a->{time} || 0) <=> ($b->{time} || 0);
+      };
+      my @threads = map { $_->{id} } reverse sort { $sort_func->($a, $b) } @candidates;
+
+      print "\n";
+      my $thread = prompt_list($prompt,
+         $threads[0],
+         sub { return @threads });
+      return unless $thread && $thread =~ m/$int_regex/;
+
+      # Find the info hash of that query on that server.
+      ( $info ) = grep { $thread == $_->{id} } @candidates;
+   }
+   else {
+      $info = $candidates[0];
+   }
+   return $info;
+}
+
+# analyze_query {{{3
+# Allows the user to show fulltext, explain, show optimized...
+sub analyze_query {
+   my ( $action ) = @_;
+
+   my $info = choose_thread(
+      sub { $_[0]->{query} },
+      'Select a thread to analyze',
+   );
+   return unless $info;
+
+   my %actions = (
+      e => \&display_explain,
+      f => \&show_full_query,
+      o => \&show_optimized_query,
+   );
+   do {
+      $actions{$action}->($info);
+      print "\n";
+      $action = pause('Press e to explain, f for full query, o for optimized query');
+   } while ( exists($actions{$action}) );
+}
+
+# inc {{{3
+# Returns the difference between two sets of variables/status/innodb stuff.
+sub inc {
+   my ( $offset, $cxn ) = @_;
+   my $vars = $vars{$cxn};
+   if ( $offset < 0 ) {
+      return $vars->{$clock};
+   }
+   elsif ( exists $vars{$clock - $offset} && !exists $vars->{$clock - $offset - 1} ) {
+      return $vars->{$clock - $offset};
+   }
+   my $cur = $vars->{$clock - $offset};
+   my $pre = $vars->{$clock - $offset - 1};
+   return {
+      # Numeric variables get subtracted, non-numeric get passed straight through.
+      map  {
+         $_ =>
+            ( (defined $cur->{$_} && $cur->{$_} =~ m/$num_regex/)
+            ?  $cur->{$_} - ($pre->{$_} || 0)
+            :  $cur->{$_} )
+      } keys %{$cur}
+   };
+}
+
+# extract_values {{{3
+# Arguments are a set of values (which may be incremental, derived from
+# current and previous), current, and previous values.
+# TODO: there are a few places that don't remember prev set so can't pass it.
+sub extract_values {
+   my ( $set, $cur, $pre, $tbl ) = @_;
+
+   # Hook in event listeners
+   foreach my $listener ( @{$event_listener_for{extract_values}} ) {
+      $listener->extract_values($set, $cur, $pre, $tbl);
+   }
+
+   my $result = {};
+   my $meta   = $tbl_meta{$tbl};
+   my $cols   = $meta->{cols};
+   foreach my $key ( keys %$cols ) {
+      my $info = $cols->{$key}
+         or die "Column '$key' doesn't exist in $tbl";
+      die "No func defined for '$key' in $tbl"
+         unless $info->{func};
+      eval {
+         $result->{$key} = $info->{func}->($set, $cur, $pre)
+      };
+      if ( $EVAL_ERROR ) {
+         if ( $config{debug}->{val} ) {
+            die $EVAL_ERROR;
+         }
+         $result->{$key} = $info->{num} ? 0 : '';
+      }
+   }
+   return $result;
+}
+
+# get_full_processlist {{{3
+sub get_full_processlist {
+   my @cxns = @_;
+   my @result;
+   foreach my $cxn ( @cxns ) {
+      my $stmt = do_stmt($cxn, 'PROCESSLIST') or next;
+      my $arr  = $stmt->fetchall_arrayref({});
+      push @result, map { $_->{cxn} = $cxn; $_ } @$arr;
+   }
+   return @result;
+}
+
+# get_open_tables {{{3
+sub get_open_tables {
+   my @cxns = @_;
+   my @result;
+   foreach my $cxn ( @cxns ) {
+      my $stmt = do_stmt($cxn, 'OPEN_TABLES') or next;
+      my $arr  = $stmt->fetchall_arrayref({});
+      push @result, map { $_->{cxn} = $cxn; $_ } @$arr;
+   }
+   return @result;
+}
+
+# get_innodb_status {{{3
+sub get_innodb_status {
+   my ( $cxns, $addl_sections ) = @_;
+   if ( !$config{skip_innodb}->{val} && !$info_gotten{innodb_status}++ ) {
+
+      # Determine which sections need to be parsed
+      my %sections_required =
+         map  { $tbl_meta{$_}->{innodb} => 1 }
+         grep { $_ && $tbl_meta{$_}->{innodb} }
+         get_visible_tables();
+
+      # Add in any other sections the caller requested.
+      foreach my $sec ( @$addl_sections ) {
+         $sections_required{$sec} = 1;
+      }
+
+      foreach my $cxn ( @$cxns ) {
+         my $innodb_status_text;
+
+         if ( $file ) { # Try to fetch status text from the file.
+            my @stat = stat($file);
+
+            # Initialize the file.
+            if ( !$file_mtime ) {
+               # Initialize to 130k from the end of the file (because the limit
+               # on the size of innodb status is 128k even with Google's patches)
+               # and try to grab the last status from the file.
+               sysseek($file, (-128 * 1_024), 2);
+            }
+
+            # Read from the file.
+            my $buffer;
+            if ( !$file_mtime || $file_mtime != $stat[9] ) {
+               $file_data = '';
+               while ( sysread($file, $buffer, 4096) ) {
+                  $file_data .= $buffer;
+               }
+               $file_mtime = $stat[9];
+            }
+
+            # Delete everything but the last InnoDB status text from the file.
+            $file_data =~ s/\A.*(?=^=====================================\n...... ........ INNODB MONITOR OUTPUT)//ms;
+            $innodb_status_text = $file_data;
+         }
+
+         else {
+            my $stmt = do_stmt($cxn, 'INNODB_STATUS') or next;
+            $innodb_status_text = $stmt->fetchrow_hashref()->{status};
+         }
+
+         next unless $innodb_status_text
+            && substr($innodb_status_text, 0, 100) =~ m/INNODB MONITOR OUTPUT/;
+
+         # Parse and merge into %vars storage
+         my %innodb_status = (
+            $innodb_parser->get_status_hash(
+               $innodb_status_text,
+               $config{debug}->{val},
+               \%sections_required,
+               0, # don't parse full lock information
+            )
+         );
+         if ( !$innodb_status{IB_got_all} && $config{auto_wipe_dl}->{val} ) {
+            clear_deadlock($cxn);
+         }
+
+         # Merge using a hash slice, which is the fastest way
+         $vars{$cxn}->{$clock} ||= {};
+         my $hash = $vars{$cxn}->{$clock};
+         @{$hash}{ keys %innodb_status } = values %innodb_status;
+         $hash->{cxn} = $cxn;
+         $hash->{Uptime_hires} ||= get_uptime($cxn);
+      }
+   }
+}
+
+# clear_deadlock {{{3
+sub clear_deadlock {
+   my ( $cxn ) = @_;
+   return if $clearing_deadlocks++;
+   my $tbl = $connections{$cxn}->{dl_table};
+   return unless $tbl;
+
+   eval {
+      # Set up the table for creating a deadlock.
+      my $engine = version_ge($dbhs{$cxn}->{dbh}, '4.1.2') ? 'engine' : 'type';
+      return unless do_query($cxn, "drop table if exists $tbl");
+      return unless do_query($cxn, "create table $tbl(a int) $engine=innodb");
+      return unless do_query($cxn, "delete from $tbl");
+      return unless do_query($cxn, "insert into $tbl(a) values(0), (1)");
+      return unless do_query($cxn, "commit"); # Or the children will block against the parent
+
+      # Fork off two children to deadlock against each other.
+      my %children;
+      foreach my $child ( 0..1 ) {
+         my $pid = fork();
+         if ( defined($pid) && $pid == 0 ) { # I am a child
+            deadlock_thread( $child, $tbl, $cxn );
+         }
+         elsif ( !defined($pid) ) {
+            die("Unable to fork for clearing deadlocks!\n");
+         }
+         # I already exited if I'm a child, so I'm the parent.
+         $children{$child} = $pid;
+      }
+
+      # Wait for the children to exit.
+      foreach my $child ( keys %children ) {
+         my $pid = waitpid($children{$child}, 0);
+      }
+
+      # Clean up.
+      do_query($cxn, "drop table $tbl");
+   };
+   if ( $EVAL_ERROR ) {
+      print $EVAL_ERROR;
+      pause();
+   }
+
+   $clearing_deadlocks = 0;
+}
+
+sub get_master_logs {
+   my @cxns = @_;
+   my @result;
+   if ( !$info_gotten{master_logs}++ ) {
+      foreach my $cxn ( @cxns ) {
+         my $stmt = do_stmt($cxn, 'SHOW_MASTER_LOGS') or next;
+         push @result, @{$stmt->fetchall_arrayref({})};
+      }
+   }
+   return @result;
+}
+
+# get_master_slave_status {{{3
+sub get_master_slave_status {
+   my @cxns = @_;
+   if ( !$info_gotten{replication_status}++ ) {
+      foreach my $cxn ( @cxns ) {
+         $vars{$cxn}->{$clock} ||= {};
+         my $vars = $vars{$cxn}->{$clock};
+         $vars->{cxn} = $cxn;
+
+         my $stmt = do_stmt($cxn, 'SHOW_MASTER_STATUS') or next;
+         my $res = $stmt->fetchall_arrayref({})->[0];
+         @{$vars}{ keys %$res } = values %$res;
+         $stmt = do_stmt($cxn, 'SHOW_SLAVE_STATUS') or next;
+         $res = $stmt->fetchall_arrayref({})->[0];
+         @{$vars}{ keys %$res } = values %$res;
+         $vars->{Uptime_hires} ||= get_uptime($cxn);
+      }
+   }
+}
+
+sub is_func {
+   my ( $word ) = @_;
+   return defined(&$word)
+      || eval "my \$x= sub { $word  }; 1"
+      || $EVAL_ERROR !~ m/^Bareword/;
+}
+
+# Documentation {{{1
+# ############################################################################
+# I put this last as per the Dog book.
+# ############################################################################
+=pod
+
+=head1 NAME
+
+innotop - MySQL and InnoDB transaction/status monitor.
+
+=head1 SYNOPSIS
+
+To monitor servers normally:
+
+ innotop
+
+To monitor InnoDB status information from a file:
+
+ innotop /var/log/mysql/mysqld.err
+
+To run innotop non-interactively in a pipe-and-filter configuration:
+
+ innotop --count 5 -d 1 -n
+
+To monitor a database on another system using a particular username and password:
+
+ innotop -u <username> -p <password> -h <hostname>
+
+=head1 DESCRIPTION
+
+innotop monitors MySQL servers.  Each of its modes shows you a different aspect
+of what's happening in the server.  For example, there's a mode for monitoring
+replication, one for queries, and one for transactions.  innotop refreshes its
+data periodically, so you see an updating view.
+
+innotop has lots of features for power users, but you can start and run it with
+virtually no configuration.  If you're just getting started, see
+L<"QUICK-START">.  Press '?' at any time while running innotop for
+context-sensitive help.
+
+=head1 QUICK-START
+
+To start innotop, open a terminal or command prompt.  If you have installed
+innotop on your system, you should be able to just type "innotop" and press
+Enter; otherwise, you will need to change to innotop's directory and type "perl
+innotop".
+
+With no options specified, innotop will attempt to connect to a MySQL server on
+localhost using mysql_read_default_group=client for other connection
+parameters.  If you need to specify a different username and password, use the
+-u and -p options, respectively.  To monitor a MySQL database on another
+host, use the -h option.
+
+After you've connected, innotop should show you something like the following:
+
+ [RO] Query List (? for help) localhost, 01:11:19, 449.44 QPS, 14/7/163 con/run
+ CXN        When   Load  QPS    Slow  QCacheHit  KCacheHit  BpsIn    BpsOut 
+ localhost  Total  0.00  1.07k   697      0.00%     98.17%  476.83k  242.83k
+
+ CXN        Cmd    ID         User  Host      DB   Time   Query
+ localhost  Query  766446598  test  10.0.0.1  foo  00:02  INSERT INTO table (
+
+
+(This sample is truncated at the right so it will fit on a terminal when running
+'man innotop')
+
+If your server is busy, you'll see more output.  Notice the first line on the
+screen, which tells you that readonly is set to true ([RO]), what mode you're
+in and what server you're connected to.  You can change to other modes with
+keystrokes; press 'T' to switch to a list of InnoDB transactions, for example.
+
+Press the '?' key to see what keys are active in the current mode.  You can
+press any of these keys and innotop will either take the requested action or
+prompt you for more input.  If your system has Term::ReadLine support, you can
+use TAB and other keys to auto-complete and edit input.
+
+To quit innotop, press the 'q' key.
+
+=head1 OPTIONS
+
+innotop is mostly configured via its configuration file, but some of the
+configuration options can come from the command line.  You can also specify a
+file to monitor for InnoDB status output; see L<"MONITORING A FILE"> for more
+details.
+
+You can negate some options by prefixing the option name with --no.  For
+example, --noinc (or --no-inc) negates L<"--inc">.
+
+=over
+
+=item --color
+
+Enable or disable terminal coloring.  Corresponds to the L<"color"> config file
+setting.
+
+=item --config
+
+Specifies a configuration file to read.  This option is non-sticky, that is to
+say it does not persist to the configuration file itself.
+
+=item --count
+
+Refresh only the specified number of times (ticks) before exiting.  Each refresh
+is a pause for L<"interval"> seconds, followed by requesting data from MySQL
+connections and printing it to the terminal.
+
+=item --delay
+
+Specifies the amount of time to pause between ticks (refreshes).  Corresponds to
+the configuration option L<"interval">.
+
+=item --help
+
+Print a summary of command-line usage and exit.
+
+=item --host
+
+Host to connect to.
+
+=item --inc
+
+Specifies whether innotop should display absolute numbers or relative numbers
+(offsets from their previous values).  Corresponds to the configuration option
+L<"status_inc">.
+
+=item --mode
+
+Specifies the mode in which innotop should start.  Corresponds to the
+configuration option L<"mode">.
+
+=item --nonint
+
+Enable non-interactive operation.  See L<"NON-INTERACTIVE OPERATION"> for more.
+
+=item --password
+
+Password to use for connection.
+
+=item --port
+
+Port to use for connection.
+
+=item --skipcentral
+
+Don't read the central configuration file.
+
+=item --user
+
+User to use for connection.
+
+=item --version
+
+Output version information and exit.
+
+=item --write
+
+Sets the configuration option L<"readonly"> to 0, making innotop write the
+running configuration to ~/.innotop/innotop.conf on exit, if no configuration
+file was loaded at start-up.
+
+=back
+
+=head1 HOTKEYS
+
+innotop is interactive, and you control it with key-presses.
+
+=over
+
+=item *
+
+Uppercase keys switch between modes.
+
+=item *
+
+Lowercase keys initiate some action within the current mode.
+
+=item *
+
+Other keys do something special like change configuration or show the
+innotop license.
+
+=back
+
+Press '?' at any time to see the currently active keys and what they do.
+
+=head1 MODES
+
+Each of innotop's modes retrieves and displays a particular type of data from
+the servers you're monitoring.  You switch between modes with uppercase keys.
+The following is a brief description of each mode, in alphabetical order.  To
+switch to the mode, press the key listed in front of its heading in the
+following list:
+
+=over
+
+=item B: InnoDB Buffers
+
+This mode displays information about the InnoDB buffer pool, page statistics,
+insert buffer, and adaptive hash index.  The data comes from SHOW INNODB STATUS.
+
+This mode contains the L<"buffer_pool">, L<"page_statistics">,
+L<"insert_buffers">, and L<"adaptive_hash_index"> tables by default.
+
+=item C: Command Summary
+
+This mode is similar to mytop's Command Summary mode.  It shows the
+L<"cmd_summary"> table, which looks something like the following:
+
+ Command Summary (? for help) localhost, 25+07:16:43, 2.45 QPS, 3 thd, 5.0.40
+ _____________________ Command Summary _____________________
+ Name                    Value    Pct     Last Incr  Pct    
+ Select_scan             3244858  69.89%          2  100.00%
+ Select_range            1354177  29.17%          0    0.00%
+ Select_full_join          39479   0.85%          0    0.00%
+ Select_full_range_join     4097   0.09%          0    0.00%
+ Select_range_check            0   0.00%          0    0.00%
+
+The command summary table is built by extracting variables from
+L<"STATUS_VARIABLES">.  The variables must be numeric and must match the prefix
+given by the L<"cmd_filter"> configuration variable.  The variables are then
+sorted by value descending and compared to the last variable, as shown above.
+The percentage columns are percentage of the total of all variables in the
+table, so you can see the relative weight of the variables.
+
+The example shows what you see if the prefix is "Select_".  The default
+prefix is "Com_".  You can choose a prefix with the 's' key.
+
+It's rather like running SHOW VARIABLES LIKE "prefix%" with memory and
+nice formatting.
+
+Values are aggregated across all servers.  The Pct columns are not correctly
+aggregated across multiple servers.  This is a known limitation of the grouping
+algorithm that may be fixed in the future.
+
+=item D: InnoDB Deadlocks
+
+This mode shows the transactions involved in the last InnoDB deadlock.  A second
+table shows the locks each transaction held and waited for.  A deadlock is
+caused by a cycle in the waits-for graph, so there should be two locks held and
+one waited for unless the deadlock information is truncated.
+
+InnoDB puts deadlock information before some other information in the SHOW
+INNODB STATUS output.  If there are a lot of locks, the deadlock information can
+grow very large, and there is a limit on the size of the SHOW INNODB
+STATUS output.  A large deadlock can fill the entire output, or even be
+truncated, and prevent you from seeing other information at all.  If you are
+running innotop in another mode, for example T mode, and suddenly you don't see
+anything, you might want to check and see if a deadlock has wiped out the data
+you need.
+
+If it has, you can create a small deadlock to replace the large one.  Use the
+'w' key to 'wipe' the large deadlock with a small one.  This will not work
+unless you have defined a deadlock table for the connection (see L<"SERVER
+CONNECTIONS">).
+
+You can also configure innotop to automatically detect when a large deadlock
+needs to be replaced with a small one (see L<"auto_wipe_dl">).
+
+This mode displays the L<"deadlock_transactions"> and L<"deadlock_locks"> tables
+by default.
+
+=item F: InnoDB Foreign Key Errors
+
+This mode shows the last InnoDB foreign key error information, such as the
+table where it happened, when and who and what query caused it, and so on.
+
+InnoDB has a huge variety of foreign key error messages, and many of them are
+just hard to parse.  innotop doesn't always do the best job here, but there's
+so much code devoted to parsing this messy, unparseable output that innotop is
+likely never to be perfect in this regard.  If innotop doesn't show you what
+you need to see, just look at the status text directly.
+
+This mode displays the L<"fk_error"> table by default.
+
+=item I: InnoDB I/O Info
+
+This mode shows InnoDB's I/O statistics, including the I/O threads, pending I/O,
+file I/O miscellaneous, and log statistics.  It displays the L<"io_threads">,
+L<"pending_io">, L<"file_io_misc">, and L<"log_statistics"> tables by default.
+
+=item L: Locks
+
+This mode shows information about current locks.  At the moment only InnoDB
+locks are supported, and by default you'll only see locks for which transactions
+are waiting.  This information comes from the TRANSACTIONS section of the InnoDB
+status text.  If you have a very busy server, you may have frequent lock waits;
+it helps to be able to see which tables and indexes are the "hot spot" for
+locks.  If your server is running pretty well, this mode should show nothing.
+
+You can configure MySQL and innotop to monitor not only locks for which a
+transaction is waiting, but those currently held, too.  You can do this with the
+InnoDB Lock Monitor (L<http://dev.mysql.com/doc/en/innodb-monitor.html>).  It's
+not documented in the MySQL manual, but creating the lock monitor with the
+following statement also affects the output of SHOW INNODB STATUS, which innotop
+uses:
+
+  CREATE TABLE innodb_lock_monitor(a int) ENGINE=INNODB;
+
+This causes InnoDB to print its output to the MySQL file every 16 seconds or so,
+as stated in the manual, but it also makes the normal SHOW INNODB STATUS output
+include lock information, which innotop can parse and display (that's the
+undocumented feature).
+
+This means you can do what may have seemed impossible: to a limited extent
+(InnoDB truncates some information in the output), you can see which transaction
+holds the locks something else is waiting for.  You can also enable and disable
+the InnoDB Lock Monitor with the key mappings in this mode.
+
+This mode displays the L<"innodb_locks"> table by default.  Here's a sample of
+the screen when one connection is waiting for locks another connection holds:
+
+ _________________________________ InnoDB Locks __________________________
+ CXN        ID  Type    Waiting  Wait   Active  Mode  DB    Table  Index
+ localhost  12  RECORD        1  00:10   00:10  X     test  t1     PRIMARY
+ localhost  12  TABLE         0  00:10   00:10  IX    test  t1
+ localhost  12  RECORD        1  00:10   00:10  X     test  t1     PRIMARY
+ localhost  11  TABLE         0  00:00   00:25  IX    test  t1
+ localhost  11  RECORD        0  00:00   00:25  X     test  t1     PRIMARY
+
+You can see the first connection, ID 12, is waiting for a lock on the PRIMARY
+key on test.t1, and has been waiting for 10 seconds.  The second connection
+isn't waiting, because the Waiting column is 0, but it holds locks on the same
+index.  That tells you connection 11 is blocking connection 12.
+
+=item M: Master/Slave Replication Status
+
+This mode shows the output of SHOW SLAVE STATUS and SHOW MASTER STATUS in three
+tables.  The first two divide the slave's status into SQL and I/O thread status,
+and the last shows master status.  Filters are applied to eliminate non-slave
+servers from the slave tables, and non-master servers from the master table.
+
+This mode displays the L<"slave_sql_status">, L<"slave_io_status">, and
+L<"master_status"> tables by default.
+
+=item O: Open Tables
+
+This section comes from MySQL's SHOW OPEN TABLES command.  By default it is
+filtered to show tables which are in use by one or more queries, so you can
+get a quick look at which tables are 'hot'.  You can use this to guess which
+tables might be locked implicitly.
+
+This mode displays the L<"open_tables"> mode by default.
+
+=item Q: Query List
+
+This mode displays the output from SHOW FULL PROCESSLIST, much like B<mytop>'s
+query list mode.  This mode does B<not> show InnoDB-related information.  This
+is probably one of the most useful modes for general usage.
+
+There is an informative header that shows general status information about
+your server.  You can toggle it on and off with the 'h' key.  By default,
+innotop hides inactive processes and its own process.  You can toggle these on
+and off with the 'i' and 'a' keys.
+
+You can EXPLAIN a query from this mode with the 'e' key.  This displays the
+query's full text, the results of EXPLAIN, and in newer MySQL versions, even
+the optimized query resulting from EXPLAIN EXTENDED.  innotop also tries to
+rewrite certain queries to make them EXPLAIN-able.  For example, INSERT/SELECT
+statements are rewritable.
+
+This mode displays the L<"q_header"> and L<"processlist"> tables by default.
+
+=item R: InnoDB Row Operations and Semaphores
+
+This mode shows InnoDB row operations, row operation miscellaneous, semaphores,
+and information from the wait array.  It displays the L<"row_operations">,
+L<"row_operation_misc">, L<"semaphores">, and L<"wait_array"> tables by default.
+
+=item S: Variables & Status
+
+This mode calculates statistics, such as queries per second, and prints them out
+in several different styles.  You can show absolute values, or incremental values
+between ticks.
+
+You can switch between the views by pressing a key.  The 's' key prints a
+single line each time the screen updates, in the style of B<vmstat>.  The 'g'
+key changes the view to a graph of the same numbers, sort of like B<tload>.
+The 'v' key changes the view to a pivoted table of variable names on the left,
+with successive updates scrolling across the screen from left to right.  You can
+choose how many updates to put on the screen with the L<"num_status_sets">
+configuration variable.
+
+Headers may be abbreviated to fit on the screen in interactive operation.  You
+choose which variables to display with the 'c' key, which selects from
+predefined sets, or lets you create your own sets.  You can edit the current set
+with the 'e' key.
+
+This mode doesn't really display any tables like other modes.  Instead, it uses
+a table definition to extract and format the data, but it then transforms the
+result in special ways before outputting it.  It uses the L<"var_status"> table
+definition for this.
+
+=item T: InnoDB Transactions
+
+This mode shows transactions from the InnoDB monitor's output, in B<top>-like
+format.  This mode is the reason I wrote innotop.
+
+You can kill queries or processes with the 'k' and 'x' keys, and EXPLAIN a query
+with the 'e' or 'f' keys.  InnoDB doesn't print the full query in transactions,
+so explaining may not work right if the query is truncated.
+
+The informational header can be toggled on and off with the 'h' key.  By
+default, innotop hides inactive transactions and its own transaction.  You can
+toggle this on and off with the 'i' and 'a' keys.
+
+This mode displays the L<"t_header"> and L<"innodb_transactions"> tables by
+default.
+
+=back
+
+=head1 INNOTOP STATUS
+
+The first line innotop displays is a "status bar" of sorts.  What it contains
+depends on the mode you're in, and what servers you're monitoring.  The first
+few words are always [RO] (if readonly is set to 1), the innotop mode, such as
+"InnoDB Txns" for T mode, followed by a reminder to press '?' for help at any
+time.
+
+=head2 ONE SERVER
+
+The simplest case is when you're monitoring a single server.  In this case, the
+name of the connection is next on the status line.  This is the name you gave
+when you created the connection -- most likely the MySQL server's hostname.
+This is followed by the server's uptime.
+
+If you're in an InnoDB mode, such as T or B, the next word is "InnoDB" followed
+by some information about the SHOW INNODB STATUS output used to render the
+screen.  The first word is the number of seconds since the last SHOW INNODB
+STATUS, which InnoDB uses to calculate some per-second statistics.  The next is
+a smiley face indicating whether the InnoDB output is truncated.  If the smiley
+face is a :-), all is well; there is no truncation.  A :^| means the transaction
+list is so long, InnoDB has only printed out some of the transactions.  Finally,
+a frown :-( means the output is incomplete, which is probably due to a deadlock
+printing too much lock information (see L<"D: InnoDB Deadlocks">).
+
+The next two words indicate the server's queries per second (QPS) and how many
+threads (connections) exist.  Finally, the server's version number is the last
+thing on the line.
+
+=head2 MULTIPLE SERVERS
+
+If you are monitoring multiple servers (see L<"SERVER CONNECTIONS">), the status
+line does not show any details about individual servers.  Instead, it shows the
+names of the connections that are active.  Again, these are connection names you
+specified, which are likely to be the server's hostname.  A connection that has
+an error is prefixed with an exclamation point.
+
+If you are monitoring a group of servers (see L<"SERVER GROUPS">), the status
+line shows the name of the group.  If any connection in the group has an
+error, the group's name is followed by the fraction of the connections that
+don't have errors.
+
+See L<"ERROR HANDLING"> for more details about innotop's error handling.
+
+=head2 MONITORING A FILE
+
+If you give a filename on the command line, innotop will not connect to ANY
+servers at all.  It will watch the specified file for InnoDB status output and
+use that as its data source.  It will always show a single connection called
+'file'.  And since it can't connect to a server, it can't determine how long the
+server it's monitoring has been up; so it calculates the server's uptime as time
+since innotop started running.
+
+=head1 SERVER ADMINISTRATION
+
+While innotop is primarily a monitor that lets you watch and analyze your
+servers, it can also send commands to servers.  The most frequently useful
+commands are killing queries and stopping or starting slaves.
+
+You can kill a connection, or in newer versions of MySQL kill a query but not a
+connection, from L<"Q: Query List"> and L<"T: InnoDB Transactions"> modes.
+Press 'k' to issue a KILL command, or 'x' to issue a KILL QUERY command.
+innotop will prompt you for the server and/or connection ID to kill (innotop
+does not prompt you if there is only one possible choice for any input).
+innotop pre-selects the longest-running query, or the oldest connection.
+Confirm the command with 'y'.
+
+In L<"M: Master/Slave Replication Status"> mode, you can start and stop slaves
+with the 'a' and 'o' keys, respectively.  You can send these commands to many
+slaves at once.  innotop fills in a default command of START SLAVE or STOP SLAVE
+for you, but you can actually edit the command and send anything you wish, such
+as SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1 to make the slave skip one binlog event
+when it starts.
+
+You can also ask innotop to calculate the earliest binlog in use by any slave
+and issue a PURGE MASTER LOGS on the master.  Use the 'b' key for this.  innotop
+will prompt you for a master to run the command on, then prompt you for the
+connection names of that master's slaves (there is no way for innotop to
+determine this reliably itself).  innotop will find the minimum binlog in use by
+these slave connections and suggest it as the argument to PURGE MASTER LOGS.
+
+=head1 SERVER CONNECTIONS
+
+When you create a server connection using '@', innotop asks you for a series of
+inputs, as follows:
+
+=over
+
+=item DSN
+
+A DSN is a Data Source Name, which is the initial argument passed to the DBI
+module for connecting to a server.  It is usually of the form
+
+ DBI:mysql:;mysql_read_default_group=mysql;host=HOSTNAME
+
+Since this DSN is passed to the DBD::mysql driver, you should read the driver's
+documentation at L<"http://search.cpan.org/dist/DBD-mysql/lib/DBD/mysql.pm"> for
+the exact details on all the options you can pass the driver in the DSN.  You
+can read more about DBI at L<http://dbi.perl.org/docs/>, and especially at
+L<http://search.cpan.org/~timb/DBI/DBI.pm>.
+
+The mysql_read_default_group=mysql option lets the DBD driver read your MySQL
+options files, such as ~/.my.cnf on UNIX-ish systems.  You can use this to avoid
+specifying a username or password for the connection.
+
+=item InnoDB Deadlock Table
+
+This optional item tells innotop a table name it can use to deliberately create
+a small deadlock (see L<"D: InnoDB Deadlocks">).  If you specify this option,
+you just need to be sure the table doesn't exist, and that innotop can create
+and drop the table with the InnoDB storage engine.  You can safely omit or just
+accept the default if you don't intend to use this.
+
+=item Username
+
+innotop will ask you if you want to specify a username.  If you say 'y', it will
+then prompt you for a user name.  If you have a MySQL option file that specifies
+your username, you don't have to specify a username.
+
+The username defaults to your login name on the system you're running innotop on.
+
+=item Password
+
+innotop will ask you if you want to specify a password.  Like the username, the
+password is optional, but there's an additional prompt that asks if you want to
+save the password in the innotop configuration file.  If you don't save it in
+the configuration file, innotop will prompt you for a password each time it
+starts.  Passwords in the innotop configuration file are saved in plain text,
+not encrypted in any way.
+
+=back
+
+Once you finish answering these questions, you should be connected to a server.
+But innotop isn't limited to monitoring a single server; you can define many
+server connections and switch between them by pressing the '@' key.  See
+L<"SWITCHING BETWEEN CONNECTIONS">.
+
+=head1 SERVER GROUPS
+
+If you have multiple MySQL instances, you can put them into named groups, such
+as 'all', 'masters', and 'slaves', which innotop can monitor all together.
+
+You can choose which group to monitor with the '#' key, and you can press the
+TAB key to switch to the next group.  If you're not currently monitoring a
+group, pressing TAB selects the first group.
+
+To create a group, press the '#' key and type the name of your new group, then
+type the names of the connections you want the group to contain.
+
+=head1 SWITCHING BETWEEN CONNECTIONS
+
+innotop lets you quickly switch which servers you're monitoring.  The most basic
+way is by pressing the '@' key and typing the name(s) of the connection(s) you
+want to use.  This setting is per-mode, so you can monitor different connections
+in each mode, and innotop remembers which connections you choose.
+
+You can quickly switch to the 'next' connection in alphabetical order with the
+'n' key.  If you're monitoring a server group (see L<"SERVER GROUPS">) this will
+switch to the first connection.
+
+You can also type many connection names, and innotop will fetch and display data
+from them all.  Just separate the connection names with spaces, for example
+"server1 server2."  Again, if you type the name of a connection that doesn't
+exist, innotop will prompt you for connection information and create the
+connection.
+
+Another way to monitor multiple connections at once is with server groups.  You
+can use the TAB key to switch to the 'next' group in alphabetical order, or if
+you're not monitoring any groups, TAB will switch to the first group.
+
+innotop does not fetch data in parallel from connections, so if you are
+monitoring a large group or many connections, you may notice increased delay
+between ticks.
+
+When you monitor more than one connection, innotop's status bar changes.  See
+L<"INNOTOP STATUS">.
+
+=head1 ERROR HANDLING
+
+Error handling is not that important when monitoring a single connection, but is
+crucial when you have many active connections.  A crashed server or lost
+connection should not crash innotop.  As a result, innotop will continue to run
+even when there is an error; it just won't display any information from the
+connection that had an error.  Because of this, innotop's behavior might confuse
+you.  It's a feature, not a bug!
+
+innotop does not continue to query connections that have errors, because they
+may slow innotop and make it hard to use, especially if the error is a problem
+connecting and causes a long time-out.  Instead, innotop retries the connection
+occasionally to see if the error still exists.  If so, it will wait until some
+point in the future.  The wait time increases in ticks as the Fibonacci series,
+so it tries less frequently as time passes.
+
+Since errors might only happen in certain modes because of the SQL commands
+issued in those modes, innotop keeps track of which mode caused the error.  If
+you switch to a different mode, innotop will retry the connection instead of
+waiting.
+
+By default innotop will display the problem in red text at the bottom of the
+first table on the screen.  You can disable this behavior with the
+L<"show_cxn_errors_in_tbl"> configuration option, which is enabled by default.
+If the L<"debug"> option is enabled, innotop will display the error at the
+bottom of every table, not just the first.  And if L<"show_cxn_errors"> is
+enabled, innotop will print the error text to STDOUT as well.  Error messages
+might only display in the mode that caused the error, depending on the mode and
+whether innotop is avoiding querying that connection.
+
+=head1 NON-INTERACTIVE OPERATION
+
+You can run innotop in non-interactive mode, in which case it is entirely
+controlled from the configuration file and command-line options.  To start
+innotop in non-interactive mode, give the L"<--nonint"> command-line option.
+This changes innotop's behavior in the following ways:
+
+=over
+
+=item *
+
+Certain Perl modules are not loaded.  Term::Readline is not loaded, since
+innotop doesn't prompt interactively.  Term::ANSIColor and Win32::Console::ANSI
+modules are not loaded.  Term::ReadKey is still used, since innotop may have to
+prompt for connection passwords when starting up.
+
+=item *
+
+innotop does not clear the screen after each tick.
+
+=item *
+
+innotop does not persist any changes to the configuration file.
+
+=item *
+
+If L<"--count"> is given and innotop is in incremental mode (see L<"status_inc">
+and L<"--inc">), innotop actually refreshes one more time than specified so it
+can print incremental statistics.  This suppresses output during the first
+tick, so innotop may appear to hang.
+
+=item *
+
+innotop only displays the first table in each mode.  This is so the output can
+be easily processed with other command-line utilities such as awk and sed.  To
+change which tables display in each mode, see L<"TABLES">.  Since L<"Q: Query
+List"> mode is so important, innotop automatically disables the L<"q_header">
+table.  This ensures you'll see the L<"processlist"> table, even if you have
+innotop configured to show the q_header table during interactive operation.
+Similarly, in L<"T: InnoDB Transactions"> mode, the L<"t_header"> table is
+suppressed so you see only the L<"innodb_transactions"> table.
+
+=item *
+
+All output is tab-separated instead of being column-aligned with whitespace, and
+innotop prints the full contents of each table instead of only printing one
+screenful at a time.
+
+=item *
+
+innotop only prints column headers once instead of every tick (see
+L<"hide_hdr">).  innotop does not print table captions (see
+L<"display_table_captions">).  innotop ensures there are no empty lines in the
+output.
+
+=item *
+
+innotop does not honor the L<"shorten"> transformation, which normally shortens
+some numbers to human-readable formats.
+
+=item *
+
+innotop does not print a status line (see L<"INNOTOP STATUS">).
+
+=back
+
+=head1 CONFIGURING
+
+Nearly everything about innotop is configurable.  Most things are possible to
+change with built-in commands, but you can also edit the configuration file.
+
+While running innotop, press the '$' key to bring up the configuration editing
+dialog.  Press another key to select the type of data you want to edit:
+
+=over
+
+=item S: Statement Sleep Times
+
+Edits SQL statement sleep delays, which make innotop pause for the specified
+amount of time after executing a statement.  See L<"SQL STATEMENTS"> for a
+definition of each statement and what it does.  By default innotop does not
+delay after any statements.
+
+This feature is included so you can customize the side-effects caused by
+monitoring your server.  You may not see any effects, but some innotop users
+have noticed that certain MySQL versions under very high load with InnoDB
+enabled take longer than usual to execute SHOW GLOBAL STATUS.  If innotop calls
+SHOW FULL PROCESSLIST immediately afterward, the processlist contains more
+queries than the machine actually averages at any given moment.  Configuring
+innotop to pause briefly after calling SHOW GLOBAL STATUS alleviates this
+effect.
+
+Sleep times are stored in the L<"stmt_sleep_times"> section of the configuration
+file.  Fractional-second sleeps are supported, subject to your hardware's
+limitations.
+
+=item c: Edit Columns
+
+Starts the table editor on one of the displayed tables.  See L<"TABLE EDITOR">.
+An alternative way to start the table editor without entering the configuration
+dialog is with the '^' key.
+
+=item g: General Configuration
+
+Starts the configuration editor to edit global and mode-specific configuration
+variables (see L<"MODES">).  innotop prompts you to choose a variable from among
+the global and mode-specific ones depending on the current mode.
+
+=item k: Row-Coloring Rules
+
+Starts the row-coloring rules editor on one of the displayed table(s).  See
+L<"COLORS"> for details.
+
+=item p: Manage Plugins
+
+Starts the plugin configuration editor.  See L<"PLUGINS"> for details.
+
+=item s: Server Groups
+
+Lets you create and edit server groups.  See L<"SERVER GROUPS">.
+
+=item t: Choose Displayed Tables
+
+Lets you choose which tables to display in this mode.  See L<"MODES"> and
+L<"TABLES">.
+
+=back
+
+=head1 CONFIGURATION FILE
+
+innotop's default configuration file locations are $HOME/.innotop and
+/etc/innotop/innotop.conf, and they are looked for in that order.  If the first
+configuration file exists, the second will not be processed.  Those can be
+overridden with the L<"--config"> command-line option.  You can edit it by hand
+safely, however innotop reads the configuration file when it starts, and, if
+readonly is set to 0, writes it out again when it exits.  Thus, if readonly is
+set to 0, any changes you make by hand while innotop is running will be lost.
+
+innotop doesn't store its entire configuration in the configuration file.  It
+has a huge set of default configuration values that it holds only in memory,
+and the configuration file only overrides these defaults.  When you customize a
+default setting, innotop notices, and then stores the customizations into the
+file.  This keeps the file size down, makes it easier to edit, and makes
+upgrades easier.
+
+A configuration file is read-only be default.  You can override that with
+L<"--write">.  See L<"readonly">.
+
+The configuration file is arranged into sections like an INI file.  Each
+section begins with [section-name] and ends with [/section-name].  Each
+section's entries have a different syntax depending on the data they need to
+store.  You can put comments in the file; any line that begins with a #
+character is a comment.  innotop will not read the comments, so it won't write
+them back out to the file when it exits.  Comments in read-only configuration
+files are still useful, though.
+
+The first line in the file is innotop's version number.  This lets innotop
+notice when the file format is not backwards-compatible, and upgrade smoothly
+without destroying your customized configuration.
+
+The following list describes each section of the configuration file and the data
+it contains:
+
+=over
+
+=item general
+
+The 'general' section contains global configuration variables and variables that
+may be mode-specific, but don't belong in any other section.  The syntax is a
+simple key=value list.  innotop writes a comment above each value to help you
+edit the file by hand.
+
+=over
+
+=item S_func
+
+Controls S mode presentation (see L<"S: Variables & Status">).  If g, values are
+graphed; if s, values are like vmstat; if p, values are in a pivoted table.
+
+=item S_set
+
+Specifies which set of variables to display in L<"S: Variables & Status"> mode.
+See L<"VARIABLE SETS">.
+
+=item auto_wipe_dl
+
+Instructs innotop to automatically wipe large deadlocks when it notices them.
+When this happens you may notice a slight delay.  At the next tick, you will
+usually see the information that was being truncated by the large deadlock.
+
+=item charset
+
+Specifies what kind of characters to allow through the L<"no_ctrl_char">
+transformation.  This keeps non-printable characters from confusing a
+terminal when you monitor queries that contain binary data, such as images.
+
+The default is 'ascii', which considers anything outside normal ASCII to be a
+control character.  The other allowable values are 'unicode' and 'none'.  'none'
+considers every character a control character, which can be useful for
+collapsing ALL text fields in queries.
+
+=item cmd_filter
+
+This is the prefix that filters variables in L<"C: Command Summary"> mode.
+
+=item color
+
+Whether terminal coloring is permitted.
+
+=item cxn_timeout
+
+On MySQL versions 4.0.3 and newer, this variable is used to set the connection's
+timeout, so MySQL doesn't close the connection if it is not used for a while.
+This might happen because a connection isn't monitored in a particular mode, for
+example.
+
+=item debug
+
+This option enables more verbose errors and makes innotop more strict in some
+places.  It can help in debugging filters and other user-defined code.  It also
+makes innotop write a lot of information to L<"debugfile"> when there is a
+crash.
+
+=item debugfile
+
+A file to which innotop will write information when there is a crash.  See
+L<"FILES">.
+
+=item display_table_captions
+
+innotop displays a table caption above most tables.  This variable suppresses or
+shows captions on all tables globally.  Some tables are configured with the
+hide_caption property, which overrides this.
+
+=item global
+
+Whether to show GLOBAL variables and status.  innotop only tries to do this on
+servers which support the GLOBAL option to SHOW VARIABLES and SHOW STATUS.  In
+some MySQL versions, you need certain privileges to do this; if you don't have
+them, innotop will not be able to fetch any variable and status data.  This
+configuration variable lets you run innotop and fetch what data you can even
+without the elevated privileges.
+
+I can no longer find or reproduce the situation where GLOBAL wasn't allowed, but
+I know there was one.
+
+=item graph_char
+
+Defines the character to use when drawing graphs in L<"S: Variables & Status">
+mode.
+
+=item header_highlight
+
+Defines how to highlight column headers.  This only works if Term::ANSIColor is
+available.  Valid values are 'bold' and 'underline'.
+
+=item hide_hdr
+
+Hides column headers globally.
+
+=item interval
+
+The interval at which innotop will refresh its data (ticks).  The interval is
+implemented as a sleep time between ticks, so the true interval will vary
+depending on how long it takes innotop to fetch and render data.
+
+This variable accepts fractions of a second.
+
+=item mode
+
+The mode in which innotop should start.  Allowable arguments are the same as the
+key presses that select a mode interactively.  See L<"MODES">.
+
+=item num_digits
+
+How many digits to show in fractional numbers and percents.  This variable's
+range is between 0 and 9 and can be set directly from L<"S: Variables & Status">
+mode with the '+' and '-' keys.  It is used in the L<"set_precision">,
+L<"shorten">, and L<"percent"> transformations.
+
+=item num_status_sets
+
+Controls how many sets of status variables to display in pivoted L<"S: Variables
+& Status"> mode.  It also controls the number of old sets of variables innotop
+keeps in its memory, so the larger this variable is, the more memory innotop
+uses.
+
+=item plugin_dir
+
+Specifies where plugins can be found.  By default, innotop stores plugins in the
+'plugins' subdirectory of your innotop configuration directory.
+
+=item readonly
+
+Whether the configuration file is readonly.  This cannot be set interactively.
+
+=item show_cxn_errors
+
+Makes innotop print connection errors to STDOUT.  See L<"ERROR HANDLING">.
+
+=item show_cxn_errors_in_tbl
+
+Makes innotop display connection errors as rows in the first table on screen.
+See L<"ERROR HANDLING">.
+
+=item show_percent
+
+Adds a '%' character after the value returned by the L<"percent">
+transformation.
+
+=item show_statusbar
+
+Controls whether to show the status bar in the display.  See L<"INNOTOP
+STATUS">.
+
+=item skip_innodb
+
+Disables fetching SHOW INNODB STATUS, in case your server(s) do not have InnoDB
+enabled and you don't want innotop to try to fetch it.  This can also be useful
+when you don't have the SUPER privilege, required to run SHOW INNODB STATUS.
+
+=item status_inc
+
+Whether to show absolute or incremental values for status variables.
+Incremental values are calculated as an offset from the last value innotop saw
+for that variable.  This is a global setting, but will probably become
+mode-specific at some point.  Right now it is honored a bit inconsistently; some
+modes don't pay attention to it.
+
+=back
+
+=item plugins
+
+This section holds a list of package names of active plugins.  If the plugin
+exists, innotop will activate it.  See L<"PLUGINS"> for more information.
+
+=item filters
+
+This section holds user-defined filters (see L<"FILTERS">).  Each line is in the
+format filter_name=text='filter text' tbls='table list'.
+
+The filter text is the text of the subroutine's code.  The table list is a list
+of tables to which the filter can apply.  By default, user-defined filters apply
+to the table for which they were created, but you can manually override that by
+editing the definition in the configuration file.
+
+=item active_filters
+
+This section stores which filters are active on each table.  Each line is in the
+format table_name=filter_list.
+
+=item tbl_meta
+
+This section stores user-defined or user-customized columns (see L<"COLUMNS">).
+Each line is in the format col_name=properties, where the properties are a
+name=quoted-value list.
+
+=item connections
+
+This section holds the server connections you have defined.  Each line is in
+the format name=properties, where the properties are a name=value list.  The
+properties are self-explanatory, and the only one that is treated specially is
+'pass' which is only present if 'savepass' is set.  This section of the
+configuration file will be skipped if any DSN, username, or password
+command-line options are used.  See L<"SERVER CONNECTIONS">.
+
+=item active_connections
+
+This section holds a list of which connections are active in each mode.  Each
+line is in the format mode_name=connection_list.
+
+=item server_groups
+
+This section holds server groups.  Each line is in the format
+name=connection_list.  See L<"SERVER GROUPS">.
+
+=item active_server_groups
+
+This section holds a list of which server group is active in each mode.  Each
+line is in the format mode_name=server_group.
+
+=item max_values_seen
+
+This section holds the maximum values seen for variables.  This is used to scale
+the graphs in L<"S: Variables & Status"> mode.  Each line is in the format
+name=value.
+
+=item active_columns
+
+This section holds table column lists.  Each line is in the format
+tbl_name=column_list.  See L<"COLUMNS">.
+
+=item sort_cols
+
+This section holds the sort definition.  Each line is in the format
+tbl_name=column_list.  If a column is prefixed with '-', that column sorts
+descending.  See L<"SORTING">.
+
+=item visible_tables
+
+This section defines which tables are visible in each mode.  Each line is in the
+format mode_name=table_list.  See L<"TABLES">.
+
+=item varsets
+
+This section defines variable sets for use in L<"S: Status & Variables"> mode.
+Each line is in the format name=variable_list.  See L<"VARIABLE SETS">.
+
+=item colors
+
+This section defines colorization rules.  Each line is in the format
+tbl_name=property_list.  See L<"COLORS">.
+
+=item stmt_sleep_times
+
+This section contains statement sleep times.  Each line is in the format
+statement_name=sleep_time.  See L<"S: Statement Sleep Times">.
+
+=item group_by
+
+This section contains column lists for table group_by expressions.  Each line is
+in the format tbl_name=column_list.  See L<"GROUPING">.
+
+=back
+
+=head1 CUSTOMIZING
+
+You can customize innotop a great deal.  For example, you can:
+
+=over
+
+=item *
+
+Choose which tables to display, and in what order.
+
+=item *
+
+Choose which columns are in those tables, and create new columns.
+
+=item *
+
+Filter which rows display with built-in filters, user-defined filters, and
+quick-filters.
+
+=item *
+
+Sort the rows to put important data first or group together related rows.
+
+=item *
+
+Highlight rows with color.
+
+=item *
+
+Customize the alignment, width, and formatting of columns, and apply
+transformations to columns to extract parts of their values or format the values
+as you wish (for example, shortening large numbers to familiar units).
+
+=item *
+
+Design your own expressions to extract and combine data as you need.  This gives
+you unlimited flexibility.
+
+=back
+
+All these and more are explained in the following sections.
+
+=head2 TABLES
+
+A table is what you'd expect: a collection of columns.  It also has some other
+properties, such as a caption.  Filters, sorting rules, and colorization rules
+belong to tables and are covered in later sections.
+
+Internally, table meta-data is defined in a data structure called %tbl_meta.
+This hash holds all built-in table definitions, which contain a lot of default
+instructions to innotop.  The meta-data includes the caption, a list of columns
+the user has customized, a list of columns, a list of visible columns, a list of
+filters, color rules, a sort-column list, sort direction, and some information
+about the table's data sources.  Most of this is customizable via the table
+editor (see L<"TABLE EDITOR">).
+
+You can choose which tables to show by pressing the '$' key.  See L<"MODES"> and
+L<"TABLES">.
+
+The table life-cycle is as follows:
+
+=over
+
+=item *
+
+Each table begins with a data source, which is an array of hashes.  See below
+for details on data sources.
+
+=item *
+
+Each element of the data source becomes a row in the final table.
+
+=item *
+
+For each element in the data source, innotop extracts values from the source and
+creates a row.  This row is another hash, which later steps will refer to as
+$set.  The values innotop extracts are determined by the table's columns.  Each
+column has an extraction subroutine, compiled from an expression (see
+L<"EXPRESSIONS">).  The resulting row is a hash whose keys are named the same as
+the column name.
+
+=item *
+
+innotop filters the rows, removing those that don't need to be displayed.  See
+L<"FILTERS">.
+
+=item *
+
+innotop sorts the rows.  See L<"SORTING">.
+
+=item *
+
+innotop groups the rows together, if specified.  See L<"GROUPING">.
+
+=item *
+
+innotop colorizes the rows.  See L<"COLORS">.
+
+=item *
+
+innotop transforms the column values in each row.  See L<"TRANSFORMATIONS">.
+
+=item *
+
+innotop optionally pivots the rows (see L<"PIVOTING">), then filters and sorts
+them.
+
+=item *
+
+innotop formats and justifies the rows as a table.  During this step, innotop
+applies further formatting to the column values, including alignment, maximum
+and minimum widths.  innotop also does final error checking to ensure there are
+no crashes due to undefined values.  innotop then adds a caption if specified,
+and the table is ready to print.
+
+=back
+
+The lifecycle is slightly different if the table is pivoted, as noted above.  To
+clarify, if the table is pivoted, the process is extract, group, transform,
+pivot, filter, sort, create.  If it's not pivoted, the process is extract,
+filter, sort, group, color, transform, create.  This slightly convoluted process
+doesn't map all that well to SQL, but pivoting complicates things pretty
+thoroughly.  Roughly speaking, filtering and sorting happen as late as needed to
+effect the final result as you might expect, but as early as possible for
+efficiency.
+
+Each built-in table is described below:
+
+=over
+
+=item adaptive_hash_index
+
+Displays data about InnoDB's adaptive hash index.  Data source:
+L<"STATUS_VARIABLES">.
+
+=item buffer_pool
+
+Displays data about InnoDB's buffer pool.  Data source: L<"STATUS_VARIABLES">.
+
+=item cmd_summary
+
+Displays weighted status variables.  Data source: L<"STATUS_VARIABLES">.
+
+=item deadlock_locks
+
+Shows which locks were held and waited for by the last detected deadlock.  Data
+source: L<"DEADLOCK_LOCKS">.
+
+=item deadlock_transactions
+
+Shows transactions involved in the last detected deadlock.  Data source:
+L<"DEADLOCK_TRANSACTIONS">.
+
+=item explain
+
+Shows the output of EXPLAIN.  Data source: L<"EXPLAIN">.
+
+=item file_io_misc
+
+Displays data about InnoDB's file and I/O operations.  Data source:
+L<"STATUS_VARIABLES">.
+
+=item fk_error
+
+Displays various data about InnoDB's last foreign key error.  Data source:
+L<"STATUS_VARIABLES">.
+
+=item innodb_locks
+
+Displays InnoDB locks.  Data source: L<"INNODB_LOCKS">.
+
+=item innodb_transactions
+
+Displays data about InnoDB's current transactions.  Data source:
+L<"INNODB_TRANSACTIONS">.
+
+=item insert_buffers
+
+Displays data about InnoDB's insert buffer.  Data source: L<"STATUS_VARIABLES">.
+
+=item io_threads
+
+Displays data about InnoDB's I/O threads.  Data source: L<"IO_THREADS">.
+
+=item log_statistics
+
+Displays data about InnoDB's logging system.  Data source: L<"STATUS_VARIABLES">.
+
+=item master_status
+
+Displays replication master status.  Data source: L<"STATUS_VARIABLES">.
+
+=item open_tables
+
+Displays open tables.  Data source: L<"OPEN_TABLES">.
+
+=item page_statistics
+
+Displays InnoDB page statistics.  Data source: L<"STATUS_VARIABLES">.
+
+=item pending_io
+
+Displays InnoDB pending I/O operations.  Data source: L<"STATUS_VARIABLES">.
+
+=item processlist
+
+Displays current MySQL processes (threads/connections).  Data source:
+L<"PROCESSLIST">.
+
+=item q_header
+
+Displays various status values.  Data source: L<"STATUS_VARIABLES">.
+
+=item row_operation_misc
+
+Displays data about InnoDB's row operations.  Data source:
+L<"STATUS_VARIABLES">.
+
+=item row_operations
+
+Displays data about InnoDB's row operations.  Data source:
+L<"STATUS_VARIABLES">.
+
+=item semaphores
+
+Displays data about InnoDB's semaphores and mutexes.  Data source:
+L<"STATUS_VARIABLES">.
+
+=item slave_io_status
+
+Displays data about the slave I/O thread.  Data source: 
+L<"STATUS_VARIABLES">.
+
+=item slave_sql_status
+
+Displays data about the slave SQL thread.  Data source: L<"STATUS_VARIABLES">.
+
+=item t_header
+
+Displays various InnoDB status values.  Data source: L<"STATUS_VARIABLES">.
+
+=item var_status
+
+Displays user-configurable data.  Data source: L<"STATUS_VARIABLES">.
+
+=item wait_array
+
+Displays data about InnoDB's OS wait array.  Data source: L<"OS_WAIT_ARRAY">.
+
+=back
+
+=head2 COLUMNS
+
+Columns belong to tables.  You can choose a table's columns by pressing the '^'
+key, which starts the L<"TABLE EDITOR"> and lets you choose and edit columns.
+Pressing 'e' from within the table editor lets you edit the column's properties:
+
+=over
+
+=item *
+
+hdr: a column header.  This appears in the first row of the table.
+
+=item *
+
+just: justification.  '-' means left-justified and '' means right-justified,
+just as with printf formatting codes (not a coincidence).
+
+=item *
+
+dec: whether to further align the column on the decimal point.
+
+=item *
+
+num: whether the column is numeric.  This affects how values are sorted
+(lexically or numerically).
+
+=item *
+
+label: a small note about the column, which appears in dialogs that help the
+user choose columns.
+
+=item *
+
+src: an expression that innotop uses to extract the column's data from its
+source (see L<"DATA SOURCES">).  See L<"EXPRESSIONS"> for more on expressions.
+
+=item *
+
+minw: specifies a minimum display width.  This helps stabilize the display,
+which makes it easier to read if the data is changing frequently.
+
+=item *
+
+maxw: similar to minw.
+
+=item *
+
+trans: a list of column transformations.  See L<"TRANSFORMATIONS">.
+
+=item *
+
+agg: an aggregate function.  See L<"GROUPING">.  The default is L<"first">.
+
+=item *
+
+aggonly: controls whether the column only shows when grouping is enabled on the
+table (see L<"GROUPING">).  By default, this is disabled.  This means columns
+will always be shown by default, whether grouping is enabled or not.  If a
+column's aggonly is set true, the column will appear when you toggle grouping on
+the table.  Several columns are set this way, such as the count column on
+L<"processlist"> and L<"innodb_transactions">, so you don't see a count when the
+grouping isn't enabled, but you do when it is.
+
+=back
+
+=head2 FILTERS
+
+Filters remove rows from the display.  They behave much like a WHERE clause in
+SQL.  innotop has several built-in filters, which remove irrelevant information
+like inactive queries, but you can define your own as well.  innotop also lets
+you create quick-filters, which do not get saved to the configuration file, and
+are just an easy way to quickly view only some rows.
+
+You can enable or disable a filter on any table.  Press the '%' key (mnemonic: %
+looks kind of like a line being filtered between two circles) and choose which
+table you want to filter, if asked.  You'll then see a list of possible filters
+and a list of filters currently enabled for that table.  Type the names of
+filters you want to apply and press Enter.
+
+=head3 USER-DEFINED FILTERS
+
+If you type a name that doesn't exist, innotop will prompt you to create the
+filter.  Filters are easy to create if you know Perl, and not hard if you don't.
+What you're doing is creating a subroutine that returns true if the row should
+be displayed.  The row is a hash reference passed to your subroutine as $set.
+
+For example, imagine you want to filter the processlist table so you only see
+queries that have been running more than five minutes.  Type a new name for your
+filter, and when prompted for the subroutine body, press TAB to initiate your
+terminal's auto-completion.  You'll see the names of the columns in the
+L<"processlist"> table (innotop generally tries to help you with auto-completion
+lists).  You want to filter on the 'time' column.  Type the text "$set->{time} >
+300" to return true when the query is more than five minutes old.  That's all
+you need to do.
+
+In other words, the code you're typing is surrounded by an implicit context,
+which looks like this:
+
+ sub filter {
+    my ( $set ) = @_;
+    # YOUR CODE HERE
+ }
+
+If your filter doesn't work, or if something else suddenly behaves differently,
+you might have made an error in your filter, and innotop is silently catching
+the error.  Try enabling L<"debug"> to make innotop throw an error instead.
+
+=head3 QUICK-FILTERS
+
+innotop's quick-filters are a shortcut to create a temporary filter that doesn't
+persist when you restart innotop.  To create a quick-filter, press the '/' key.
+innotop will prompt you for the column name and filter text.  Again, you can use
+auto-completion on column names.  The filter text can be just the text you want
+to "search for."  For example, to filter the L<"processlist"> table on queries
+that refer to the products table, type '/' and then 'info product'.
+
+The filter text can actually be any Perl regular expression, but of course a
+literal string like 'product' works fine as a regular expression.
+
+Behind the scenes innotop compiles the quick-filter into a specially tagged
+filter that is otherwise like any other filter.  It just isn't saved to the
+configuration file.
+
+To clear quick-filters, press the '\' key and innotop will clear them all at
+once.
+
+=head2 SORTING
+
+innotop has sensible built-in defaults to sort the most important rows to the
+top of the table.  Like anything else in innotop, you can customize how any
+table is sorted.
+
+To start the sort dialog, start the L<"TABLE EDITOR"> with the '^' key, choose a
+table if necessary, and press the 's' key.  You'll see a list of columns you can
+use in the sort expression and the current sort expression, if any.  Enter a
+list of columns by which you want to sort and press Enter.  If you want to
+reverse sort, prefix the column name with a minus sign.  For example, if you
+want to sort by column a ascending, then column b descending, type 'a -b'.  You
+can also explicitly add a + in front of columns you want to sort ascending, but
+it's not required.
+
+Some modes have keys mapped to open this dialog directly, and to quickly reverse
+sort direction.  Press '?' as usual to see which keys are mapped in any mode.
+
+=head2 GROUPING
+
+innotop can group, or aggregate, rows together (the terms are used
+interchangeably).  This is quite similar to an SQL GROUP BY clause.  You can
+specify to group on certain columns, or if you don't specify any, the entire set
+of rows is treated as one group.  This is quite like SQL so far, but unlike SQL,
+you can also select un-grouped columns.  innotop actually aggregates every
+column.  If you don't explicitly specify a grouping function, the default is
+'first'.  This is basically a convenience so you don't have to specify an
+aggregate function for every column you want in the result.
+
+You can quickly toggle grouping on a table with the '=' key, which toggles its
+aggregate property.  This property doesn't persist to the config file.
+
+The columns by which the table is grouped are specified in its group_by
+property.  When you turn grouping on, innotop places the group_by columns at the
+far left of the table, even if they're not supposed to be visible.  The rest of
+the visible columns appear in order after them.
+
+Two tables have default group_by lists and a count column built in:
+L<"processlist"> and L<"innodb_transactions">.  The grouping is by connection
+and status, so you can quickly see how many queries or transactions are in a
+given status on each server you're monitoring.  The time columns are aggregated
+as a sum; other columns are left at the default 'first' aggregation.
+
+By default, the table shown in L<"S: Variables & Status"> mode also uses
+grouping so you can monitor variables and status across many servers.  The
+default aggregation function in this mode is 'avg'.
+
+Valid grouping functions are defined in the %agg_funcs hash.  They include
+
+=over
+
+=item first
+
+Returns the first element in the group.
+
+=item count
+
+Returns the number of elements in the group, including undefined elements, much
+like SQL's COUNT(*).
+
+=item avg
+
+Returns the average of defined elements in the group.
+
+=item sum
+
+Returns the sum of elements in the group.
+
+=back
+
+Here's an example of grouping at work.  Suppose you have a very busy server with
+hundreds of open connections, and you want to see how many connections are in
+what status.  Using the built-in grouping rules, you can press 'Q' to enter
+L<"Q: Query List"> mode.  Press '=' to toggle grouping (if necessary, select the
+L<"processlist"> table when prompted).
+
+Your display might now look like the following:
+
+ Query List (? for help) localhost, 32:33, 0.11 QPS, 1 thd, 5.0.38-log
+ CXN        Cmd        Cnt  ID      User   Host           Time   Query       
+ localhost  Query      49    12933  webusr localhost      19:38  SELECT * FROM
+ localhost  Sending Da 23     2383  webusr localhost      12:43  SELECT col1,
+ localhost  Sleep      120     140  webusr localhost    5:18:12
+ localhost  Statistics 12    19213  webusr localhost      01:19  SELECT * FROM
+
+That's actually quite a worrisome picture.  You've got a lot of idle connections
+(Sleep), and some connections executing queries (Query and Sending Data).
+That's okay, but you also have a lot in Statistics status, collectively spending
+over a minute.  That means the query optimizer is having a really hard time
+optimizing your statements.  Something is wrong; it should normally take
+milliseconds to optimize queries.  You might not have seen this pattern if you
+didn't look at your connections in aggregate.  (This is a made-up example, but
+it can happen in real life).
+
+=head2 PIVOTING
+
+innotop can pivot a table for more compact display, similar to a Pivot Table in
+a spreadsheet (also known as a crosstab).  Pivoting a table makes columns into
+rows.  Assume you start with this table:
+
+ foo bar
+ === ===
+ 1   3
+ 2   4
+
+After pivoting, the table will look like this:
+
+ name set0 set1
+ ==== ==== ====
+ foo  1    2
+ bar  3    4
+
+To get reasonable results, you might need to group as well as pivoting.
+innotop currently does this for L<"S: Variables & Status"> mode.
+
+=head2 COLORS
+
+By default, innotop highlights rows with color so you can see at a glance which
+rows are more important.  You can customize the colorization rules and add your
+own to any table.  Open the table editor with the '^' key, choose a table if
+needed, and press 'o' to open the color editor dialog.
+
+The color editor dialog displays the rules applied to the table, in the order
+they are evaluated.  Each row is evaluated against each rule to see if the rule
+matches the row; if it does, the row gets the specified color, and no further
+rules are evaluated.  The rules look like the following:
+
+ state  eq  Locked       black on_red
+ cmd    eq  Sleep        white       
+ user   eq  system user  white       
+ cmd    eq  Connect      white       
+ cmd    eq  Binlog Dump  white       
+ time   >   600          red         
+ time   >   120          yellow      
+ time   >   60           green       
+ time   >   30           cyan        
+
+This is the default rule set for the L<"processlist"> table.  In order of
+priority, these rules make locked queries black on a red background, "gray out"
+connections from replication and sleeping queries, and make queries turn from
+cyan to red as they run longer.
+
+(For some reason, the ANSI color code "white" is actually a light gray.  Your
+terminal's display may vary; experiment to find colors you like).
+
+You can use keystrokes to move the rules up and down, which re-orders their
+priority.  You can also delete rules and add new ones.  If you add a new rule,
+innotop prompts you for the column, an operator for the comparison, a value
+against which to compare the column, and a color to assign if the rule matches.
+There is auto-completion and prompting at each step.
+
+The value in the third step needs to be correctly quoted.  innotop does not try
+to quote the value because it doesn't know whether it should treat the value as
+a string or a number.  If you want to compare the column against a string, as
+for example in the first rule above, you should enter 'Locked' surrounded by
+quotes.  If you get an error message about a bareword, you probably should have
+quoted something.
+
+=head2 EXPRESSIONS
+
+Expressions are at the core of how innotop works, and are what enables you to
+extend innotop as you wish.  Recall the table lifecycle explained in
+L<"TABLES">.  Expressions are used in the earliest step, where it extracts
+values from a data source to form rows.
+
+It does this by calling a subroutine for each column, passing it the source data
+set, a set of current values, and a set of previous values.  These are all
+needed so the subroutine can calculate things like the difference between this
+tick and the previous tick.
+
+The subroutines that extract the data from the set are compiled from
+expressions.  This gives significantly more power than just naming the values to
+fill the columns, because it allows the column's value to be calculated from
+whatever data is necessary, but avoids the need to write complicated and lengthy
+Perl code.
+
+innotop begins with a string of text that can look as simple as a value's name
+or as complicated as a full-fledged Perl expression.  It looks at each
+'bareword' token in the string and decides whether it's supposed to be a key
+into the $set hash.  A bareword is an unquoted value that isn't already
+surrounded by code-ish things like dollar signs or curly brackets.  If innotop
+decides that the bareword isn't a function or other valid Perl code, it converts
+it into a hash access.  After the whole string is processed, innotop compiles a
+subroutine, like this:
+
+ sub compute_column_value {
+    my ( $set, $cur, $pre ) = @_;
+    my $val = # EXPANDED STRING GOES HERE
+    return $val;
+ }
+
+Here's a concrete example, taken from the header table L<"q_header"> in L<"Q:
+Query List"> mode.  This expression calculates the qps, or Queries Per Second,
+column's values, from the values returned by SHOW STATUS:
+
+ Questions/Uptime_hires
+
+innotop decides both words are barewords, and transforms this expression into
+the following Perl code:
+
+ $set->{Questions}/$set->{Uptime_hires}
+
+When surrounded by the rest of the subroutine's code, this is executable Perl
+that calculates a high-resolution queries-per-second value.
+
+The arguments to the subroutine are named $set, $cur, and $pre.  In most cases,
+$set and $cur will be the same values.  However, if L<"status_inc"> is set, $cur
+will not be the same as $set, because $set will already contain values that are
+the incremental difference between $cur and $pre.
+
+Every column in innotop is computed by subroutines compiled in the same fashion.
+There is no difference between innotop's built-in columns and user-defined
+columns.  This keeps things consistent and predictable.
+
+=head2 TRANSFORMATIONS
+
+Transformations change how a value is rendered.  For example, they can take a
+number of seconds and display it in H:M:S format.  The following transformations
+are defined:
+
+=over
+
+=item commify
+
+Adds commas to large numbers every three decimal places.
+
+=item dulint_to_int
+
+Accepts two unsigned integers and converts them into a single longlong.  This is
+useful for certain operations with InnoDB, which uses two integers as
+transaction identifiers, for example.
+
+=item no_ctrl_char
+
+Removes quoted control characters from the value.  This is affected by the
+L<"charset"> configuration variable.
+
+This transformation only operates within quoted strings, for example, values to
+a SET clause in an UPDATE statement.  It will not alter the UPDATE statement,
+but will collapse the quoted string to [BINARY] or [TEXT], depending on the
+charset.
+
+=item percent
+
+Converts a number to a percentage by multiplying it by two, formatting it with
+L<"num_digits"> digits after the decimal point, and optionally adding a percent
+sign (see L<"show_percent">).
+
+=item secs_to_time
+
+Formats a number of seconds as time in days+hours:minutes:seconds format.
+
+=item set_precision
+
+Formats numbers with L<"num_digits"> number of digits after the decimal point.
+
+=item shorten
+
+Formats a number as a unit of 1024 (k/M/G/T) and with L<"num_digits"> number of
+digits after the decimal point.
+
+=back
+
+=head2 TABLE EDITOR
+
+The innotop table editor lets you customize tables with keystrokes.  You start
+the table editor with the '^' key.  If there's more than one table on the
+screen, it will prompt you to choose one of them.  Once you do, innotop will
+show you something like this:
+
+ Editing table definition for Buffer Pool.  Press ? for help, q to quit.
+ name               hdr          label                  src          
+ cxn                CXN          Connection from which  cxn          
+ buf_pool_size      Size         Buffer pool size       IB_bp_buf_poo
+ buf_free           Free Bufs    Buffers free in the b  IB_bp_buf_fre
+ pages_total        Pages        Pages total            IB_bp_pages_t
+ pages_modified     Dirty Pages  Pages modified (dirty  IB_bp_pages_m
+ buf_pool_hit_rate  Hit Rate     Buffer pool hit rate   IB_bp_buf_poo
+ total_mem_alloc    Memory       Total memory allocate  IB_bp_total_m
+ add_pool_alloc     Add'l Pool   Additonal pool alloca  IB_bp_add_poo
+
+The first line shows which table you're editing, and reminds you again to press
+'?' for a list of key mappings.  The rest is a tabular representation of the
+table's columns, because that's likely what you're trying to edit.  However, you
+can edit more than just the table's columns; this screen can start the filter
+editor, color rule editor, and more.
+
+Each row in the display shows a single column in the table you're editing, along
+with a couple of its properties such as its header and source expression (see
+L<"EXPRESSIONS">).
+
+The key mappings are Vim-style, as in many other places.  Pressing 'j' and 'k'
+moves the highlight up or down.  You can then (d)elete or (e)dit the highlighted
+column.  You can also (a)dd a column to the table.  This actually just activates
+one of the columns already defined for the table; it prompts you to choose from
+among the columns available but not currently displayed.  Finally, you can
+re-order the columns with the '+' and '-' keys.
+
+You can do more than just edit the columns with the table editor, you can also
+edit other properties, such as the table's sort expression and group-by
+expression.  Press '?' to see the full list, of course.
+
+If you want to really customize and create your own column, as opposed to just
+activating a built-in one that's not currently displayed, press the (n)ew key,
+and innotop will prompt you for the information it needs:
+
+=over
+
+=item *
+
+The column name: this needs to be a word without any funny characters, e.g. just
+letters, numbers and underscores.
+
+=item *
+
+The column header: this is the label that appears at the top of the column, in
+the table header.  This can have spaces and funny characters, but be careful not
+to make it too wide and waste space on-screen.
+
+=item *
+
+The column's data source: this is an expression that determines what data from
+the source (see L<"TABLES">) innotop will put into the column.  This can just be
+the name of an item in the source, or it can be a more complex expression, as
+described in L<"EXPRESSIONS">.
+
+=back
+
+Once you've entered the required data, your table has a new column.  There is no
+difference between this column and the built-in ones; it can have all the same
+properties and behaviors.  innotop will write the column's definition to the
+configuration file, so it will persist across sessions.
+
+Here's an example: suppose you want to track how many times your slaves have
+retried transactions.  According to the MySQL manual, the
+Slave_retried_transactions status variable gives you that data: "The total
+number of times since startup that the replication slave SQL thread has retried
+transactions. This variable was added in version 5.0.4."  This is appropriate to
+add to the L<"slave_sql_status"> table.
+
+To add the column, switch to the replication-monitoring mode with the 'M' key,
+and press the '^' key to start the table editor.  When prompted, choose
+slave_sql_status as the table, then press 'n' to create the column.  Type
+'retries' as the column name, 'Retries' as the column header, and
+'Slave_retried_transactions' as the source.  Now the column is created, and you
+see the table editor screen again.  Press 'q' to exit the table editor, and
+you'll see your column at the end of the table.
+
+=head1 VARIABLE SETS
+
+Variable sets are used in L<"S: Variables & Status"> mode to define more easily
+what variables you want to monitor.  Behind the scenes they are compiled to a
+list of expressions, and then into a column list so they can be treated just
+like columns in any other table, in terms of data extraction and
+transformations.  However, you're protected from the tedious details by a syntax
+that ought to feel very natural to you: a SQL SELECT list.
+
+The data source for variable sets, and indeed the entire S mode, is the
+combination of SHOW STATUS, SHOW VARIABLES, and SHOW INNODB STATUS.  Imagine
+that you had a huge table with one column per variable returned from those
+statements.  That's the data source for variable sets.  You can now query this
+data source just like you'd expect.  For example:
+
+ Questions, Uptime, Questions/Uptime as QPS
+
+Behind the scenes innotop will split that variable set into three expressions,
+compile them and turn them into a table definition, then extract as usual.  This
+becomes a "variable set," or a "list of variables you want to monitor."
+
+innotop lets you name and save your variable sets, and writes them to the
+configuration file.  You can choose which variable set you want to see with the
+'c' key, or activate the next and previous sets with the '>' and '<' keys.
+There are many built-in variable sets as well, which should give you a good
+start for creating your own.  Press 'e' to edit the current variable set, or
+just to see how it's defined.  To create a new one, just press 'c' and type its
+name.
+
+You may want to use some of the functions listed in L<"TRANSFORMATIONS"> to help
+format the results.  In particular, L<"set_precision"> is often useful to limit
+the number of digits you see.  Extending the above example, here's how:
+
+ Questions, Uptime, set_precision(Questions/Uptime) as QPS
+
+Actually, this still needs a little more work.  If your L<"interval"> is less
+than one second, you might be dividing by zero because Uptime is incremental in
+this mode by default.  Instead, use Uptime_hires:
+
+ Questions, Uptime, set_precision(Questions/Uptime_hires) as QPS
+
+This example is simple, but it shows how easy it is to choose which variables
+you want to monitor.
+
+=head1 PLUGINS
+
+innotop has a simple but powerful plugin mechanism by which you can extend
+or modify its existing functionality, and add new functionality.  innotop's
+plugin functionality is event-based: plugins register themselves to be called
+when events happen.  They then have a chance to influence the event.
+
+An innotop plugin is a Perl module placed in innotop's L<"plugin_dir">
+directory.  On UNIX systems, you can place a symbolic link to the module instead
+of putting the actual file there.  innotop automatically discovers the file.  If
+there is a corresponding entry in the L<"plugins"> configuration file section,
+innotop loads and activates the plugin.
+
+The module must conform to innotop's plugin interface.  Additionally, the source
+code of the module must be written in such a way that innotop can inspect the
+file and determine the package name and description.
+
+=head2 Package Source Convention
+
+innotop inspects the plugin module's source to determine the Perl package name.
+It looks for a line of the form "package Foo;" and if found, considers the
+plugin's package name to be Foo.  Of course the package name can be a valid Perl
+package name, with double semicolons and so on.
+
+It also looks for a description in the source code, to make the plugin editor
+more human-friendly.  The description is a comment line of the form "#
+description: Foo", where "Foo" is the text innotop will consider to be the
+plugin's description.
+
+=head2 Plugin Interface
+
+The innotop plugin interface is quite simple: innotop expects the plugin to be
+an object-oriented module it can call certain methods on.  The methods are
+
+=over
+
+=item new(%variables)
+
+This is the plugin's constructor.  It is passed a hash of innotop's variables,
+which it can manipulate (see L<"Plugin Variables">).  It must return a reference
+to the newly created plugin object.
+
+At construction time, innotop has only loaded the general configuration and
+created the default built-in variables with their default contents (which is
+quite a lot).  Therefore, the state of the program is exactly as in the innotop
+source code, plus the configuration variables from the L<"general"> section in
+the config file.
+
+If your plugin manipulates the variables, it is changing global data, which is
+shared by innotop and all plugins.  Plugins are loaded in the order they're
+listed in the config file.  Your plugin may load before or after another plugin,
+so there is a potential for conflict or interaction between plugins if they
+modify data other plugins use or modify.
+
+=item register_for_events()
+
+This method must return a list of events in which the plugin is interested, if
+any.  See L<"Plugin Events"> for the defined events.  If the plugin returns an
+event that's not defined, the event is ignored.
+
+=item event handlers
+
+The plugin must implement a method named the same as each event for which it has
+registered.  In other words, if the plugin returns qw(foo bar) from
+register_for_events(), it must have foo() and bar() methods.  These methods are
+callbacks for the events.  See L<"Plugin Events"> for more details about each
+event.
+
+=back
+
+=head2 Plugin Variables
+
+The plugin's constructor is passed a hash of innotop's variables, which it can
+manipulate.  It is probably a good idea if the plugin object saves a copy of it
+for later use.  The variables are defined in the innotop variable
+%pluggable_vars, and are as follows:
+
+=over
+
+=item action_for
+
+A hashref of key mappings.  These are innotop's global hot-keys.
+
+=item agg_funcs
+
+A hashref of functions that can be used for grouping.  See L<"GROUPING">.
+
+=item config
+
+The global configuration hash.
+
+=item connections
+
+A hashref of connection specifications.  These are just specifications of how to
+connect to a server.
+
+=item dbhs
+
+A hashref of innotop's database connections.  These are actual DBI connection
+objects.
+
+=item filters
+
+A hashref of filters applied to table rows.  See L<"FILTERS"> for more.
+
+=item modes
+
+A hashref of modes.  See L<"MODES"> for more.
+
+=item server_groups
+
+A hashref of server groups.  See L<"SERVER GROUPS">.
+
+=item tbl_meta
+
+A hashref of innotop's table meta-data, with one entry per table (see
+L<"TABLES"> for more information).
+
+=item trans_funcs
+
+A hashref of transformation functions.  See L<"TRANSFORMATIONS">.
+
+=item var_sets
+
+A hashref of variable sets.  See L<"VARIABLE SETS">.
+
+=back
+
+=head2 Plugin Events
+
+Each event is defined somewhere in the innotop source code.  When innotop runs
+that code, it executes the callback function for each plugin that expressed its
+interest in the event.  innotop passes some data for each event.  The events are
+defined in the %event_listener_for variable, and are as follows:
+
+=over
+
+=item extract_values($set, $cur, $pre, $tbl)
+
+This event occurs inside the function that extracts values from a data source.
+The arguments are the set of values, the current values, the previous values,
+and the table name.
+
+=item set_to_tbl
+
+Events are defined at many places in this subroutine, which is responsible for
+turning an arrayref of hashrefs into an arrayref of lines that can be printed to
+the screen.  The events all pass the same data: an arrayref of rows and the name
+of the table being created.  The events are set_to_tbl_pre_filter,
+set_to_tbl_pre_sort,set_to_tbl_pre_group, set_to_tbl_pre_colorize,
+set_to_tbl_pre_transform, set_to_tbl_pre_pivot, set_to_tbl_pre_create,
+set_to_tbl_post_create.
+
+=item draw_screen($lines)
+
+This event occurs inside the subroutine that prints the lines to the screen.
+$lines is an arrayref of strings.
+
+=back
+
+=head2 Simple Plugin Example
+
+The easiest way to explain the plugin functionality is probably with a simple
+example.  The following module adds a column to the beginning of every table and
+sets its value to 1.
+
+ use strict;
+ use warnings FATAL => 'all';
+ package Innotop::Plugin::Example;
+ # description: Adds an 'example' column to every table
+ sub new {
+    my ( $class, %vars ) = @_;
+    # Store reference to innotop's variables in $self
+    my $self = bless { %vars }, $class;
+    # Design the example column
+    my $col = {
+       hdr   => 'Example',
+       just  => '',
+       dec   => 0,
+       num   => 1,
+       label => 'Example',
+       src   => 'example', # Get data from this column in the data source
+       tbl   => '',
+       trans => [],
+    };
+    # Add the column to every table.
+    my $tbl_meta = $vars{tbl_meta};
+    foreach my $tbl ( values %$tbl_meta ) {
+       # Add the column to the list of defined columns
+       $tbl->{cols}->{example} = $col;
+       # Add the column to the list of visible columns
+       unshift @{$tbl->{visible}}, 'example';
+    }
+    # Be sure to return a reference to the object.
+    return $self;
+ }
+ # I'd like to be called when a data set is being rendered into a table, please.
+ sub register_for_events {
+    my ( $self ) = @_;
+    return qw(set_to_tbl_pre_filter);
+ }
+ # This method will be called when the event fires.
+ sub set_to_tbl_pre_filter {
+    my ( $self, $rows, $tbl ) = @_;
+    # Set the example column's data source to the value 1.
+    foreach my $row ( @$rows ) {
+       $row->{example} = 1;
+    }
+ }
+ 1;
+
+=head2 Plugin Editor
+
+The plugin editor lets you view the plugins innotop discovered and activate or
+deactivate them.  Start the editor by pressing $ to start the configuration
+editor from any mode.  Press the 'p' key to start the plugin editor.  You'll see
+a list of plugins innotop discovered.  You can use the 'j' and 'k' keys to move
+the highlight to the desired one, then press the * key to toggle it active or
+inactive.  Exit the editor and restart innotop for the changes to take effect.
+
+=head1 SQL STATEMENTS
+
+innotop uses a limited set of SQL statements to retrieve data from MySQL for
+display.  The statements are customized depending on the server version against
+which they are executed; for example, on MySQL 5 and newer, INNODB_STATUS
+executes "SHOW ENGINE INNODB STATUS", while on earlier versions it executes
+"SHOW INNODB STATUS".  The statements are as follows:
+
+ Statement           SQL executed
+ =================== ===============================
+ INNODB_STATUS       SHOW [ENGINE] INNODB STATUS
+ KILL_CONNECTION     KILL
+ KILL_QUERY          KILL QUERY
+ OPEN_TABLES         SHOW OPEN TABLES
+ PROCESSLIST         SHOW FULL PROCESSLIST
+ SHOW_MASTER_LOGS    SHOW MASTER LOGS
+ SHOW_MASTER_STATUS  SHOW MASTER STATUS
+ SHOW_SLAVE_STATUS   SHOW SLAVE STATUS
+ SHOW_STATUS         SHOW [GLOBAL] STATUS
+ SHOW_VARIABLES      SHOW [GLOBAL] VARIABLES
+
+=head1 DATA SOURCES
+
+Each time innotop extracts values to create a table (see L<"EXPRESSIONS"> and
+L<"TABLES">), it does so from a particular data source.  Largely because of the
+complex data extracted from SHOW INNODB STATUS, this is slightly messy.  SHOW
+INNODB STATUS contains a mixture of single values and repeated values that form
+nested data sets.
+
+Whenever innotop fetches data from MySQL, it adds two extra bits to each set:
+cxn and Uptime_hires.  cxn is the name of the connection from which the data
+came.  Uptime_hires is a high-resolution version of the server's Uptime status
+variable, which is important if your L<"interval"> setting is sub-second.
+
+Here are the kinds of data sources from which data is extracted:
+
+=over
+
+=item STATUS_VARIABLES
+
+This is the broadest category, into which the most kinds of data fall.  It
+begins with the combination of SHOW STATUS and SHOW VARIABLES, but other sources
+may be included as needed, for example, SHOW MASTER STATUS and SHOW SLAVE
+STATUS, as well as many of the non-repeated values from SHOW INNODB STATUS.
+
+=item DEADLOCK_LOCKS
+
+This data is extracted from the transaction list in the LATEST DETECTED DEADLOCK
+section of SHOW INNODB STATUS.  It is nested two levels deep: transactions, then
+locks.
+
+=item DEADLOCK_TRANSACTIONS
+
+This data is from the transaction list in the LATEST DETECTED DEADLOCK
+section of SHOW INNODB STATUS.  It is nested one level deep.
+
+=item EXPLAIN
+
+This data is from the result set returned by EXPLAIN.
+
+=item INNODB_TRANSACTIONS
+
+This data is from the TRANSACTIONS section of SHOW INNODB STATUS.
+
+=item IO_THREADS
+
+This data is from the list of threads in the the FILE I/O section of SHOW INNODB
+STATUS.
+
+=item INNODB_LOCKS
+
+This data is from the TRANSACTIONS section of SHOW INNODB STATUS and is nested
+two levels deep.
+
+=item OPEN_TABLES
+
+This data is from SHOW OPEN TABLES.
+
+=item PROCESSLIST
+
+This data is from SHOW FULL PROCESSLIST.
+
+=item OS_WAIT_ARRAY
+
+This data is from the SEMAPHORES section of SHOW INNODB STATUS and is nested one
+level deep.  It comes from the lines that look like this:
+
+ --Thread 1568861104 has waited at btr0cur.c line 424 ....
+
+=back
+
+=head1 MYSQL PRIVILEGES
+
+=over
+
+=item *
+
+You must connect to MySQL as a user who has the SUPER privilege for many of the
+functions.
+
+=item *
+
+If you don't have the SUPER privilege, you can still run some functions, but you
+won't necessarily see all the same data.
+
+=item *
+
+You need the PROCESS privilege to see the list of currently running queries in Q
+mode.
+
+=item *
+
+You need special privileges to start and stop slave servers.
+
+=item *
+
+You need appropriate privileges to create and drop the deadlock tables if needed
+(see L<"SERVER CONNECTIONS">).
+
+=back
+
+=head1 SYSTEM REQUIREMENTS
+
+You need Perl to run innotop, of course.  You also need a few Perl modules: DBI,
+DBD::mysql,  Term::ReadKey, and Time::HiRes.  These should be included with most
+Perl distributions, but in case they are not, I recommend using versions
+distributed with your operating system or Perl distribution, not from CPAN.
+Term::ReadKey in particular has been known to cause problems if installed from
+CPAN.
+
+If you have Term::ANSIColor, innotop will use it to format headers more readably
+and compactly.  (Under Microsoft Windows, you also need Win32::Console::ANSI for
+terminal formatting codes to be honored).  If you install Term::ReadLine,
+preferably Term::ReadLine::Gnu, you'll get nice auto-completion support.
+
+I run innotop on Gentoo GNU/Linux, Debian and Ubuntu, and I've had feedback from
+people successfully running it on Red Hat, CentOS, Solaris, and Mac OSX.  I
+don't see any reason why it won't work on other UNIX-ish operating systems, but
+I don't know for sure.  It also runs on Windows under ActivePerl without
+problem.
+
+innotop has been used on MySQL versions 3.23.58, 4.0.27, 4.1.0, 4.1.22, 5.0.26,
+5.1.15, and 5.2.3.  If it doesn't run correctly for you, that is a bug that
+should be reported.
+
+=head1 FILES
+
+$HOMEDIR/.innotop and/or /etc/innotop are used to store
+configuration information.  Files include the configuration file innotop.conf,
+the core_dump file which contains verbose error messages if L<"debug"> is
+enabled, and the plugins/ subdirectory.
+
+=head1 GLOSSARY OF TERMS
+
+=over
+
+=item tick
+
+A tick is a refresh event, when innotop re-fetches data from connections and
+displays it.
+
+=back
+
+=head1 ACKNOWLEDGEMENTS
+
+The following people and organizations are acknowledged for various reasons.
+Hopefully no one has been forgotten.
+
+Allen K. Smith,
+Aurimas Mikalauskas,
+Bartosz Fenski,
+Brian Miezejewski,
+Christian Hammers, 
+Cyril Scetbon,
+Dane Miller,
+David Multer,
+Dr. Frank Ullrich,
+Giuseppe Maxia,
+Google.com Site Reliability Engineers,
+Google Code,
+Jan Pieter Kunst,
+Jari Aalto,
+Jay Pipes,
+Jeremy Zawodny,
+Johan Idren,
+Kristian Kohntopp,
+Lenz Grimmer,
+Maciej Dobrzanski,
+Michiel Betel,
+MySQL AB,
+Paul McCullagh,
+Sebastien Estienne,
+Sourceforge.net,
+Steven Kreuzer,
+The Gentoo MySQL Team,
+Trevor Price,
+Yaar Schnitman,
+and probably more people that have not been included.
+
+(If your name has been misspelled, it's probably out of fear of putting
+international characters into this documentation; earlier versions of Perl might
+not be able to compile it then).
+
+=head1 COPYRIGHT, LICENSE AND WARRANTY
+
+This program is copyright (c) 2006 Baron Schwartz.
+Feedback and improvements are welcome.
+
+THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+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; OR the Perl Artistic License.  On UNIX and similar
+systems, you can issue `man perlgpl' or `man perlartistic' to read these
+licenses.
+
+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., 59 Temple
+Place, Suite 330, Boston, MA  02111-1307  USA.
+
+Execute innotop and press '!' to see this information at any time.
+
+=head1 AUTHOR
+
+Originally written by Baron Schwartz; currently maintained by Aaron Racine.
+
+=head1 BUGS
+
+You can report bugs, ask for improvements, and get other help and support at
+L<http://code.google.com/p/innotop/>.  There are mailing lists, a source code
+browser, a bug tracker, etc.  Please use these instead of contacting the
+maintainer or author directly, as it makes our job easier and benefits others if the
+discussions are permanent and public.  Of course, if you need to contact us in
+private, please do.
+
+=cut
diff --git a/mysql-wsrep-5.6/debian/additions/innotop/innotop.1 b/mysql-wsrep-5.6/debian/additions/innotop/innotop.1
new file mode 100644 (file)
index 0000000..b2e7fce
--- /dev/null
@@ -0,0 +1,2084 @@
+.\" Automatically generated by Pod::Man 2.1801 (Pod::Simple 3.07)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings.  \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
+.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+.    ds -- \(*W-
+.    ds PI pi
+.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
+.    ds L" ""
+.    ds R" ""
+.    ds C` ""
+.    ds C' ""
+'br\}
+.el\{\
+.    ds -- \|\(em\|
+.    ds PI \(*p
+.    ds L" ``
+.    ds R" ''
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD.  Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.ie \nF \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
+..
+.    nr % 0
+.    rr F
+.\}
+.el \{\
+.    de IX
+..
+.\}
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
+.    \" fudge factors for nroff and troff
+.if n \{\
+.    ds #H 0
+.    ds #V .8m
+.    ds #F .3m
+.    ds #[ \f1
+.    ds #] \fP
+.\}
+.if t \{\
+.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+.    ds #V .6m
+.    ds #F 0
+.    ds #[ \&
+.    ds #] \&
+.\}
+.    \" simple accents for nroff and troff
+.if n \{\
+.    ds ' \&
+.    ds ` \&
+.    ds ^ \&
+.    ds , \&
+.    ds ~ ~
+.    ds /
+.\}
+.if t \{\
+.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+.    \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+.    \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+.    \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+.    ds : e
+.    ds 8 ss
+.    ds o a
+.    ds d- d\h'-1'\(ga
+.    ds D- D\h'-1'\(hy
+.    ds th \o'bp'
+.    ds Th \o'LP'
+.    ds ae ae
+.    ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "INNOTOP 1"
+.TH INNOTOP 1 "2009-03-09" "perl v5.10.0" "User Contributed Perl Documentation"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH "NAME"
+innotop \- MySQL and InnoDB transaction/status monitor.
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+To monitor servers normally:
+.PP
+.Vb 1
+\& innotop
+.Ve
+.PP
+To monitor InnoDB status information from a file:
+.PP
+.Vb 1
+\& innotop /var/log/mysql/mysqld.err
+.Ve
+.PP
+To run innotop non-interactively in a pipe-and-filter configuration:
+.PP
+.Vb 1
+\& innotop \-\-count 5 \-d 1 \-n
+.Ve
+.PP
+To monitor a database on another system using a particular username and password:
+.PP
+.Vb 1
+\& innotop \-u <username> \-p <password> \-h <hostname>
+.Ve
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+innotop monitors MySQL servers.  Each of its modes shows you a different aspect
+of what's happening in the server.  For example, there's a mode for monitoring
+replication, one for queries, and one for transactions.  innotop refreshes its
+data periodically, so you see an updating view.
+.PP
+innotop has lots of features for power users, but you can start and run it with
+virtually no configuration.  If you're just getting started, see
+\&\*(L"QUICK-START\*(R".  Press '?' at any time while running innotop for
+context-sensitive help.
+.SH "QUICK-START"
+.IX Header "QUICK-START"
+To start innotop, open a terminal or command prompt.  If you have installed
+innotop on your system, you should be able to just type \*(L"innotop\*(R" and press
+Enter; otherwise, you will need to change to innotop's directory and type \*(L"perl
+innotop\*(R".
+.PP
+With no options specified, innotop will attempt to connect to a MySQL server on
+localhost using mysql_read_default_group=client for other connection
+parameters.  If you need to specify a different username and password, use the
+\&\-u and \-p options, respectively.  To monitor a MySQL database on another
+host, use the \-h option.
+.PP
+After you've connected, innotop should show you something like the following:
+.PP
+.Vb 1
+\& [RO] Query List (? for help) localhost, 01:11:19, 449.44 QPS, 14/7/163 con/run
+\& 
+\& CXN        When   Load  QPS    Slow  QCacheHit  KCacheHit  BpsIn    BpsOut 
+\& localhost  Total  0.00  1.07k   697      0.00%     98.17%  476.83k  242.83k
+\&
+\& CXN        Cmd    ID         User  Host      DB   Time   Query
+\& localhost  Query  766446598  test  10.0.0.1  foo  00:02  INSERT INTO table (
+.Ve
+.PP
+(This sample is truncated at the right so it will fit on a terminal when running
+\&'man innotop')
+.PP
+If your server is busy, you'll see more output.  Notice the first line on the
+screen, which tells you that readonly is set to true ([\s-1RO\s0]), what mode you're
+in and what server you're connected to.  You can change to other modes with
+keystrokes; press 'T' to switch to a list of InnoDB transactions, for example.
+.PP
+Press the '?' key to see what keys are active in the current mode.  You can
+press any of these keys and innotop will either take the requested action or
+prompt you for more input.  If your system has Term::ReadLine support, you can
+use \s-1TAB\s0 and other keys to auto-complete and edit input.
+.PP
+To quit innotop, press the 'q' key.
+.SH "OPTIONS"
+.IX Header "OPTIONS"
+innotop is mostly configured via its configuration file, but some of the
+configuration options can come from the command line.  You can also specify a
+file to monitor for InnoDB status output; see \*(L"\s-1MONITORING\s0 A \s-1FILE\s0\*(R" for more
+details.
+.PP
+You can negate some options by prefixing the option name with \-\-no.  For
+example, \-\-noinc (or \-\-no\-inc) negates \*(L"\-\-inc\*(R".
+.IP "\-\-color" 4
+.IX Item "--color"
+Enable or disable terminal coloring.  Corresponds to the \*(L"color\*(R" config file
+setting.
+.IP "\-\-config" 4
+.IX Item "--config"
+Specifies a configuration file to read.  This option is non-sticky, that is to
+say it does not persist to the configuration file itself.
+.IP "\-\-count" 4
+.IX Item "--count"
+Refresh only the specified number of times (ticks) before exiting.  Each refresh
+is a pause for \*(L"interval\*(R" seconds, followed by requesting data from MySQL
+connections and printing it to the terminal.
+.IP "\-\-delay" 4
+.IX Item "--delay"
+Specifies the amount of time to pause between ticks (refreshes).  Corresponds to
+the configuration option \*(L"interval\*(R".
+.IP "\-\-help" 4
+.IX Item "--help"
+Print a summary of command-line usage and exit.
+.IP "\-\-host" 4
+.IX Item "--host"
+Host to connect to.
+.IP "\-\-inc" 4
+.IX Item "--inc"
+Specifies whether innotop should display absolute numbers or relative numbers
+(offsets from their previous values).  Corresponds to the configuration option
+\&\*(L"status_inc\*(R".
+.IP "\-\-mode" 4
+.IX Item "--mode"
+Specifies the mode in which innotop should start.  Corresponds to the
+configuration option \*(L"mode\*(R".
+.IP "\-\-nonint" 4
+.IX Item "--nonint"
+Enable non-interactive operation.  See \*(L"NON-INTERACTIVE \s-1OPERATION\s0\*(R" for more.
+.IP "\-\-password" 4
+.IX Item "--password"
+Password to use for connection.
+.IP "\-\-port" 4
+.IX Item "--port"
+Port to use for connection.
+.IP "\-\-skipcentral" 4
+.IX Item "--skipcentral"
+Don't read the central configuration file.
+.IP "\-\-user" 4
+.IX Item "--user"
+User to use for connection.
+.IP "\-\-version" 4
+.IX Item "--version"
+Output version information and exit.
+.IP "\-\-write" 4
+.IX Item "--write"
+Sets the configuration option \*(L"readonly\*(R" to 0, making innotop write the
+running configuration to ~/.innotop/innotop.conf on exit, if no configuration
+file was loaded at start-up.
+.SH "HOTKEYS"
+.IX Header "HOTKEYS"
+innotop is interactive, and you control it with key-presses.
+.IP "\(bu" 4
+Uppercase keys switch between modes.
+.IP "\(bu" 4
+Lowercase keys initiate some action within the current mode.
+.IP "\(bu" 4
+Other keys do something special like change configuration or show the
+innotop license.
+.PP
+Press '?' at any time to see the currently active keys and what they do.
+.SH "MODES"
+.IX Header "MODES"
+Each of innotop's modes retrieves and displays a particular type of data from
+the servers you're monitoring.  You switch between modes with uppercase keys.
+The following is a brief description of each mode, in alphabetical order.  To
+switch to the mode, press the key listed in front of its heading in the
+following list:
+.IP "B: InnoDB Buffers" 4
+.IX Item "B: InnoDB Buffers"
+This mode displays information about the InnoDB buffer pool, page statistics,
+insert buffer, and adaptive hash index.  The data comes from \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0.
+.Sp
+This mode contains the \*(L"buffer_pool\*(R", \*(L"page_statistics\*(R",
+\&\*(L"insert_buffers\*(R", and \*(L"adaptive_hash_index\*(R" tables by default.
+.IP "C: Command Summary" 4
+.IX Item "C: Command Summary"
+This mode is similar to mytop's Command Summary mode.  It shows the
+\&\*(L"cmd_summary\*(R" table, which looks something like the following:
+.Sp
+.Vb 8
+\& Command Summary (? for help) localhost, 25+07:16:43, 2.45 QPS, 3 thd, 5.0.40
+\& _\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_ Command Summary _\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_
+\& Name                    Value    Pct     Last Incr  Pct    
+\& Select_scan             3244858  69.89%          2  100.00%
+\& Select_range            1354177  29.17%          0    0.00%
+\& Select_full_join          39479   0.85%          0    0.00%
+\& Select_full_range_join     4097   0.09%          0    0.00%
+\& Select_range_check            0   0.00%          0    0.00%
+.Ve
+.Sp
+The command summary table is built by extracting variables from
+\&\*(L"\s-1STATUS_VARIABLES\s0\*(R".  The variables must be numeric and must match the prefix
+given by the \*(L"cmd_filter\*(R" configuration variable.  The variables are then
+sorted by value descending and compared to the last variable, as shown above.
+The percentage columns are percentage of the total of all variables in the
+table, so you can see the relative weight of the variables.
+.Sp
+The example shows what you see if the prefix is \*(L"Select_\*(R".  The default
+prefix is \*(L"Com_\*(R".  You can choose a prefix with the 's' key.
+.Sp
+It's rather like running \s-1SHOW\s0 \s-1VARIABLES\s0 \s-1LIKE\s0 \*(L"prefix%\*(R" with memory and
+nice formatting.
+.Sp
+Values are aggregated across all servers.  The Pct columns are not correctly
+aggregated across multiple servers.  This is a known limitation of the grouping
+algorithm that may be fixed in the future.
+.IP "D: InnoDB Deadlocks" 4
+.IX Item "D: InnoDB Deadlocks"
+This mode shows the transactions involved in the last InnoDB deadlock.  A second
+table shows the locks each transaction held and waited for.  A deadlock is
+caused by a cycle in the waits-for graph, so there should be two locks held and
+one waited for unless the deadlock information is truncated.
+.Sp
+InnoDB puts deadlock information before some other information in the \s-1SHOW\s0
+\&\s-1INNODB\s0 \s-1STATUS\s0 output.  If there are a lot of locks, the deadlock information can
+grow very large, and there is a limit on the size of the \s-1SHOW\s0 \s-1INNODB\s0
+\&\s-1STATUS\s0 output.  A large deadlock can fill the entire output, or even be
+truncated, and prevent you from seeing other information at all.  If you are
+running innotop in another mode, for example T mode, and suddenly you don't see
+anything, you might want to check and see if a deadlock has wiped out the data
+you need.
+.Sp
+If it has, you can create a small deadlock to replace the large one.  Use the
+\&'w' key to 'wipe' the large deadlock with a small one.  This will not work
+unless you have defined a deadlock table for the connection (see \*(L"\s-1SERVER\s0
+\&\s-1CONNECTIONS\s0\*(R").
+.Sp
+You can also configure innotop to automatically detect when a large deadlock
+needs to be replaced with a small one (see \*(L"auto_wipe_dl\*(R").
+.Sp
+This mode displays the \*(L"deadlock_transactions\*(R" and \*(L"deadlock_locks\*(R" tables
+by default.
+.IP "F: InnoDB Foreign Key Errors" 4
+.IX Item "F: InnoDB Foreign Key Errors"
+This mode shows the last InnoDB foreign key error information, such as the
+table where it happened, when and who and what query caused it, and so on.
+.Sp
+InnoDB has a huge variety of foreign key error messages, and many of them are
+just hard to parse.  innotop doesn't always do the best job here, but there's
+so much code devoted to parsing this messy, unparseable output that innotop is
+likely never to be perfect in this regard.  If innotop doesn't show you what
+you need to see, just look at the status text directly.
+.Sp
+This mode displays the \*(L"fk_error\*(R" table by default.
+.IP "I: InnoDB I/O Info" 4
+.IX Item "I: InnoDB I/O Info"
+This mode shows InnoDB's I/O statistics, including the I/O threads, pending I/O,
+file I/O miscellaneous, and log statistics.  It displays the \*(L"io_threads\*(R",
+\&\*(L"pending_io\*(R", \*(L"file_io_misc\*(R", and \*(L"log_statistics\*(R" tables by default.
+.IP "L: Locks" 4
+.IX Item "L: Locks"
+This mode shows information about current locks.  At the moment only InnoDB
+locks are supported, and by default you'll only see locks for which transactions
+are waiting.  This information comes from the \s-1TRANSACTIONS\s0 section of the InnoDB
+status text.  If you have a very busy server, you may have frequent lock waits;
+it helps to be able to see which tables and indexes are the \*(L"hot spot\*(R" for
+locks.  If your server is running pretty well, this mode should show nothing.
+.Sp
+You can configure MySQL and innotop to monitor not only locks for which a
+transaction is waiting, but those currently held, too.  You can do this with the
+InnoDB Lock Monitor (<http://dev.mysql.com/doc/en/innodb\-monitor.html>).  It's
+not documented in the MySQL manual, but creating the lock monitor with the
+following statement also affects the output of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0, which innotop
+uses:
+.Sp
+.Vb 1
+\&  CREATE TABLE innodb_lock_monitor(a int) ENGINE=INNODB;
+.Ve
+.Sp
+This causes InnoDB to print its output to the MySQL file every 16 seconds or so,
+as stated in the manual, but it also makes the normal \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0 output
+include lock information, which innotop can parse and display (that's the
+undocumented feature).
+.Sp
+This means you can do what may have seemed impossible: to a limited extent
+(InnoDB truncates some information in the output), you can see which transaction
+holds the locks something else is waiting for.  You can also enable and disable
+the InnoDB Lock Monitor with the key mappings in this mode.
+.Sp
+This mode displays the \*(L"innodb_locks\*(R" table by default.  Here's a sample of
+the screen when one connection is waiting for locks another connection holds:
+.Sp
+.Vb 7
+\& _\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_ InnoDB Locks _\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_\|_
+\& CXN        ID  Type    Waiting  Wait   Active  Mode  DB    Table  Index
+\& localhost  12  RECORD        1  00:10   00:10  X     test  t1     PRIMARY
+\& localhost  12  TABLE         0  00:10   00:10  IX    test  t1
+\& localhost  12  RECORD        1  00:10   00:10  X     test  t1     PRIMARY
+\& localhost  11  TABLE         0  00:00   00:25  IX    test  t1
+\& localhost  11  RECORD        0  00:00   00:25  X     test  t1     PRIMARY
+.Ve
+.Sp
+You can see the first connection, \s-1ID\s0 12, is waiting for a lock on the \s-1PRIMARY\s0
+key on test.t1, and has been waiting for 10 seconds.  The second connection
+isn't waiting, because the Waiting column is 0, but it holds locks on the same
+index.  That tells you connection 11 is blocking connection 12.
+.IP "M: Master/Slave Replication Status" 4
+.IX Item "M: Master/Slave Replication Status"
+This mode shows the output of \s-1SHOW\s0 \s-1SLAVE\s0 \s-1STATUS\s0 and \s-1SHOW\s0 \s-1MASTER\s0 \s-1STATUS\s0 in three
+tables.  The first two divide the slave's status into \s-1SQL\s0 and I/O thread status,
+and the last shows master status.  Filters are applied to eliminate non-slave
+servers from the slave tables, and non-master servers from the master table.
+.Sp
+This mode displays the \*(L"slave_sql_status\*(R", \*(L"slave_io_status\*(R", and
+\&\*(L"master_status\*(R" tables by default.
+.IP "O: Open Tables" 4
+.IX Item "O: Open Tables"
+This section comes from MySQL's \s-1SHOW\s0 \s-1OPEN\s0 \s-1TABLES\s0 command.  By default it is
+filtered to show tables which are in use by one or more queries, so you can
+get a quick look at which tables are 'hot'.  You can use this to guess which
+tables might be locked implicitly.
+.Sp
+This mode displays the \*(L"open_tables\*(R" mode by default.
+.IP "Q: Query List" 4
+.IX Item "Q: Query List"
+This mode displays the output from \s-1SHOW\s0 \s-1FULL\s0 \s-1PROCESSLIST\s0, much like \fBmytop\fR's
+query list mode.  This mode does \fBnot\fR show InnoDB-related information.  This
+is probably one of the most useful modes for general usage.
+.Sp
+There is an informative header that shows general status information about
+your server.  You can toggle it on and off with the 'h' key.  By default,
+innotop hides inactive processes and its own process.  You can toggle these on
+and off with the 'i' and 'a' keys.
+.Sp
+You can \s-1EXPLAIN\s0 a query from this mode with the 'e' key.  This displays the
+query's full text, the results of \s-1EXPLAIN\s0, and in newer MySQL versions, even
+the optimized query resulting from \s-1EXPLAIN\s0 \s-1EXTENDED\s0.  innotop also tries to
+rewrite certain queries to make them EXPLAIN-able.  For example, \s-1INSERT/SELECT\s0
+statements are rewritable.
+.Sp
+This mode displays the \*(L"q_header\*(R" and \*(L"processlist\*(R" tables by default.
+.IP "R: InnoDB Row Operations and Semaphores" 4
+.IX Item "R: InnoDB Row Operations and Semaphores"
+This mode shows InnoDB row operations, row operation miscellaneous, semaphores,
+and information from the wait array.  It displays the \*(L"row_operations\*(R",
+\&\*(L"row_operation_misc\*(R", \*(L"semaphores\*(R", and \*(L"wait_array\*(R" tables by default.
+.IP "S: Variables & Status" 4
+.IX Item "S: Variables & Status"
+This mode calculates statistics, such as queries per second, and prints them out
+in several different styles.  You can show absolute values, or incremental values
+between ticks.
+.Sp
+You can switch between the views by pressing a key.  The 's' key prints a
+single line each time the screen updates, in the style of \fBvmstat\fR.  The 'g'
+key changes the view to a graph of the same numbers, sort of like \fBtload\fR.
+The 'v' key changes the view to a pivoted table of variable names on the left,
+with successive updates scrolling across the screen from left to right.  You can
+choose how many updates to put on the screen with the \*(L"num_status_sets\*(R"
+configuration variable.
+.Sp
+Headers may be abbreviated to fit on the screen in interactive operation.  You
+choose which variables to display with the 'c' key, which selects from
+predefined sets, or lets you create your own sets.  You can edit the current set
+with the 'e' key.
+.Sp
+This mode doesn't really display any tables like other modes.  Instead, it uses
+a table definition to extract and format the data, but it then transforms the
+result in special ways before outputting it.  It uses the \*(L"var_status\*(R" table
+definition for this.
+.IP "T: InnoDB Transactions" 4
+.IX Item "T: InnoDB Transactions"
+This mode shows transactions from the InnoDB monitor's output, in \fBtop\fR\-like
+format.  This mode is the reason I wrote innotop.
+.Sp
+You can kill queries or processes with the 'k' and 'x' keys, and \s-1EXPLAIN\s0 a query
+with the 'e' or 'f' keys.  InnoDB doesn't print the full query in transactions,
+so explaining may not work right if the query is truncated.
+.Sp
+The informational header can be toggled on and off with the 'h' key.  By
+default, innotop hides inactive transactions and its own transaction.  You can
+toggle this on and off with the 'i' and 'a' keys.
+.Sp
+This mode displays the \*(L"t_header\*(R" and \*(L"innodb_transactions\*(R" tables by
+default.
+.SH "INNOTOP STATUS"
+.IX Header "INNOTOP STATUS"
+The first line innotop displays is a \*(L"status bar\*(R" of sorts.  What it contains
+depends on the mode you're in, and what servers you're monitoring.  The first
+few words are always [\s-1RO\s0] (if readonly is set to 1), the innotop mode, such as
+\&\*(L"InnoDB Txns\*(R" for T mode, followed by a reminder to press '?' for help at any
+time.
+.SS "\s-1ONE\s0 \s-1SERVER\s0"
+.IX Subsection "ONE SERVER"
+The simplest case is when you're monitoring a single server.  In this case, the
+name of the connection is next on the status line.  This is the name you gave
+when you created the connection \*(-- most likely the MySQL server's hostname.
+This is followed by the server's uptime.
+.PP
+If you're in an InnoDB mode, such as T or B, the next word is \*(L"InnoDB\*(R" followed
+by some information about the \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0 output used to render the
+screen.  The first word is the number of seconds since the last \s-1SHOW\s0 \s-1INNODB\s0
+\&\s-1STATUS\s0, which InnoDB uses to calculate some per-second statistics.  The next is
+a smiley face indicating whether the InnoDB output is truncated.  If the smiley
+face is a :\-), all is well; there is no truncation.  A :^| means the transaction
+list is so long, InnoDB has only printed out some of the transactions.  Finally,
+a frown :\-( means the output is incomplete, which is probably due to a deadlock
+printing too much lock information (see \*(L"D: InnoDB Deadlocks\*(R").
+.PP
+The next two words indicate the server's queries per second (\s-1QPS\s0) and how many
+threads (connections) exist.  Finally, the server's version number is the last
+thing on the line.
+.SS "\s-1MULTIPLE\s0 \s-1SERVERS\s0"
+.IX Subsection "MULTIPLE SERVERS"
+If you are monitoring multiple servers (see \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R"), the status
+line does not show any details about individual servers.  Instead, it shows the
+names of the connections that are active.  Again, these are connection names you
+specified, which are likely to be the server's hostname.  A connection that has
+an error is prefixed with an exclamation point.
+.PP
+If you are monitoring a group of servers (see \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R"), the status
+line shows the name of the group.  If any connection in the group has an
+error, the group's name is followed by the fraction of the connections that
+don't have errors.
+.PP
+See \*(L"\s-1ERROR\s0 \s-1HANDLING\s0\*(R" for more details about innotop's error handling.
+.SS "\s-1MONITORING\s0 A \s-1FILE\s0"
+.IX Subsection "MONITORING A FILE"
+If you give a filename on the command line, innotop will not connect to \s-1ANY\s0
+servers at all.  It will watch the specified file for InnoDB status output and
+use that as its data source.  It will always show a single connection called
+\&'file'.  And since it can't connect to a server, it can't determine how long the
+server it's monitoring has been up; so it calculates the server's uptime as time
+since innotop started running.
+.SH "SERVER ADMINISTRATION"
+.IX Header "SERVER ADMINISTRATION"
+While innotop is primarily a monitor that lets you watch and analyze your
+servers, it can also send commands to servers.  The most frequently useful
+commands are killing queries and stopping or starting slaves.
+.PP
+You can kill a connection, or in newer versions of MySQL kill a query but not a
+connection, from \*(L"Q: Query List\*(R" and \*(L"T: InnoDB Transactions\*(R" modes.
+Press 'k' to issue a \s-1KILL\s0 command, or 'x' to issue a \s-1KILL\s0 \s-1QUERY\s0 command.
+innotop will prompt you for the server and/or connection \s-1ID\s0 to kill (innotop
+does not prompt you if there is only one possible choice for any input).
+innotop pre-selects the longest-running query, or the oldest connection.
+Confirm the command with 'y'.
+.PP
+In \*(L"Slave Replication Status\*(R"\*(L" in \*(R"M: Master mode, you can start and stop slaves
+with the 'a' and 'o' keys, respectively.  You can send these commands to many
+slaves at once.  innotop fills in a default command of \s-1START\s0 \s-1SLAVE\s0 or \s-1STOP\s0 \s-1SLAVE\s0
+for you, but you can actually edit the command and send anything you wish, such
+as \s-1SET\s0 \s-1GLOBAL\s0 SQL_SLAVE_SKIP_COUNTER=1 to make the slave skip one binlog event
+when it starts.
+.PP
+You can also ask innotop to calculate the earliest binlog in use by any slave
+and issue a \s-1PURGE\s0 \s-1MASTER\s0 \s-1LOGS\s0 on the master.  Use the 'b' key for this.  innotop
+will prompt you for a master to run the command on, then prompt you for the
+connection names of that master's slaves (there is no way for innotop to
+determine this reliably itself).  innotop will find the minimum binlog in use by
+these slave connections and suggest it as the argument to \s-1PURGE\s0 \s-1MASTER\s0 \s-1LOGS\s0.
+.SH "SERVER CONNECTIONS"
+.IX Header "SERVER CONNECTIONS"
+When you create a server connection using '@', innotop asks you for a series of
+inputs, as follows:
+.IP "\s-1DSN\s0" 4
+.IX Item "DSN"
+A \s-1DSN\s0 is a Data Source Name, which is the initial argument passed to the \s-1DBI\s0
+module for connecting to a server.  It is usually of the form
+.Sp
+.Vb 1
+\& DBI:mysql:;mysql_read_default_group=mysql;host=HOSTNAME
+.Ve
+.Sp
+Since this \s-1DSN\s0 is passed to the DBD::mysql driver, you should read the driver's
+documentation at \*(L"/search.cpan.org/dist/DBD\-mysql/lib/DBD/mysql.pm\*(R"\*(L" in \*(R"http: for
+the exact details on all the options you can pass the driver in the \s-1DSN\s0.  You
+can read more about \s-1DBI\s0 at <http://dbi.perl.org/docs/>, and especially at
+<http://search.cpan.org/~timb/DBI/DBI.pm>.
+.Sp
+The mysql_read_default_group=mysql option lets the \s-1DBD\s0 driver read your MySQL
+options files, such as ~/.my.cnf on UNIX-ish systems.  You can use this to avoid
+specifying a username or password for the connection.
+.IP "InnoDB Deadlock Table" 4
+.IX Item "InnoDB Deadlock Table"
+This optional item tells innotop a table name it can use to deliberately create
+a small deadlock (see \*(L"D: InnoDB Deadlocks\*(R").  If you specify this option,
+you just need to be sure the table doesn't exist, and that innotop can create
+and drop the table with the InnoDB storage engine.  You can safely omit or just
+accept the default if you don't intend to use this.
+.IP "Username" 4
+.IX Item "Username"
+innotop will ask you if you want to specify a username.  If you say 'y', it will
+then prompt you for a user name.  If you have a MySQL option file that specifies
+your username, you don't have to specify a username.
+.Sp
+The username defaults to your login name on the system you're running innotop on.
+.IP "Password" 4
+.IX Item "Password"
+innotop will ask you if you want to specify a password.  Like the username, the
+password is optional, but there's an additional prompt that asks if you want to
+save the password in the innotop configuration file.  If you don't save it in
+the configuration file, innotop will prompt you for a password each time it
+starts.  Passwords in the innotop configuration file are saved in plain text,
+not encrypted in any way.
+.PP
+Once you finish answering these questions, you should be connected to a server.
+But innotop isn't limited to monitoring a single server; you can define many
+server connections and switch between them by pressing the '@' key.  See
+\&\*(L"\s-1SWITCHING\s0 \s-1BETWEEN\s0 \s-1CONNECTIONS\s0\*(R".
+.SH "SERVER GROUPS"
+.IX Header "SERVER GROUPS"
+If you have multiple MySQL instances, you can put them into named groups, such
+as 'all', 'masters', and 'slaves', which innotop can monitor all together.
+.PP
+You can choose which group to monitor with the '#' key, and you can press the
+\&\s-1TAB\s0 key to switch to the next group.  If you're not currently monitoring a
+group, pressing \s-1TAB\s0 selects the first group.
+.PP
+To create a group, press the '#' key and type the name of your new group, then
+type the names of the connections you want the group to contain.
+.SH "SWITCHING BETWEEN CONNECTIONS"
+.IX Header "SWITCHING BETWEEN CONNECTIONS"
+innotop lets you quickly switch which servers you're monitoring.  The most basic
+way is by pressing the '@' key and typing the name(s) of the connection(s) you
+want to use.  This setting is per-mode, so you can monitor different connections
+in each mode, and innotop remembers which connections you choose.
+.PP
+You can quickly switch to the 'next' connection in alphabetical order with the
+\&'n' key.  If you're monitoring a server group (see \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R") this will
+switch to the first connection.
+.PP
+You can also type many connection names, and innotop will fetch and display data
+from them all.  Just separate the connection names with spaces, for example
+\&\*(L"server1 server2.\*(R"  Again, if you type the name of a connection that doesn't
+exist, innotop will prompt you for connection information and create the
+connection.
+.PP
+Another way to monitor multiple connections at once is with server groups.  You
+can use the \s-1TAB\s0 key to switch to the 'next' group in alphabetical order, or if
+you're not monitoring any groups, \s-1TAB\s0 will switch to the first group.
+.PP
+innotop does not fetch data in parallel from connections, so if you are
+monitoring a large group or many connections, you may notice increased delay
+between ticks.
+.PP
+When you monitor more than one connection, innotop's status bar changes.  See
+\&\*(L"\s-1INNOTOP\s0 \s-1STATUS\s0\*(R".
+.SH "ERROR HANDLING"
+.IX Header "ERROR HANDLING"
+Error handling is not that important when monitoring a single connection, but is
+crucial when you have many active connections.  A crashed server or lost
+connection should not crash innotop.  As a result, innotop will continue to run
+even when there is an error; it just won't display any information from the
+connection that had an error.  Because of this, innotop's behavior might confuse
+you.  It's a feature, not a bug!
+.PP
+innotop does not continue to query connections that have errors, because they
+may slow innotop and make it hard to use, especially if the error is a problem
+connecting and causes a long time-out.  Instead, innotop retries the connection
+occasionally to see if the error still exists.  If so, it will wait until some
+point in the future.  The wait time increases in ticks as the Fibonacci series,
+so it tries less frequently as time passes.
+.PP
+Since errors might only happen in certain modes because of the \s-1SQL\s0 commands
+issued in those modes, innotop keeps track of which mode caused the error.  If
+you switch to a different mode, innotop will retry the connection instead of
+waiting.
+.PP
+By default innotop will display the problem in red text at the bottom of the
+first table on the screen.  You can disable this behavior with the
+\&\*(L"show_cxn_errors_in_tbl\*(R" configuration option, which is enabled by default.
+If the \*(L"debug\*(R" option is enabled, innotop will display the error at the
+bottom of every table, not just the first.  And if \*(L"show_cxn_errors\*(R" is
+enabled, innotop will print the error text to \s-1STDOUT\s0 as well.  Error messages
+might only display in the mode that caused the error, depending on the mode and
+whether innotop is avoiding querying that connection.
+.SH "NON-INTERACTIVE OPERATION"
+.IX Header "NON-INTERACTIVE OPERATION"
+You can run innotop in non-interactive mode, in which case it is entirely
+controlled from the configuration file and command-line options.  To start
+innotop in non-interactive mode, give the L\*(L"<\-\-nonint\*(R"> command-line option.
+This changes innotop's behavior in the following ways:
+.IP "\(bu" 4
+Certain Perl modules are not loaded.  Term::Readline is not loaded, since
+innotop doesn't prompt interactively.  Term::ANSIColor and Win32::Console::ANSI
+modules are not loaded.  Term::ReadKey is still used, since innotop may have to
+prompt for connection passwords when starting up.
+.IP "\(bu" 4
+innotop does not clear the screen after each tick.
+.IP "\(bu" 4
+innotop does not persist any changes to the configuration file.
+.IP "\(bu" 4
+If \*(L"\-\-count\*(R" is given and innotop is in incremental mode (see \*(L"status_inc\*(R"
+and \*(L"\-\-inc\*(R"), innotop actually refreshes one more time than specified so it
+can print incremental statistics.  This suppresses output during the first
+tick, so innotop may appear to hang.
+.IP "\(bu" 4
+innotop only displays the first table in each mode.  This is so the output can
+be easily processed with other command-line utilities such as awk and sed.  To
+change which tables display in each mode, see \*(L"\s-1TABLES\s0\*(R".  Since \*(L"Q: Query
+List\*(R" mode is so important, innotop automatically disables the \*(L"q_header\*(R"
+table.  This ensures you'll see the \*(L"processlist\*(R" table, even if you have
+innotop configured to show the q_header table during interactive operation.
+Similarly, in \*(L"T: InnoDB Transactions\*(R" mode, the \*(L"t_header\*(R" table is
+suppressed so you see only the \*(L"innodb_transactions\*(R" table.
+.IP "\(bu" 4
+All output is tab-separated instead of being column-aligned with whitespace, and
+innotop prints the full contents of each table instead of only printing one
+screenful at a time.
+.IP "\(bu" 4
+innotop only prints column headers once instead of every tick (see
+\&\*(L"hide_hdr\*(R").  innotop does not print table captions (see
+\&\*(L"display_table_captions\*(R").  innotop ensures there are no empty lines in the
+output.
+.IP "\(bu" 4
+innotop does not honor the \*(L"shorten\*(R" transformation, which normally shortens
+some numbers to human-readable formats.
+.IP "\(bu" 4
+innotop does not print a status line (see \*(L"\s-1INNOTOP\s0 \s-1STATUS\s0\*(R").
+.SH "CONFIGURING"
+.IX Header "CONFIGURING"
+Nearly everything about innotop is configurable.  Most things are possible to
+change with built-in commands, but you can also edit the configuration file.
+.PP
+While running innotop, press the '$' key to bring up the configuration editing
+dialog.  Press another key to select the type of data you want to edit:
+.IP "S: Statement Sleep Times" 4
+.IX Item "S: Statement Sleep Times"
+Edits \s-1SQL\s0 statement sleep delays, which make innotop pause for the specified
+amount of time after executing a statement.  See \*(L"\s-1SQL\s0 \s-1STATEMENTS\s0\*(R" for a
+definition of each statement and what it does.  By default innotop does not
+delay after any statements.
+.Sp
+This feature is included so you can customize the side-effects caused by
+monitoring your server.  You may not see any effects, but some innotop users
+have noticed that certain MySQL versions under very high load with InnoDB
+enabled take longer than usual to execute \s-1SHOW\s0 \s-1GLOBAL\s0 \s-1STATUS\s0.  If innotop calls
+\&\s-1SHOW\s0 \s-1FULL\s0 \s-1PROCESSLIST\s0 immediately afterward, the processlist contains more
+queries than the machine actually averages at any given moment.  Configuring
+innotop to pause briefly after calling \s-1SHOW\s0 \s-1GLOBAL\s0 \s-1STATUS\s0 alleviates this
+effect.
+.Sp
+Sleep times are stored in the \*(L"stmt_sleep_times\*(R" section of the configuration
+file.  Fractional-second sleeps are supported, subject to your hardware's
+limitations.
+.IP "c: Edit Columns" 4
+.IX Item "c: Edit Columns"
+Starts the table editor on one of the displayed tables.  See \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R".
+An alternative way to start the table editor without entering the configuration
+dialog is with the '^' key.
+.IP "g: General Configuration" 4
+.IX Item "g: General Configuration"
+Starts the configuration editor to edit global and mode-specific configuration
+variables (see \*(L"\s-1MODES\s0\*(R").  innotop prompts you to choose a variable from among
+the global and mode-specific ones depending on the current mode.
+.IP "k: Row-Coloring Rules" 4
+.IX Item "k: Row-Coloring Rules"
+Starts the row-coloring rules editor on one of the displayed table(s).  See
+\&\*(L"\s-1COLORS\s0\*(R" for details.
+.IP "p: Manage Plugins" 4
+.IX Item "p: Manage Plugins"
+Starts the plugin configuration editor.  See \*(L"\s-1PLUGINS\s0\*(R" for details.
+.IP "s: Server Groups" 4
+.IX Item "s: Server Groups"
+Lets you create and edit server groups.  See \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R".
+.IP "t: Choose Displayed Tables" 4
+.IX Item "t: Choose Displayed Tables"
+Lets you choose which tables to display in this mode.  See \*(L"\s-1MODES\s0\*(R" and
+\&\*(L"\s-1TABLES\s0\*(R".
+.SH "CONFIGURATION FILE"
+.IX Header "CONFIGURATION FILE"
+innotop's default configuration file locations are \f(CW$HOME\fR/.innotop and
+/etc/innotop/innotop.conf, and they are looked for in that order.  If the first
+configuration file exists, the second will not be processed.  Those can be
+overridden with the \*(L"\-\-config\*(R" command-line option.  You can edit it by hand
+safely, however innotop reads the configuration file when it starts, and, if
+readonly is set to 0, writes it out again when it exits.  Thus, if readonly is
+set to 0, any changes you make by hand while innotop is running will be lost.
+.PP
+innotop doesn't store its entire configuration in the configuration file.  It
+has a huge set of default configuration values that it holds only in memory,
+and the configuration file only overrides these defaults.  When you customize a
+default setting, innotop notices, and then stores the customizations into the
+file.  This keeps the file size down, makes it easier to edit, and makes
+upgrades easier.
+.PP
+A configuration file is read-only be default.  You can override that with
+\&\*(L"\-\-write\*(R".  See \*(L"readonly\*(R".
+.PP
+The configuration file is arranged into sections like an \s-1INI\s0 file.  Each
+section begins with [section\-name] and ends with [/section\-name].  Each
+section's entries have a different syntax depending on the data they need to
+store.  You can put comments in the file; any line that begins with a #
+character is a comment.  innotop will not read the comments, so it won't write
+them back out to the file when it exits.  Comments in read-only configuration
+files are still useful, though.
+.PP
+The first line in the file is innotop's version number.  This lets innotop
+notice when the file format is not backwards-compatible, and upgrade smoothly
+without destroying your customized configuration.
+.PP
+The following list describes each section of the configuration file and the data
+it contains:
+.IP "general" 4
+.IX Item "general"
+The 'general' section contains global configuration variables and variables that
+may be mode-specific, but don't belong in any other section.  The syntax is a
+simple key=value list.  innotop writes a comment above each value to help you
+edit the file by hand.
+.RS 4
+.IP "S_func" 4
+.IX Item "S_func"
+Controls S mode presentation (see \*(L"S: Variables & Status\*(R").  If g, values are
+graphed; if s, values are like vmstat; if p, values are in a pivoted table.
+.IP "S_set" 4
+.IX Item "S_set"
+Specifies which set of variables to display in \*(L"S: Variables & Status\*(R" mode.
+See \*(L"\s-1VARIABLE\s0 \s-1SETS\s0\*(R".
+.IP "auto_wipe_dl" 4
+.IX Item "auto_wipe_dl"
+Instructs innotop to automatically wipe large deadlocks when it notices them.
+When this happens you may notice a slight delay.  At the next tick, you will
+usually see the information that was being truncated by the large deadlock.
+.IP "charset" 4
+.IX Item "charset"
+Specifies what kind of characters to allow through the \*(L"no_ctrl_char\*(R"
+transformation.  This keeps non-printable characters from confusing a
+terminal when you monitor queries that contain binary data, such as images.
+.Sp
+The default is 'ascii', which considers anything outside normal \s-1ASCII\s0 to be a
+control character.  The other allowable values are 'unicode' and 'none'.  'none'
+considers every character a control character, which can be useful for
+collapsing \s-1ALL\s0 text fields in queries.
+.IP "cmd_filter" 4
+.IX Item "cmd_filter"
+This is the prefix that filters variables in \*(L"C: Command Summary\*(R" mode.
+.IP "color" 4
+.IX Item "color"
+Whether terminal coloring is permitted.
+.IP "cxn_timeout" 4
+.IX Item "cxn_timeout"
+On MySQL versions 4.0.3 and newer, this variable is used to set the connection's
+timeout, so MySQL doesn't close the connection if it is not used for a while.
+This might happen because a connection isn't monitored in a particular mode, for
+example.
+.IP "debug" 4
+.IX Item "debug"
+This option enables more verbose errors and makes innotop more strict in some
+places.  It can help in debugging filters and other user-defined code.  It also
+makes innotop write a lot of information to \*(L"debugfile\*(R" when there is a
+crash.
+.IP "debugfile" 4
+.IX Item "debugfile"
+A file to which innotop will write information when there is a crash.  See
+\&\*(L"\s-1FILES\s0\*(R".
+.IP "display_table_captions" 4
+.IX Item "display_table_captions"
+innotop displays a table caption above most tables.  This variable suppresses or
+shows captions on all tables globally.  Some tables are configured with the
+hide_caption property, which overrides this.
+.IP "global" 4
+.IX Item "global"
+Whether to show \s-1GLOBAL\s0 variables and status.  innotop only tries to do this on
+servers which support the \s-1GLOBAL\s0 option to \s-1SHOW\s0 \s-1VARIABLES\s0 and \s-1SHOW\s0 \s-1STATUS\s0.  In
+some MySQL versions, you need certain privileges to do this; if you don't have
+them, innotop will not be able to fetch any variable and status data.  This
+configuration variable lets you run innotop and fetch what data you can even
+without the elevated privileges.
+.Sp
+I can no longer find or reproduce the situation where \s-1GLOBAL\s0 wasn't allowed, but
+I know there was one.
+.IP "graph_char" 4
+.IX Item "graph_char"
+Defines the character to use when drawing graphs in \*(L"S: Variables & Status\*(R"
+mode.
+.IP "header_highlight" 4
+.IX Item "header_highlight"
+Defines how to highlight column headers.  This only works if Term::ANSIColor is
+available.  Valid values are 'bold' and 'underline'.
+.IP "hide_hdr" 4
+.IX Item "hide_hdr"
+Hides column headers globally.
+.IP "interval" 4
+.IX Item "interval"
+The interval at which innotop will refresh its data (ticks).  The interval is
+implemented as a sleep time between ticks, so the true interval will vary
+depending on how long it takes innotop to fetch and render data.
+.Sp
+This variable accepts fractions of a second.
+.IP "mode" 4
+.IX Item "mode"
+The mode in which innotop should start.  Allowable arguments are the same as the
+key presses that select a mode interactively.  See \*(L"\s-1MODES\s0\*(R".
+.IP "num_digits" 4
+.IX Item "num_digits"
+How many digits to show in fractional numbers and percents.  This variable's
+range is between 0 and 9 and can be set directly from \*(L"S: Variables & Status\*(R"
+mode with the '+' and '\-' keys.  It is used in the \*(L"set_precision\*(R",
+\&\*(L"shorten\*(R", and \*(L"percent\*(R" transformations.
+.IP "num_status_sets" 4
+.IX Item "num_status_sets"
+Controls how many sets of status variables to display in pivoted \*(L"S: Variables
+& Status\*(R" mode.  It also controls the number of old sets of variables innotop
+keeps in its memory, so the larger this variable is, the more memory innotop
+uses.
+.IP "plugin_dir" 4
+.IX Item "plugin_dir"
+Specifies where plugins can be found.  By default, innotop stores plugins in the
+\&'plugins' subdirectory of your innotop configuration directory.
+.IP "readonly" 4
+.IX Item "readonly"
+Whether the configuration file is readonly.  This cannot be set interactively.
+.IP "show_cxn_errors" 4
+.IX Item "show_cxn_errors"
+Makes innotop print connection errors to \s-1STDOUT\s0.  See \*(L"\s-1ERROR\s0 \s-1HANDLING\s0\*(R".
+.IP "show_cxn_errors_in_tbl" 4
+.IX Item "show_cxn_errors_in_tbl"
+Makes innotop display connection errors as rows in the first table on screen.
+See \*(L"\s-1ERROR\s0 \s-1HANDLING\s0\*(R".
+.IP "show_percent" 4
+.IX Item "show_percent"
+Adds a '%' character after the value returned by the \*(L"percent\*(R"
+transformation.
+.IP "show_statusbar" 4
+.IX Item "show_statusbar"
+Controls whether to show the status bar in the display.  See \*(L"\s-1INNOTOP\s0
+\&\s-1STATUS\s0\*(R".
+.IP "skip_innodb" 4
+.IX Item "skip_innodb"
+Disables fetching \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0, in case your server(s) do not have InnoDB
+enabled and you don't want innotop to try to fetch it.  This can also be useful
+when you don't have the \s-1SUPER\s0 privilege, required to run \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0.
+.IP "status_inc" 4
+.IX Item "status_inc"
+Whether to show absolute or incremental values for status variables.
+Incremental values are calculated as an offset from the last value innotop saw
+for that variable.  This is a global setting, but will probably become
+mode-specific at some point.  Right now it is honored a bit inconsistently; some
+modes don't pay attention to it.
+.RE
+.RS 4
+.RE
+.IP "plugins" 4
+.IX Item "plugins"
+This section holds a list of package names of active plugins.  If the plugin
+exists, innotop will activate it.  See \*(L"\s-1PLUGINS\s0\*(R" for more information.
+.IP "filters" 4
+.IX Item "filters"
+This section holds user-defined filters (see \*(L"\s-1FILTERS\s0\*(R").  Each line is in the
+format filter_name=text='filter text' tbls='table list'.
+.Sp
+The filter text is the text of the subroutine's code.  The table list is a list
+of tables to which the filter can apply.  By default, user-defined filters apply
+to the table for which they were created, but you can manually override that by
+editing the definition in the configuration file.
+.IP "active_filters" 4
+.IX Item "active_filters"
+This section stores which filters are active on each table.  Each line is in the
+format table_name=filter_list.
+.IP "tbl_meta" 4
+.IX Item "tbl_meta"
+This section stores user-defined or user-customized columns (see \*(L"\s-1COLUMNS\s0\*(R").
+Each line is in the format col_name=properties, where the properties are a
+name=quoted\-value list.
+.IP "connections" 4
+.IX Item "connections"
+This section holds the server connections you have defined.  Each line is in
+the format name=properties, where the properties are a name=value list.  The
+properties are self-explanatory, and the only one that is treated specially is
+\&'pass' which is only present if 'savepass' is set.  This section of the
+configuration file will be skipped if any \s-1DSN\s0, username, or password
+command-line options are used.  See \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R".
+.IP "active_connections" 4
+.IX Item "active_connections"
+This section holds a list of which connections are active in each mode.  Each
+line is in the format mode_name=connection_list.
+.IP "server_groups" 4
+.IX Item "server_groups"
+This section holds server groups.  Each line is in the format
+name=connection_list.  See \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R".
+.IP "active_server_groups" 4
+.IX Item "active_server_groups"
+This section holds a list of which server group is active in each mode.  Each
+line is in the format mode_name=server_group.
+.IP "max_values_seen" 4
+.IX Item "max_values_seen"
+This section holds the maximum values seen for variables.  This is used to scale
+the graphs in \*(L"S: Variables & Status\*(R" mode.  Each line is in the format
+name=value.
+.IP "active_columns" 4
+.IX Item "active_columns"
+This section holds table column lists.  Each line is in the format
+tbl_name=column_list.  See \*(L"\s-1COLUMNS\s0\*(R".
+.IP "sort_cols" 4
+.IX Item "sort_cols"
+This section holds the sort definition.  Each line is in the format
+tbl_name=column_list.  If a column is prefixed with '\-', that column sorts
+descending.  See \*(L"\s-1SORTING\s0\*(R".
+.IP "visible_tables" 4
+.IX Item "visible_tables"
+This section defines which tables are visible in each mode.  Each line is in the
+format mode_name=table_list.  See \*(L"\s-1TABLES\s0\*(R".
+.IP "varsets" 4
+.IX Item "varsets"
+This section defines variable sets for use in \*(L"S: Status & Variables\*(R" mode.
+Each line is in the format name=variable_list.  See \*(L"\s-1VARIABLE\s0 \s-1SETS\s0\*(R".
+.IP "colors" 4
+.IX Item "colors"
+This section defines colorization rules.  Each line is in the format
+tbl_name=property_list.  See \*(L"\s-1COLORS\s0\*(R".
+.IP "stmt_sleep_times" 4
+.IX Item "stmt_sleep_times"
+This section contains statement sleep times.  Each line is in the format
+statement_name=sleep_time.  See \*(L"S: Statement Sleep Times\*(R".
+.IP "group_by" 4
+.IX Item "group_by"
+This section contains column lists for table group_by expressions.  Each line is
+in the format tbl_name=column_list.  See \*(L"\s-1GROUPING\s0\*(R".
+.SH "CUSTOMIZING"
+.IX Header "CUSTOMIZING"
+You can customize innotop a great deal.  For example, you can:
+.IP "\(bu" 4
+Choose which tables to display, and in what order.
+.IP "\(bu" 4
+Choose which columns are in those tables, and create new columns.
+.IP "\(bu" 4
+Filter which rows display with built-in filters, user-defined filters, and
+quick-filters.
+.IP "\(bu" 4
+Sort the rows to put important data first or group together related rows.
+.IP "\(bu" 4
+Highlight rows with color.
+.IP "\(bu" 4
+Customize the alignment, width, and formatting of columns, and apply
+transformations to columns to extract parts of their values or format the values
+as you wish (for example, shortening large numbers to familiar units).
+.IP "\(bu" 4
+Design your own expressions to extract and combine data as you need.  This gives
+you unlimited flexibility.
+.PP
+All these and more are explained in the following sections.
+.SS "\s-1TABLES\s0"
+.IX Subsection "TABLES"
+A table is what you'd expect: a collection of columns.  It also has some other
+properties, such as a caption.  Filters, sorting rules, and colorization rules
+belong to tables and are covered in later sections.
+.PP
+Internally, table meta-data is defined in a data structure called \f(CW%tbl_meta\fR.
+This hash holds all built-in table definitions, which contain a lot of default
+instructions to innotop.  The meta-data includes the caption, a list of columns
+the user has customized, a list of columns, a list of visible columns, a list of
+filters, color rules, a sort-column list, sort direction, and some information
+about the table's data sources.  Most of this is customizable via the table
+editor (see \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R").
+.PP
+You can choose which tables to show by pressing the '$' key.  See \*(L"\s-1MODES\s0\*(R" and
+\&\*(L"\s-1TABLES\s0\*(R".
+.PP
+The table life-cycle is as follows:
+.IP "\(bu" 4
+Each table begins with a data source, which is an array of hashes.  See below
+for details on data sources.
+.IP "\(bu" 4
+Each element of the data source becomes a row in the final table.
+.IP "\(bu" 4
+For each element in the data source, innotop extracts values from the source and
+creates a row.  This row is another hash, which later steps will refer to as
+\&\f(CW$set\fR.  The values innotop extracts are determined by the table's columns.  Each
+column has an extraction subroutine, compiled from an expression (see
+\&\*(L"\s-1EXPRESSIONS\s0\*(R").  The resulting row is a hash whose keys are named the same as
+the column name.
+.IP "\(bu" 4
+innotop filters the rows, removing those that don't need to be displayed.  See
+\&\*(L"\s-1FILTERS\s0\*(R".
+.IP "\(bu" 4
+innotop sorts the rows.  See \*(L"\s-1SORTING\s0\*(R".
+.IP "\(bu" 4
+innotop groups the rows together, if specified.  See \*(L"\s-1GROUPING\s0\*(R".
+.IP "\(bu" 4
+innotop colorizes the rows.  See \*(L"\s-1COLORS\s0\*(R".
+.IP "\(bu" 4
+innotop transforms the column values in each row.  See \*(L"\s-1TRANSFORMATIONS\s0\*(R".
+.IP "\(bu" 4
+innotop optionally pivots the rows (see \*(L"\s-1PIVOTING\s0\*(R"), then filters and sorts
+them.
+.IP "\(bu" 4
+innotop formats and justifies the rows as a table.  During this step, innotop
+applies further formatting to the column values, including alignment, maximum
+and minimum widths.  innotop also does final error checking to ensure there are
+no crashes due to undefined values.  innotop then adds a caption if specified,
+and the table is ready to print.
+.PP
+The lifecycle is slightly different if the table is pivoted, as noted above.  To
+clarify, if the table is pivoted, the process is extract, group, transform,
+pivot, filter, sort, create.  If it's not pivoted, the process is extract,
+filter, sort, group, color, transform, create.  This slightly convoluted process
+doesn't map all that well to \s-1SQL\s0, but pivoting complicates things pretty
+thoroughly.  Roughly speaking, filtering and sorting happen as late as needed to
+effect the final result as you might expect, but as early as possible for
+efficiency.
+.PP
+Each built-in table is described below:
+.IP "adaptive_hash_index" 4
+.IX Item "adaptive_hash_index"
+Displays data about InnoDB's adaptive hash index.  Data source:
+\&\*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "buffer_pool" 4
+.IX Item "buffer_pool"
+Displays data about InnoDB's buffer pool.  Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "cmd_summary" 4
+.IX Item "cmd_summary"
+Displays weighted status variables.  Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "deadlock_locks" 4
+.IX Item "deadlock_locks"
+Shows which locks were held and waited for by the last detected deadlock.  Data
+source: \*(L"\s-1DEADLOCK_LOCKS\s0\*(R".
+.IP "deadlock_transactions" 4
+.IX Item "deadlock_transactions"
+Shows transactions involved in the last detected deadlock.  Data source:
+\&\*(L"\s-1DEADLOCK_TRANSACTIONS\s0\*(R".
+.IP "explain" 4
+.IX Item "explain"
+Shows the output of \s-1EXPLAIN\s0.  Data source: \*(L"\s-1EXPLAIN\s0\*(R".
+.IP "file_io_misc" 4
+.IX Item "file_io_misc"
+Displays data about InnoDB's file and I/O operations.  Data source:
+\&\*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "fk_error" 4
+.IX Item "fk_error"
+Displays various data about InnoDB's last foreign key error.  Data source:
+\&\*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "innodb_locks" 4
+.IX Item "innodb_locks"
+Displays InnoDB locks.  Data source: \*(L"\s-1INNODB_LOCKS\s0\*(R".
+.IP "innodb_transactions" 4
+.IX Item "innodb_transactions"
+Displays data about InnoDB's current transactions.  Data source:
+\&\*(L"\s-1INNODB_TRANSACTIONS\s0\*(R".
+.IP "insert_buffers" 4
+.IX Item "insert_buffers"
+Displays data about InnoDB's insert buffer.  Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "io_threads" 4
+.IX Item "io_threads"
+Displays data about InnoDB's I/O threads.  Data source: \*(L"\s-1IO_THREADS\s0\*(R".
+.IP "log_statistics" 4
+.IX Item "log_statistics"
+Displays data about InnoDB's logging system.  Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "master_status" 4
+.IX Item "master_status"
+Displays replication master status.  Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "open_tables" 4
+.IX Item "open_tables"
+Displays open tables.  Data source: \*(L"\s-1OPEN_TABLES\s0\*(R".
+.IP "page_statistics" 4
+.IX Item "page_statistics"
+Displays InnoDB page statistics.  Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "pending_io" 4
+.IX Item "pending_io"
+Displays InnoDB pending I/O operations.  Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "processlist" 4
+.IX Item "processlist"
+Displays current MySQL processes (threads/connections).  Data source:
+\&\*(L"\s-1PROCESSLIST\s0\*(R".
+.IP "q_header" 4
+.IX Item "q_header"
+Displays various status values.  Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "row_operation_misc" 4
+.IX Item "row_operation_misc"
+Displays data about InnoDB's row operations.  Data source:
+\&\*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "row_operations" 4
+.IX Item "row_operations"
+Displays data about InnoDB's row operations.  Data source:
+\&\*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "semaphores" 4
+.IX Item "semaphores"
+Displays data about InnoDB's semaphores and mutexes.  Data source:
+\&\*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "slave_io_status" 4
+.IX Item "slave_io_status"
+Displays data about the slave I/O thread.  Data source: 
+\&\*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "slave_sql_status" 4
+.IX Item "slave_sql_status"
+Displays data about the slave \s-1SQL\s0 thread.  Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "t_header" 4
+.IX Item "t_header"
+Displays various InnoDB status values.  Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "var_status" 4
+.IX Item "var_status"
+Displays user-configurable data.  Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R".
+.IP "wait_array" 4
+.IX Item "wait_array"
+Displays data about InnoDB's \s-1OS\s0 wait array.  Data source: \*(L"\s-1OS_WAIT_ARRAY\s0\*(R".
+.SS "\s-1COLUMNS\s0"
+.IX Subsection "COLUMNS"
+Columns belong to tables.  You can choose a table's columns by pressing the '^'
+key, which starts the \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R" and lets you choose and edit columns.
+Pressing 'e' from within the table editor lets you edit the column's properties:
+.IP "\(bu" 4
+hdr: a column header.  This appears in the first row of the table.
+.IP "\(bu" 4
+just: justification.  '\-' means left-justified and '' means right-justified,
+just as with printf formatting codes (not a coincidence).
+.IP "\(bu" 4
+dec: whether to further align the column on the decimal point.
+.IP "\(bu" 4
+num: whether the column is numeric.  This affects how values are sorted
+(lexically or numerically).
+.IP "\(bu" 4
+label: a small note about the column, which appears in dialogs that help the
+user choose columns.
+.IP "\(bu" 4
+src: an expression that innotop uses to extract the column's data from its
+source (see \*(L"\s-1DATA\s0 \s-1SOURCES\s0\*(R").  See \*(L"\s-1EXPRESSIONS\s0\*(R" for more on expressions.
+.IP "\(bu" 4
+minw: specifies a minimum display width.  This helps stabilize the display,
+which makes it easier to read if the data is changing frequently.
+.IP "\(bu" 4
+maxw: similar to minw.
+.IP "\(bu" 4
+trans: a list of column transformations.  See \*(L"\s-1TRANSFORMATIONS\s0\*(R".
+.IP "\(bu" 4
+agg: an aggregate function.  See \*(L"\s-1GROUPING\s0\*(R".  The default is \*(L"first\*(R".
+.IP "\(bu" 4
+aggonly: controls whether the column only shows when grouping is enabled on the
+table (see \*(L"\s-1GROUPING\s0\*(R").  By default, this is disabled.  This means columns
+will always be shown by default, whether grouping is enabled or not.  If a
+column's aggonly is set true, the column will appear when you toggle grouping on
+the table.  Several columns are set this way, such as the count column on
+\&\*(L"processlist\*(R" and \*(L"innodb_transactions\*(R", so you don't see a count when the
+grouping isn't enabled, but you do when it is.
+.SS "\s-1FILTERS\s0"
+.IX Subsection "FILTERS"
+Filters remove rows from the display.  They behave much like a \s-1WHERE\s0 clause in
+\&\s-1SQL\s0.  innotop has several built-in filters, which remove irrelevant information
+like inactive queries, but you can define your own as well.  innotop also lets
+you create quick-filters, which do not get saved to the configuration file, and
+are just an easy way to quickly view only some rows.
+.PP
+You can enable or disable a filter on any table.  Press the '%' key (mnemonic: %
+looks kind of like a line being filtered between two circles) and choose which
+table you want to filter, if asked.  You'll then see a list of possible filters
+and a list of filters currently enabled for that table.  Type the names of
+filters you want to apply and press Enter.
+.PP
+\fIUSER-DEFINED \s-1FILTERS\s0\fR
+.IX Subsection "USER-DEFINED FILTERS"
+.PP
+If you type a name that doesn't exist, innotop will prompt you to create the
+filter.  Filters are easy to create if you know Perl, and not hard if you don't.
+What you're doing is creating a subroutine that returns true if the row should
+be displayed.  The row is a hash reference passed to your subroutine as \f(CW$set\fR.
+.PP
+For example, imagine you want to filter the processlist table so you only see
+queries that have been running more than five minutes.  Type a new name for your
+filter, and when prompted for the subroutine body, press \s-1TAB\s0 to initiate your
+terminal's auto-completion.  You'll see the names of the columns in the
+\&\*(L"processlist\*(R" table (innotop generally tries to help you with auto-completion
+lists).  You want to filter on the 'time' column.  Type the text \*(L"$set\->{time} >
+300\*(R" to return true when the query is more than five minutes old.  That's all
+you need to do.
+.PP
+In other words, the code you're typing is surrounded by an implicit context,
+which looks like this:
+.PP
+.Vb 4
+\& sub filter {
+\&    my ( $set ) = @_;
+\&    # YOUR CODE HERE
+\& }
+.Ve
+.PP
+If your filter doesn't work, or if something else suddenly behaves differently,
+you might have made an error in your filter, and innotop is silently catching
+the error.  Try enabling \*(L"debug\*(R" to make innotop throw an error instead.
+.PP
+\fIQUICK-FILTERS\fR
+.IX Subsection "QUICK-FILTERS"
+.PP
+innotop's quick-filters are a shortcut to create a temporary filter that doesn't
+persist when you restart innotop.  To create a quick-filter, press the '/' key.
+innotop will prompt you for the column name and filter text.  Again, you can use
+auto-completion on column names.  The filter text can be just the text you want
+to \*(L"search for.\*(R"  For example, to filter the \*(L"processlist\*(R" table on queries
+that refer to the products table, type '/' and then 'info product'.
+.PP
+The filter text can actually be any Perl regular expression, but of course a
+literal string like 'product' works fine as a regular expression.
+.PP
+Behind the scenes innotop compiles the quick-filter into a specially tagged
+filter that is otherwise like any other filter.  It just isn't saved to the
+configuration file.
+.PP
+To clear quick-filters, press the '\e' key and innotop will clear them all at
+once.
+.SS "\s-1SORTING\s0"
+.IX Subsection "SORTING"
+innotop has sensible built-in defaults to sort the most important rows to the
+top of the table.  Like anything else in innotop, you can customize how any
+table is sorted.
+.PP
+To start the sort dialog, start the \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R" with the '^' key, choose a
+table if necessary, and press the 's' key.  You'll see a list of columns you can
+use in the sort expression and the current sort expression, if any.  Enter a
+list of columns by which you want to sort and press Enter.  If you want to
+reverse sort, prefix the column name with a minus sign.  For example, if you
+want to sort by column a ascending, then column b descending, type 'a \-b'.  You
+can also explicitly add a + in front of columns you want to sort ascending, but
+it's not required.
+.PP
+Some modes have keys mapped to open this dialog directly, and to quickly reverse
+sort direction.  Press '?' as usual to see which keys are mapped in any mode.
+.SS "\s-1GROUPING\s0"
+.IX Subsection "GROUPING"
+innotop can group, or aggregate, rows together (the terms are used
+interchangeably).  This is quite similar to an \s-1SQL\s0 \s-1GROUP\s0 \s-1BY\s0 clause.  You can
+specify to group on certain columns, or if you don't specify any, the entire set
+of rows is treated as one group.  This is quite like \s-1SQL\s0 so far, but unlike \s-1SQL\s0,
+you can also select un-grouped columns.  innotop actually aggregates every
+column.  If you don't explicitly specify a grouping function, the default is
+\&'first'.  This is basically a convenience so you don't have to specify an
+aggregate function for every column you want in the result.
+.PP
+You can quickly toggle grouping on a table with the '=' key, which toggles its
+aggregate property.  This property doesn't persist to the config file.
+.PP
+The columns by which the table is grouped are specified in its group_by
+property.  When you turn grouping on, innotop places the group_by columns at the
+far left of the table, even if they're not supposed to be visible.  The rest of
+the visible columns appear in order after them.
+.PP
+Two tables have default group_by lists and a count column built in:
+\&\*(L"processlist\*(R" and \*(L"innodb_transactions\*(R".  The grouping is by connection
+and status, so you can quickly see how many queries or transactions are in a
+given status on each server you're monitoring.  The time columns are aggregated
+as a sum; other columns are left at the default 'first' aggregation.
+.PP
+By default, the table shown in \*(L"S: Variables & Status\*(R" mode also uses
+grouping so you can monitor variables and status across many servers.  The
+default aggregation function in this mode is 'avg'.
+.PP
+Valid grouping functions are defined in the \f(CW%agg_funcs\fR hash.  They include
+.IP "first" 4
+.IX Item "first"
+Returns the first element in the group.
+.IP "count" 4
+.IX Item "count"
+Returns the number of elements in the group, including undefined elements, much
+like \s-1SQL\s0's \s-1COUNT\s0(*).
+.IP "avg" 4
+.IX Item "avg"
+Returns the average of defined elements in the group.
+.IP "sum" 4
+.IX Item "sum"
+Returns the sum of elements in the group.
+.PP
+Here's an example of grouping at work.  Suppose you have a very busy server with
+hundreds of open connections, and you want to see how many connections are in
+what status.  Using the built-in grouping rules, you can press 'Q' to enter
+\&\*(L"Q: Query List\*(R" mode.  Press '=' to toggle grouping (if necessary, select the
+\&\*(L"processlist\*(R" table when prompted).
+.PP
+Your display might now look like the following:
+.PP
+.Vb 1
+\& Query List (? for help) localhost, 32:33, 0.11 QPS, 1 thd, 5.0.38\-log
+\& 
+\& CXN        Cmd        Cnt  ID      User   Host           Time   Query       
+\& localhost  Query      49    12933  webusr localhost      19:38  SELECT * FROM
+\& localhost  Sending Da 23     2383  webusr localhost      12:43  SELECT col1,
+\& localhost  Sleep      120     140  webusr localhost    5:18:12
+\& localhost  Statistics 12    19213  webusr localhost      01:19  SELECT * FROM
+.Ve
+.PP
+That's actually quite a worrisome picture.  You've got a lot of idle connections
+(Sleep), and some connections executing queries (Query and Sending Data).
+That's okay, but you also have a lot in Statistics status, collectively spending
+over a minute.  That means the query optimizer is having a really hard time
+optimizing your statements.  Something is wrong; it should normally take
+milliseconds to optimize queries.  You might not have seen this pattern if you
+didn't look at your connections in aggregate.  (This is a made-up example, but
+it can happen in real life).
+.SS "\s-1PIVOTING\s0"
+.IX Subsection "PIVOTING"
+innotop can pivot a table for more compact display, similar to a Pivot Table in
+a spreadsheet (also known as a crosstab).  Pivoting a table makes columns into
+rows.  Assume you start with this table:
+.PP
+.Vb 4
+\& foo bar
+\& === ===
+\& 1   3
+\& 2   4
+.Ve
+.PP
+After pivoting, the table will look like this:
+.PP
+.Vb 4
+\& name set0 set1
+\& ==== ==== ====
+\& foo  1    2
+\& bar  3    4
+.Ve
+.PP
+To get reasonable results, you might need to group as well as pivoting.
+innotop currently does this for \*(L"S: Variables & Status\*(R" mode.
+.SS "\s-1COLORS\s0"
+.IX Subsection "COLORS"
+By default, innotop highlights rows with color so you can see at a glance which
+rows are more important.  You can customize the colorization rules and add your
+own to any table.  Open the table editor with the '^' key, choose a table if
+needed, and press 'o' to open the color editor dialog.
+.PP
+The color editor dialog displays the rules applied to the table, in the order
+they are evaluated.  Each row is evaluated against each rule to see if the rule
+matches the row; if it does, the row gets the specified color, and no further
+rules are evaluated.  The rules look like the following:
+.PP
+.Vb 9
+\& state  eq  Locked       black on_red
+\& cmd    eq  Sleep        white       
+\& user   eq  system user  white       
+\& cmd    eq  Connect      white       
+\& cmd    eq  Binlog Dump  white       
+\& time   >   600          red         
+\& time   >   120          yellow      
+\& time   >   60           green       
+\& time   >   30           cyan
+.Ve
+.PP
+This is the default rule set for the \*(L"processlist\*(R" table.  In order of
+priority, these rules make locked queries black on a red background, \*(L"gray out\*(R"
+connections from replication and sleeping queries, and make queries turn from
+cyan to red as they run longer.
+.PP
+(For some reason, the \s-1ANSI\s0 color code \*(L"white\*(R" is actually a light gray.  Your
+terminal's display may vary; experiment to find colors you like).
+.PP
+You can use keystrokes to move the rules up and down, which re-orders their
+priority.  You can also delete rules and add new ones.  If you add a new rule,
+innotop prompts you for the column, an operator for the comparison, a value
+against which to compare the column, and a color to assign if the rule matches.
+There is auto-completion and prompting at each step.
+.PP
+The value in the third step needs to be correctly quoted.  innotop does not try
+to quote the value because it doesn't know whether it should treat the value as
+a string or a number.  If you want to compare the column against a string, as
+for example in the first rule above, you should enter 'Locked' surrounded by
+quotes.  If you get an error message about a bareword, you probably should have
+quoted something.
+.SS "\s-1EXPRESSIONS\s0"
+.IX Subsection "EXPRESSIONS"
+Expressions are at the core of how innotop works, and are what enables you to
+extend innotop as you wish.  Recall the table lifecycle explained in
+\&\*(L"\s-1TABLES\s0\*(R".  Expressions are used in the earliest step, where it extracts
+values from a data source to form rows.
+.PP
+It does this by calling a subroutine for each column, passing it the source data
+set, a set of current values, and a set of previous values.  These are all
+needed so the subroutine can calculate things like the difference between this
+tick and the previous tick.
+.PP
+The subroutines that extract the data from the set are compiled from
+expressions.  This gives significantly more power than just naming the values to
+fill the columns, because it allows the column's value to be calculated from
+whatever data is necessary, but avoids the need to write complicated and lengthy
+Perl code.
+.PP
+innotop begins with a string of text that can look as simple as a value's name
+or as complicated as a full-fledged Perl expression.  It looks at each
+\&'bareword' token in the string and decides whether it's supposed to be a key
+into the \f(CW$set\fR hash.  A bareword is an unquoted value that isn't already
+surrounded by code-ish things like dollar signs or curly brackets.  If innotop
+decides that the bareword isn't a function or other valid Perl code, it converts
+it into a hash access.  After the whole string is processed, innotop compiles a
+subroutine, like this:
+.PP
+.Vb 5
+\& sub compute_column_value {
+\&    my ( $set, $cur, $pre ) = @_;
+\&    my $val = # EXPANDED STRING GOES HERE
+\&    return $val;
+\& }
+.Ve
+.PP
+Here's a concrete example, taken from the header table \*(L"q_header\*(R" in \*(L"Q:
+Query List\*(R" mode.  This expression calculates the qps, or Queries Per Second,
+column's values, from the values returned by \s-1SHOW\s0 \s-1STATUS:\s0
+.PP
+.Vb 1
+\& Questions/Uptime_hires
+.Ve
+.PP
+innotop decides both words are barewords, and transforms this expression into
+the following Perl code:
+.PP
+.Vb 1
+\& $set\->{Questions}/$set\->{Uptime_hires}
+.Ve
+.PP
+When surrounded by the rest of the subroutine's code, this is executable Perl
+that calculates a high-resolution queries-per-second value.
+.PP
+The arguments to the subroutine are named \f(CW$set\fR, \f(CW$cur\fR, and \f(CW$pre\fR.  In most cases,
+\&\f(CW$set\fR and \f(CW$cur\fR will be the same values.  However, if \*(L"status_inc\*(R" is set, \f(CW$cur\fR
+will not be the same as \f(CW$set\fR, because \f(CW$set\fR will already contain values that are
+the incremental difference between \f(CW$cur\fR and \f(CW$pre\fR.
+.PP
+Every column in innotop is computed by subroutines compiled in the same fashion.
+There is no difference between innotop's built-in columns and user-defined
+columns.  This keeps things consistent and predictable.
+.SS "\s-1TRANSFORMATIONS\s0"
+.IX Subsection "TRANSFORMATIONS"
+Transformations change how a value is rendered.  For example, they can take a
+number of seconds and display it in H:M:S format.  The following transformations
+are defined:
+.IP "commify" 4
+.IX Item "commify"
+Adds commas to large numbers every three decimal places.
+.IP "dulint_to_int" 4
+.IX Item "dulint_to_int"
+Accepts two unsigned integers and converts them into a single longlong.  This is
+useful for certain operations with InnoDB, which uses two integers as
+transaction identifiers, for example.
+.IP "no_ctrl_char" 4
+.IX Item "no_ctrl_char"
+Removes quoted control characters from the value.  This is affected by the
+\&\*(L"charset\*(R" configuration variable.
+.Sp
+This transformation only operates within quoted strings, for example, values to
+a \s-1SET\s0 clause in an \s-1UPDATE\s0 statement.  It will not alter the \s-1UPDATE\s0 statement,
+but will collapse the quoted string to [\s-1BINARY\s0] or [\s-1TEXT\s0], depending on the
+charset.
+.IP "percent" 4
+.IX Item "percent"
+Converts a number to a percentage by multiplying it by two, formatting it with
+\&\*(L"num_digits\*(R" digits after the decimal point, and optionally adding a percent
+sign (see \*(L"show_percent\*(R").
+.IP "secs_to_time" 4
+.IX Item "secs_to_time"
+Formats a number of seconds as time in days+hours:minutes:seconds format.
+.IP "set_precision" 4
+.IX Item "set_precision"
+Formats numbers with \*(L"num_digits\*(R" number of digits after the decimal point.
+.IP "shorten" 4
+.IX Item "shorten"
+Formats a number as a unit of 1024 (k/M/G/T) and with \*(L"num_digits\*(R" number of
+digits after the decimal point.
+.SS "\s-1TABLE\s0 \s-1EDITOR\s0"
+.IX Subsection "TABLE EDITOR"
+The innotop table editor lets you customize tables with keystrokes.  You start
+the table editor with the '^' key.  If there's more than one table on the
+screen, it will prompt you to choose one of them.  Once you do, innotop will
+show you something like this:
+.PP
+.Vb 1
+\& Editing table definition for Buffer Pool.  Press ? for help, q to quit.
+\& 
+\& name               hdr          label                  src          
+\& cxn                CXN          Connection from which  cxn          
+\& buf_pool_size      Size         Buffer pool size       IB_bp_buf_poo
+\& buf_free           Free Bufs    Buffers free in the b  IB_bp_buf_fre
+\& pages_total        Pages        Pages total            IB_bp_pages_t
+\& pages_modified     Dirty Pages  Pages modified (dirty  IB_bp_pages_m
+\& buf_pool_hit_rate  Hit Rate     Buffer pool hit rate   IB_bp_buf_poo
+\& total_mem_alloc    Memory       Total memory allocate  IB_bp_total_m
+\& add_pool_alloc     Add\*(Aql Pool   Additonal pool alloca  IB_bp_add_poo
+.Ve
+.PP
+The first line shows which table you're editing, and reminds you again to press
+\&'?' for a list of key mappings.  The rest is a tabular representation of the
+table's columns, because that's likely what you're trying to edit.  However, you
+can edit more than just the table's columns; this screen can start the filter
+editor, color rule editor, and more.
+.PP
+Each row in the display shows a single column in the table you're editing, along
+with a couple of its properties such as its header and source expression (see
+\&\*(L"\s-1EXPRESSIONS\s0\*(R").
+.PP
+The key mappings are Vim-style, as in many other places.  Pressing 'j' and 'k'
+moves the highlight up or down.  You can then (d)elete or (e)dit the highlighted
+column.  You can also (a)dd a column to the table.  This actually just activates
+one of the columns already defined for the table; it prompts you to choose from
+among the columns available but not currently displayed.  Finally, you can
+re-order the columns with the '+' and '\-' keys.
+.PP
+You can do more than just edit the columns with the table editor, you can also
+edit other properties, such as the table's sort expression and group-by
+expression.  Press '?' to see the full list, of course.
+.PP
+If you want to really customize and create your own column, as opposed to just
+activating a built-in one that's not currently displayed, press the (n)ew key,
+and innotop will prompt you for the information it needs:
+.IP "\(bu" 4
+The column name: this needs to be a word without any funny characters, e.g. just
+letters, numbers and underscores.
+.IP "\(bu" 4
+The column header: this is the label that appears at the top of the column, in
+the table header.  This can have spaces and funny characters, but be careful not
+to make it too wide and waste space on-screen.
+.IP "\(bu" 4
+The column's data source: this is an expression that determines what data from
+the source (see \*(L"\s-1TABLES\s0\*(R") innotop will put into the column.  This can just be
+the name of an item in the source, or it can be a more complex expression, as
+described in \*(L"\s-1EXPRESSIONS\s0\*(R".
+.PP
+Once you've entered the required data, your table has a new column.  There is no
+difference between this column and the built-in ones; it can have all the same
+properties and behaviors.  innotop will write the column's definition to the
+configuration file, so it will persist across sessions.
+.PP
+Here's an example: suppose you want to track how many times your slaves have
+retried transactions.  According to the MySQL manual, the
+Slave_retried_transactions status variable gives you that data: \*(L"The total
+number of times since startup that the replication slave \s-1SQL\s0 thread has retried
+transactions. This variable was added in version 5.0.4.\*(R"  This is appropriate to
+add to the \*(L"slave_sql_status\*(R" table.
+.PP
+To add the column, switch to the replication-monitoring mode with the 'M' key,
+and press the '^' key to start the table editor.  When prompted, choose
+slave_sql_status as the table, then press 'n' to create the column.  Type
+\&'retries' as the column name, 'Retries' as the column header, and
+\&'Slave_retried_transactions' as the source.  Now the column is created, and you
+see the table editor screen again.  Press 'q' to exit the table editor, and
+you'll see your column at the end of the table.
+.SH "VARIABLE SETS"
+.IX Header "VARIABLE SETS"
+Variable sets are used in \*(L"S: Variables & Status\*(R" mode to define more easily
+what variables you want to monitor.  Behind the scenes they are compiled to a
+list of expressions, and then into a column list so they can be treated just
+like columns in any other table, in terms of data extraction and
+transformations.  However, you're protected from the tedious details by a syntax
+that ought to feel very natural to you: a \s-1SQL\s0 \s-1SELECT\s0 list.
+.PP
+The data source for variable sets, and indeed the entire S mode, is the
+combination of \s-1SHOW\s0 \s-1STATUS\s0, \s-1SHOW\s0 \s-1VARIABLES\s0, and \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0.  Imagine
+that you had a huge table with one column per variable returned from those
+statements.  That's the data source for variable sets.  You can now query this
+data source just like you'd expect.  For example:
+.PP
+.Vb 1
+\& Questions, Uptime, Questions/Uptime as QPS
+.Ve
+.PP
+Behind the scenes innotop will split that variable set into three expressions,
+compile them and turn them into a table definition, then extract as usual.  This
+becomes a \*(L"variable set,\*(R" or a \*(L"list of variables you want to monitor.\*(R"
+.PP
+innotop lets you name and save your variable sets, and writes them to the
+configuration file.  You can choose which variable set you want to see with the
+\&'c' key, or activate the next and previous sets with the '>' and '<' keys.
+There are many built-in variable sets as well, which should give you a good
+start for creating your own.  Press 'e' to edit the current variable set, or
+just to see how it's defined.  To create a new one, just press 'c' and type its
+name.
+.PP
+You may want to use some of the functions listed in \*(L"\s-1TRANSFORMATIONS\s0\*(R" to help
+format the results.  In particular, \*(L"set_precision\*(R" is often useful to limit
+the number of digits you see.  Extending the above example, here's how:
+.PP
+.Vb 1
+\& Questions, Uptime, set_precision(Questions/Uptime) as QPS
+.Ve
+.PP
+Actually, this still needs a little more work.  If your \*(L"interval\*(R" is less
+than one second, you might be dividing by zero because Uptime is incremental in
+this mode by default.  Instead, use Uptime_hires:
+.PP
+.Vb 1
+\& Questions, Uptime, set_precision(Questions/Uptime_hires) as QPS
+.Ve
+.PP
+This example is simple, but it shows how easy it is to choose which variables
+you want to monitor.
+.SH "PLUGINS"
+.IX Header "PLUGINS"
+innotop has a simple but powerful plugin mechanism by which you can extend
+or modify its existing functionality, and add new functionality.  innotop's
+plugin functionality is event-based: plugins register themselves to be called
+when events happen.  They then have a chance to influence the event.
+.PP
+An innotop plugin is a Perl module placed in innotop's \*(L"plugin_dir\*(R"
+directory.  On \s-1UNIX\s0 systems, you can place a symbolic link to the module instead
+of putting the actual file there.  innotop automatically discovers the file.  If
+there is a corresponding entry in the \*(L"plugins\*(R" configuration file section,
+innotop loads and activates the plugin.
+.PP
+The module must conform to innotop's plugin interface.  Additionally, the source
+code of the module must be written in such a way that innotop can inspect the
+file and determine the package name and description.
+.SS "Package Source Convention"
+.IX Subsection "Package Source Convention"
+innotop inspects the plugin module's source to determine the Perl package name.
+It looks for a line of the form \*(L"package Foo;\*(R" and if found, considers the
+plugin's package name to be Foo.  Of course the package name can be a valid Perl
+package name, with double semicolons and so on.
+.PP
+It also looks for a description in the source code, to make the plugin editor
+more human-friendly.  The description is a comment line of the form \*(L"#
+description: Foo\*(R", where \*(L"Foo\*(R" is the text innotop will consider to be the
+plugin's description.
+.SS "Plugin Interface"
+.IX Subsection "Plugin Interface"
+The innotop plugin interface is quite simple: innotop expects the plugin to be
+an object-oriented module it can call certain methods on.  The methods are
+.IP "new(%variables)" 4
+.IX Item "new(%variables)"
+This is the plugin's constructor.  It is passed a hash of innotop's variables,
+which it can manipulate (see \*(L"Plugin Variables\*(R").  It must return a reference
+to the newly created plugin object.
+.Sp
+At construction time, innotop has only loaded the general configuration and
+created the default built-in variables with their default contents (which is
+quite a lot).  Therefore, the state of the program is exactly as in the innotop
+source code, plus the configuration variables from the \*(L"general\*(R" section in
+the config file.
+.Sp
+If your plugin manipulates the variables, it is changing global data, which is
+shared by innotop and all plugins.  Plugins are loaded in the order they're
+listed in the config file.  Your plugin may load before or after another plugin,
+so there is a potential for conflict or interaction between plugins if they
+modify data other plugins use or modify.
+.IP "\fIregister_for_events()\fR" 4
+.IX Item "register_for_events()"
+This method must return a list of events in which the plugin is interested, if
+any.  See \*(L"Plugin Events\*(R" for the defined events.  If the plugin returns an
+event that's not defined, the event is ignored.
+.IP "event handlers" 4
+.IX Item "event handlers"
+The plugin must implement a method named the same as each event for which it has
+registered.  In other words, if the plugin returns qw(foo bar) from
+\&\fIregister_for_events()\fR, it must have \fIfoo()\fR and \fIbar()\fR methods.  These methods are
+callbacks for the events.  See \*(L"Plugin Events\*(R" for more details about each
+event.
+.SS "Plugin Variables"
+.IX Subsection "Plugin Variables"
+The plugin's constructor is passed a hash of innotop's variables, which it can
+manipulate.  It is probably a good idea if the plugin object saves a copy of it
+for later use.  The variables are defined in the innotop variable
+\&\f(CW%pluggable_vars\fR, and are as follows:
+.IP "action_for" 4
+.IX Item "action_for"
+A hashref of key mappings.  These are innotop's global hot-keys.
+.IP "agg_funcs" 4
+.IX Item "agg_funcs"
+A hashref of functions that can be used for grouping.  See \*(L"\s-1GROUPING\s0\*(R".
+.IP "config" 4
+.IX Item "config"
+The global configuration hash.
+.IP "connections" 4
+.IX Item "connections"
+A hashref of connection specifications.  These are just specifications of how to
+connect to a server.
+.IP "dbhs" 4
+.IX Item "dbhs"
+A hashref of innotop's database connections.  These are actual \s-1DBI\s0 connection
+objects.
+.IP "filters" 4
+.IX Item "filters"
+A hashref of filters applied to table rows.  See \*(L"\s-1FILTERS\s0\*(R" for more.
+.IP "modes" 4
+.IX Item "modes"
+A hashref of modes.  See \*(L"\s-1MODES\s0\*(R" for more.
+.IP "server_groups" 4
+.IX Item "server_groups"
+A hashref of server groups.  See \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R".
+.IP "tbl_meta" 4
+.IX Item "tbl_meta"
+A hashref of innotop's table meta-data, with one entry per table (see
+\&\*(L"\s-1TABLES\s0\*(R" for more information).
+.IP "trans_funcs" 4
+.IX Item "trans_funcs"
+A hashref of transformation functions.  See \*(L"\s-1TRANSFORMATIONS\s0\*(R".
+.IP "var_sets" 4
+.IX Item "var_sets"
+A hashref of variable sets.  See \*(L"\s-1VARIABLE\s0 \s-1SETS\s0\*(R".
+.SS "Plugin Events"
+.IX Subsection "Plugin Events"
+Each event is defined somewhere in the innotop source code.  When innotop runs
+that code, it executes the callback function for each plugin that expressed its
+interest in the event.  innotop passes some data for each event.  The events are
+defined in the \f(CW%event_listener_for\fR variable, and are as follows:
+.ie n .IP "extract_values($set, $cur, $pre, $tbl)" 4
+.el .IP "extract_values($set, \f(CW$cur\fR, \f(CW$pre\fR, \f(CW$tbl\fR)" 4
+.IX Item "extract_values($set, $cur, $pre, $tbl)"
+This event occurs inside the function that extracts values from a data source.
+The arguments are the set of values, the current values, the previous values,
+and the table name.
+.IP "set_to_tbl" 4
+.IX Item "set_to_tbl"
+Events are defined at many places in this subroutine, which is responsible for
+turning an arrayref of hashrefs into an arrayref of lines that can be printed to
+the screen.  The events all pass the same data: an arrayref of rows and the name
+of the table being created.  The events are set_to_tbl_pre_filter,
+set_to_tbl_pre_sort,set_to_tbl_pre_group, set_to_tbl_pre_colorize,
+set_to_tbl_pre_transform, set_to_tbl_pre_pivot, set_to_tbl_pre_create,
+set_to_tbl_post_create.
+.IP "draw_screen($lines)" 4
+.IX Item "draw_screen($lines)"
+This event occurs inside the subroutine that prints the lines to the screen.
+\&\f(CW$lines\fR is an arrayref of strings.
+.SS "Simple Plugin Example"
+.IX Subsection "Simple Plugin Example"
+The easiest way to explain the plugin functionality is probably with a simple
+example.  The following module adds a column to the beginning of every table and
+sets its value to 1.
+.PP
+.Vb 2
+\& use strict;
+\& use warnings FATAL => \*(Aqall\*(Aq;
+\& 
+\& package Innotop::Plugin::Example;
+\& # description: Adds an \*(Aqexample\*(Aq column to every table
+\& 
+\& sub new {
+\&    my ( $class, %vars ) = @_;
+\&    # Store reference to innotop\*(Aqs variables in $self
+\&    my $self = bless { %vars }, $class;
+\& 
+\&    # Design the example column
+\&    my $col = {
+\&       hdr   => \*(AqExample\*(Aq,
+\&       just  => \*(Aq\*(Aq,
+\&       dec   => 0,
+\&       num   => 1,
+\&       label => \*(AqExample\*(Aq,
+\&       src   => \*(Aqexample\*(Aq, # Get data from this column in the data source
+\&       tbl   => \*(Aq\*(Aq,
+\&       trans => [],
+\&    };
+\& 
+\&    # Add the column to every table.
+\&    my $tbl_meta = $vars{tbl_meta};
+\&    foreach my $tbl ( values %$tbl_meta ) {
+\&       # Add the column to the list of defined columns
+\&       $tbl\->{cols}\->{example} = $col;
+\&       # Add the column to the list of visible columns
+\&       unshift @{$tbl\->{visible}}, \*(Aqexample\*(Aq;
+\&    }
+\& 
+\&    # Be sure to return a reference to the object.
+\&    return $self;
+\& }
+\& 
+\& # I\*(Aqd like to be called when a data set is being rendered into a table, please.
+\& sub register_for_events {
+\&    my ( $self ) = @_;
+\&    return qw(set_to_tbl_pre_filter);
+\& }
+\& 
+\& # This method will be called when the event fires.
+\& sub set_to_tbl_pre_filter {
+\&    my ( $self, $rows, $tbl ) = @_;
+\&    # Set the example column\*(Aqs data source to the value 1.
+\&    foreach my $row ( @$rows ) {
+\&       $row\->{example} = 1;
+\&    }
+\& }
+\& 
+\& 1;
+.Ve
+.SS "Plugin Editor"
+.IX Subsection "Plugin Editor"
+The plugin editor lets you view the plugins innotop discovered and activate or
+deactivate them.  Start the editor by pressing $ to start the configuration
+editor from any mode.  Press the 'p' key to start the plugin editor.  You'll see
+a list of plugins innotop discovered.  You can use the 'j' and 'k' keys to move
+the highlight to the desired one, then press the * key to toggle it active or
+inactive.  Exit the editor and restart innotop for the changes to take effect.
+.SH "SQL STATEMENTS"
+.IX Header "SQL STATEMENTS"
+innotop uses a limited set of \s-1SQL\s0 statements to retrieve data from MySQL for
+display.  The statements are customized depending on the server version against
+which they are executed; for example, on MySQL 5 and newer, \s-1INNODB_STATUS\s0
+executes \*(L"\s-1SHOW\s0 \s-1ENGINE\s0 \s-1INNODB\s0 \s-1STATUS\s0\*(R", while on earlier versions it executes
+\&\*(L"\s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0\*(R".  The statements are as follows:
+.PP
+.Vb 12
+\& Statement           SQL executed
+\& =================== ===============================
+\& INNODB_STATUS       SHOW [ENGINE] INNODB STATUS
+\& KILL_CONNECTION     KILL
+\& KILL_QUERY          KILL QUERY
+\& OPEN_TABLES         SHOW OPEN TABLES
+\& PROCESSLIST         SHOW FULL PROCESSLIST
+\& SHOW_MASTER_LOGS    SHOW MASTER LOGS
+\& SHOW_MASTER_STATUS  SHOW MASTER STATUS
+\& SHOW_SLAVE_STATUS   SHOW SLAVE STATUS
+\& SHOW_STATUS         SHOW [GLOBAL] STATUS
+\& SHOW_VARIABLES      SHOW [GLOBAL] VARIABLES
+.Ve
+.SH "DATA SOURCES"
+.IX Header "DATA SOURCES"
+Each time innotop extracts values to create a table (see \*(L"\s-1EXPRESSIONS\s0\*(R" and
+\&\*(L"\s-1TABLES\s0\*(R"), it does so from a particular data source.  Largely because of the
+complex data extracted from \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0, this is slightly messy.  \s-1SHOW\s0
+\&\s-1INNODB\s0 \s-1STATUS\s0 contains a mixture of single values and repeated values that form
+nested data sets.
+.PP
+Whenever innotop fetches data from MySQL, it adds two extra bits to each set:
+cxn and Uptime_hires.  cxn is the name of the connection from which the data
+came.  Uptime_hires is a high-resolution version of the server's Uptime status
+variable, which is important if your \*(L"interval\*(R" setting is sub-second.
+.PP
+Here are the kinds of data sources from which data is extracted:
+.IP "\s-1STATUS_VARIABLES\s0" 4
+.IX Item "STATUS_VARIABLES"
+This is the broadest category, into which the most kinds of data fall.  It
+begins with the combination of \s-1SHOW\s0 \s-1STATUS\s0 and \s-1SHOW\s0 \s-1VARIABLES\s0, but other sources
+may be included as needed, for example, \s-1SHOW\s0 \s-1MASTER\s0 \s-1STATUS\s0 and \s-1SHOW\s0 \s-1SLAVE\s0
+\&\s-1STATUS\s0, as well as many of the non-repeated values from \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0.
+.IP "\s-1DEADLOCK_LOCKS\s0" 4
+.IX Item "DEADLOCK_LOCKS"
+This data is extracted from the transaction list in the \s-1LATEST\s0 \s-1DETECTED\s0 \s-1DEADLOCK\s0
+section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0.  It is nested two levels deep: transactions, then
+locks.
+.IP "\s-1DEADLOCK_TRANSACTIONS\s0" 4
+.IX Item "DEADLOCK_TRANSACTIONS"
+This data is from the transaction list in the \s-1LATEST\s0 \s-1DETECTED\s0 \s-1DEADLOCK\s0
+section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0.  It is nested one level deep.
+.IP "\s-1EXPLAIN\s0" 4
+.IX Item "EXPLAIN"
+This data is from the result set returned by \s-1EXPLAIN\s0.
+.IP "\s-1INNODB_TRANSACTIONS\s0" 4
+.IX Item "INNODB_TRANSACTIONS"
+This data is from the \s-1TRANSACTIONS\s0 section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0.
+.IP "\s-1IO_THREADS\s0" 4
+.IX Item "IO_THREADS"
+This data is from the list of threads in the the \s-1FILE\s0 I/O section of \s-1SHOW\s0 \s-1INNODB\s0
+\&\s-1STATUS\s0.
+.IP "\s-1INNODB_LOCKS\s0" 4
+.IX Item "INNODB_LOCKS"
+This data is from the \s-1TRANSACTIONS\s0 section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0 and is nested
+two levels deep.
+.IP "\s-1OPEN_TABLES\s0" 4
+.IX Item "OPEN_TABLES"
+This data is from \s-1SHOW\s0 \s-1OPEN\s0 \s-1TABLES\s0.
+.IP "\s-1PROCESSLIST\s0" 4
+.IX Item "PROCESSLIST"
+This data is from \s-1SHOW\s0 \s-1FULL\s0 \s-1PROCESSLIST\s0.
+.IP "\s-1OS_WAIT_ARRAY\s0" 4
+.IX Item "OS_WAIT_ARRAY"
+This data is from the \s-1SEMAPHORES\s0 section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0 and is nested one
+level deep.  It comes from the lines that look like this:
+.Sp
+.Vb 1
+\& \-\-Thread 1568861104 has waited at btr0cur.c line 424 ....
+.Ve
+.SH "MYSQL PRIVILEGES"
+.IX Header "MYSQL PRIVILEGES"
+.IP "\(bu" 4
+You must connect to MySQL as a user who has the \s-1SUPER\s0 privilege for many of the
+functions.
+.IP "\(bu" 4
+If you don't have the \s-1SUPER\s0 privilege, you can still run some functions, but you
+won't necessarily see all the same data.
+.IP "\(bu" 4
+You need the \s-1PROCESS\s0 privilege to see the list of currently running queries in Q
+mode.
+.IP "\(bu" 4
+You need special privileges to start and stop slave servers.
+.IP "\(bu" 4
+You need appropriate privileges to create and drop the deadlock tables if needed
+(see \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R").
+.SH "SYSTEM REQUIREMENTS"
+.IX Header "SYSTEM REQUIREMENTS"
+You need Perl to run innotop, of course.  You also need a few Perl modules: \s-1DBI\s0,
+DBD::mysql,  Term::ReadKey, and Time::HiRes.  These should be included with most
+Perl distributions, but in case they are not, I recommend using versions
+distributed with your operating system or Perl distribution, not from \s-1CPAN\s0.
+Term::ReadKey in particular has been known to cause problems if installed from
+\&\s-1CPAN\s0.
+.PP
+If you have Term::ANSIColor, innotop will use it to format headers more readably
+and compactly.  (Under Microsoft Windows, you also need Win32::Console::ANSI for
+terminal formatting codes to be honored).  If you install Term::ReadLine,
+preferably Term::ReadLine::Gnu, you'll get nice auto-completion support.
+.PP
+I run innotop on Gentoo GNU/Linux, Debian and Ubuntu, and I've had feedback from
+people successfully running it on Red Hat, CentOS, Solaris, and Mac \s-1OSX\s0.  I
+don't see any reason why it won't work on other UNIX-ish operating systems, but
+I don't know for sure.  It also runs on Windows under ActivePerl without
+problem.
+.PP
+innotop has been used on MySQL versions 3.23.58, 4.0.27, 4.1.0, 4.1.22, 5.0.26,
+5.1.15, and 5.2.3.  If it doesn't run correctly for you, that is a bug that
+should be reported.
+.SH "FILES"
+.IX Header "FILES"
+\&\f(CW$HOMEDIR\fR/.innotop and/or /etc/innotop are used to store
+configuration information.  Files include the configuration file innotop.conf,
+the core_dump file which contains verbose error messages if \*(L"debug\*(R" is
+enabled, and the plugins/ subdirectory.
+.SH "GLOSSARY OF TERMS"
+.IX Header "GLOSSARY OF TERMS"
+.IP "tick" 4
+.IX Item "tick"
+A tick is a refresh event, when innotop re-fetches data from connections and
+displays it.
+.SH "ACKNOWLEDGEMENTS"
+.IX Header "ACKNOWLEDGEMENTS"
+The following people and organizations are acknowledged for various reasons.
+Hopefully no one has been forgotten.
+.PP
+Allen K. Smith,
+Aurimas Mikalauskas,
+Bartosz Fenski,
+Brian Miezejewski,
+Christian Hammers, 
+Cyril Scetbon,
+Dane Miller,
+David Multer,
+Dr. Frank Ullrich,
+Giuseppe Maxia,
+Google.com Site Reliability Engineers,
+Google Code,
+Jan Pieter Kunst,
+Jari Aalto,
+Jay Pipes,
+Jeremy Zawodny,
+Johan Idren,
+Kristian Kohntopp,
+Lenz Grimmer,
+Maciej Dobrzanski,
+Michiel Betel,
+MySQL \s-1AB\s0,
+Paul McCullagh,
+Sebastien Estienne,
+Sourceforge.net,
+Steven Kreuzer,
+The Gentoo MySQL Team,
+Trevor Price,
+Yaar Schnitman,
+and probably more people that have not been included.
+.PP
+(If your name has been misspelled, it's probably out of fear of putting
+international characters into this documentation; earlier versions of Perl might
+not be able to compile it then).
+.SH "COPYRIGHT, LICENSE AND WARRANTY"
+.IX Header "COPYRIGHT, LICENSE AND WARRANTY"
+This program is copyright (c) 2006 Baron Schwartz.
+Feedback and improvements are welcome.
+.PP
+\&\s-1THIS\s0 \s-1PROGRAM\s0 \s-1IS\s0 \s-1PROVIDED\s0 \*(L"\s-1AS\s0 \s-1IS\s0\*(R" \s-1AND\s0 \s-1WITHOUT\s0 \s-1ANY\s0 \s-1EXPRESS\s0 \s-1OR\s0 \s-1IMPLIED\s0
+\&\s-1WARRANTIES\s0, \s-1INCLUDING\s0, \s-1WITHOUT\s0 \s-1LIMITATION\s0, \s-1THE\s0 \s-1IMPLIED\s0 \s-1WARRANTIES\s0 \s-1OF\s0
+\&\s-1MERCHANTIBILITY\s0 \s-1AND\s0 \s-1FITNESS\s0 \s-1FOR\s0 A \s-1PARTICULAR\s0 \s-1PURPOSE\s0.
+.PP
+This program is free software; you can redistribute it and/or modify it under
+the terms of the \s-1GNU\s0 General Public License as published by the Free Software
+Foundation, version 2; \s-1OR\s0 the Perl Artistic License.  On \s-1UNIX\s0 and similar
+systems, you can issue `man perlgpl' or `man perlartistic' to read these
+licenses.
+.PP
+You should have received a copy of the \s-1GNU\s0 General Public License along with
+this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+Place, Suite 330, Boston, \s-1MA\s0  02111\-1307  \s-1USA\s0.
+.PP
+Execute innotop and press '!' to see this information at any time.
+.SH "AUTHOR"
+.IX Header "AUTHOR"
+Originally written by Baron Schwartz; currently maintained by Aaron Racine.
+.SH "BUGS"
+.IX Header "BUGS"
+You can report bugs, ask for improvements, and get other help and support at
+<http://code.google.com/p/innotop/>.  There are mailing lists, a source code
+browser, a bug tracker, etc.  Please use these instead of contacting the
+maintainer or author directly, as it makes our job easier and benefits others if the
+discussions are permanent and public.  Of course, if you need to contact us in
+private, please do.
diff --git a/mysql-wsrep-5.6/debian/additions/my.cnf b/mysql-wsrep-5.6/debian/additions/my.cnf
new file mode 100644 (file)
index 0000000..4df5bd0
--- /dev/null
@@ -0,0 +1,127 @@
+#
+# The MySQL database server configuration file.
+#
+# You can copy this to one of:
+# - "/etc/mysql/my.cnf" to set global options,
+# - "~/.my.cnf" to set user-specific options.
+# 
+# One can use all long options that the program supports.
+# Run program with --help to get a list of available options and with
+# --print-defaults to see which it would actually understand and use.
+#
+# For explanations see
+# http://dev.mysql.com/doc/mysql/en/server-system-variables.html
+
+# This will be passed to all mysql clients
+# It has been reported that passwords should be enclosed with ticks/quotes
+# escpecially if they contain "#" chars...
+# Remember to edit /etc/mysql/debian.cnf when changing the socket location.
+[client]
+port           = 3306
+socket         = /var/run/mysqld/mysqld.sock
+
+# Here is entries for some specific programs
+# The following values assume you have at least 32M ram
+
+# This was formally known as [safe_mysqld]. Both versions are currently parsed.
+[mysqld_safe]
+socket         = /var/run/mysqld/mysqld.sock
+nice           = 0
+
+[mysqld]
+#
+# * Basic Settings
+#
+user           = mysql
+pid-file       = /var/run/mysqld/mysqld.pid
+socket         = /var/run/mysqld/mysqld.sock
+port           = 3306
+basedir                = /usr
+datadir                = /var/lib/mysql
+tmpdir         = /tmp
+lc-messages-dir        = /usr/share/mysql
+skip-external-locking
+#
+# Instead of skip-networking the default is now to listen only on
+# localhost which is more compatible and is not less secure.
+bind-address           = 127.0.0.1
+#
+# * Fine Tuning
+#
+key_buffer             = 16M
+max_allowed_packet     = 16M
+thread_stack           = 192K
+thread_cache_size       = 8
+# This replaces the startup script and checks MyISAM tables if needed
+# the first time they are touched
+myisam-recover         = BACKUP
+#max_connections        = 100
+#table_cache            = 64
+#thread_concurrency     = 10
+#
+# * Query Cache Configuration
+#
+query_cache_limit      = 1M
+query_cache_size        = 16M
+#
+# * Logging and Replication
+#
+# Both location gets rotated by the cronjob.
+# Be aware that this log type is a performance killer.
+# As of 5.1 you can enable the log at runtime!
+#general_log_file        = /var/log/mysql/mysql.log
+#general_log             = 1
+#
+# Error log - should be very few entries.
+#
+log_error = /var/log/mysql/error.log
+#
+# Here you can see queries with especially long duration
+#log_slow_queries      = /var/log/mysql/mysql-slow.log
+#long_query_time = 2
+#log-queries-not-using-indexes
+#
+# The following can be used as easy to replay backup logs or for replication.
+# note: if you are setting up a replication slave, see README.Debian about
+#       other settings you may need to change.
+#server-id             = 1
+#log_bin                       = /var/log/mysql/mysql-bin.log
+expire_logs_days       = 10
+max_binlog_size         = 100M
+#binlog_do_db          = include_database_name
+#binlog_ignore_db      = include_database_name
+#
+# * InnoDB
+#
+# InnoDB is enabled by default with a 10MB datafile in /var/lib/mysql/.
+# Read the manual for more InnoDB related options. There are many!
+#
+# * Security Features
+#
+# Read the manual, too, if you want chroot!
+# chroot = /var/lib/mysql/
+#
+# For generating SSL certificates I recommend the OpenSSL GUI "tinyca".
+#
+# ssl-ca=/etc/mysql/cacert.pem
+# ssl-cert=/etc/mysql/server-cert.pem
+# ssl-key=/etc/mysql/server-key.pem
+
+
+
+[mysqldump]
+quick
+quote-names
+max_allowed_packet     = 16M
+
+[mysql]
+#no-auto-rehash        # faster start of mysql but no tab completition
+
+[isamchk]
+key_buffer             = 16M
+
+#
+# * IMPORTANT: Additional settings that can override those from this file!
+#   The files must end with '.cnf', otherwise they'll be ignored.
+#
+!includedir /etc/mysql/conf.d/
diff --git a/mysql-wsrep-5.6/debian/additions/my5.6.cnf b/mysql-wsrep-5.6/debian/additions/my5.6.cnf
new file mode 100644 (file)
index 0000000..da49311
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# The MySQL 5.6 database server configuration file.
+#
+# This custom MySQL 5.6 specific configuration file
+# adds on top of the existing default my.cnf file at
+# - /etc/mysql/my.cnf.
+# 
+# Please add any extra MySQL 5.6 options in this file
+# for sake of clarity.
+#
+# You may uncomment any existing option to enable it
+#
+# sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES
diff --git a/mysql-wsrep-5.6/debian/additions/mysql-server.lintian-overrides b/mysql-wsrep-5.6/debian/additions/mysql-server.lintian-overrides
new file mode 100644 (file)
index 0000000..9d741cf
--- /dev/null
@@ -0,0 +1,2 @@
+W: mysql-dfsg source: maintainer-script-lacks-debhelper-token debian/mysql-server.postinst
+W: mysql-server: possible-bashism-in-maintainer-script postinst:68 'p{("a".."z","A".."Z",0..9)[int(rand(62))]}'
diff --git a/mysql-wsrep-5.6/debian/additions/mysql_config_pic.1 b/mysql-wsrep-5.6/debian/additions/mysql_config_pic.1
new file mode 100644 (file)
index 0000000..4c9de7b
--- /dev/null
@@ -0,0 +1 @@
+.so man1/mysql_config.1
diff --git a/mysql-wsrep-5.6/debian/additions/mysql_embedded.1 b/mysql-wsrep-5.6/debian/additions/mysql_embedded.1
new file mode 100644 (file)
index 0000000..735c4e0
--- /dev/null
@@ -0,0 +1 @@
+.so man1/mysql.1
diff --git a/mysql-wsrep-5.6/debian/additions/mysqld_safe_syslog.cnf b/mysql-wsrep-5.6/debian/additions/mysqld_safe_syslog.cnf
new file mode 100644 (file)
index 0000000..3b0445d
--- /dev/null
@@ -0,0 +1,2 @@
+[mysqld_safe]
+syslog
diff --git a/mysql-wsrep-5.6/debian/additions/mysqlreport b/mysql-wsrep-5.6/debian/additions/mysqlreport
new file mode 100644 (file)
index 0000000..402a5be
--- /dev/null
@@ -0,0 +1,1298 @@
+#!/usr/bin/perl -w
+
+# mysqlreport v3.5 Apr 16 2008
+# http://hackmysql.com/mysqlreport
+
+# mysqlreport makes an easy-to-read report of important MySQL status values.
+# Copyright 2006-2008 Daniel Nichter
+#
+# 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; either version 2
+# of the License, or (at your option) any later version.
+#
+# 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.
+#
+# The GNU General Public License is available at:
+# http://www.gnu.org/copyleft/gpl.html
+
+use strict;
+use File::Temp qw(tempfile);
+use DBI;
+use Getopt::Long;
+eval { require Term::ReadKey; };
+my $RK = ($@ ? 0 : 1);
+
+sub have_op;
+
+my $WIN = ($^O eq 'MSWin32' ? 1 : 0);
+my %op;
+my %mycnf; # ~/.my.cnf
+my ($tmpfile_fh, $tmpfile);
+my ($stat_name, $stat_val, $stat_label);
+my $MySQL_version;
+my (%stats, %vars); # SHOW STATUS, SHOW VARIABLES
+my (%DMS_vals, %Com_vals, %ib_vals);
+my ($dbh, $query);
+my ($questions, $key_read_ratio, $key_write_ratio, $dms, $slow_query_t);
+my ($key_cache_block_size, $key_buffer_used, $key_buffer_usage);
+my ($qc_mem_used, $qc_hi_r, $qc_ip_r); # Query Cache
+my $have_innodb_vals;
+my ($ib_bp_used, $ib_bp_total, $ib_bp_read_ratio);
+my ($relative_live, $relative_infiles);
+my $real_uptime;
+my (%stats_present, %stats_past); # For relative reports
+      
+GetOptions (
+   \%op,
+   "user=s",
+   "password:s",
+   "host=s",
+   "port=s",
+   "socket=s",
+   "no-mycnf",
+   "infile|in=s",
+   "outfile=s",
+   "flush-status",
+   "email=s",
+   "r|relative:i",
+   "c|report-count=i",
+   "detach",
+   "help|?",
+   "debug"
+);
+
+show_help_and_exit() if $op{'help'};
+
+get_user_mycnf() unless $op{'no-mycnf'};
+
+# Command line options override ~/.my.cnf
+$mycnf{'host'}   = $op{'host'}   if have_op 'host';
+$mycnf{'port'}   = $op{'port'}   if have_op 'port';
+$mycnf{'socket'} = $op{'socket'} if have_op 'socket'; 
+$mycnf{'user'}   = $op{'user'}   if have_op 'user';
+
+$mycnf{'user'} ||= $ENV{'USER'};
+
+if(exists $op{'password'})
+{
+   if($op{'password'} eq '') # Prompt for password
+   {
+      Term::ReadKey::ReadMode(2) if $RK;
+      print "Password for database user $mycnf{'user'}: ";
+      chomp($mycnf{'pass'} = <STDIN>);
+      Term::ReadKey::ReadMode(0), print "\n" if $RK;
+   }
+   else { $mycnf{'pass'} = $op{'password'}; } # Use password given on command line
+}
+
+$op{'com'} ||= 3;
+$op{'c'}   ||= 1; # Used in collect_reports() if --r given integer value
+
+$relative_live    = 0;
+$relative_infiles = 0;
+
+if(defined $op{'r'})
+{
+   if($op{r}) { $relative_live    = 1; }  # if -r was given an integer value
+   else       { $relative_infiles = 1; }
+}
+
+# The report is written to a tmp file first.
+# Later it will be moved to $op{'outfile'} or emailed $op{'email'} if needed.
+($tmpfile_fh, $tmpfile) = tempfile() or die "Cannot open temporary file for writing: $!\n";
+
+if($op{'detach'})
+{
+   $SIG{'TERM'} = 'sig_handler';
+
+   if(fork())
+   {
+      print "mysqlreport has forked and detached.\n";
+      print "While running detached, mysqlreport writes reports to '$tmpfile'.\n";
+
+      exit;
+   }
+
+   open(STDIN, "</dev/null");
+   open(STDOUT, "> $tmpfile") or die "Cannot dup STDOUT: $!\n";
+   open(STDERR, "> $tmpfile") or die "Cannot dup STDERR: $!\n";
+}
+
+select $tmpfile_fh;
+$| = 1 if ($op{'detach'} || $relative_live);
+
+print "tmp file: $tmpfile\n" if $op{debug};
+
+# Connect to MySQL
+if(!$op{'infile'} && !$relative_infiles)
+{
+   connect_to_MySQL();
+}
+
+$have_innodb_vals = 1; # This might be set to 0 later in get_MySQL_version()
+
+if(defined $op{'r'})
+{
+   if($relative_live)
+   { 
+      print STDERR "mysqlreport is writing relative reports to '$tmpfile'.\n" unless $op{'detach'}; 
+      get_MySQL_version();
+      collect_reports();
+   }
+
+   if($relative_infiles) { read_relative_infiles(); }
+}
+else
+{
+   if(!$op{'infile'})
+   {
+      get_MySQL_version();
+      get_vals();
+      get_vars();
+   }
+   else
+   {
+      read_infile($op{'infile'});
+   }
+
+   get_Com_values();
+
+   set_myisam_vals();
+   set_ib_vals() if $have_innodb_vals;
+
+   write_report();
+}
+
+exit_tasks_and_cleanup();
+
+exit;
+
+#
+# Subroutines
+#
+sub show_help_and_exit
+{
+   print <<"HELP";
+mysqlreport v3.5 Apr 16 2008
+mysqlreport makes an easy-to-read report of important MySQL status values.
+
+Command line options (abbreviations work):
+   --user USER       Connect to MySQL as USER
+   --password PASS   Use PASS or prompt for MySQL user's password
+   --host ADDRESS    Connect to MySQL at ADDRESS
+   --port PORT       Connect to MySQL at PORT
+   --socket SOCKET   Connect to MySQL at SOCKET
+   --no-mycnf        Don't read ~/.my.cnf
+   --infile FILE     Read status values from FILE instead of MySQL
+   --outfile FILE    Write report to FILE
+   --email ADDRESS   Email report to ADDRESS (doesn't work on Windows)
+   --flush-status    Issue FLUSH STATUS; after getting current values
+   --relative X      Generate relative reports. If X is an integer,
+                     reports are live from the MySQL server X seconds apart.
+                     If X is a list of infiles (file1 file2 etc.),
+                     reports are generated from the infiles in the order
+                     that they are given.
+   --report-count N  Collect N number of live relative reports (default 1)
+   --detach          Fork and detach from terminal (run in background)
+   --help            Prints this
+   --debug           Print debugging information
+
+Visit http://hackmysql.com/mysqlreport for more information.
+HELP
+
+   exit;
+}
+
+sub get_user_mycnf
+{
+   print "get_user_mycnf\n" if $op{debug};
+
+   return if $WIN;
+   open MYCNF, "$ENV{HOME}/.my.cnf" or return;
+   while(<MYCNF>)
+   {
+      if(/^(.+?)\s*=\s*"?(.+?)"?\s*$/)
+      {
+         $mycnf{$1} = $2;
+         print "get_user_mycnf: read '$1 = $2'\n" if $op{debug};
+      }
+   }
+   $mycnf{'pass'} ||= $mycnf{'password'} if exists $mycnf{'password'};
+   close MYCNF;
+}
+
+sub connect_to_MySQL
+{
+   print "connect_to_MySQL\n" if $op{debug};
+
+   my $dsn;
+
+   if($mycnf{'socket'} && -S $mycnf{'socket'})
+   {
+      $dsn = "DBI:mysql:mysql_socket=$mycnf{socket}";
+   }
+   elsif($mycnf{'host'})
+   {
+      $dsn = "DBI:mysql:host=$mycnf{host}" . ($mycnf{port} ? ";port=$mycnf{port}" : "");
+   }
+   else
+   {
+      $dsn = "DBI:mysql:host=localhost";
+   }
+
+   print "connect_to_MySQL: DBI DSN: $dsn\n" if $op{debug};
+
+   $dbh = DBI->connect($dsn, $mycnf{'user'}, $mycnf{'pass'}) or die;
+}
+
+sub collect_reports
+{
+   print "collect_reports\n" if $op{debug};
+
+   my $i;
+
+   get_vals();
+   get_vars();
+
+   get_Com_values();
+
+   %stats_past = %stats;
+
+   set_myisam_vals();
+   set_ib_vals() if $have_innodb_vals;
+
+   print "#\n# Beginning report, 0 0:0:0\n#\n";
+
+   write_report();
+
+   for($i = 0; $i < $op{'c'}; $i++)
+   {
+      $dbh->disconnect();
+
+      sleep($op{'r'});
+
+      connect_to_MySQL();
+
+      print "\n#\n# Interval report " , $i + 1 , ", +", sec_to_dhms(($i + 1) * $op{'r'}), "\n#\n";
+
+      get_vals();
+
+      write_relative_report();
+   }
+}
+
+sub read_relative_infiles
+{
+   print "read_relative_infiles\n" if $op{debug};
+
+   my $slurp;    # Used to check infiles for multiple sets of status values
+   my $n_stats;  # Number of multiple sets of status values in an infile
+   my $infile;
+   my $report_n; # Report number
+
+   $report_n = 1;
+
+   foreach $infile (@ARGV)
+   {
+      # Read all of infile into $slurp
+      open INFILE, "< $infile" or warn and next;
+      $slurp = do { local $/;  <INFILE> };
+      close INFILE;
+
+      $n_stats = 0;
+
+      # Count number of status value sets
+      $n_stats++ while $slurp =~ /Aborted_clients/g;
+
+      print "read_relative_infiles: found $n_stats sets of status values in file '$infile'\n"
+         if $op{debug};
+
+      if($n_stats == 1)
+      {
+         read_infile($infile);
+         relative_infile_report($report_n++);
+      }
+
+      if($n_stats > 1)
+      {
+         my @tmpfile_fh;
+         my @tmpfile_name;
+         my $i;
+         my $stat_n;  # Status value set number
+
+         # Create a tmp file for each set of status values
+         for($i = 0; $i < $n_stats; $i++)
+         {
+            my ($fh, $name) = tempfile()
+               or die "read_relative_infiles: cannot open temporary file for writing: $!\n";
+
+            push(@tmpfile_fh, $fh);
+            push(@tmpfile_name, $name);
+
+            print "read_relative_infiles: created tmp file '$name' for set $i\n" if $op{debug};
+         }
+
+         $i = 0;
+         $stat_n = 0;
+
+         select $tmpfile_fh[$i];
+
+         # Read infile again and copy each set of status values to seperate tmp files
+         open INFILE, "< $infile" or warn and next;
+         while(<INFILE>)
+         {
+            next if /^\+/;
+            next if /^$/;
+
+            # The infile must begin with the system variable values.
+            # Therefore, the first occurance of Aborted_clients indicates the beginning
+            # of the first set of status values if no sets have occured yet ($stat_n == 0).
+            # In this case, the following status values are printed to the current fh,
+            # along with the system variable values read thus far, until Aborted_clients
+            # occurs again. Then begins the second and subsequent sets of status values.
+
+            if(/Aborted_clients/)
+            {
+               print and next if $stat_n++ == 0;
+               select $tmpfile_fh[++$i];
+            }
+
+            print;
+         }
+         close INFILE;
+
+         # Re-select the main tmp file into which the reports are being written.
+         select $tmpfile_fh;
+
+         for($i = 0; $i < $n_stats; $i++)
+         {
+            close $tmpfile_fh[$i];
+
+            print "read_relative_infiles: reading set $i tmp file '$tmpfile_name[$i]'\n"
+               if $op{debug};
+
+            read_infile($tmpfile_name[$i]);
+            relative_infile_report($report_n++);
+
+            if($WIN) { `del $tmpfile_name[$i]`;   }
+            else     { `rm -f $tmpfile_name[$i]`; }
+
+            print "read_relative_infiles: deleted set $i tmp file '$tmpfile_name[$i]'\n"
+               if $op{debug};
+         }
+
+      } # if($n_stats > 1)
+   } # foreach $infile (@files)
+}
+
+sub relative_infile_report
+{
+   print "relative_infile_report\n" if $op{debug};
+
+   my $report_n = shift;
+
+   if($report_n == 1)
+   {
+      get_Com_values();
+
+      %stats_past = %stats;
+
+      set_myisam_vals();
+      set_ib_vals() if $have_innodb_vals;
+
+      print "#\n# Beginning report, 0 0:0:0\n#\n";
+
+      write_report();
+   }
+   else
+   {
+      print "\n#\n# Interval report ", $report_n - 1, ", +",
+         sec_to_dhms($stats{Uptime} - $stats_past{Uptime}),
+         "\n#\n";
+
+      write_relative_report();
+   }
+}
+
+sub get_vals
+{
+   print "get_vals\n" if $op{debug};
+
+   my @row;
+
+   # Get status values
+   if($MySQL_version >= 50002)
+   {
+      $query = $dbh->prepare("SHOW GLOBAL STATUS;");
+   }
+   else
+   {
+      $query = $dbh->prepare("SHOW STATUS;");
+   }
+   $query->execute();
+   while(@row = $query->fetchrow_array()) { $stats{$row[0]} = $row[1]; }
+
+   $real_uptime = $stats{'Uptime'};
+}
+
+sub get_vars
+{
+   print "get_vars\n" if $op{debug};
+
+   my @row;
+
+   # Get server system variables
+   $query = $dbh->prepare("SHOW VARIABLES;");
+   $query->execute();
+   while(@row = $query->fetchrow_array()) { $vars{$row[0]} = $row[1]; }
+
+   # table_cache was renamed to table_open_cache in MySQL 5.1.3
+   if($MySQL_version >= 50103)
+   {
+      $vars{'table_cache'} = $vars{'table_open_cache'};
+   }
+}
+
+sub read_infile
+{
+   print "read_infile\n" if $op{debug};
+
+   my $infile = shift;
+
+   # Default required system variable values if not set in INFILE.
+   # As of mysqlreport v3.5 the direct output from SHOW VARIABLES;
+   # can be put into INFILE instead. See http://hackmysql.com/mysqlreportdoc
+   # for details.
+   $vars{'version'} = "0.0.0"         if !exists $vars{'version'};
+   $vars{'table_cache'} = 64          if !exists $vars{'table_cache'};
+   $vars{'max_connections'} = 100     if !exists $vars{'max_connections'};
+   $vars{'key_buffer_size'} = 8388600 if !exists $vars{'key_buffer_size'}; # 8M
+   $vars{'thread_cache_size'} = 0     if !exists $vars{'thread_cache_size'}; 
+   $vars{'tmp_table_size'} = 0        if !exists $vars{'tmp_table_size'};
+   $vars{'long_query_time'} = '?'     if !exists $vars{'long_query_time'};
+   $vars{'log_slow_queries'} = '?'    if !exists $vars{'log_slow_queries'};
+
+   # One should also add:
+   #    key_cache_block_size
+   #    query_cache_size
+   # to INFILE if needed.
+
+   open INFILE, "< $infile" or die "Cannot open INFILE '$infile': $!\n";
+
+   while(<INFILE>)
+   {
+      last if !defined $_;
+
+      next if /^\+/;  # skip divider lines 
+      next if /^$/;   # skip blank lines
+
+      next until /(Aborted_clients|back_log|=)/;
+
+      if($1 eq 'Aborted_clients')  # status values
+      {
+         print "read_infile: start stats\n" if $op{debug};
+
+         while($_)
+         {
+            chomp;
+            if(/([A-Za-z_]+)[\s\t|]+(\d+)/)
+            {
+               $stats{$1} = $2;
+               print "read_infile: save $1 = $2\n" if $op{debug};
+            }
+            else { print "read_infile: ignore '$_'\n" if $op{debug}; }
+
+            last if $1 eq 'Uptime';  # exit while() if end of status values
+            $_ = <INFILE>; # otherwise, read next line of status values
+         }
+      }
+      elsif($1 eq  'back_log')  # system variable values
+      {
+         print "read_infile: start vars\n" if $op{debug};
+
+         while($_)
+         {
+            chomp;
+            if(/([A-Za-z_]+)[\s\t|]+([\w\.\-]+)/)  # This will exclude some vars
+            {                                      # like pid_file which we don't need
+               $vars{$1} = $2;
+               print "read_infile: save $1 = $2\n" if $op{debug};
+            }
+            else { print "read_infile: ignore '$_'\n" if $op{debug}; }
+
+            last if $1 eq 'wait_timeout';  # exit while() if end of vars
+            $_ = <INFILE>; # otherwise, read next line of vars
+         }
+      }
+      elsif($1 eq '=')  # old style, manually added system variable values
+      {
+         print "read_infile: start old vars\n" if $op{debug};
+
+         while($_ && $_ =~ /=/)
+         {
+            chomp;
+            if(/^\s*(\w+)\s*=\s*([0-9.]+)(M*)\s*$/)  # e.g.: key_buffer_size = 128M
+            {
+               $vars{$1} = ($3 ? $2 * 1024 * 1024 : $2);
+               print "read_infile: read '$_' as $1 = $vars{$1}\n" if $op{debug};
+            }
+            else { print "read_infile: ignore '$_'\n" if $op{debug}; }
+
+            $_ = <INFILE>; # otherwise, read next line of old vars
+         }
+
+         redo;
+      }
+      else
+      {
+         print "read_infile: unrecognized line: '$_'\n" if $op{debug};
+      }
+   }
+
+   close INFILE;
+
+   $real_uptime = $stats{'Uptime'};
+
+   $vars{'table_cache'} = $vars{'table_open_cache'} if exists $vars{'table_open_cache'};
+
+   get_MySQL_version();
+}
+
+sub get_MySQL_version
+{
+   print "get_MySQL_version\n" if $op{debug};
+
+   return if $MySQL_version;
+
+   my ($major, $minor, $patch);
+
+   if($op{'infile'} || $relative_infiles)
+   {
+      ($major, $minor, $patch) = ($vars{'version'} =~ /(\d{1,2})\.(\d{1,2})\.(\d{1,2})/);
+   }
+   else
+   {
+      my @row;
+
+      $query = $dbh->prepare("SHOW VARIABLES LIKE 'version';");
+      $query->execute();
+      @row = $query->fetchrow_array();
+      ($major, $minor, $patch) = ($row[1] =~ /(\d{1,2})\.(\d{1,2})\.(\d{1,2})/);
+   }
+
+   $MySQL_version = sprintf("%d%02d%02d", $major, $minor, $patch);
+
+   # Innodb_ status values were added in 5.0.2
+   if($MySQL_version < 50002)
+   {
+      $have_innodb_vals = 0;
+      print "get_MySQL_version: no InnoDB reports because MySQL version is older than 5.0.2\n" if $op{debug};
+   }
+}
+
+sub set_myisam_vals
+{
+   print "set_myisam_vals\n" if $op{debug};
+
+   $questions = $stats{'Questions'};
+
+   $key_read_ratio = sprintf "%.2f",
+                     ($stats{'Key_read_requests'} ?
+                      100 - ($stats{'Key_reads'} / $stats{'Key_read_requests'}) * 100 :
+                      0);
+
+   $key_write_ratio = sprintf "%.2f",
+                      ($stats{'Key_write_requests'} ?
+                       100 - ($stats{'Key_writes'} / $stats{'Key_write_requests'}) * 100 :
+                       0);
+
+   $key_cache_block_size = (defined $vars{'key_cache_block_size'} ?
+                            $vars{'key_cache_block_size'} :
+                            1024);
+
+   $key_buffer_used = $stats{'Key_blocks_used'} * $key_cache_block_size;
+
+   if(defined $stats{'Key_blocks_unused'}) # MySQL 4.1.2+
+   {
+      $key_buffer_usage =  $vars{'key_buffer_size'} -
+                           ($stats{'Key_blocks_unused'} * $key_cache_block_size);
+   }
+   else { $key_buffer_usage = -1; }
+
+   # Data Manipulation Statements: http://dev.mysql.com/doc/refman/5.0/en/data-manipulation.html
+   %DMS_vals =
+   (
+      SELECT  => $stats{'Com_select'},
+      INSERT  => $stats{'Com_insert'}  + $stats{'Com_insert_select'},
+      REPLACE => $stats{'Com_replace'} + $stats{'Com_replace_select'},
+      UPDATE  => $stats{'Com_update'}  +
+                 (exists $stats{'Com_update_multi'} ? $stats{'Com_update_multi'} : 0),
+      DELETE  => $stats{'Com_delete'}  +
+                 (exists $stats{'Com_delete_multi'} ? $stats{'Com_delete_multi'} : 0)
+   );
+
+   $dms = $DMS_vals{SELECT} + $DMS_vals{INSERT} + $DMS_vals{REPLACE} + $DMS_vals{UPDATE} + $DMS_vals{DELETE};
+
+   $slow_query_t = format_u_time($vars{long_query_time});
+
+}
+
+sub set_ib_vals
+{
+   print "set_ib_vals\n" if $op{debug};
+
+   $ib_bp_used  = ($stats{'Innodb_buffer_pool_pages_total'} -
+                   $stats{'Innodb_buffer_pool_pages_free'}) *
+                   $stats{'Innodb_page_size'};
+
+   $ib_bp_total = $stats{'Innodb_buffer_pool_pages_total'} * $stats{'Innodb_page_size'};
+
+   $ib_bp_read_ratio = sprintf "%.2f",
+                       ($stats{'Innodb_buffer_pool_read_requests'} ?
+                        100 - ($stats{'Innodb_buffer_pool_reads'} /
+                           $stats{'Innodb_buffer_pool_read_requests'}) * 100 :
+                        0);
+}
+
+sub write_relative_report
+{
+   print "write_relative_report\n" if $op{debug};
+
+   %stats_present = %stats;
+
+   for(keys %stats)
+   {
+      if($stats_past{$_} =~ /\d+/)
+      {
+         if($stats_present{$_} >= $stats_past{$_}) # Avoid negative values
+         {
+            $stats{$_} = $stats_present{$_} - $stats_past{$_};
+         }
+      }
+   }
+
+   # These values are either "at present" or "high water marks".
+   # Therefore, it is more logical to not relativize these values.
+   # Doing otherwise causes strange and misleading values.
+   $stats{'Key_blocks_used'}      = $stats_present{'Key_blocks_used'};
+   $stats{'Open_tables'}          = $stats_present{'Open_tables'};
+   $stats{'Max_used_connections'} = $stats_present{'Max_used_connections'};
+   $stats{'Threads_running'}      = $stats_present{'Threads_running'};
+   $stats{'Threads_connected'}    = $stats_present{'Threads_connected'};
+   $stats{'Threads_cached'}       = $stats_present{'Threads_cached'};
+   $stats{'Qcache_free_blocks'}   = $stats_present{'Qcache_free_blocks'};
+   $stats{'Qcache_total_blocks'}  = $stats_present{'Qcache_total_blocks'};
+   $stats{'Qcache_free_memory'}   = $stats_present{'Qcache_free_memory'};
+   if($have_innodb_vals)
+   {
+      $stats{'Innodb_page_size'}                 = $stats_present{'Innodb_page_size'};
+      $stats{'Innodb_buffer_pool_pages_data'}    = $stats_present{'Innodb_buffer_pool_pages_data'};
+      $stats{'Innodb_buffer_pool_pages_dirty'}   = $stats_present{'Innodb_buffer_pool_pages_dirty'};
+      $stats{'Innodb_buffer_pool_pages_free'}    = $stats_present{'Innodb_buffer_pool_pages_free'};
+      $stats{'Innodb_buffer_pool_pages_latched'} = $stats_present{'Innodb_buffer_pool_pages_latched'};
+      $stats{'Innodb_buffer_pool_pages_misc'}    = $stats_present{'Innodb_buffer_pool_pages_misc'};
+      $stats{'Innodb_buffer_pool_pages_total'}   = $stats_present{'Innodb_buffer_pool_pages_total'};
+      $stats{'Innodb_data_pending_fsyncs'}       = $stats_present{'Innodb_data_pending_fsyncs'};
+      $stats{'Innodb_data_pending_reads'}        = $stats_present{'Innodb_data_pending_reads'};
+      $stats{'Innodb_data_pending_writes'}       = $stats_present{'Innodb_data_pending_writes'};
+
+      # Innodb_row_lock_ values were added in MySQL 5.0.3
+      if($MySQL_version >= 50003)
+      {
+         $stats{'Innodb_row_lock_current_waits'} = $stats_present{'Innodb_row_lock_current_waits'};
+         $stats{'Innodb_row_lock_time_avg'}      = $stats_present{'Innodb_row_lock_time_avg'};
+         $stats{'Innodb_row_lock_time_max'}      = $stats_present{'Innodb_row_lock_time_max'};
+      }
+   }
+
+   get_Com_values();
+
+   %stats_past = %stats_present;
+
+   set_myisam_vals();
+   set_ib_vals() if $have_innodb_vals;
+
+   write_report();
+}
+
+sub write_report
+{
+   print "write_report\n" if $op{debug};
+
+   $~ = 'MYSQL_TIME', write;
+   $~ = 'KEY_BUFF_MAX', write;
+   if($key_buffer_usage != -1) { $~ = 'KEY_BUFF_USAGE', write }
+   $~ = 'KEY_RATIOS', write;
+   write_DTQ();
+   $~ = 'SLOW_DMS', write;
+   write_DMS();
+   write_Com();
+   $~ = 'SAS', write; 
+   write_qcache(); 
+   $~ = 'REPORT_END', write;
+   $~ = 'TAB', write;
+
+   write_InnoDB() if $have_innodb_vals;
+}
+
+sub sec_to_dhms # Seconds to days hours:minutes:seconds
+{
+   my $s = shift;
+   my ($d, $h, $m) = (0, 0, 0);
+
+   return '0 0:0:0' if $s <= 0;
+
+   if($s >= 86400)
+   {
+      $d = int $s / 86400;
+      $s -= $d * 86400;
+   }
+
+   if($s >= 3600)
+   {
+     $h = int $s / 3600;
+     $s -= $h * 3600;
+   }
+   
+   $m = int $s / 60;
+   $s -= $m * 60;
+   
+   return "$d $h:$m:$s";
+}
+
+sub make_short
+{
+   my ($number, $kb, $d) = @_;
+   my $n = 0;
+   my $short;
+
+   $d ||= 2;
+
+   if($kb) { while ($number > 1023) { $number /= 1024; $n++; }; }
+   else { while ($number > 999) { $number /= 1000; $n++; }; }
+
+   $short = sprintf "%.${d}f%s", $number, ('','k','M','G','T')[$n];
+   if($short =~ /^(.+)\.(00)$/) { return $1; } # 12.00 -> 12 but not 12.00k -> 12k
+
+   return $short;
+}
+
+# What began as a simple but great idea has become the new standard:
+# long_query_time in microseconds. For MySQL 5.1.21+ and 6.0.4+ this
+# is now standard. For 4.1 and 5.0 patches, the architects of this
+# idea provide: http://www.mysqlperformanceblog.com/mysql-patches/
+# Relevant notes in MySQL manual:
+# http://dev.mysql.com/doc/refman/5.1/en/slow-query-log.html
+# http://dev.mysql.com/doc/refman/6.0/en/slow-query-log.html
+#
+# The format_u_time sub simply beautifies long_query_time.
+
+sub format_u_time  # format microsecond (µ) time value
+{
+   # 0.000000 - 0.000999 = 0 - 999 µ
+   # 0.001000 - 0.999999 = 1 ms - 999.999 ms
+   # 1.000000 - n.nnnnnn = 1 s - n.nnnnn s
+
+   my $t = shift;
+   my $f;  # formatted µ time
+   my $u = chr(($WIN ? 230 : 181));
+
+   $t = 0 if $t < 0;
+
+   if($t > 0 && $t <= 0.000999)
+   {
+      $f = ($t * 1000000) . " $u";
+   }
+   elsif($t >= 0.001000 && $t <= 0.999999)
+   {
+      $f = ($t * 1000) . ' ms';
+   }
+   elsif($t >= 1)
+   {
+      $f = ($t * 1) . ' s';  # * 1 to remove insignificant zeros
+   }
+   else
+   {
+      $f = 0;  # $t should = 0 at this point
+   }
+
+   return $f;
+}
+
+sub perc # Percentage
+{
+   my($is, $of) = @_;
+   $is = 0 if (not defined $is);
+   return sprintf "%.2f", ($is * 100) / ($of ||= 1);
+}
+
+sub t # Time average per second
+{
+   my $val = shift;
+   return 0 if !$val;
+   return(make_short($val / $stats{'Uptime'}, 0, 1));
+}
+
+sub email_report # Email given report to $op{'email'}
+{
+   print "email_report\n" if $op{debug};
+
+   return if $WIN;
+
+   my $report = shift;
+
+   open SENDMAIL, "|/usr/sbin/sendmail -t";
+   print SENDMAIL "From: mysqlreport\n";
+   print SENDMAIL "To: $op{email}\n";
+   print SENDMAIL "Subject: MySQL status report on " . ($mycnf{'host'} || 'localhost') . "\n\n";
+   print SENDMAIL `cat $report`;
+   close SENDMAIL;
+}
+
+sub cat_report # Print given report to screen
+{
+   print "cat_report\n" if $op{debug};
+
+   my $report = shift;
+   my @report;
+
+   open REPORT, "< $report";
+   @report = <REPORT>;
+   close REPORT;
+   print @report;
+}
+
+sub get_Com_values
+{
+   print "get_Com_values\n" if $op{debug};
+
+   %Com_vals = ();
+
+   # Make copy of just the Com_ values
+   for(keys %stats)
+   {
+      if(grep /^Com_/, $_ and $stats{$_} > 0)
+      {
+         /^Com_(.*)/;
+         $Com_vals{$1} = $stats{$_};
+      }
+   }
+
+   # Remove DMS values
+   delete $Com_vals{'select'};
+   delete $Com_vals{'insert'};
+   delete $Com_vals{'insert_select'};
+   delete $Com_vals{'replace'};
+   delete $Com_vals{'replace_select'};
+   delete $Com_vals{'update'};
+   delete $Com_vals{'update_multi'} if exists $Com_vals{'update_multi'};
+   delete $Com_vals{'delete'};
+   delete $Com_vals{'delete_multi'} if exists $Com_vals{'delete_multi'};
+}
+
+sub write_DTQ # Write DTQ report in descending order by values
+{
+   print "write_DTQ\n" if $op{debug};
+
+   $~ = 'DTQ';
+
+   my %DTQ;
+   my $first = 1;
+
+   # Total Com values
+   $stat_val = 0;
+   for(values %Com_vals) { $stat_val += $_; }
+   $DTQ{'Com_'} = $stat_val;
+
+   $DTQ{'DMS'}      = $dms;
+   $DTQ{'QC Hits'}  = $stats{'Qcache_hits'} if $stats{'Qcache_hits'} != 0;
+   $DTQ{'COM_QUIT'} = int (($stats{'Connections'} - 2) - ($stats{'Aborted_clients'} / 2));
+
+   $stat_val = 0;
+   for(values %DTQ) { $stat_val += $_; }
+   if($questions != $stat_val)
+   {
+      $DTQ{($questions > $stat_val ? '+Unknown' : '-Unknown')} = abs $questions - $stat_val;
+   }
+
+   for(sort { $DTQ{$b} <=> $DTQ{$a} } keys(%DTQ))
+   {
+      if($first) { $stat_label = '%Total:'; $first = 0; }
+      else       { $stat_label = ''; }
+
+      $stat_name = $_;
+      $stat_val  = $DTQ{$_};
+      write;
+   }
+}
+
+sub write_DMS # Write DMS report in descending order by values
+{
+   print "write_DMS\n" if $op{debug};
+
+   $~ = 'DMS';
+
+   for(sort { $DMS_vals{$b} <=> $DMS_vals{$a} } keys(%DMS_vals))
+   {
+      $stat_name = $_;
+      $stat_val  = $DMS_vals{$_};
+      write;
+   }
+}
+
+sub write_Com # Write COM report in descending order by values
+{
+   print "write_Com\n" if $op{debug};
+
+   my $i = $op{'com'};
+
+   $~ = 'COM_1';
+
+   # Total Com values and write first line of COM report
+   $stat_label = '%Total:' unless $op{'dtq'};
+   $stat_val   = 0;
+   for(values %Com_vals) { $stat_val += $_; }
+   write;
+
+   $~ = 'COM_2';
+
+   # Sort remaining Com values, print only the top $op{'com'} number of values
+   for(sort { $Com_vals{$b} <=> $Com_vals{$a} } keys(%Com_vals))
+   {
+      $stat_name = $_;
+      $stat_val  = $Com_vals{$_};
+      write;
+
+      last if !(--$i);
+   }
+}
+
+sub write_qcache
+{
+   print "write_qcache\n" if $op{debug};
+
+   # Query cache was added in 4.0.1, but have_query_cache was added in 4.0.2,
+   # ergo this method is slightly more reliable
+   return if not exists $vars{'query_cache_size'};
+   return if $vars{'query_cache_size'} == 0;
+
+   $qc_mem_used = $vars{'query_cache_size'} - $stats{'Qcache_free_memory'};
+   $qc_hi_r = sprintf "%.2f", $stats{'Qcache_hits'} / ($stats{'Qcache_inserts'} ||= 1);
+   $qc_ip_r = sprintf "%.2f", $stats{'Qcache_inserts'} / ($stats{'Qcache_lowmem_prunes'} ||= 1);
+
+   $~ = 'QCACHE';
+   write;
+}
+
+sub write_InnoDB
+{
+   print "write_InnoDB\n" if $op{debug};
+
+   return if not defined $stats{'Innodb_page_size'};
+
+   $stats{'Innodb_buffer_pool_pages_latched'} = 0 if not defined $stats{'Innodb_buffer_pool_pages_latched'};
+
+   $~ = 'IB';
+   write;
+
+   # Innodb_row_lock_ values were added in MySQL 5.0.3
+   if($MySQL_version >= 50003)
+   {
+      $~ = 'IB_LOCK';
+      write;
+   }
+
+   # Data, Pages, Rows
+   $~ = 'IB_DPR';
+   write;
+}
+
+sub have_op
+{
+   my $key = shift;
+   return 1 if (exists $op{$key} && $op{$key} ne '');
+   return 0;
+}
+
+sub sig_handler
+{
+   print "\nReceived signal at " , scalar localtime , "\n";
+   exit_tasks_and_cleanup();
+   exit;
+}
+
+sub exit_tasks_and_cleanup
+{
+   print "exit_tasks_and_cleanup\n" if $op{debug};
+
+   close $tmpfile_fh;
+   select STDOUT unless $op{'detach'};
+
+   email_report($tmpfile) if $op{'email'};
+
+   cat_report($tmpfile) unless $op{'detach'};
+
+   if($op{'outfile'})
+   {
+      if($WIN) { `move $tmpfile $op{outfile}`; }
+      else     { `mv $tmpfile $op{outfile}`;   }
+   }
+   else
+   {
+      if($WIN) { `del $tmpfile`;   }
+      else     { `rm -f $tmpfile`; }
+   }
+
+   if(!$op{'infile'} && !$relative_infiles)
+   {
+      if($op{'flush-status'})
+      {
+         $query = $dbh->prepare("FLUSH STATUS;");
+         $query->execute();
+      }
+
+      $query->finish();
+      $dbh->disconnect();
+   }
+}
+
+#
+# Formats
+#
+
+format MYSQL_TIME =
+MySQL @<<<<<<<<<<<<<<<<  uptime @<<<<<<<<<<<   @>>>>>>>>>>>>>>>>>>>>>>>>
+$vars{'version'}, sec_to_dhms($real_uptime), (($op{infile} || $relative_infiles) ? '' : scalar localtime)
+.
+
+format KEY_BUFF_MAX =
+
+__ Key _________________________________________________________________
+Buffer used   @>>>>>> of @>>>>>>  %Used: @>>>>>
+make_short($key_buffer_used, 1), make_short($vars{'key_buffer_size'}, 1), perc($key_buffer_used, $vars{'key_buffer_size'})
+.
+
+format KEY_BUFF_USAGE =
+  Current     @>>>>>>            %Usage: @>>>>>
+make_short($key_buffer_usage, 1), perc($key_buffer_usage, $vars{'key_buffer_size'})
+.
+
+format KEY_RATIOS =
+Write hit     @>>>>>%
+$key_write_ratio
+Read hit      @>>>>>%
+$key_read_ratio
+
+__ Questions ___________________________________________________________
+Total       @>>>>>>>>  @>>>>>/s
+make_short($questions), t($questions)
+.
+
+format DTQ =
+  @<<<<<<<  @>>>>>>>>  @>>>>>/s  @>>>>>> @>>>>>
+$stat_name, make_short($stat_val), t($stat_val), $stat_label, perc($stat_val, $questions)
+.
+
+format SLOW_DMS =
+Slow @<<<<<<< @>>>>>>  @>>>>>/s          @>>>>>  %DMS: @>>>>>  Log: @>> 
+$slow_query_t, make_short($stats{'Slow_queries'}), t($stats{'Slow_queries'}), perc($stats{'Slow_queries'}, $questions), perc($stats{'Slow_queries'}, $dms), $vars{'log_slow_queries'}
+DMS         @>>>>>>>>  @>>>>>/s          @>>>>>
+make_short($dms), t($dms), perc($dms, $questions)
+.
+
+format DMS =
+  @<<<<<<<  @>>>>>>>>  @>>>>>/s          @>>>>>        @>>>>>
+$stat_name, make_short($stat_val), t($stat_val), perc($stat_val, $questions), perc($stat_val, $dms)
+.
+
+format COM_1 =
+Com_        @>>>>>>>>  @>>>>>/s          @>>>>>
+make_short($stat_val), t($stat_val), perc($stat_val, $questions)
+.
+
+format COM_2 =
+  @<<<<<<<<<< @>>>>>>  @>>>>>/s          @>>>>>
+$stat_name, make_short($stat_val), t($stat_val), perc($stat_val, $questions)
+.
+
+format SAS =
+
+__ SELECT and Sort _____________________________________________________
+Scan          @>>>>>>   @>>>>/s %SELECT: @>>>>>
+make_short($stats{'Select_scan'}), t($stats{'Select_scan'}), perc($stats{'Select_scan'}, $stats{'Com_select'})
+Range         @>>>>>>   @>>>>/s          @>>>>>
+make_short($stats{'Select_range'}), t($stats{'Select_range'}), perc($stats{'Select_range'}, $stats{'Com_select'})
+Full join     @>>>>>>   @>>>>/s          @>>>>>
+make_short($stats{'Select_full_join'}), t($stats{'Select_full_join'}), perc($stats{'Select_full_join'}, $stats{'Com_select'})
+Range check   @>>>>>>   @>>>>/s          @>>>>>
+make_short($stats{'Select_range_check'}), t($stats{'Select_range_check'}), perc($stats{'Select_range_check'}, $stats{'Com_select'})
+Full rng join @>>>>>>   @>>>>/s          @>>>>>
+make_short($stats{'Select_full_range_join'}), t($stats{'Select_full_range_join'}), perc($stats{'Select_full_range_join'}, $stats{'Com_select'})
+Sort scan     @>>>>>>   @>>>>/s
+make_short($stats{'Sort_scan'}), t($stats{'Sort_scan'})
+Sort range    @>>>>>>   @>>>>/s
+make_short($stats{'Sort_range'}), t($stats{'Sort_range'})
+Sort mrg pass @>>>>>>   @>>>>/s
+make_short($stats{'Sort_merge_passes'}), t($stats{'Sort_merge_passes'})
+.
+
+format QCACHE =
+
+__ Query Cache _________________________________________________________
+Memory usage  @>>>>>> of @>>>>>>  %Used: @>>>>>
+make_short($qc_mem_used, 1), make_short($vars{'query_cache_size'}, 1), perc($qc_mem_used, $vars{'query_cache_size'})
+Block Fragmnt @>>>>>%
+perc($stats{'Qcache_free_blocks'}, $stats{'Qcache_total_blocks'})
+Hits          @>>>>>>   @>>>>/s
+make_short($stats{'Qcache_hits'}), t($stats{'Qcache_hits'})
+Inserts       @>>>>>>   @>>>>/s
+make_short($stats{'Qcache_inserts'}), t($stats{'Qcache_inserts'})
+Insrt:Prune @>>>>>>:1   @>>>>/s
+make_short($qc_ip_r), t($stats{'Qcache_inserts'} - $stats{'Qcache_lowmem_prunes'})
+Hit:Insert  @>>>>>>:1
+$qc_hi_r, t($qc_hi_r)
+.
+
+# Not really the end...
+format REPORT_END =
+
+__ Table Locks _________________________________________________________
+Waited      @>>>>>>>>  @>>>>>/s  %Total: @>>>>>
+make_short($stats{'Table_locks_waited'}), t($stats{'Table_locks_waited'}), perc($stats{'Table_locks_waited'}, $stats{'Table_locks_waited'} + $stats{'Table_locks_immediate'});
+Immediate   @>>>>>>>>  @>>>>>/s
+make_short($stats{'Table_locks_immediate'}), t($stats{'Table_locks_immediate'})
+
+__ Tables ______________________________________________________________
+Open        @>>>>>>>> of @>>>    %Cache: @>>>>>
+$stats{'Open_tables'}, $vars{'table_cache'}, perc($stats{'Open_tables'}, $vars{'table_cache'})
+Opened      @>>>>>>>>  @>>>>>/s
+make_short($stats{'Opened_tables'}), t($stats{'Opened_tables'})
+
+__ Connections _________________________________________________________
+Max used    @>>>>>>>> of @>>>      %Max: @>>>>>
+$stats{'Max_used_connections'}, $vars{'max_connections'}, perc($stats{'Max_used_connections'}, $vars{'max_connections'})
+Total       @>>>>>>>>  @>>>>>/s
+make_short($stats{'Connections'}), t($stats{'Connections'})
+
+__ Created Temp ________________________________________________________
+Disk table  @>>>>>>>>  @>>>>>/s
+make_short($stats{'Created_tmp_disk_tables'}), t($stats{'Created_tmp_disk_tables'})
+Table       @>>>>>>>>  @>>>>>/s    Size: @>>>>>
+make_short($stats{'Created_tmp_tables'}), t($stats{'Created_tmp_tables'}), make_short($vars{'tmp_table_size'}, 1, 1)
+File        @>>>>>>>>  @>>>>>/s
+make_short($stats{'Created_tmp_files'}), t($stats{'Created_tmp_files'})
+.
+
+format TAB =
+
+__ Threads _____________________________________________________________
+Running     @>>>>>>>> of @>>>
+$stats{'Threads_running'}, $stats{'Threads_connected'}
+Cached      @>>>>>>>> of @>>>      %Hit: @>>>>>
+$stats{'Threads_cached'}, $vars{'thread_cache_size'}, make_short(100 - perc($stats{'Threads_created'}, $stats{'Connections'}))
+Created     @>>>>>>>>  @>>>>>/s
+make_short($stats{'Threads_created'}), t($stats{'Threads_created'})
+Slow        @>>>>>>>>  @>>>>>/s
+$stats{'Slow_launch_threads'}, t($stats{'Slow_launch_threads'})
+
+__ Aborted _____________________________________________________________
+Clients     @>>>>>>>>  @>>>>>/s
+make_short($stats{'Aborted_clients'}), t($stats{'Aborted_clients'})
+Connects    @>>>>>>>>  @>>>>>/s
+make_short($stats{'Aborted_connects'}), t($stats{'Aborted_connects'})
+
+__ Bytes _______________________________________________________________
+Sent        @>>>>>>>>  @>>>>>/s
+make_short($stats{'Bytes_sent'}), t($stats{'Bytes_sent'})
+Received    @>>>>>>>>  @>>>>>/s
+make_short($stats{'Bytes_received'}), t($stats{'Bytes_received'})
+.
+
+format IB =
+
+__ InnoDB Buffer Pool __________________________________________________
+Usage         @>>>>>> of @>>>>>>  %Used: @>>>>>
+make_short($ib_bp_used, 1), make_short($ib_bp_total, 1), perc($ib_bp_used, $ib_bp_total)
+Read hit      @>>>>>%
+$ib_bp_read_ratio;
+Pages
+  Free      @>>>>>>>>            %Total: @>>>>>
+make_short($stats{'Innodb_buffer_pool_pages_free'}), perc($stats{'Innodb_buffer_pool_pages_free'}, $stats{'Innodb_buffer_pool_pages_total'})
+  Data      @>>>>>>>>                    @>>>>> %Drty: @>>>>>
+make_short($stats{'Innodb_buffer_pool_pages_data'}), perc($stats{'Innodb_buffer_pool_pages_data'}, $stats{'Innodb_buffer_pool_pages_total'}), perc($stats{'Innodb_buffer_pool_pages_dirty'}, $stats{'Innodb_buffer_pool_pages_data'})
+  Misc      @>>>>>>>>                    @>>>>>
+  $stats{'Innodb_buffer_pool_pages_misc'}, perc($stats{'Innodb_buffer_pool_pages_misc'}, $stats{'Innodb_buffer_pool_pages_total'})
+  Latched   @>>>>>>>>                    @>>>>>
+$stats{'Innodb_buffer_pool_pages_latched'}, perc($stats{'Innodb_buffer_pool_pages_latched'}, $stats{'Innodb_buffer_pool_pages_total'})
+Reads       @>>>>>>>>  @>>>>>/s  
+make_short($stats{'Innodb_buffer_pool_read_requests'}), t($stats{'Innodb_buffer_pool_read_requests'})
+  From file @>>>>>>>>  @>>>>>/s          @>>>>>
+make_short($stats{'Innodb_buffer_pool_reads'}), t($stats{'Innodb_buffer_pool_reads'}), perc($stats{'Innodb_buffer_pool_reads'}, $stats{'Innodb_buffer_pool_read_requests'})
+  Ahead Rnd @>>>>>>>>  @>>>>>/s
+$stats{'Innodb_buffer_pool_read_ahead_rnd'}, t($stats{'Innodb_buffer_pool_read_ahead_rnd'})
+  Ahead Sql @>>>>>>>>  @>>>>>/s
+$stats{'Innodb_buffer_pool_read_ahead_seq'}, t($stats{'Innodb_buffer_pool_read_ahead_seq'})
+Writes      @>>>>>>>>  @>>>>>/s
+make_short($stats{'Innodb_buffer_pool_write_requests'}), t($stats{'Innodb_buffer_pool_write_requests'})
+Flushes     @>>>>>>>>  @>>>>>/s
+make_short($stats{'Innodb_buffer_pool_pages_flushed'}), t($stats{'Innodb_buffer_pool_pages_flushed'})
+Wait Free   @>>>>>>>>  @>>>>>/s
+$stats{'Innodb_buffer_pool_wait_free'}, t($stats{'Innodb_buffer_pool_wait_free'})
+.
+
+format IB_LOCK =
+
+__ InnoDB Lock _________________________________________________________
+Waits       @>>>>>>>>  @>>>>>/s
+$stats{'Innodb_row_lock_waits'}, t($stats{'Innodb_row_lock_waits'})
+Current     @>>>>>>>>
+$stats{'Innodb_row_lock_current_waits'}
+Time acquiring
+  Total     @>>>>>>>> ms
+$stats{'Innodb_row_lock_time'}
+  Average   @>>>>>>>> ms
+$stats{'Innodb_row_lock_time_avg'}
+  Max       @>>>>>>>> ms
+$stats{'Innodb_row_lock_time_max'}
+.
+
+format IB_DPR =
+
+__ InnoDB Data, Pages, Rows ____________________________________________
+Data
+  Reads     @>>>>>>>>  @>>>>>/s
+make_short($stats{'Innodb_data_reads'}), t($stats{'Innodb_data_reads'})
+  Writes    @>>>>>>>>  @>>>>>/s
+make_short($stats{'Innodb_data_writes'}), t($stats{'Innodb_data_writes'})
+  fsync     @>>>>>>>>  @>>>>>/s
+make_short($stats{'Innodb_data_fsyncs'}), t($stats{'Innodb_data_fsyncs'})
+  Pending
+    Reads   @>>>>>>>>
+$stats{'Innodb_data_pending_reads'}, t($stats{'Innodb_data_pending_reads'})
+    Writes  @>>>>>>>>
+$stats{'Innodb_data_pending_writes'}, t($stats{'Innodb_data_pending_writes'})
+    fsync   @>>>>>>>>
+$stats{'Innodb_data_pending_fsyncs'}, t($stats{'Innodb_data_pending_fsyncs'})
+
+Pages
+  Created   @>>>>>>>>  @>>>>>/s
+make_short($stats{'Innodb_pages_created'}), t($stats{'Innodb_pages_created'})
+  Read      @>>>>>>>>  @>>>>>/s
+make_short($stats{'Innodb_pages_read'}), t($stats{'Innodb_pages_read'})
+  Written   @>>>>>>>>  @>>>>>/s
+make_short($stats{'Innodb_pages_written'}), t($stats{'Innodb_pages_written'})
+
+Rows
+  Deleted   @>>>>>>>>  @>>>>>/s
+make_short($stats{'Innodb_rows_deleted'}), t($stats{'Innodb_rows_deleted'})
+  Inserted  @>>>>>>>>  @>>>>>/s
+make_short($stats{'Innodb_rows_inserted'}), t($stats{'Innodb_rows_inserted'})
+  Read      @>>>>>>>>  @>>>>>/s
+make_short($stats{'Innodb_rows_read'}), t($stats{'Innodb_rows_read'})
+  Updated   @>>>>>>>>  @>>>>>/s
+make_short($stats{'Innodb_rows_updated'}), t($stats{'Innodb_rows_updated'})
+.
diff --git a/mysql-wsrep-5.6/debian/additions/mysqlreport.1 b/mysql-wsrep-5.6/debian/additions/mysqlreport.1
new file mode 100644 (file)
index 0000000..5ae6b9e
--- /dev/null
@@ -0,0 +1,180 @@
+.TH "mysqlreport" "1" "2.5 2006-09-01 (docrev 2006-05-19)" "Daniel Nichter" "MYSQL"
+.SH "NAME"
+.LP 
+mysqlreport \- Makes a friendly report of important MySQL status values
+.SH "SYNTAX"
+.LP 
+mysqlreport [\fIoptions\fP]
+.SH "DESCRIPTION"
+.LP 
+mysqlreport makes a friendly report of important MySQL status values. Actually,
+it makes a friendly report of nearly every status value from SHOW STATUS.
+Unlike SHOW STATUS which simply dumps over 100 values to screen in one long
+list, mysqlreport interprets and formats the values and presents the basic
+values and many more inferred values in a human\-readable format. Numerous
+example reports are available at the mysqlreport web page at
+http://hackmysql.com/mysqlreport.
+
+The benefit of mysqlreport is that it allows you to very quickly see a wide
+array of performance indicators for your MySQL server which would otherwise
+need to be calculated by hand from all the various SHOW STATUS values. For
+example, the Index Read Ratio is an important value but it's not present in
+SHOW STATUS; it's an inferred value (the ratio of Key_reads to
+Key_read_requests).
+
+This documentation outlines all the command line options in mysqlreport, most
+of which control which reports are printed. This document does not address
+how to interpret these reports; that topic is covered in the document Guide
+To Understanding mysqlreport at http://hackmysql.com/mysqlreportguide.
+
+.SH "OPTIONS"
+Technically, command line options are in the form \-\-option, but \-option works
+too. All options can be abbreviated if the abbreviation is unique. For example,
+option \-\-host can be abbreviated \-\-ho but not \-\-h because \-\-h is ambiguous: it
+could mean \-\-host or \-\-help.
+
+.LP 
+
+.TP 
+\fB\-\-help\fR
+Output help information and exit.
+
+.TP 
+\fB\-\-user USER\fR
+
+.TP 
+\fB\-\-password\fR
+As of version 2.3 \-\-password can take the password on the
+command line like "\-\-password FOO". Using \-\-password
+alone without giving a password on the command line
+causes mysqlreport to prompt for a password.
+
+.TP 
+\fB\-\-host ADDRESS\fR
+
+.TP 
+\fB\-\-port PORT\fR
+
+.TP
+\fB\-\-socket SOCKET\fR
+
+.TP 
+\fB\-\-no\-mycnf\fR
+\-\-no\-mycnf makes mysqlreport not read ~/.my.cnf which it does by default
+otherwise. \-\-user and \-\-password always override values from ~/.my.cnf.
+
+.TP 
+\fB\-\-dtq\fR
+Print Distribution of Total Queries (DTQ) report (under
+Total in Questions report). Queries (or Questions) can
+be divided into four main areas: DMS (see \-\-dms below),
+Com_ (see \-\-com below), COM_QUIT (see COM_QUIT and
+Questions at http://hackmysql.com/com_quit), and
+Unknown. \-\-dtq lists the number of queries in each of
+these areas in descending order.
+
+.TP 
+\fB\-\-dms\fR
+Print Data Manipulation Statements (DMS) report (under
+DMS in Questions report). DMS are those from the MySQL
+manual section 13.2. Data Manipulation Statements.
+(Currently, mysqlreport considers only SELECT, INSERT,
+REPLACE, UPDATE, and DELETE.) Each DMS is listed in
+descending order by count.
+
+.TP 
+\fB\-\-com N\fR
+Print top N number of non\-DMS Com_ status values in
+descending order (after DMS in Questions report). If N
+is not given, default is 3. Such non\-DMS Com_ values
+include Com_change_db, Com_show_tables, Com_rollback,
+etc.
+
+.TP 
+\fB\-\-sas\fR
+Print report for Select_ and Sort_ status values (after
+Questions report). See MySQL Select and Sort Status
+Variables at http://hackmysql.com/selectandsort.
+
+.TP
+\fB\-\-tab\fR
+Print Threads, Aborted, and Bytes status reports (after
+Created temp report). As of mysqlreport v2.3 the
+Threads report reports on all Threads_ status values.
+
+.TP
+\fB\-\-qcache\fR
+Print Query Cache report.
+.TP
+\fB\-\-all\fR
+Equivalent to "\-\-dtq \-\-dms \-\-com 3 \-\-sas \-\-qcache".
+(Notice \-\-tab is not invoked by \-\-all.)
+
+.TP
+\fB\-\-infile FILE\fR
+Instead of getting SHOW STATUS values from MySQL, read
+values from FILE. FILE is often a copy of the output of
+SHOW STATUS including formatting characters (|, +, \-).
+mysqlreport expects FILE to have the format
+" value number " where value is only alpha and
+underscore characters (A\-Z and _) and number is a
+positive integer. Anything before, between, or after
+value and number is ignored. mysqlreport also needs
+the following MySQL server variables: version,
+table_cache, max_connections, key_buffer_size,
+query_cache_size. These values can be specified in
+INFILE in the format "name = value" where name is one
+of the aforementioned server variables and value is a
+positive integer with or without a trailing M and
+possible periods (for version). For example, to specify
+an 18M key_buffer_size: key_buffer_size = 18M. Or, a
+256 table_cache: table_cache = 256. The M implies
+Megabytes not million, so 18M means 18,874,368 not
+18,000,000. If these server variables are not specified
+the following defaults are used (respectively) which
+may cause strange values to be reported: 0.0.0, 64,
+100, 8M, 0.
+
+.TP
+\fB\-\-outfile FILE\fR  
+After printing the report to screen, print the report
+to FILE too. Internally, mysqlreport always writes the
+report to a temp file first: /tmp/mysqlreport.PID on
+*nix, c:\mysqlreport.PID on Windows (PID is the
+script's process ID). Then it prints the temp file to
+screen. Then if \-\-outfile is specified, the temp file
+is copied to OUTFILE. After \-\-email (below), the temp
+file is deleted.
+
+.TP
+\fB\-\-email ADDRESS\fR
+After printing the report to screen, email the report
+to ADDRESS. This option requires sendmail in
+/usr/sbin/, therefore it does not work on Windows.
+/usr/sbin/sendmail can be a sym link to qmail, for
+example, or any MTA that emulates sendmail's \-t
+command line option and operation. The FROM: field is
+"mysqlreport", SUBJECT: is "MySQL status report".
+
+.TP
+\fB\-\-flush\-status\fR
+Execute a "FLUSH STATUS;" after generating the reports.
+If you do not have permissions in MySQL to do this an
+error from DBD::mysql::st will be printed after the
+reports.
+
+.SH "AUTHORS"
+.LP 
+Daniel Nichter
+
+If mysqlreport breaks, send me a message from 
+http://hackmysql.com/feedback 
+with the error.
+
+.SH "SEE ALSO"
+.LP 
+mytop(1)
+.LP
+The comprehensive Guide To Understanding mysqlreport at 
+http://hackmysql.com/mysqlreportguide.
+
diff --git a/mysql-wsrep-5.6/debian/apparmor-profile b/mysql-wsrep-5.6/debian/apparmor-profile
new file mode 100644 (file)
index 0000000..04272ac
--- /dev/null
@@ -0,0 +1 @@
+# This file is intensionally empty to disable apparmor by default
diff --git a/mysql-wsrep-5.6/debian/changelog b/mysql-wsrep-5.6/debian/changelog
new file mode 100644 (file)
index 0000000..0b2f759
--- /dev/null
@@ -0,0 +1,5 @@
+mysql-wsrep-5.6 (5.6.30-25.15-1) UNRELEASED; urgency=low
+
+  * Bump version numbers
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Wed, 22 Jun 2016 11:58:20 +0300
diff --git a/mysql-wsrep-5.6/debian/clean b/mysql-wsrep-5.6/debian/clean
new file mode 100644 (file)
index 0000000..16b91f4
--- /dev/null
@@ -0,0 +1,2 @@
+debian/libmysqlclient18.links
+debian/libmysqlclient-dev.links
diff --git a/mysql-wsrep-5.6/debian/compat b/mysql-wsrep-5.6/debian/compat
new file mode 100644 (file)
index 0000000..ec63514
--- /dev/null
@@ -0,0 +1 @@
+9
diff --git a/mysql-wsrep-5.6/debian/control b/mysql-wsrep-5.6/debian/control
new file mode 100644 (file)
index 0000000..7385d8d
--- /dev/null
@@ -0,0 +1,159 @@
+Source: mysql-wsrep-5.6
+Section: database
+Priority: optional
+Maintainer: Codership Oy <info@codership.com>
+Build-Depends: bison,
+               chrpath,
+               cmake,
+               debhelper (>= 8.1.3~),
+               dh-apparmor,
+               dpkg-dev (>= 1.16.1~),
+               libaio-dev[linux-any],
+               libedit-dev,
+               libncurses5-dev (>= 5.0-6),
+               libwrap0-dev (>= 7.6-8.3),
+               lsb-release,
+               perl,
+               po-debconf,
+               psmisc,
+               zlib1g-dev (>= 1:1.1.3-5),
+               libssl-dev
+Standards-Version: 3.9.3
+Homepage: http://galeracluster.com/
+Vcs-Git: https://github.com/codership/mysql-wsrep.git
+Vcs-Browser: https://github.com/codership/mysql-wsrep
+
+Package: mysql-wsrep-libmysqlclient18
+Section: libs
+Architecture: any
+Depends: mysql-wsrep-common-5.6, ${misc:Depends}, ${shlibs:Depends}
+Pre-Depends: multiarch-support, ${misc:Pre-Depends}
+Replaces: libmysqlclient18
+Provides: libmysqlclient18
+Multi-Arch: same
+Description: MySQL database client library
+ MySQL is a fast, stable and true multi-user, multi-threaded SQL database
+ server. SQL (Structured Query Language) is the most popular database query
+ language in the world. The main goals of MySQL are speed, robustness and
+ ease of use.
+ .
+ This package includes the client library.
+
+Package: mysql-wsrep-libmysqlclient-dev
+Architecture: any
+Section: libdevel
+Depends: mysql-wsrep-libmysqlclient18 (= ${binary:Version}),
+         zlib1g-dev,
+         ${misc:Depends},
+         ${shlibs:Depends}
+Description: MySQL database development files
+ MySQL is a fast, stable and true multi-user, multi-threaded SQL database
+ server. SQL (Structured Query Language) is the most popular database query
+ language in the world. The main goals of MySQL are speed, robustness and
+ ease of use.
+ .
+ This package includes development libraries and header files.
+
+Package: mysql-wsrep-common-5.6
+Architecture: all
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Multi-Arch: foreign
+Provides: mysql-common, mysql-common-5.6
+Replaces: mysql-common, mysql-common-5.6
+Description: MySQL 5.6 specific common files, e.g. /etc/mysql/conf.d/my-5.6.cnf
+ MySQL is a fast, stable and true multi-user, multi-threaded SQL database
+ server. SQL (Structured Query Language) is the most popular database query
+ language in the world. The main goals of MySQL are speed, robustness and
+ ease of use.
+ .
+ This package also includes files needed by all versions of the client library,
+ e.g. /etc/mysql/my.cnf.
+
+Package: mysql-wsrep-client-5.6
+Architecture: any
+Depends: debianutils (>=1.6),
+         mysql-wsrep-common-5.6,
+         mysql-wsrep-libmysqlclient18,
+         ${misc:Depends},
+         ${perl:Depends},
+         ${shlibs:Depends}
+Provides: virtual-mysql-client
+Breaks: mysql-client-5.5,
+        mysql-client-5.6,
+        mysql-client-core-5.5,
+        mysql-client-core-5.6,
+        virtual-mysql-client
+Replaces: mysql-client-5.5,
+          mysql-client-5.6,
+          mysql-client-core-5.5,
+          mysql-client-core-5.6,
+          virtual-mysql-client
+Recommends: libdbd-mysql-perl (>= 1.2202),
+            libdbi-perl,
+            libterm-readkey-perl
+Description: MySQL database client binaries
+ MySQL is a fast, stable and true multi-user, multi-threaded SQL database
+ server. SQL (Structured Query Language) is the most popular database query
+ language in the world. The main goals of MySQL are speed, robustness and
+ ease of use.
+ .
+ This package includes the client binaries and the additional tools
+ innotop and mysqlreport.
+
+Package: mysql-wsrep-server-5.6
+Architecture: any
+Recommends: libhtml-template-perl
+Suggests: mailx, tinyca
+Pre-Depends: adduser (>= 3.40), debconf, mysql-wsrep-common-5.6
+Depends: initscripts,
+         libdbi-perl,
+         lsb-base (>= 3.0-10),
+         lsof,
+         mysql-wsrep-client-5.6 (>= ${binary:Version}),
+         passwd,
+         perl (>= 5.6),
+         psmisc,
+         rsync,
+         socat,
+         ${misc:Depends},
+         ${shlibs:Depends}
+Provides: virtual-mysql-server
+Breaks: mysql-server-5.5,
+        mysql-server-5.6,
+        mysql-server-core-5.5,
+        mysql-server-core-5.6,
+        virtual-mysql-server
+Replaces: mysql-server-5.5, mysql-server-5.6, virtual-mysql-server
+Description: MySQL database wsrep server binaries and system database setup
+ MySQL is a fast, stable and true multi-user, multi-threaded SQL database
+ server. SQL (Structured Query Language) is the most popular database query
+ language in the world. The main goals of MySQL are speed, robustness and
+ ease of use.
+ .
+ This package contains all the infrastructure needed to setup system
+ databases.
+
+Package: mysql-wsrep-testsuite-5.6
+Architecture: any
+Depends: mysql-wsrep-client-5.6 (= ${binary:Version}),
+         mysql-wsrep-server-5.6 (= ${binary:Version}),
+         python,
+         ${misc:Depends},
+         ${shlibs:Depends}
+Provides: virtual-mysql-testsuite
+Breaks: mysql-testsuite-5.5, mysql-testsuite-5.6, virtual-mysql-testsuite
+Replaces: mysql-testsuite-5.5, mysql-testsuite-5.6, virtual-mysql-testsuite
+Description: MySQL 5.6 testsuite
+ MySQL is a fast, stable, and true multi-user, multi-threaded SQL database
+ server.  SQL (Structured Query Language) is the most popular database query
+ language in the world. The main goals of MySQL are speed, robustness and
+ ease of use.
+ .
+ This package includes the MySQL testsuite.
+
+Package: mysql-wsrep-5.6
+Architecture: any
+Depends: mysql-wsrep-client-5.6 (= ${binary:Version}),
+         mysql-wsrep-server-5.6 (= ${binary:Version}),
+         ${misc:Depends}
+Description: Metapackage that installs mysql-wsrep client and server packages.
diff --git a/mysql-wsrep-5.6/debian/copyright b/mysql-wsrep-5.6/debian/copyright
new file mode 100644 (file)
index 0000000..73f971f
--- /dev/null
@@ -0,0 +1,773 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: MySQL 5.6
+Upstream-Contact: http://bugs.mysql.com/
+Source: http://dev.mysql.com/downloads/mysql/5.6.html
+Comments:
+ The file Docs/mysql.info is removed from the upstream source
+ because it is incompatible with the Debian Free Software Guidelines.
+ See debian/README.source for how this repacking was done.
+ .
+ Originally produced by a modified version of licensecheck2dep5
+ from CDBS by Clint Byrum <clint@ubuntu.com>. Hand modified to reduce
+ redundancy in the output and add appropriate license text.
+ .
+ Also, MySQL carries the "FOSS License Exception" specified in README
+ .
+ Quoting from README:
+ .
+ MySQL FOSS License Exception We want free and open source
+ software applications under certain licenses to be able to use
+ specified GPL-licensed MySQL client libraries despite the fact
+ that not all such FOSS licenses are compatible with version
+ 2 of the GNU General Public License.  Therefore there are
+ special exceptions to the terms and conditions of the GPLv2
+ as applied to these client libraries, which are identified
+ and described in more detail in the FOSS License Exception at
+ <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
+ .
+ The text of the Above URL is quoted below, as of Aug 17, 2011.
+ .
+ > FOSS License Exception
+ > .
+ > Updated July 1, 2010
+ > .
+ > What is the FOSS License Exception?  Oracle's Free and Open Source
+ > Software ("FOSS") License Exception (formerly known as the FLOSS
+ > License Exception) allows developers of FOSS applications to include
+ > Oracle's MySQL Client Libraries (also referred to as "MySQL Drivers"
+ > or "MySQL Connectors") with their FOSS applications. MySQL Client
+ > Libraries are typically licensed pursuant to version 2 of the General
+ > Public License ("GPL"), but this exception permits distribution of
+ > certain MySQL Client Libraries with a developer's FOSS applications
+ > licensed under the terms of another FOSS license listed below,
+ > even though such other FOSS license may be incompatible with the GPL.
+ > .
+ > The following terms and conditions describe the circumstances under
+ > which Oracle's FOSS License Exception applies.
+ > .
+ > Oracle's FOSS License Exception Terms and Conditions Definitions.
+ > "Derivative Work" means a derivative work, as defined under applicable
+ > copyright law, formed entirely from the Program and one or more
+ > FOSS Applications.
+ > .
+ > "FOSS Application" means a free and open source software application
+ > distributed subject to a license listed in the section below titled
+ > "FOSS License List."
+ > .
+ > "FOSS Notice" means a notice placed by Oracle or MySQL in a copy
+ > of the MySQL Client Libraries stating that such copy of the MySQL
+ > Client Libraries may be distributed under Oracle's or MySQL's FOSS
+ > (or FLOSS) License Exception.
+ > .
+ > "Independent Work" means portions of the Derivative Work that are not
+ > derived from the Program and can reasonably be considered independent
+ > and separate works.
+ > .
+ > "Program" means a copy of Oracle's MySQL Client Libraries that
+ > contains a FOSS Notice.
+ > .
+ > A FOSS application developer ("you" or "your") may distribute a
+ > Derivative Work provided that you and the Derivative Work meet all
+ > of the following conditions: You obey the GPL in all respects for
+ > the Program and all portions (including modifications) of the Program
+ > included in the Derivative Work (provided that this condition does not
+ > apply to Independent Works); The Derivative Work does not include any
+ > work licensed under the GPL other than the Program; You distribute
+ > Independent Works subject to a license listed in the section below
+ > titled "FOSS License List"; You distribute Independent Works in
+ > object code or executable form with the complete corresponding
+ > machine-readable source code on the same medium and under the same
+ > FOSS license applying to the object code or executable forms; All
+ > works that are aggregated with the Program or the Derivative Work
+ > on a medium or volume of storage are not derivative works of the
+ > Program, Derivative Work or FOSS Application, and must reasonably
+ > be considered independent and separate works.  Oracle reserves all
+ > rights not expressly granted in these terms and conditions. If all
+ > of the above conditions are not met, then this FOSS License Exception
+ > does not apply to you or your Derivative Work.
+ > .
+ > FOSS License List
+ > .
+ > License Name    Version(s)/Copyright Date
+ > Release Early    Certified Software
+ > Academic Free License    2.0
+ > Apache Software License  1.0/1.1/2.0
+ > Apple Public Source License  2.0
+ > Artistic license     From Perl 5.8.0
+ > BSD license  "July 22 1999"
+ > Common Development and Distribution License (CDDL)   1.0
+ > Common Public License    1.0
+ > Eclipse Public License   1.0
+ > European Union Public License (EUPL)[1]    1.1
+ > GNU Library or "Lesser" General Public License (LGPL)    2.0/2.1/3.0
+ > GNU General Public License (GPL)     3.0
+ > IBM Public License   1.0
+ > Jabber Open Source License   1.0
+ > MIT License (As listed in file MIT-License.txt)  -
+ > Mozilla Public License (MPL)     1.0/1.1
+ > Open Software License    2.0
+ > OpenSSL license (with original SSLeay license)   "2003" ("1998")
+ > PHP License  3.0/3.01
+ > Python license (CNRI Python License)     -
+ > Python Software Foundation License   2.1.1
+ > Sleepycat License   "1999"
+ > University of Illinois/NCSA Open Source License  -
+ > W3C License  "2001"
+ > X11 License  "2001"
+ > Zlib/libpng License  -
+ > Zope Public License  2.0
+ > [1] When an Independent Work is licensed under a "Compatible License"
+ > pursuant to the EUPL, the Compatible License rather than the EUPL is
+ > the applicable license for purposes of these FOSS License Exception
+ > Terms and Conditions.
+ .
+ The above text is subject to this copyright notice:
+ © 2010, Oracle and/or its affiliates.
+
+Files: cmd-line-utils/libedit/config.h
+ dbug/example1.c
+ dbug/example2.c
+ dbug/example3.c
+ dbug/factorial.c
+ dbug/main.c
+ dbug/my_main.c
+ dbug/remove_function_from_trace.pl
+ dbug/tests.c
+ dbug/tests-t.pl
+ extra/yassl/src/dummy.cpp
+ include/probes_mysql_nodtrace.h
+ libmysqld/resource.h
+ mysql-test/*
+ regex/*
+ sql-bench/graph-compare-results.sh
+ storage/ndb/bin/*
+ storage/ndb/demos/*
+ support-files/binary-configure.sh
+ support-files/my-huge.cnf.sh
+ support-files/my-innodb-heavy-4G.cnf.sh
+ support-files/my-large.cnf.sh
+ support-files/my-medium.cnf.sh
+ support-files/my-small.cnf.sh
+ support-files/mysqld_multi.server.sh
+ support-files/mysql-log-rotate.sh
+ support-files/mysql.server-sys5.sh
+Copyright: UNKNOWN
+Comment: These files fall under the blanket license specified in the file
+ COPYING and README
+License: GPL-2
+ GPLv2 Disclaimer
+ For the avoidance of doubt, except that if any license choice
+ other than GPL or LGPL is available it will apply instead,
+ Oracle elects to use only the General Public License version 2
+ (GPLv2) at this time for any software where a choice of GPL
+ license versions is made available with the language indicating
+ that GPLv2 or any later version may be used, or where a choice
+ of which version of the GPL is applied is otherwise unspecified.
+
+Files: BUILD/*
+ Docs/*
+ client/*
+ client/echo.c
+ client/get_password.c
+ cmake/*
+ dbug/dbug_add_tags.pl
+ extra/*
+ include/*
+ libmysql/*
+ libmysqld/*
+ libservices/*
+ mysql-test/include/have_perfschema.inc
+ mysql-test/include/have_perfschema.inc
+ mysql-test/lib/mtr_cases.pm
+ mysql-test/lib/mtr_gcov.pl
+ mysql-test/lib/mtr_gprof.pl
+ mysql-test/lib/mtr_io.pl
+ mysql-test/lib/mtr_match.pm
+ mysql-test/lib/mtr_misc.pl
+ mysql-test/lib/mtr_process.pl
+ mysql-test/lib/mtr_report.pm
+ mysql-test/lib/mtr_results.pm
+ mysql-test/lib/mtr_stress.pl
+ mysql-test/lib/mtr_unique.pm
+ mysql-test/lib/My/ConfigFactory.pm
+ mysql-test/lib/My/Config.pm
+ mysql-test/lib/My/CoreDump.pm
+ mysql-test/lib/My/File/*
+ mysql-test/lib/My/Find.pm
+ mysql-test/lib/My/Handles.pm
+ mysql-test/lib/My/Options.pm
+ mysql-test/lib/My/Platform.pm
+ mysql-test/lib/My/SafeProcess/Base.pm
+ mysql-test/lib/My/SafeProcess.pm
+ mysql-test/lib/My/SafeProcess/safe_kill_win.cc
+ mysql-test/lib/My/SafeProcess/safe_process.cc
+ mysql-test/lib/My/SafeProcess/safe_process.pl
+ mysql-test/lib/My/SafeProcess/safe_process_win.cc
+ mysql-test/lib/My/SysInfo.pm
+ mysql-test/lib/My/Test.pm
+ mysql-test/lib/t/*
+ mysql-test/lib/v1/mtr_cases.pl
+ mysql-test/lib/v1/mtr_gcov.pl
+ mysql-test/lib/v1/mtr_gprof.pl
+ mysql-test/lib/v1/mtr_im.pl
+ mysql-test/lib/v1/mtr_io.pl
+ mysql-test/lib/v1/mtr_match.pl
+ mysql-test/lib/v1/mtr_misc.pl
+ mysql-test/lib/v1/mtr_process.pl
+ mysql-test/lib/v1/mtr_report.pl
+ mysql-test/lib/v1/mtr_stress.pl
+ mysql-test/lib/v1/mtr_timer.pl
+ mysql-test/lib/v1/mtr_unique.pl
+ mysql-test/lib/v1/My/*
+ mysql-test/lib/v1/My/*
+ mysql-test/lib/v1/mysql-test-run.pl
+ mysql-test/mysql-stress-test.pl
+ mysql-test/mysql-test-run.pl
+ mysql-test/std_data/*
+ mysql-test/suite/perfschema/include/*
+ mysql-test/suite/perfschema_stress/include/*
+ mysql-test/suite/perfschema_stress/include/*
+ mysys/*
+ packaging/WiX/ca/*
+ plugin/audit_null/*
+ plugin/auth/*
+ plugin/daemon_example/*
+ plugin/fulltext/*
+ plugin/semisync/semisync_slave.cc
+ plugin/semisync/semisync_slave.h
+ scripts/*
+ sql/*
+ sql-common/*
+ storage/*
+ strings/*
+ support-files/config.huge.ini.sh
+ support-files/config.medium.ini.sh
+ support-files/config.small.ini.sh
+ support-files/MacOSX/Description.plist.sh
+ support-files/MacOSX/Info.plist.sh
+ support-files/MacOSX/StartupParameters.plist.sh
+ support-files/MySQL-shared-compat.spec.sh
+ support-files/mysql.spec.sh
+ support-files/ndb-config-2-node.ini.sh
+ tests/*
+ unittest/*
+ vio/*
+Copyright: 1979-2008 MySQL AB
+           1995-2010 MySQL AB Sun Microsystems Inc
+           1994-1997,2000-2011 Oracle and/or its affiliates.
+License: GPL-2
+
+Files: storage/innobase/*
+Copyright: 1994-2011 Innobase Oy.
+License: GPL-2
+
+Files: cmd-line-utils/readline/*
+Copyright: 1987-2006 Free Software Foundation Inc
+License: GPL-2+
+
+Files: cmd-line-utils/libedit/*
+Copyright: 1989-1990,1992-1993 The Regents of the University of California.
+License: BSD (3 clause)
+
+Files: cmd-line-utils/libedit/filecomplete.c
+ cmd-line-utils/libedit/filecomplete.h
+ cmd-line-utils/libedit/np/fgetln.c
+ cmd-line-utils/libedit/read.h
+ cmd-line-utils/libedit/readline.c
+ cmd-line-utils/libedit/readline/*
+Copyright: 1997-2001 The NetBSD Foundation Inc
+License: BSD (2 clause)
+ This code is derived from software contributed to The NetBSD Foundation
+ by Jaromir Dolecek.
+ .
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+
+Files: client/completion_hash.h
+ scripts/mysqlaccess.sh
+ scripts/mysql_fix_extensions.sh
+ scripts/mysql_setpermission.sh
+ sql-bench/*
+ storage/myisam/ftbench/ft-test-run.sh
+ storage/myisam/mi_test_all.sh
+ storage/ndb/test/run-test/atrt-analyze-result.sh
+ storage/ndb/test/run-test/atrt-clear-result.sh
+ storage/ndb/test/run-test/atrt-gather-result.sh
+ storage/ndb/test/run-test/atrt-setup.sh
+ storage/ndb/test/run-test/make-config.sh
+ storage/ndb/test/run-test/make-html-reports.sh
+ storage/ndb/test/run-test/make-index.sh
+ storage/ndb/test/run-test/ndb-autotest.sh
+ strings/strxmov.c
+ strings/strxnmov.c
+ support-files/MacOSX/postflight.sh
+ support-files/MacOSX/preflight.sh
+Copyright: 2000-2009 MySQL AB Sun Microsystems Inc
+           2000-2007 MySQL AB
+License: LGPL
+
+Files: storage/archive/azio.c
+ storage/archive/azlib.h
+ zlib/*
+Copyright: 1995-2005 Jean-loup Gailly and Mark Adler
+License: zlib/libpng
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+  .
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+  .
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+Files: sql-bench/innotest1.sh
+ sql-bench/innotest1a.sh
+ sql-bench/innotest1b.sh
+ sql-bench/innotest2.sh
+ sql-bench/innotest2a.sh
+ sql-bench/innotest2b.sh
+Copyright: 2000-2002 Innobase Oy & MySQL AB
+Comment: These files fall under the blanket license specified in the file COPYING
+License: GPL-2
+
+Files: storage/innobase/btr/btr0sea.c
+ storage/innobase/include/log0log.h
+ storage/innobase/include/os0sync.h
+ storage/innobase/log/log0log.c
+ storage/innobase/row/row0sel.c
+Copyright: 1995-1997,2009-2010 Innobase Oy.
+ 2008-2009 Google Inc
+License: GPL-2
+
+Files: storage/innobase/btr/btr0cur.c
+ storage/innobase/buf/buf0buf.c
+ storage/innobase/include/sync0rw.h
+ storage/innobase/include/sync0sync.h
+ storage/innobase/sync/*
+Copyright: 1994-2011 Oracle and/or its affiliates.
+ 2008 Google Inc
+License: GPL-2
+
+Files: storage/myisam/rt_index.h
+ storage/myisam/rt_key.c
+ storage/myisam/rt_mbr.c
+ storage/myisam/rt_mbr.h
+ storage/myisam/sp_defs.h
+Copyright: 2000,2002-2006 MySQL AB & Ramil Kalimullin
+License: GPL-2
+
+Files: storage/innobase/include/ut0bh.h
+ storage/innobase/trx/trx0rseg.c
+ storage/innobase/ut/ut0bh.c
+ storage/innobase/ut/ut0ut.c
+Copyright: 1996,2010-2011 Oracle Corpn.
+License: GPL-2
+
+Files: plugin/semisync/semisync.cc
+ plugin/semisync/semisync.h
+ plugin/semisync/semisync_slave_plugin.cc
+Copyright: 2008 MySQL AB
+ 2007 Google Inc
+License: GPL-2
+
+Files: strings/ctype-bin.c
+ strings/ctype-eucjpms.c
+ strings/ctype-ujis.c
+Copyright: 2000,2002,2005-2011 Oracle and/or its affiliates. & tommy@valley.ne.jp
+License: LGPL
+ On Debian and systems the full text of the GNU Library General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/LGPL-2`
+
+Files: scripts/mysqld_safe.sh
+ support-files/mysql-multi.server.sh
+ support-files/mysql.server.sh
+Copyright: 1996 Abandoned TCX DataKonsult AB & Monty Program KB & Detron HB
+License: public-domain
+ This file is public domain and comes with NO WARRANTY of any kind
+
+Files: sql/sql_yacc.cc
+ sql/sql_yacc.h
+Copyright: 1984,1989-1990,2000-2006 Free Software Foundation, Inc.
+License: GPL-2+
+
+Files: storage/innobase/include/pars0grm.h
+ storage/innobase/pars/pars0grm.c
+Copyright: 1995-2009 Innobase Oy.
+ 1984,1989-1990,2000-2004 Free Software Foundation Inc.
+License: GPL-2
+ As a special exception, when this file is copied by Bison into a
+ Bison output file, you may use that output file without restriction.
+ This special exception was added by the Free Software Foundation
+ in version 1.24 of Bison.
+ .
+ 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+Files: storage/innobase/include/srv0srv.h
+ storage/innobase/srv/srv0start.c
+Copyright: 1995-1996,2010-2011 Innobase Oy.
+ 2008-2009 Google Inc
+ 2009 Percona Inc
+License: GPL-2
+
+Files: plugin/semisync/semisync_master.cc
+ plugin/semisync/semisync_master_plugin.cc
+Copyright: 2008-2009 MySQL AB Sun Microsystems Inc
+ 2007 Google Inc
+License: GPL-2
+
+Files: storage/innobase/include/os0file.h
+ storage/innobase/os/os0file.c
+Copyright: 1995-2010 Innobase Oy.
+ 2009 Percona Inc
+License: GPL-2
+
+Files: include/t_ctype.h
+ strings/t_ctype.h
+Copyright: 2000 MySQL AB
+ 1998 Theppitak Karoonboonyanan
+ 1998-1999 Pruet Boonma
+License: GPL-2
+
+Files: cmd-line-utils/libedit/np/strlcat.c
+ cmd-line-utils/libedit/np/strlcpy.c
+Copyright: 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+License: ISC
+ Permission to use, copy, modify, and distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+ .
+ THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL
+ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE
+ FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+Files: sql/nt_servc.cc
+ sql/nt_servc.h
+Copyright: 1998 Abandoned Irena Pancirov - Irnet Snc
+License: public-domain
+ This file is public domain and comes with NO WARRANTY of any kind
+
+Files: dbug/dbug.c
+ dbug/dbug_long.h
+Copyright: 1987 Abandoned Fred Fish
+License: public-domain
+ N O T I C E
+ .
+ Copyright Abandoned, 1987, Fred Fish
+ .
+ .
+ This previously copyrighted work has been placed into the  public
+ domain        by  the  author  and  may be freely used for any purpose,
+ private or commercial.
+ .
+ Because of the number of inquiries I was receiving about the  use
+ of this product in commercially developed works I have decided to
+ simply make it public domain to further its unrestricted use. I
+ specifically  would  be  most happy to see this material become a
+ part of the standard Unix distributions by AT&T and the  Berkeley
+ Computer  Science  Research Group, and a standard part of the GNU
+ system from the Free Software Foundation.
+ .
+ I would appreciate it, as a courtesy, if this notice is  left  in
+ all copies and derivative works.  Thank you.
+ .
+ The author makes no warranty of any kind  with        respect  to  this
+ product  and  explicitly disclaims any implied warranties of mer-
+ chantability or fitness for any particular purpose.
+
+Files: cmd-line-utils/libedit/np/vis.c
+Copyright: 1989-1993 The Regents of the University of California.
+ 1999-2005 The NetBSD Foundation Inc
+License: BSD (3 clause)
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the University nor the names of its contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+Files: scripts/dheadgen.pl
+Copyright: 2008-2009 Sun Microsystems Inc
+License: BSD (3 clause)
+
+Files: storage/ndb/test/src/getarg.c
+Copyright: 1997-2000 - Kungliga Tekniska Högskolan
+License: BSD (3 clause)
+
+Files: storage/ndb/test/include/getarg.h
+Copyright: 2003 MySQL AB
+ 1997-1999 Kungliga Tekniska Högskolan
+License: BSD (3 clause) GPL-2
+ 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
+ .
+ Copyright (c) 1997, 1999 Kungliga Tekniska Högskolan
+ (Royal Institute of Technology, Stockholm, Sweden).
+ All rights reserved.
+ .
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ .
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ .
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+ .
+ 3. Neither the name of the Institute nor the names of its contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+Files: storage/innobase/handler/ha_innodb.cc
+Copyright: 2008-2009 Google Inc
+ 2009 Percona Inc
+ 2000-2011 MySQL AB & Innobase Oy.
+License: GPL-2
+
+Files: plugin/semisync/semisync_master.h
+Copyright: 2008-2009 MySQL AB Sun Microsystems Inc
+ 2007 Google Inc
+License: GPL-2
+
+Files: storage/innobase/srv/srv0srv.c
+Copyright: 2008-2009 Google Inc
+ 1995-2011 Oracle and/or its affiliates.
+ 2009 Percona Inc
+License: GPL-2
+
+Files: storage/innobase/ut/ut0rbt.c
+Copyright: 2007-2010 Innobase Oy.
+ 2007 Oracle/Innobase Oy
+License: GPL-2
+
+Files: strings/ctype-win1250ch.c
+Copyright: 2002-2010 Oracle and/or its affiliates.
+ 2001 Jan Pazdziora
+License: GPL-2
+
+Files: strings/ctype-tis620.c
+Copyright: 1998 Theppitak Karoonboonyanan <thep@links.nectec.or.th>
+ 1989-1991 Samphan Raruenrom <samphan@thai.com>
+ 2000-2010 Oracle and/or its affiliates.
+ 2003 Sathit Jittanupat
+ 2001 Korakot Chaovavanich <korakot@iname.com> and
+ 1998-1999 Pruet Boonma <pruet@eng.cmu.ac.th>
+License: GPL-2
+
+Files: storage/innobase/handler/ha_innodb.h
+Copyright: 2000-2010 MySQL AB & Innobase Oy.
+License: GPL-2
+
+Files: strings/dtoa.c
+Copyright: 2007-2010 Oracle and/or its affiliates.
+ 1991,2000-2001 Lucent Technologies
+License: LGPL
+
+Files: scripts/mysqldumpslow.sh
+Copyright: 2000-2002,2005-2009 MySQL AB Sun Microsystems Inc
+License: LGPL
+
+Files: libmysqld/lib_sql.cc
+Copyright: 2000 SWsoft  company
+License: SWsoft
+ This material is provided "as is", with absolutely no warranty expressed
+ or implied. Any use is at your own risk.
+ .
+ Permission to use or copy this software for any purpose is hereby granted
+ without fee, provided the above notices are retained on all copies.
+ Permission to modify the code and to distribute modified code is granted,
+ provided the above notices are retained, and a notice that the code was
+ modified is included with the above copyright notice.
+
+Files: tests/mail_to_db.pl
+Copyright: 1998 Abandoned TCX DataKonsult AB & Monty Program KB & Detron HB
+License: public-domain
+ This file is public domain and comes with NO WARRANTY of any kind
+
+Files: dbug/dbug_analyze.c
+Copyright: 1987 June Binayak Banerjee
+License: public-domain
+ This program may be freely distributed under the same terms and
+ conditions as Fred Fish's Dbug package.
+
+Files: regex/regexp.c
+Copyright: 1986 University of Toronto
+License: BSD-like
+ Permission is granted to anyone to use this software for any
+ purpose on any computer system, and to redistribute it freely,
+ subject to the following restrictions:
+ .
+ 1. The author is not responsible for the consequences of use of
+        this software, no matter how awful, even if they arise
+    from defects in it.
+ .
+ 2. The origin of this software must not be misrepresented, either
+    by explicit claim or by omission.
+ .
+ 3. Altered versions must be plainly marked as such, and must not
+    be misrepresented as being the original software.
+
+License: GPL-2
+ 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 St, Fifth Floor, Boston, MA 02110-1301, USA.
+ .
+ On Debian and systems the full text of the GNU General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/GPL-2`
+
+License: GPL-2+
+ This file is part of GNU Readline, a library for reading lines
+ of text with interactive input and history editing.
+ .
+ Readline 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; either version 2, or (at your option) any
+ later version.
+ .
+ Readline 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 Readline; see the file COPYING.  If not, write to the Free
+ Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+ .
+ On Debian and systems the full text of the GNU General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/GPL-2`
+
+License: LGPL
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; version 2
+ of the License.
+ .
+ This library 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
+ Library General Public License for more details.
+ .
+ You should have received a copy of the GNU Library General Public
+ License along with this library; if not, write to the Free
+ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301, USA
+ .
+ On Debian and systems the full text of the GNU Library General Public
+ License version 2 can be found in the file
+ `/usr/share/common-licenses/LGPL-2`
+
+License: BSD (3 clause)
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+ 3. Neither the name of the University nor the names of its contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+ .
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
diff --git a/mysql-wsrep-5.6/debian/gbp.conf b/mysql-wsrep-5.6/debian/gbp.conf
new file mode 100644 (file)
index 0000000..e69ccf8
--- /dev/null
@@ -0,0 +1,8 @@
+[DEFAULT]
+# Ignore requirement to use branch name 'master' to make it easier
+# for contributors to work with feature and bugfix branches
+ignore-branch = True
+
+upstream-branch = 5.6
+upstream-tree = branch
+pristine-tar = False
diff --git a/mysql-wsrep-5.6/debian/libmysqld-dev.install b/mysql-wsrep-5.6/debian/libmysqld-dev.install
new file mode 100644 (file)
index 0000000..f050094
--- /dev/null
@@ -0,0 +1 @@
+usr/lib/*/libmysqlservices.a
diff --git a/mysql-wsrep-5.6/debian/libmysqld-pic.README.Debian b/mysql-wsrep-5.6/debian/libmysqld-pic.README.Debian
new file mode 100644 (file)
index 0000000..4ec22b7
--- /dev/null
@@ -0,0 +1,5 @@
+This package was requested in http://bugs.debian.org/508406 because it
+is needed by programs want to include the embedded MySQL into their
+shared libraries.
+
+In order to get the full compile flags, use /bin/mysql_config_pic
diff --git a/mysql-wsrep-5.6/debian/libmysqld-pic.install b/mysql-wsrep-5.6/debian/libmysqld-pic.install
new file mode 100644 (file)
index 0000000..7ff38b3
--- /dev/null
@@ -0,0 +1,2 @@
+usr/bin/mysql_config_pic
+usr/lib/mysql/libmysqld_pic.a
diff --git a/mysql-wsrep-5.6/debian/libmysqld-pic.manpages b/mysql-wsrep-5.6/debian/libmysqld-pic.manpages
new file mode 100644 (file)
index 0000000..3e2e2b2
--- /dev/null
@@ -0,0 +1 @@
+debian/tmp/usr/share/man/man1/mysql_config_pic.1
diff --git a/mysql-wsrep-5.6/debian/mysql-server-5.6.py b/mysql-wsrep-5.6/debian/mysql-server-5.6.py
new file mode 100644 (file)
index 0000000..3888c05
--- /dev/null
@@ -0,0 +1,52 @@
+'''apport package hook for mysql-5.6
+
+(c) 2009 Canonical Ltd.
+Author: Mathias Gug <mathias.gug@canonical.com>
+'''
+
+from __future__ import print_function, unicode_literals
+import os, os.path
+
+from apport.hookutils import *
+
+def _add_my_conf_files(report, filename):
+    key = 'MySQLConf' + path_to_key(filename)
+    report[key] = ""
+    for line in read_file(filename).split('\n'):
+        try:
+            if 'password' in line.split('=')[0]:
+                line = "%s = @@APPORTREPLACED@@" % (line.split('=')[0])
+            report[key] += line + '\n'
+        except IndexError:
+            continue
+
+def add_info(report):
+    attach_conffiles(report, 'mysql-server-5.6', conffiles=None)
+    key = 'Logs' + path_to_key('/var/log/daemon.log')
+    report[key] = ""
+    for line in read_file('/var/log/daemon.log').split('\n'):
+        try:
+            if 'mysqld' in line.split()[4]:
+                report[key] += line + '\n'
+        except IndexError:
+            continue
+    if os.path.exists('/var/log/mysql/error.log'):
+        key = 'Logs' + path_to_key('/var/log/mysql/error.log')
+        report[key] = ""
+        for line in read_file('/var/log/mysql/error.log').split('\n'):
+            report[key] += line + '\n'
+    attach_mac_events(report, '/usr/sbin/mysqld')
+    attach_file(report,'/etc/apparmor.d/usr.sbin.mysqld')
+    _add_my_conf_files(report, '/etc/mysql/my.cnf')
+    for f in os.listdir('/etc/mysql/conf.d'):
+        _add_my_conf_files(report, os.path.join('/etc/mysql/conf.d', f))
+    try:
+        report['MySQLVarLibDirListing'] = str(os.listdir('/var/lib/mysql'))
+    except OSError:
+        report['MySQLVarLibDirListing'] = str(False)
+
+if __name__ == '__main__':
+    report = {}
+    add_info(report)
+    for key in report:
+        print('%s: %s' % (key, report[key].split('\n', 1)[0]))
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.README.Debian b/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.README.Debian
new file mode 100644 (file)
index 0000000..b245638
--- /dev/null
@@ -0,0 +1,4 @@
+FAQ:
+
+Q: My <tab> completition is gone, why?
+A: You have "no-auto-rehash" in the "[mysql]" section of /etc/mysql/my.cnf!
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.dirs b/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.dirs
new file mode 100644 (file)
index 0000000..ceda592
--- /dev/null
@@ -0,0 +1,3 @@
+usr/bin/
+usr/share/man/man1/
+usr/share/perl5/
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.docs b/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.docs
new file mode 100644 (file)
index 0000000..2144685
--- /dev/null
@@ -0,0 +1,2 @@
+debian/additions/innotop/changelog.innotop
+README
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.examples b/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.examples
new file mode 100644 (file)
index 0000000..ef08ce1
--- /dev/null
@@ -0,0 +1 @@
+debian/tmp/usr/bin/mysqlaccess.conf
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.install b/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.install
new file mode 100644 (file)
index 0000000..29fd8df
--- /dev/null
@@ -0,0 +1,21 @@
+# this executable reprsent the embedded mysql server client
+debian/additions/innotop/innotop usr/bin/
+debian/additions/mysqlreport usr/bin/
+usr/bin/innochecksum
+usr/bin/myisam_ftdump
+usr/bin/mysql
+usr/bin/mysql_client_test
+usr/bin/mysql_config_editor
+usr/bin/mysql_find_rows
+usr/bin/mysql_fix_extensions
+usr/bin/mysql_plugin
+usr/bin/mysql_waitpid
+usr/bin/mysqlaccess
+usr/bin/mysqladmin
+usr/bin/mysqlbug
+usr/bin/mysqlcheck
+usr/bin/mysqldump
+usr/bin/mysqldumpslow
+usr/bin/mysqlimport
+usr/bin/mysqlshow
+usr/bin/mysqlslap
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.links b/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.links
new file mode 100644 (file)
index 0000000..0b86e87
--- /dev/null
@@ -0,0 +1,6 @@
+usr/bin/mysqlcheck usr/bin/mysqlrepair
+usr/bin/mysqlcheck usr/bin/mysqlanalyze
+usr/bin/mysqlcheck usr/bin/mysqloptimize
+usr/share/man/man1/mysqlcheck.1.gz usr/share/man/man1/mysqlrepair.1.gz
+usr/share/man/man1/mysqlcheck.1.gz usr/share/man/man1/mysqlanalyze.1.gz
+usr/share/man/man1/mysqlcheck.1.gz usr/share/man/man1/mysqloptimize.1.gz
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.lintian-overrides b/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.lintian-overrides
new file mode 100644 (file)
index 0000000..0b99bae
--- /dev/null
@@ -0,0 +1,9 @@
+# Will look at man pages later 
+# 2012-03-08 periapt
+# still no update
+# 2012-01-09 jesusch-guest
+mysql-client-5.6: binary-without-manpage usr/bin/innochecksum
+# These long lines reproduce actual output and to reformat them
+# would damage the integrity of the man page.
+mysql-client-5.6: manpage-has-errors-from-man usr/share/man/man1/mysqladmin.1.gz 28: warning [p 1, 1.5i]: can't break line
+mysql-client-5.6: manpage-has-errors-from-man usr/share/man/man1/mysqldump.1.gz 2151: warning [p 12, 6.5i, div `3tbd2,1', 0.2i]: can't break line
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.manpages b/mysql-wsrep-5.6/debian/mysql-wsrep-client-5.6.manpages
new file mode 100644 (file)
index 0000000..2458e1f
--- /dev/null
@@ -0,0 +1,4 @@
+debian/additions/innotop/innotop.1
+debian/tmp/usr/share/man/man1/mysqlman.1
+debian/additions/mysqlreport.1
+debian/tmp/usr/share/man/man1/mysql_embedded.1
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-common-5.6.dirs b/mysql-wsrep-5.6/debian/mysql-wsrep-common-5.6.dirs
new file mode 100644 (file)
index 0000000..a5a88ed
--- /dev/null
@@ -0,0 +1 @@
+etc/mysql/conf.d/
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-common-5.6.install b/mysql-wsrep-5.6/debian/mysql-wsrep-common-5.6.install
new file mode 100644 (file)
index 0000000..9ead641
--- /dev/null
@@ -0,0 +1,2 @@
+debian/additions/my.cnf etc/mysql/
+debian/additions/my5.6.cnf etc/mysql/conf.d/
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-common-5.6.postrm b/mysql-wsrep-5.6/debian/mysql-wsrep-common-5.6.postrm
new file mode 100644 (file)
index 0000000..8b12d46
--- /dev/null
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+set -e
+
+if [ "$1" = "purge" ]; then
+  rmdir /etc/mysql 2>/dev/null || true
+fi
+
+#DEBHELPER#
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.README.Maintainer b/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.README.Maintainer
new file mode 100644 (file)
index 0000000..f24cdcd
--- /dev/null
@@ -0,0 +1,4 @@
+The examples directory includes files that might be needed by some
+developers:
+- header files not installed by default
+- the example file udf_example.c
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.dirs b/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.dirs
new file mode 100644 (file)
index 0000000..f6ad287
--- /dev/null
@@ -0,0 +1,2 @@
+usr/include/
+usr/lib/
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.examples b/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.examples
new file mode 100644 (file)
index 0000000..80a749f
--- /dev/null
@@ -0,0 +1 @@
+sql/udf_example.cc
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.install b/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.install
new file mode 100644 (file)
index 0000000..769007d
--- /dev/null
@@ -0,0 +1,7 @@
+usr/bin/mysql_config
+usr/include/mysql/*
+usr/lib/*/libmysqlclient.a
+usr/lib/*/libmysqlclient.so
+usr/lib/*/libmysqlclient_r.a
+usr/lib/*/libmysqlclient_r.so
+usr/share/aclocal/mysql.m4
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.manpages b/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient-dev.manpages
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient18.dirs b/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient18.dirs
new file mode 100644 (file)
index 0000000..2964de6
--- /dev/null
@@ -0,0 +1 @@
+usr/lib/
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient18.install b/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient18.install
new file mode 100644 (file)
index 0000000..0feb497
--- /dev/null
@@ -0,0 +1,2 @@
+usr/lib/*/libmysqlclient.so.18*
+usr/lib/*/libmysqlclient_r.so.18*
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient18.lintian-overrides b/mysql-wsrep-5.6/debian/mysql-wsrep-libmysqlclient18.lintian-overrides
new file mode 100644 (file)
index 0000000..7aff544
--- /dev/null
@@ -0,0 +1,3 @@
+# I take this issue seriously but as per bug #590905
+# it will need playing with in experimental. - periapt
+libmysqlclient18: no-symbols-control-file usr/lib/i386-linux-gnu/libmysqlclient.so.18.1.0
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.NEWS b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.NEWS
new file mode 100644 (file)
index 0000000..44baefe
--- /dev/null
@@ -0,0 +1,34 @@
+mysql-dfsg-5.1 (5.1.36-1) unstable; urgency=low
+
+  * Please read http://dev.mysql.com/doc/refman/5.1/en/upgrading-from-5-0.html
+  * Make sure to do a REPAIR TABLE on all tables that use UTF-8 and have a
+    FULLTEXT index.
+
+ -- Christian Hammers <ch@debian.org>  Sat,  4 Jul 2009 02:31:21 +0200
+
+mysql-dfsg-5.0 (5.1.14beta-2) unstable; urgency=low
+
+  * The BerkeleyDB Storage Engine is no longer supported. If the options
+    have-bdb or skip-bdb are found, MySQL will not start. If you have BDB
+    tables, you should change them to use another storage engine before 
+    upgrading to 5.1.   
+
+ -- Monty Taylor <mordred@inaugust.com>  Thu, 18 Jan 2007 12:28:21 -0800
+
+mysql-dfsg-5.0 (5.0.45-2) unstable; urgency=low
+
+  * Binary logging is now disabled by default. If you really need it (e.g. on
+    a replication master), remove the comment from the log_bin line in my.cnf.
+
+ -- Norbert Tretkowski <norbert@tretkowski.de>  Sat, 10 Nov 2007 16:26:35 +0100
+
+mysql-dfsg-5.0 (5.0.18-9) unstable; urgency=low
+
+  * Rotation of the binary logs is now configured in /etc/mysql/my.cnf with
+    "expire-logs-days" which defaults to 20 days. The old file
+    /etc/mysql/debian-log-rotate.conf should be removed together with
+    /etc/cron.daily/mysql-server after this value has been adjusted. Note that
+    the old variable defined the number of files whereas the new one defines 
+    a time span in days.
+
+ -- Christian Hammers <ch@debian.org>  Tue, 24 Jan 2006 22:18:21 +0100
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.README.Debian b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.README.Debian
new file mode 100644 (file)
index 0000000..741243f
--- /dev/null
@@ -0,0 +1,109 @@
+* MYSQL WON'T START OR STOP?:
+=============================
+You may never ever delete the special mysql user "debian-sys-maint". This
+user together with the credentials in /etc/mysql/debian.cnf are used by the
+init scripts to stop the server as they would require knowledge of the mysql
+root users password else.
+So in most of the times you can fix the situation by making sure that the
+debian.cnf file contains the right password, e.g. by setting a new one
+(remember to do a "flush privileges" then).
+
+* WHAT TO DO AFTER UPGRADES:
+============================
+The privilege tables are automatically updated so all there is left is read
+the changelogs on dev.mysql.com to see if any changes affect custom apps.
+
+* WHAT TO DO AFTER INSTALLATION:
+================================
+The MySQL manual describes certain steps to do at this stage in a separate
+chapter.  They are not necessary as the Debian packages does them
+automatically.
+
+The only thing that is left over for the admin is 
+ - setting the passwords
+ - creating new users and databases
+ - read the rest of this text
+
+* DOWNGRADING TO 4.0 or 4.1:
+============================
+Unsupported. Period.
+But if you do and get problems or make interesting experiences, mail me, it
+might help others.
+Ok, if you really want, I would recommend to "mysqldump --opt" all tables,
+then purge 4.1, delete /var/lib/mysql, install 4.0 and insert the dumps.  Be
+carefully, though, with the "mysql" table, you might not simply overwrite that
+one as the password for the mysql "debian-sys-maint" user is stored in
+/etc/mysql/debian.cnf and needed by /etc/init.d/ to start mysql and check if
+it's alive. 
+
+* SOME APPLICATION CAN NO LONGER CONNECT:
+=========================================
+This application is probably linked against libmysqlclient12 or below and
+somebody has created a mysql user with new-style passwords.
+The old_passwords=1 option in /etc/mysql/my.cnf might help. If not the
+application that inserted the user has to be changed or the application that
+tries to connect updated to libmysqlclient14 or -15.
+
+* NETWORKING:
+=============
+For security reasons, the Debian package has enabled networking only on the
+loop-back device using "bind-address" in /etc/mysql/my.cnf.  Check with
+"netstat -tlnp" where it is listening. If your connection is aborted
+immediately see if "mysqld: all" or similar is in /etc/hosts.allow and read
+hosts_access(5).
+
+* WHERE IS THE DOCUMENTATION?:
+==============================
+Unfortunately due to licensing restrictions, debian currently not able
+to provide the mysql-doc package in any format.  For the most up to date
+documentation, please go to http://dev.mysql.com/doc.
+
+* PASSWORDS:
+============
+It is strongly recommended to set a password for the mysql root user (which
+  /usr/bin/mysql -u root -D mysql -e "update user set password=password('new-password') where user='root'"
+  /usr/bin/mysql -u root -e "flush privileges"
+If you already had a password set add "-p" before "-u" to the lines above.
+
+
+If you are tired to type the password in every time or want to automate your
+scripts you can store it in the file $HOME/.my.cnf. It should be chmod 0600
+(-rw------- username username .my.cnf) to ensure that nobody else can read
+it.  Every other configuration parameter can be stored there, too. You will
+find an example below and more information in the MySQL manual in
+/usr/share/doc/mysql-doc or www.mysql.com.
+
+ATTENTION: It is necessary, that a .my.cnf from root always contains a "user"
+line wherever there is a "password" line, else, the Debian maintenance
+scripts, that use /etc/mysql/debian.cnf, will use the username
+"debian-sys-maint" but the password that is in root's .my.cnf. Also note,
+that every change you make in the /root/.my.cnf will affect the mysql cron
+script, too.
+
+        # an example of $HOME/.my.cnf
+       [client]
+       user            = your-mysql-username
+       password        = enter-your-good-new-password-here
+
+* BIG_ROWS FOR EVEN MORE ROWS IN A TABLE:
+=========================================
+If you ever run out of rows in a table there is the possibility of building
+the package with "-DBIG_ROWS" which, according to a MySQL employee on
+packagers@lists.mysql.com should lead to a 64bit row index (I guess > 2^32
+rows) but also to an approx. 5% performance loss.
+
+* BerkeleyDB Storage Engine
+===========================
+Support for BerkeleyDB has been removed in 5.1, and consequently both the
+have-bdb and skip-bdb configuration options will cause the server to fail. 
+Removing the options from /etc/mysql/my.cnf will fix this problem.
+
+* FURTHER NOTES ON REPLICATION
+===============================
+If the MySQL server is acting as a replication slave, you should not
+set --tmpdir to point to a directory on a memory-based filesystem or to
+a directory that is cleared when the server host restarts. A replication
+slave needs some of its temporary files to survive a machine restart so
+that it can replicate temporary tables or LOAD DATA INFILE operations. If
+files in the temporary file directory are lost when the server restarts,
+replication fails.
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.config b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.config
new file mode 100644 (file)
index 0000000..c2f016e
--- /dev/null
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+set -e
+
+. /usr/share/debconf/confmodule
+
+if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi
+${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 }
+
+CNF=/etc/mysql/my.cnf
+
+# Beware that there are two ypwhich one of them needs the 2>/dev/null!
+if test -n "`which ypwhich 2>/dev/null`"  &&  ypwhich >/dev/null 2>&1; then
+  db_input high mysql-server-5.6/nis_warning || true
+  db_go
+fi
+
+# only ask this question on fresh installs, during "reconfiguration" and when
+# not upgrading from an existing 5.0 installation.
+# there is also an additional check for empty root passwords in the
+# postinst script when the tools are available for us to use.
+if [ "$1" = "configure" ] && ([ -z "$2" ] && [ ! -e "/var/lib/mysql/debian-5.0.flag" ] ) || [ "$1" = "reconfigure" ]; then
+  while :; do
+    RET=""
+    db_input high mysql-server/root_password || true
+    db_go
+    db_get mysql-server/root_password
+    # if password isn't empty we ask for password verification
+    if [ -z "$RET" ]; then
+      db_fset mysql-server/root_password seen false
+      db_fset mysql-server/root_password_again seen false
+      break
+    fi
+    ROOT_PW="$RET"
+    db_input high mysql-server/root_password_again || true
+    db_go
+    db_get mysql-server/root_password_again
+    if [ "$RET" == "$ROOT_PW" ]; then
+      ROOT_PW=''
+      break
+    fi
+    db_fset mysql-server/password_mismatch seen false
+    db_input critical mysql-server/password_mismatch
+    db_set mysql-server/root_password ""
+    db_set mysql-server/root_password_again ""
+    db_go
+  done
+fi
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.dirs b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.dirs
new file mode 100644 (file)
index 0000000..6c3fdac
--- /dev/null
@@ -0,0 +1,8 @@
+etc/init.d
+etc/logrotate.d
+etc/mysql/conf.d
+usr/bin
+usr/share/mysql
+var/lib/mysql-upgrade
+usr/sbin
+usr/share/man/man8
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.examples b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.examples
new file mode 100644 (file)
index 0000000..219e7bc
--- /dev/null
@@ -0,0 +1,3 @@
+debian/tmp/usr/share/mysql/wsrep.cnf
+debian/tmp/usr/share/mysql/magic
+debian/tmp/usr/lib/mysql/plugin/daemon_example.ini
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.install b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.install
new file mode 100644 (file)
index 0000000..eb40f0b
--- /dev/null
@@ -0,0 +1,100 @@
+#usr/share/mysql/config.huge.ini
+#usr/share/mysql/config.medium.ini
+#usr/share/mysql/config.small.ini
+#usr/share/mysql/ndb-config-2-node.ini
+debian/additions/mysqld_safe_syslog.cnf etc/mysql/conf.d/
+etc/apparmor.d/usr.sbin.mysqld
+etc/init.d/mysql
+etc/mysql/debian-start
+usr/bin/msql2mysql
+usr/bin/my_print_defaults
+usr/bin/myisamchk
+usr/bin/myisamlog
+usr/bin/myisampack
+usr/bin/mysql_convert_table_format
+usr/bin/mysql_install_db
+usr/bin/mysql_secure_installation
+usr/bin/mysql_setpermission
+usr/bin/mysql_tzinfo_to_sql
+usr/bin/mysql_upgrade
+usr/bin/mysql_zap
+usr/bin/mysqlbinlog
+usr/bin/mysqld_multi
+usr/bin/mysqld_safe
+usr/bin/mysqlhotcopy
+usr/bin/mysqltest
+usr/bin/perror
+usr/bin/replace
+usr/bin/resolve_stack_dump
+usr/bin/resolveip
+usr/bin/wsrep_sst_common
+usr/bin/wsrep_sst_mysqldump
+usr/bin/wsrep_sst_rsync
+usr/bin/wsrep_sst_xtrabackup
+usr/lib/mysql/plugin/*.so
+usr/sbin/mysqld
+usr/sbin/mysqld
+usr/share/doc/mysql-server-5.6/
+usr/share/mysql/bulgarian
+usr/share/mysql/charsets
+usr/share/mysql/charsets
+usr/share/mysql/czech
+usr/share/mysql/czech
+usr/share/mysql/danish
+usr/share/mysql/danish
+usr/share/mysql/debian-start.inc.sh
+usr/share/mysql/debian_create_root_user.sql
+usr/share/mysql/dictionary.txt
+usr/share/mysql/dutch
+usr/share/mysql/dutch
+usr/share/mysql/echo_stderr
+usr/share/mysql/english
+usr/share/mysql/english
+usr/share/mysql/errmsg-utf8.txt
+usr/share/mysql/estonian
+usr/share/mysql/estonian
+usr/share/mysql/fill_help_tables.sql
+usr/share/mysql/french
+usr/share/mysql/french
+usr/share/mysql/german
+usr/share/mysql/german
+usr/share/mysql/greek
+usr/share/mysql/greek
+usr/share/mysql/hungarian
+usr/share/mysql/hungarian
+usr/share/mysql/innodb_memcached_config.sql
+usr/share/mysql/italian
+usr/share/mysql/italian
+usr/share/mysql/japanese
+usr/share/mysql/japanese
+usr/share/mysql/korean
+usr/share/mysql/korean
+usr/share/mysql/mysql_security_commands.sql
+usr/share/mysql/mysql_system_tables.sql
+usr/share/mysql/mysql_system_tables_data.sql
+usr/share/mysql/mysql_test_data_timezone.sql
+usr/share/mysql/mysqld_multi.server
+usr/share/mysql/norwegian
+usr/share/mysql/norwegian
+usr/share/mysql/norwegian-ny
+usr/share/mysql/norwegian-ny
+usr/share/mysql/polish
+usr/share/mysql/polish
+usr/share/mysql/portuguese
+usr/share/mysql/portuguese
+usr/share/mysql/romanian
+usr/share/mysql/romanian
+usr/share/mysql/russian
+usr/share/mysql/russian
+usr/share/mysql/serbian
+usr/share/mysql/serbian
+usr/share/mysql/slovak
+usr/share/mysql/slovak
+usr/share/mysql/spanish
+usr/share/mysql/spanish
+usr/share/mysql/swedish
+usr/share/mysql/swedish
+usr/share/mysql/ukrainian
+usr/share/mysql/ukrainian
+usr/share/mysql/wsrep.cnf
+usr/share/mysql/my-default.cnf
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.lintian-overrides b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.lintian-overrides
new file mode 100644 (file)
index 0000000..a0e6f63
--- /dev/null
@@ -0,0 +1,5 @@
+# These long lines reproduce actual output and to reformat them
+# would damage the integrity of the man page.
+# mysql-server-5.6: manpage-has-errors-from-man usr/share/man/man1/mysqlbinlog.1.gz 1405: warning [p 9, 7.5i, div `3tbd3,2', 0.8i]: can't break line
+# These are random occurrences of a pseudo word in a binary.
+mysql-server-5.6: spelling-error-in-binary usr/sbin/mysqld yuR your
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.logcheck.ignore.paranoid b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.logcheck.ignore.paranoid
new file mode 100644 (file)
index 0000000..00cc5c3
--- /dev/null
@@ -0,0 +1,9 @@
+/etc/init.d/mysql\[[0-9]+\]: Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists\!$
+/etc/init.d/mysql\[[0-9]+\]: '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$
+/etc/mysql/debian-start\[[0-9]+\]: Checking for crashed MySQL tables\.$
+mysqld\[[0-9]+\]: $
+mysqld\[[0-9]+\]: Version: .* socket: '/var/run/mysqld/mysqld.sock'  port: 3306$
+mysqld\[[0-9]+\]: Warning: Ignoring user change to 'mysql' because the user was set to 'mysql' earlier on the command line$
+mysqld_safe\[[0-9]+\]: started$
+usermod\[[0-9]+\]: change user `mysql' GID from `([0-9]+)' to `\1'$
+usermod\[[0-9]+\]: change user `mysql' shell from `/bin/false' to `/bin/false'$
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.logcheck.ignore.server b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.logcheck.ignore.server
new file mode 100644 (file)
index 0000000..37f25cb
--- /dev/null
@@ -0,0 +1,32 @@
+/etc/init.d/mysql\[[0-9]+\]: [0-9]+ processes alive and '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$
+/etc/init.d/mysql\[[0-9]+\]: Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists\!$
+/etc/init.d/mysql\[[0-9]+\]: '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$
+/etc/mysql/debian-start\[[0-9]+\]: Checking for crashed MySQL tables\.$
+mysqld\[[0-9]+\]: ?$
+mysqld\[[0-9]+\]: .*InnoDB: Shutdown completed
+mysqld\[[0-9]+\]: .*InnoDB: Started;
+mysqld\[[0-9]+\]: .*InnoDB: Starting shutdown\.\.\.$
+mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Normal shutdown$
+mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: ready for connections\.$
+mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Shutdown complete$
+mysqld\[[0-9]+\]: /usr/sbin/mysqld: ready for connections\.$
+mysqld\[[0-9]+\]: .*/usr/sbin/mysqld: Shutdown Complete$
+mysqld\[[0-9]+\]: Version: .* socket
+mysqld\[[0-9]+\]: Warning: Ignoring user change to 'mysql' because the user was set to 'mysql' earlier on the command line$
+mysqld_safe\[[0-9]+\]: ?$
+mysqld_safe\[[0-9]+\]: able to use the new GRANT command!$
+mysqld_safe\[[0-9]+\]: ended$
+mysqld_safe\[[0-9]+\]: http://www.mysql.com$
+mysqld_safe\[[0-9]+\]: NOTE:  If you are upgrading from a MySQL <= 3.22.10 you should run$
+mysqld_safe\[[0-9]+\]: PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !$
+mysqld_safe\[[0-9]+\]: Please report any problems with the /usr/bin/mysqlbug script!$
+mysqld_safe\[[0-9]+\]: See the manual for more instructions.$
+mysqld_safe\[[0-9]+\]: started$
+mysqld_safe\[[0-9]+\]: Support MySQL by buying support/licenses at https://order.mysql.com$
+mysqld_safe\[[0-9]+\]: The latest information about MySQL is available on the web at$
+mysqld_safe\[[0-9]+\]: the /usr/bin/mysql_fix_privilege_tables. Otherwise you will not be$
+mysqld_safe\[[0-9]+\]: To do so, start the server, then issue the following commands:$
+mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root -h app109 password 'new-password'$
+mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root password 'new-password'$
+usermod\[[0-9]+\]: change user `mysql' GID from `([0-9]+)' to `\1'$
+usermod\[[0-9]+\]: change user `mysql' shell from `/bin/false' to `/bin/false'$
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.logcheck.ignore.workstation b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.logcheck.ignore.workstation
new file mode 100644 (file)
index 0000000..37f25cb
--- /dev/null
@@ -0,0 +1,32 @@
+/etc/init.d/mysql\[[0-9]+\]: [0-9]+ processes alive and '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$
+/etc/init.d/mysql\[[0-9]+\]: Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists\!$
+/etc/init.d/mysql\[[0-9]+\]: '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$
+/etc/mysql/debian-start\[[0-9]+\]: Checking for crashed MySQL tables\.$
+mysqld\[[0-9]+\]: ?$
+mysqld\[[0-9]+\]: .*InnoDB: Shutdown completed
+mysqld\[[0-9]+\]: .*InnoDB: Started;
+mysqld\[[0-9]+\]: .*InnoDB: Starting shutdown\.\.\.$
+mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Normal shutdown$
+mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: ready for connections\.$
+mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Shutdown complete$
+mysqld\[[0-9]+\]: /usr/sbin/mysqld: ready for connections\.$
+mysqld\[[0-9]+\]: .*/usr/sbin/mysqld: Shutdown Complete$
+mysqld\[[0-9]+\]: Version: .* socket
+mysqld\[[0-9]+\]: Warning: Ignoring user change to 'mysql' because the user was set to 'mysql' earlier on the command line$
+mysqld_safe\[[0-9]+\]: ?$
+mysqld_safe\[[0-9]+\]: able to use the new GRANT command!$
+mysqld_safe\[[0-9]+\]: ended$
+mysqld_safe\[[0-9]+\]: http://www.mysql.com$
+mysqld_safe\[[0-9]+\]: NOTE:  If you are upgrading from a MySQL <= 3.22.10 you should run$
+mysqld_safe\[[0-9]+\]: PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !$
+mysqld_safe\[[0-9]+\]: Please report any problems with the /usr/bin/mysqlbug script!$
+mysqld_safe\[[0-9]+\]: See the manual for more instructions.$
+mysqld_safe\[[0-9]+\]: started$
+mysqld_safe\[[0-9]+\]: Support MySQL by buying support/licenses at https://order.mysql.com$
+mysqld_safe\[[0-9]+\]: The latest information about MySQL is available on the web at$
+mysqld_safe\[[0-9]+\]: the /usr/bin/mysql_fix_privilege_tables. Otherwise you will not be$
+mysqld_safe\[[0-9]+\]: To do so, start the server, then issue the following commands:$
+mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root -h app109 password 'new-password'$
+mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root password 'new-password'$
+usermod\[[0-9]+\]: change user `mysql' GID from `([0-9]+)' to `\1'$
+usermod\[[0-9]+\]: change user `mysql' shell from `/bin/false' to `/bin/false'$
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.manpages b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.manpages
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.mysql-server.logrotate b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.mysql-server.logrotate
new file mode 100644 (file)
index 0000000..2d9c71a
--- /dev/null
@@ -0,0 +1,27 @@
+# - I put everything in one block and added sharedscripts, so that mysql gets 
+#   flush-logs'd only once.
+#   Else the binary logs would automatically increase by n times every day.
+# - The error log is obsolete, messages go to syslog now.
+/var/log/mysql.log /var/log/mysql/*log {
+       daily
+       rotate 7
+       missingok
+       create 640 mysql adm
+       compress
+       sharedscripts
+       postrotate
+               test -x /usr/bin/mysqladmin || exit 0
+               # If this fails, check debian.conf! 
+               MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
+               if [ -z "`$MYADMIN ping 2>/dev/null`" ]; then
+                 # Really no mysqld or rather a missing debian-sys-maint user?
+                 # If this occurs and is not a error please report a bug.
+                 #if ps cax | grep -q mysqld; then
+                 if killall -q -s0 -umysql mysqld; then
+                   exit 1
+                 fi 
+               else
+                 $MYADMIN flush-logs
+               fi
+       endscript
+}
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.mysql.upstart.disabled b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.mysql.upstart.disabled
new file mode 100644 (file)
index 0000000..a9247a0
--- /dev/null
@@ -0,0 +1,63 @@
+description     "MySQL 5.6 Server"
+author          "Mario Limonciello <superm1@ubuntu.com>"
+
+start on runlevel [2345]
+stop on starting rc RUNLEVEL=[016]
+
+respawn
+respawn limit 2 5
+
+env HOME=/etc/mysql
+umask 007
+
+# The default of 5 seconds is too low for mysql which needs to flush buffers
+kill timeout 300
+
+pre-start script
+    ## Fetch a particular option from mysql's invocation.
+    # Usage: void mysqld_get_param option
+    mysqld_get_param() {
+      /usr/sbin/mysqld --print-defaults \
+        | tr " " "\n" \
+        | grep -- "--$1" \
+        | tail -n 1 \
+        | cut -d= -f2
+    }
+
+    # priority can be overriden and "-s" adds output to stderr
+    ERR_LOGGER="logger -p daemon.err -t /etc/init/mysql.conf -i"
+
+    #Sanity checks
+    [ -r $HOME/my.cnf ]
+    [ -d /var/run/mysqld ] || install -m 755 -o mysql -g root -d /var/run/mysqld
+    /lib/init/apparmor-profile-load usr.sbin.mysqld
+
+    # check for diskspace shortage
+    datadir=`mysqld_get_param datadir`
+    BLOCKSIZE=`LC_ALL=C df --portability $datadir/. | tail -n 1 | awk '{print $4}'`
+    if [ $BLOCKSIZE -le 4096 ] ; then
+      echo "$0: ERROR: The partition with $datadir is too full!" >&2
+      echo "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER
+      exit 1
+    fi
+end script
+
+exec /usr/sbin/mysqld
+
+post-start script
+   for i in `seq 1 30` ; do
+        /usr/bin/mysqladmin --defaults-file="${HOME}"/debian.cnf ping && {
+            exec "${HOME}"/debian-start
+            # should not reach this line
+            exit 2
+        }
+        statusnow=`status`
+        if echo $statusnow | grep -q 'stop/' ; then
+            exit 0
+        elif echo $statusnow | grep -q 'respawn/' ; then
+            exit 1
+        fi
+        sleep 1
+    done
+    exit 1
+end script
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.postinst b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.postinst
new file mode 100644 (file)
index 0000000..18d4e3d
--- /dev/null
@@ -0,0 +1,241 @@
+#!/bin/bash
+
+set -e
+
+. /usr/share/debconf/confmodule
+
+if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi
+${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 }
+export PATH=$PATH:/sbin:/usr/sbin:/bin:/usr/bin
+
+# This command can be used as pipe to syslog. With "-s" it also logs to stderr.
+ERR_LOGGER="logger -p daemon.err -t mysqld_safe -i"
+
+invoke() {
+  if [ -x /usr/sbin/invoke-rc.d ]; then
+    invoke-rc.d mysql $1
+  else
+    /etc/init.d/mysql $1
+  fi
+}
+
+MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --skip-grant-tables"
+
+test_mysql_access() {
+       mysql --no-defaults -u root -h localhost </dev/null >/dev/null 2>&1
+}
+
+# call with $1 = "online" to connect to the server, otherwise it bootstraps
+set_mysql_rootpw() {
+       # forget we ever saw the password.  don't use reset to keep the seen status
+       db_set mysql-server/root_password ""
+       db_set mysql-server/root_password_again ""
+
+       tfile=`mktemp`
+       if [ ! -f "$tfile" ]; then
+               return 1
+       fi
+
+       # this avoids us having to call "test" or "[" on $rootpw
+       cat << EOF > $tfile
+USE mysql;
+UPDATE user SET password=PASSWORD("$rootpw") WHERE user='root';
+FLUSH PRIVILEGES;
+EOF
+       if grep -q 'PASSWORD("")' $tfile; then
+               retval=0
+       elif [ "$1" = "online" ]; then
+               mysql --no-defaults -u root -h localhost <$tfile >/dev/null
+               retval=$?
+       else
+               $MYSQL_BOOTSTRAP <$tfile
+               retval=$?
+       fi
+       rm -f $tfile
+       return $retval
+}
+
+# This is necessary because mysql_install_db removes the pid file in /var/run
+# and because changed configuration options should take effect immediately.
+# In case the server wasn't running at all it should be ok if the stop
+# script fails. I can't tell at this point because of the cleaned /var/run.
+set +e; invoke stop; set -e
+    
+case "$1" in
+  configure)
+    mysql_datadir=/usr/share/mysql
+    mysql_statedir=/var/lib/mysql
+    mysql_rundir=/var/run/mysqld
+    mysql_logdir=/var/log/mysql
+    mysql_cfgdir=/etc/mysql
+    mysql_upgradedir=/var/lib/mysql-upgrade
+    mysql_filesdir=/var/lib/mysql-files
+
+    # Ensure the existence and right permissions for the database and
+    # log files.
+
+    # MySQL 5.6.34 needs this
+
+    if [ ! -d ${mysql_filesdir} -a ! -L ${mysql_filesdir} ];
+    then
+        mkdir ${mysql_filesdir}
+        chown mysql:mysql ${mysql_filesdir}
+        chmod 770 ${mysql_filesdir}
+    fi
+
+    if [ ! -d "$mysql_statedir"       -a ! -L "$mysql_statedir"       ]; then mkdir "$mysql_statedir"; fi
+    if [ ! -d "$mysql_statedir/mysql" -a ! -L "$mysql_statedir/mysql" ]; then mkdir "$mysql_statedir/mysql"; fi
+    if [ ! -d "$mysql_logdir"         -a ! -L "$mysql_logdir"         ]; then mkdir "$mysql_logdir"; fi
+    # When creating an ext3 jounal on an already mounted filesystem like e.g.
+    # /var/lib/mysql, you get a .journal file that is not modifyable by chown.
+    # The mysql_datadir must not be writable by the mysql user under any
+    # circumstances as it contains scripts that are executed by root.
+    set +e
+    chown -R 0:0 $mysql_datadir
+    chown -R mysql $mysql_statedir
+    chmod 700 $mysql_statedir $mysql_statedir/mysql
+    if [ ! -d "$mysql_rundir" ]; then mkdir "$mysql_rundir"; fi
+    chown -R mysql $mysql_rundir
+    touch $mysql_logdir/error.log
+    chown -R mysql:adm $mysql_logdir
+    chmod 0750 $mysql_logdir
+    chmod 0640 $mysql_logdir/error.log
+    set -e
+
+    # This is important to avoid dataloss when there is a removed
+    # mysql-server version from Woody lying around which used the same
+    # data directory and then somewhen gets purged by the admin.
+    db_set mysql-server/postrm_remove_database false || true
+
+    # To avoid downgrades.
+    touch $mysql_statedir/debian-5.6.flag
+
+    # initiate databases. Output is not allowed by debconf :-(
+    # Debian: can safely run on upgrades with existing databases 
+
+    set +e
+    tfile_select_db=`mktemp`
+    echo "USE mysql;" > $tfile_select_db
+    MYSQL_EXTRA_OPTS=" --default-storage-engine=myisam --lc-messages-dir=/usr/share/mysql/english/.."
+    MYSQL_CMDLINE=$MYSQL_BOOTSTRAP$MYSQL_EXTRA_OPTS
+    cat $tfile_select_db $mysql_datadir/mysql_system_tables.sql $mysql_datadir/debian_create_root_user.sql $mysql_datadir/fill_help_tables.sql | $MYSQL_CMDLINE 2>&1 | $ERR_LOGGER
+    rm $tfile_select_db
+    set -e
+
+    ## On every reconfiguration the maintenance user is recreated.
+    #
+    # - It is easier to regenerate the password every time but as people
+    #   use fancy rsync scripts and file alteration monitors, the existing
+    #   password is used and existing files not touched.
+    # - The mysqld statement is like that in mysql_install_db because the
+    #   server is not already running. This has some implications:
+    #  - The amount of newlines and semicolons in the query is important!
+    #   - GRANT is not possible with --skip-grant-tables and "INSERT
+    #     (user,host..) VALUES" is not --ansi compliant
+    # - The echo is just for readability. ash's buildin has no "-e" so use /bin/echo.
+    # - The Super_priv, Show_db_priv, Create_tmp_table_priv and Lock_tables_priv
+    #   may not be present as old Woody 3.23 databases did not have it and the
+    #   admin might not already have run mysql_upgrade which adds them.
+    #   As the binlog cron scripts to need at least the Super_priv, I do first
+    #   the old query which always succeeds and then the new which may or may not.
+
+    # recreate the credentials file if not present or without mysql_upgrade stanza
+    dc=$mysql_cfgdir/debian.cnf; 
+    if [ -e "$dc" -a -n "`fgrep mysql_upgrade $dc 2>/dev/null`" ]; then
+        pass="`sed -n 's/^[     ]*password *= *// p' $dc | head -n 1`"
+    else
+       pass=`perl -e 'print map{("a".."z","A".."Z",0..9)[int(rand(62))]}(1..16)'`;
+        if [ ! -d "$mysql_cfgdir" ]; then install -o 0 -g 0 -m 0755 -d $mysql_cfgdir; fi
+        umask 066
+        cat /dev/null > $dc
+        umask 022
+        echo "# Automatically generated for Debian scripts. DO NOT TOUCH!" >>$dc
+        echo "[client]"                                                    >>$dc
+        echo "host     = localhost"                                        >>$dc
+        echo "user     = debian-sys-maint"                                 >>$dc
+        echo "password = $pass"                                            >>$dc
+        echo "socket   = $mysql_rundir/mysqld.sock"                        >>$dc
+        echo "[mysql_upgrade]"                                             >>$dc
+        echo "host     = localhost"                                        >>$dc
+        echo "user     = debian-sys-maint"                                 >>$dc
+        echo "password = $pass"                                            >>$dc
+        echo "socket   = $mysql_rundir/mysqld.sock"                        >>$dc
+        echo "basedir  = /usr"                                             >>$dc
+    fi
+    # If this dir chmod go+w then the admin did it. But this file should not.
+    chown 0:0 $dc
+    chmod 0600 $dc
+
+    replace_query=`echo -e \
+        "USE mysql;\n" \
+        "REPLACE INTO user SET " \
+        "  host='localhost', user='debian-sys-maint', password=password('$pass'), " \
+        "  Select_priv='Y', Insert_priv='Y', Update_priv='Y', Delete_priv='Y', " \
+        "  Create_priv='Y', Drop_priv='Y', Reload_priv='Y', Shutdown_priv='Y', " \
+        "  Process_priv='Y',  File_priv='Y', Grant_priv='Y', References_priv='Y', " \
+        "  Index_priv='Y', Alter_priv='Y', Super_priv='Y', Show_db_priv='Y', "\
+        "  Create_tmp_table_priv='Y', Lock_tables_priv='Y', Execute_priv='Y', "\
+        "  Repl_slave_priv='Y', Repl_client_priv='Y', Create_view_priv='Y', "\
+        "  Show_view_priv='Y', Create_routine_priv='Y', Alter_routine_priv='Y', "\
+        "  Create_user_priv='Y', Event_priv='Y', Trigger_priv='Y'; "`;
+    # Engines supported by etch should be installed per default. The query sequence is supposed
+    # to be aborted if the CREATE TABLE fails due to an already existent table in which case the
+    # admin might already have chosen to remove one or more plugins. Newlines are necessary.
+    install_plugins=`echo -e \
+        "USE mysql;\n" \
+        "CREATE TABLE IF NOT EXISTS plugin (name char(64) COLLATE utf8_bin NOT NULL DEFAULT '', " \
+        "  dl char(128) COLLATE utf8_bin NOT NULL DEFAULT '', " \
+        "  PRIMARY KEY (name)) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='MySQL plugins';\n" \
+        "INSERT INTO plugin VALUES ('innodb',    'ha_innodb.so');\n" \
+        "INSERT INTO plugin VALUES ('federated', 'ha_federated.so');\n" \
+        "INSERT INTO plugin VALUES ('blackhole', 'ha_blackhole.so');\n" \
+        "INSERT INTO plugin VALUES ('archive',   'ha_archive.so');" `
+
+    db_get mysql-server/root_password && rootpw="$RET"
+    if ! set_mysql_rootpw; then
+        password_error="yes"
+    fi
+
+    echo "$replace_query"                                    | $MYSQL_BOOTSTRAP 2>&1 | $ERR_LOGGER
+    set +e
+    echo "$install_plugins"                                  | $MYSQL_BOOTSTRAP 2>&1 | $ERR_LOGGER
+    set -e
+  ;;
+
+  abort-upgrade|abort-remove|abort-configure)
+  ;;
+
+  *)
+    echo "postinst called with unknown argument '$1'" 1>&2
+    exit 1
+  ;;
+esac
+
+# here we check to see if we can connect as root without a password
+# this should catch upgrades from previous versions where the root
+# password wasn't set.  if there is a password, or if the connection
+# fails for any other reason, nothing happens.
+if [ "$1" = "configure" ]; then
+       if test_mysql_access; then
+               db_input medium mysql-server/root_password || true
+               db_go
+               db_get mysql-server/root_password && rootpw="$RET"
+
+               if ! set_mysql_rootpw "online"; then
+                       password_error="yes"
+               fi
+       fi
+
+       if [ "$password_error" = "yes" ]; then
+               db_input high mysql-server/error_setting_password || true
+               db_go
+       fi
+
+fi
+
+db_stop # in case invoke failes
+
+#DEBHELPER#
+
+exit 0
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.postrm b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.postrm
new file mode 100644 (file)
index 0000000..70c6fb5
--- /dev/null
@@ -0,0 +1,79 @@
+#!/bin/bash
+
+set -e
+
+# It is possible that Debconf has already been removed, too.
+if [ -f /usr/share/debconf/confmodule ]; then
+  . /usr/share/debconf/confmodule
+fi
+
+if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi
+${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 }
+
+MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
+
+# Try to stop the server in a sane way. If it does not success let the admin
+# do it himself. No database directories should be removed while the server
+# is running!
+stop_server() {
+  set +e
+  if [ -x /usr/sbin/invoke-rc.d ]; then
+    invoke-rc.d mysql stop
+  else
+    /etc/init.d/mysql stop
+  fi
+  errno=$?
+  set -e
+
+  if [ "$?" != 0 ]; then
+    echo "Trying to stop the MySQL server resulted in exitcode $?." 1>&2
+    echo "Stop it yourself and try again!" 1>&2
+    exit 1
+  fi
+}
+
+case "$1" in
+  purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
+    if [ -n "`$MYADMIN ping 2>/dev/null`" ]; then
+      stop_server
+      sleep 2
+    fi
+  ;;
+  *)
+    echo "postrm called with unknown argument '$1'" 1>&2
+    exit 1
+  ;;
+esac
+
+#
+# - Do NOT purge logs or data if another mysql-sever* package is installed (#307473)
+# - Remove the mysql user only after all his owned files are purged.
+#   
+if [ "$1" = "purge" -a ! \( -x /usr/sbin/mysqld -o -L /usr/sbin/mysqld \) ]; then
+  # we remove the mysql user only after all his owned files are purged
+  rm -f /var/log/mysql.{log,err}{,.0,.[1234567].gz}
+  rm -rf /var/log/mysql
+
+  db_input high mysql-server-5.6/postrm_remove_databases || true
+  db_go || true
+  db_get mysql-server-5.6/postrm_remove_databases || true
+  if [ "$RET" = "true" ]; then
+    # never remove the debian.cnf when the databases are still existing
+    # else we ran into big trouble on the next install!
+    rm -f /etc/mysql/debian.cnf
+    rm -rf /var/lib/mysql
+    rm -rf /var/run/mysqld
+    userdel mysql || true
+  fi
+fi
+
+# (normally) Automatically added by dh_installdebconf
+if [ "$1" = purge ] && [ -e /usr/share/debconf/confmodule ]; then
+        . /usr/share/debconf/confmodule
+        db_purge
+fi
+# (normally) End automatically added section
+
+#DEBHELPER#
+
+exit 0
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.preinst b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.preinst
new file mode 100644 (file)
index 0000000..320c748
--- /dev/null
@@ -0,0 +1,185 @@
+#!/bin/bash
+#
+# summary of how this script can be called:
+#        * <new-preinst> install
+#        * <new-preinst> install <old-version>
+#        * <new-preinst> upgrade <old-version>
+#        * <old-preinst> abort-upgrade <new-version>
+#
+
+set -e
+
+. /usr/share/debconf/confmodule
+
+if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi
+${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 }
+
+export PATH=$PATH:/sbin:/usr/sbin:/bin:/usr/bin
+MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
+DATADIR=/var/lib/mysql
+LOGDIR=/var/log/mysql
+UPGRADEDIR=/var/lib/mysql-upgrade
+
+# Try to stop the server in a sane way. If it does not success let the admin
+# do it himself. No database directories should be removed while the server
+# is running! Another mysqld in e.g. a different chroot is fine for us.
+stop_server() {
+    if [ ! -x /etc/init.d/mysql ]; then return; fi
+
+    set +e
+    if [ -x /usr/sbin/invoke-rc.d ]; then
+      cmd="invoke-rc.d mysql stop"
+    else
+      cmd="/etc/init.d/mysql stop"
+    fi
+    $cmd
+    errno=$?
+    set -e
+   
+    # 0=ok, 100=no init script (fresh install)
+    if [ "$errno" != 0 -a "$errno" != 100 ]; then
+      echo "${cmd/ */} returned $errno" 1>&2
+      echo "There is a MySQL server running, but we failed in our attempts to stop it." 1>&2
+      echo "Stop it yourself and try again!" 1>&2
+      db_stop          
+      exit 1
+    fi
+}
+
+################################ main() ##########################
+
+this_version=5.6
+
+# Abort if an NDB cluster is in use.
+if egrep -qi -r '^[^#]*ndb.connectstring|^[[:space:]]*\[[[:space:]]*ndb_mgmd' /etc/mysql/; then
+  db_fset mysql-server/no_upgrade_when_using_ndb seen false || true
+  db_input high mysql-server/no_upgrade_when_using_ndb || true
+  db_go
+  db_stop
+  exit 1
+fi
+
+# Abort if skip-bdb option is enabled, required for 5.0 -> 5.1 upgrades.
+#TODO
+
+# Safe the user from stupidities.
+show_downgrade_warning=0
+for i in `ls $DATADIR/debian-*.flag 2>/dev/null`; do
+  found_version=`echo $i | sed 's/.*debian-\([0-9\.]\+\).flag/\1/'`
+  if dpkg --compare-versions "$this_version" '<<' "$found_version"; then
+    show_downgrade_warning=1
+    break;
+  fi
+done
+if [ "$show_downgrade_warning" = 1 ]; then
+  db_fset mysql-server-$this_version/really_downgrade seen false || true
+  db_input medium mysql-server-$this_version/really_downgrade || true
+  db_go
+  db_get mysql-server-$this_version/really_downgrade || true
+  if [ "$RET" = "true" ]; then
+    rm -f $DATADIR/debian-*.flag
+    touch $DATADIR/debian-$this_version.flag
+  else
+    echo "Aborting downgrade from (at least) $found_version to $this_version." 1>&2
+    echo "If are sure you want to downgrade to $this_version, remove the file" 1>&2
+    echo "$DATADIR/debian-*.flag and try installing again." 1>&2
+    db_stop
+    exit 1
+  fi
+fi
+
+# to be sure
+stop_server
+
+# If we use NIS then errors should be tolerated. It's up to the
+# user to ensure that the mysql user is correctly setup.
+# Beware that there are two ypwhich one of them needs the 2>/dev/null!
+if test -n "`which ypwhich 2>/dev/null`"  &&  ypwhich >/dev/null 2>&1; then
+  set +e
+fi
+
+#
+# Now we have to ensure the following state:
+# /etc/passwd: mysql:x:100:101:MySQL Server:/nonexistent:/bin/false
+# /etc/group:  mysql:x:101:
+# 
+# Sadly there could any state be present on the system so we have to
+# modify everything carefully i.e. not doing a chown before creating
+# the user etc...
+#
+
+# creating mysql group if he isn't already there
+if ! getent group mysql >/dev/null; then
+       # Adding system group: mysql.
+       addgroup --system mysql >/dev/null
+fi
+
+# creating mysql user if he isn't already there
+if ! getent passwd mysql >/dev/null; then
+       # Adding system user: mysql.
+       adduser \
+         --system \
+          --disabled-login \
+         --ingroup mysql \
+         --no-create-home \
+         --home /nonexistent \
+         --gecos "MySQL Server" \
+         --shell /bin/false \
+         mysql  >/dev/null
+fi
+
+# end of NIS tolerance zone
+set -e
+
+# if there's a symlink, let's store where it's pointing, because otherwise
+# it's going to be lost in some situations
+for dir in DATADIR LOGDIR; do
+    checkdir=`eval echo "$"$dir`
+    if [ -L "$checkdir" ]; then
+       mkdir -p "$UPGRADEDIR"
+       cp -d "$checkdir" "$UPGRADEDIR/$dir.link"
+    fi
+done
+
+# creating mysql home directory
+if [ ! -d $DATADIR -a ! -L $DATADIR ]; then
+       mkdir $DATADIR
+fi
+
+# checking disc space
+if LC_ALL=C BLOCKSIZE= df --portability $DATADIR/. | tail -n 1 | awk '{ exit ($4>1000) }'; then
+  echo "ERROR: There's not enough space in $DATADIR/" 1>&2
+  db_stop
+  exit 1
+fi
+
+# Since the home directory was created before putting the user into
+# the mysql group and moreover we cannot guarantee that the 
+# permissions were correctly *before* calling this script, we fix them now.
+# In case we use NIS and no mysql user is present then this script should
+# better fail now than later..
+# The "set +e" is necessary as e.g. a ".journal" of a ext3 partition is
+# not chgrp'able (#318435).
+set +e
+chown mysql:mysql $DATADIR
+find $DATADIR -follow -not -group mysql -print0 2>/dev/null \
+  | xargs -0 --no-run-if-empty chgrp mysql
+set -e
+
+# Some files below /etc/ were possibly in the mysql-server-5.0/etch package
+# before. They get overwritten by current ones to avoid unnecessary dpkg questions.
+while read md5 file; do
+  if [ "`md5sum $file 2>/dev/null`" = "$md5  $file" ]; then
+    cp /usr/share/mysql-common/internal-use-only/`echo $file | sed 's°/°_°g'` $file
+  fi
+done <<EOT
+6691f2fdc5c6d27ff0260eb79813e1bc  /etc/init.d/mysql
+b53b9552d44661361d39157c3c7c51d3  /etc/logrotate.d/mysql-server
+57f3e58f72582ca55100dc1ba0f1a8ae  /etc/mysql/debian-start
+EOT
+
+db_stop
+
+#DEBHELPER#
+
+exit 0
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.prerm b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.prerm
new file mode 100644 (file)
index 0000000..0371bbf
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+set -e
+
+. /usr/share/debconf/confmodule
+
+if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi
+${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 }
+
+#DEBHELPER#
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.templates b/mysql-wsrep-5.6/debian/mysql-wsrep-server-5.6.templates
new file mode 100644 (file)
index 0000000..3e72c90
--- /dev/null
@@ -0,0 +1,89 @@
+# These templates have been reviewed by the debian-l10n-english
+# team
+#
+# If modifications/additions/rewording are needed, please ask
+# for an advice to debian-l10n-english@lists.debian.org
+#
+# Even minor modifications require translation updates and such
+# changes should be coordinated with translators and reviewers.
+
+Template: mysql-server-5.6/really_downgrade
+Type: boolean
+Default: false
+_Description: Really proceed with downgrade?
+ A file named /var/lib/mysql/debian-*.flag exists on this system.
+ .
+ Such a file is an indication that a mysql-server package with a higher
+ version has been installed previously.
+ .
+ There is no guarantee that the version you're currently installing
+ will be able to use the current databases.
+
+Template: mysql-server-5.6/nis_warning
+Type: note
+#flag:translate!:3,5
+_Description: Important note for NIS/YP users
+ Using MySQL under NIS/YP requires a mysql user account to be added on
+ the local system with:
+ .
+  adduser --system --group --home /var/lib/mysql mysql
+ .
+ You should also check the permissions and ownership of the
+ /var/lib/mysql directory:
+ .
+  /var/lib/mysql: drwxr-xr-x   mysql    mysql
+
+Template: mysql-server-5.6/postrm_remove_databases
+Type: boolean
+Default: false
+_Description: Remove all MySQL databases?
+ The /var/lib/mysql directory which contains the MySQL databases is about
+ to be removed.
+ .
+ If you're removing the MySQL package in order to later install a more
+ recent version or if a different mysql-server package is already
+ using it, the data should be kept.
+
+Template: mysql-server-5.6/start_on_boot
+Type: boolean
+Default: true
+_Description: Start the MySQL server on boot?
+ The MySQL server can be launched automatically at boot time or manually
+ with the '/etc/init.d/mysql start' command.
+
+Template: mysql-server/root_password
+Type: password
+_Description: New password for the MySQL "root" user:
+ While not mandatory, it is highly recommended that you set a password
+ for the MySQL administrative "root" user.
+ .
+ If this field is left blank, the password will not be changed.
+
+Template: mysql-server/root_password_again
+Type: password
+_Description: Repeat password for the MySQL "root" user:
+
+Template: mysql-server/error_setting_password
+Type: error
+_Description: Unable to set password for the MySQL "root" user
+ An error occurred while setting the password for the MySQL
+ administrative user. This may have happened because the account
+ already has a password, or because of a communication problem with
+ the MySQL server.
+ .
+ You should check the account's password after the package installation.
+ .
+ Please read the /usr/share/doc/mysql-server-5.6/README.Debian file
+ for more information.
+
+Template: mysql-server/password_mismatch
+Type: error
+_Description: Password input error
+ The two passwords you entered were not the same. Please try again.
+
+Template: mysql-server/no_upgrade_when_using_ndb
+Type: error
+_Description: NDB Cluster seems to be in use
+ MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new
+ mysql-cluster-server package and remove all lines starting with "ndb" from
+ all config files below /etc/mysql/.
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-testsuite-5.6.dirs b/mysql-wsrep-5.6/debian/mysql-wsrep-testsuite-5.6.dirs
new file mode 100644 (file)
index 0000000..e637692
--- /dev/null
@@ -0,0 +1,4 @@
+/usr/lib/mysql-testsuite
+usr/share/mysql/mysql-test/suite/wsrep
+usr/share/mysql/mysql-test/suite/wsrep/t
+usr/share/mysql/mysql-test/suite/wsrep/r
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-testsuite-5.6.install b/mysql-wsrep-5.6/debian/mysql-wsrep-testsuite-5.6.install
new file mode 100644 (file)
index 0000000..ccadd9f
--- /dev/null
@@ -0,0 +1 @@
+usr/share/mysql-test/* usr/lib/mysql-testsuite/
diff --git a/mysql-wsrep-5.6/debian/mysql-wsrep-testsuite-5.6.lintian-overrides b/mysql-wsrep-5.6/debian/mysql-wsrep-testsuite-5.6.lintian-overrides
new file mode 100644 (file)
index 0000000..e94549f
--- /dev/null
@@ -0,0 +1,4 @@
+# These are random occurrences of a pseudo word in a binary.
+mysql-testsuite-5.6: spelling-error-in-binary usr/bin/mysql_client_test_embedded yuR your
+mysql-testsuite-5.6: spelling-error-in-binary usr/bin/mysql_embedded yuR your
+mysql-testsuite-5.6: spelling-error-in-binary usr/bin/mysqltest_embedded yuR your
diff --git a/mysql-wsrep-5.6/debian/patches/fix_standalone_tests.patch b/mysql-wsrep-5.6/debian/patches/fix_standalone_tests.patch
new file mode 100644 (file)
index 0000000..faedcc4
--- /dev/null
@@ -0,0 +1,17 @@
+From: Clint Byrum <clint@ubuntu.com>
+Description: makes mtr look in the standard location from the 
+ mysql-testsuite-5.5 package.
+Forwarded: not-needed
+
+--- a/mysql-test/lib/mtr_cases.pm
++++ b/mysql-test/lib/mtr_cases.pm
+@@ -287,7 +287,8 @@ sub collect_one_suite($)
+     else
+     {
+       $suitedir= my_find_dir($::basedir,
+-                           ["share/mysql-test/suite",
++                             ["lib/mysql-testsuite/suite",
++                              "share/mysql-test/suite",
+                             "mysql-test/suite",
+                             "internal/mysql-test/suite",
+                             "mysql-test",
diff --git a/mysql-wsrep-5.6/debian/patches/hurd.patch b/mysql-wsrep-5.6/debian/patches/hurd.patch
new file mode 100644 (file)
index 0000000..b64feeb
--- /dev/null
@@ -0,0 +1,41 @@
+Author: Pino Toscano <pino@debian.org>
+Subject: cmake options for GNU/Hurd
+Bug: http://bugs.mysql.com/bug.php?id=64685
+Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=651002
+Last-Update: 2012-03-18
+Reviewed-by: Nicholas Bamber <nicholas@periapt.co.uk>
+--- /dev/null
++++ b/cmake/os/GNU.cmake
+@@ -0,0 +1,20 @@
++# This file includes GNU/Hurd specific options and quirks, related to system checks
++
++INCLUDE(CheckSymbolExists)
++
++SET(_GNU_SOURCE 1)
++
++# Fix CMake (< 2.8) flags. -rdynamic exports too many symbols.
++FOREACH(LANG C CXX)
++  STRING(REPLACE "-rdynamic" ""
++  CMAKE_SHARED_LIBRARY_LINK_${LANG}_FLAGS
++  "${CMAKE_SHARED_LIBRARY_LINK_${LANG}_FLAGS}"
++  )
++ENDFOREACH()
++
++# Ensure we have clean build for shared libraries
++# without unresolved symbols
++SET(LINK_FLAG_NO_UNDEFINED "-Wl,--no-undefined")
++
++# 64 bit file offset support flag
++SET(_FILE_OFFSET_BITS 64)
+--- a/mysql-test/lib/My/Platform.pm
++++ b/mysql-test/lib/My/Platform.pm
+@@ -110,6 +110,9 @@ sub check_socket_path_length {
+   # This may not be true, but we can't test for it on AIX due to Perl bug
+   # See Bug #45771
+   return 0 if ($^O eq 'aix');
++  # Similarly the path length is hidden.
++  # See Debian bug #651002
++  return 0 if ($^O eq 'gnu');
+   require IO::Socket::UNIX;
diff --git a/mysql-wsrep-5.6/debian/patches/kfreebsd_tests.patch b/mysql-wsrep-5.6/debian/patches/kfreebsd_tests.patch
new file mode 100644 (file)
index 0000000..981e0a9
--- /dev/null
@@ -0,0 +1,18 @@
+Author: Nicholas Bamber <nicholas@periapt.co.uk>
+Debian-Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=540153
+Subject: tests not getting started on kFreeBSD
+ As per #670722 I found that the test socket created to test
+ file name truncation was barfing even for the shortened form.
+Forwarded: no
+Last-Update: 2012-04-28
+--- a/mysql-test/lib/My/Platform.pm
++++ b/mysql-test/lib/My/Platform.pm
+@@ -113,6 +113,8 @@ sub check_socket_path_length {
+   # Similarly the path length is hidden.
+   # See Debian bug #651002
+   return 0 if ($^O eq 'gnu');
++  # See Debian bug #670722 - failing on kFreeBSD even after setting short path
++  return 0 if length $path < 40;
+   require IO::Socket::UNIX;
diff --git a/mysql-wsrep-5.6/debian/patches/scripts__mysqld_safe.sh__signals.patch b/mysql-wsrep-5.6/debian/patches/scripts__mysqld_safe.sh__signals.patch
new file mode 100644 (file)
index 0000000..984fd8c
--- /dev/null
@@ -0,0 +1,45 @@
+Author: Christian Hammers  <ch@debian.org>
+Subject: Executes /etc/init.d/mysql on signals
+ Note if you check the bug report on mysql.com the patch is accepted
+ as interesting but they were waiting on Christian Hammers to sign an SCA.
+ Meanwhile this bug report fell off in the transition from 5.0 to 5.1.
+Bug: http://bugs.mysql.com/bug.php?id=31361
+Debian-Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=527623
+Last-Update: 2012-03-07
+Reviewed-by: Nicholas Bamber <nicholas@periapt.co.uk>
+
+--- a/scripts/mysqld_safe.sh
++++ b/scripts/mysqld_safe.sh
+@@ -29,9 +29,6 @@ err_log=
+ syslog_tag_mysqld=mysqld
+ syslog_tag_mysqld_safe=mysqld_safe
+-trap '' 1 2 3 15                      # we shouldn't let anyone kill us
+-trap '' 13                              # not even SIGPIPE
+-
+ # MySQL-specific environment variable. First off, it's not really a umask,
+ # it's the desired mode. Second, it follows umask(2), not umask(3) in that
+ # octal needs to be explicit. Our shell might be a proper sh without printf,
+@@ -154,7 +151,7 @@ eval_log_error () {
+       # sed buffers output (only GNU sed supports a -u (unbuffered) option)
+       # which means that messages may not get sent to syslog until the
+       # mysqld process quits.
+-      cmd="$cmd 2>&1 | logger -t '$syslog_tag_mysqld' -p daemon.error"
++      cmd="$cmd 2>&1 | logger -t '$syslog_tag_mysqld' -p daemon.error & wait"
+       ;;
+     *)
+       echo "Internal program error (non-fatal):" \
+@@ -815,6 +815,13 @@ mysqld daemon not started"
+ fi
+ #
++# From now on, we catch signals to do a proper shutdown of mysqld
++# when signalled to do so.
++#
++trap '/usr/bin/mysqladmin --defaults-extra-file=/etc/mysql/debian.cnf refresh & wait' 1 # HUP
++trap '/usr/bin/mysqladmin --defaults-extra-file=/etc/mysql/debian.cnf shutdown' 2 3 15 # INT QUIT and TERM
++
++#
+ # Uncomment the following lines if you want all tables to be automatically
+ # checked and repaired during startup. You should add sensible key_buffer
+ # and sort_buffer values to my.cnf to improve check performance or require
diff --git a/mysql-wsrep-5.6/debian/patches/series b/mysql-wsrep-5.6/debian/patches/series
new file mode 100644 (file)
index 0000000..08ed2f9
--- /dev/null
@@ -0,0 +1,4 @@
+hurd.patch
+scripts__mysqld_safe.sh__signals.patch
+fix_standalone_tests.patch
+kfreebsd_tests.patch
diff --git a/mysql-wsrep-5.6/debian/patches/spelling.patch b/mysql-wsrep-5.6/debian/patches/spelling.patch
new file mode 100644 (file)
index 0000000..7b7b8d1
--- /dev/null
@@ -0,0 +1,249 @@
+Author <nicholas@periapt.co.uk>
+Subject: spelling errors
+ Preceeding -> preceding
+Last-Update: 2012-05-19
+Forwarded: no
+--- a/libevent/event.3
++++ b/libevent/event.3
+@@ -253,7 +253,7 @@ the type of event which will be either
+ or
+ .Va EV_WRITE .
+ Additionally, an event which has registered interest in more than one of the
+-preceeding events, via bitwise-OR to
++preceding events, via bitwise-OR to
+ .Fn event_set ,
+ can provide its callback function with a bitwise-OR of more than one triggered
+ event.
+--- a/mysql-test/extra/rpl_tests/rpl_ddl.test
++++ b/mysql-test/extra/rpl_tests/rpl_ddl.test
+@@ -98,8 +98,8 @@
+ #       --> less switching of AUTOCOMMIT mode on master side.
+ #
+ #    4. Never use a test object, which was direct or indirect affected by a
+-#       preceeding test sequence again.
+-#       If one preceeding test sequence hits a (sometimes not visible,
++#       preceding test sequence again.
++#       If one preceding test sequence hits a (sometimes not visible,
+ #       because the sql error code of the statement might be 0) bug
+ #       and these rules are ignored, a following test sequence might earn ugly
+ #       effects like failing 'sync_slave_with_master', crashes of the slave or
+--- a/mysql-test/extra/rpl_tests/rpl_row_basic.test
++++ b/mysql-test/extra/rpl_tests/rpl_row_basic.test
+@@ -221,7 +221,7 @@ INSERT INTO t7 VALUES (1,3), (2,6), (3,9
+ SELECT * FROM t7 ORDER BY C1;
+ # since bug#31552/31609 idempotency is not default any longer. In order
+-# the preceeding test INSERT INTO t7 to pass the mode is switched
++# the preceding test INSERT INTO t7 to pass the mode is switched
+ # temprorarily
+ set @@global.slave_exec_mode= 'IDEMPOTENT';
+@@ -260,7 +260,7 @@ INSERT INTO t8 VALUES (1,2,3), (2,4,6),
+ SELECT * FROM t8 ORDER BY a;
+ # since bug#31552/31609 idempotency is not default any longer. In order
+-# the preceeding test INSERT INTO t8 to pass the mode is switched
++# the preceding test INSERT INTO t8 to pass the mode is switched
+ # temprorarily
+ set @@global.slave_exec_mode= 'IDEMPOTENT';
+--- a/mysql-test/include/wait_until_count_sessions.inc
++++ b/mysql-test/include/wait_until_count_sessions.inc
+@@ -10,7 +10,7 @@
+ #    1. We wait for $current_sessions <= $count_sessions because in the use case
+ #       with count_sessions.inc before and wait_until_count_sessions.inc after
+ #       the core of the test it could happen that the disconnects of sessions
+-#       belonging to the preceeding test are not finished.
++#       belonging to the preceding test are not finished.
+ #       sessions at test begin($count_sessions) =  m + n
+ #       sessions of the previous test which will be soon disconnected = n (n >= 0)
+ #       sessions at test end ($current sessions, assuming the test disconnects
+--- a/mysql-test/suite/funcs_1/views/func_view.inc
++++ b/mysql-test/suite/funcs_1/views/func_view.inc
+@@ -285,7 +285,7 @@ INSERT INTO t1_values SET
+ #               other interesting value
+ #     numbers   -> 0
+ #     strings, blobs, binaries -> not full length of used data type, "exotic"
+-#                                 characters and preceeding and trailing spaces
++#                                 characters and preceding and trailing spaces
+ #     FIXME enum, set ??
+ INSERT INTO t1_values SET
+        my_char_30 = ' ---äÖüß@µ*$-- ',
+--- a/mysql-test/suite/funcs_1/views/views_master.inc
++++ b/mysql-test/suite/funcs_1/views/views_master.inc
+@@ -545,7 +545,7 @@ let $message= Testcase 3.3.1.7 ;
+ #                   view names are accepted, at creation time, alteration time,
+ #                   and drop time.
+ ###############################################################################
+-# Note(mleich): non-qualified view name means a view name without preceeding
++# Note(mleich): non-qualified view name means a view name without preceding
+ #               database name
+ --disable_warnings
+ DROP VIEW  IF EXISTS v1 ;
+--- a/mysql-test/suite/rpl/t/rpl_ddl.test
++++ b/mysql-test/suite/rpl/t/rpl_ddl.test
+@@ -13,10 +13,10 @@
+ #         sequences start.
+ #
+ #      2. Never use a test object, which was direct or indirect affected by a
+-#         preceeding test sequence again.
++#         preceding test sequence again.
+ #         Except table d1.t1 where ONLY DML is allowed.
+ #
+-#         If one preceeding test sequence hits a (sometimes not good visible,
++#         If one preceding test sequence hits a (sometimes not good visible,
+ #         because the sql error code of the statement might be 0) bug
+ #         and these rules are ignored, a following test sequence might earn ugly
+ #         effects like failing 'sync_slave_with_master', crashes of the slave or
+--- a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test
++++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test
+@@ -239,7 +239,7 @@ INSERT INTO t1 VALUES (1,'master,slave')
+ UPDATE t1 SET a = 5, b = 'slave' WHERE a = 1;
+ SELECT * FROM t1 ORDER BY a;
+ # since bug#31552/31609 idempotency is not default any longer. In
+-# order for the preceeding test UPDATE t1 to pass, the mode is switched
++# order for the preceding test UPDATE t1 to pass, the mode is switched
+ # temprorarily
+ set @@global.slave_exec_mode= 'IDEMPOTENT';
+ --echo **** On Master ****
+--- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_ddl.test
++++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_ddl.test
+@@ -13,10 +13,10 @@
+ #         sequences start.
+ #
+ #      2. Never use a test object, which was direct or indirect affected by a
+-#         preceeding test sequence again.
++#         preceding test sequence again.
+ #         Except table d1.t1 where ONLY DML is allowed.
+ #
+-#         If one preceeding test sequence hits a (sometimes not good visible,
++#         If one preceding test sequence hits a (sometimes not good visible,
+ #         because the sql error code of the statement might be 0) bug
+ #         and these rules are ignored, a following test sequence might earn ugly
+ #         effects like failing 'sync_slave_with_master', crashes of the slave or
+--- a/sql/abstract_query_plan.cc
++++ b/sql/abstract_query_plan.cc
+@@ -336,7 +336,7 @@ namespace AQP
+       {
+         /*
+           use_quick == 2 means that the decision on which access method to use
+-          will be taken late (as rows from the preceeding operation arrive).
++          will be taken late (as rows from the preceding operation arrive).
+           This operation is therefor not pushable.
+         */
+         DBUG_PRINT("info",
+--- a/sql/ha_ndbcluster_push.cc
++++ b/sql/ha_ndbcluster_push.cc
+@@ -1271,7 +1271,7 @@ ndb_pushed_builder_ctx::build_key(const
+         if (m_join_scope.contain(referred_table_no))
+         {
+           // Locate the parent operation for this 'join_items[]'.
+-          // May refer any of the preceeding parent tables
++          // May refer any of the preceding parent tables
+           const NdbQueryOperationDef* const parent_op= m_tables[referred_table_no].m_op;
+           DBUG_ASSERT(parent_op != NULL);
+--- a/sql/log_event.cc
++++ b/sql/log_event.cc
+@@ -4625,7 +4625,7 @@ int Query_log_event::do_apply_event(Rela
+     if ((error= rows_event_stmt_cleanup(const_cast<Relay_log_info*>(rli), thd)))
+     {
+       const_cast<Relay_log_info*>(rli)->report(ERROR_LEVEL, error,
+-                  "Error in cleaning up after an event preceeding the commit; "
++                  "Error in cleaning up after an event preceding the commit; "
+                   "the group log file/position: %s %s",
+                   const_cast<Relay_log_info*>(rli)->get_group_master_log_name(),
+                   llstr(const_cast<Relay_log_info*>(rli)->get_group_master_log_pos(),
+--- a/sql/rpl_utility.cc
++++ b/sql/rpl_utility.cc
+@@ -1564,7 +1564,7 @@ bool Deferred_log_events::execute(Relay_
+ void Deferred_log_events::rewind()
+ {
+   /*
+-    Reset preceeding Query log event events which execution was
++    Reset preceding Query log event events which execution was
+     deferred because of slave side filtering.
+   */
+   if (!is_empty())
+--- a/sql/sql_optimizer.cc
++++ b/sql/sql_optimizer.cc
+@@ -971,7 +971,7 @@ JOIN::optimize()
+         }
+       }
+     }
+-    else if (order &&                      // ORDER BY wo/ preceeding GROUP BY
++    else if (order &&                      // ORDER BY wo/ preceding GROUP BY
+              (simple_order || skip_sort_order)) // which is possibly skippable
+     {
+       if (test_if_skip_sort_order(tab, order, m_select_limit, false, 
+--- a/sql/sql_rewrite.cc
++++ b/sql/sql_rewrite.cc
+@@ -40,7 +40,7 @@
+ /**
+-  Append a key/value pair to a string, with an optional preceeding comma.
++  Append a key/value pair to a string, with an optional preceding comma.
+   For numeric values.
+   @param           str                  The string to append to
+@@ -72,7 +72,7 @@ bool append_int(String *str, bool comma,
+ /**
+   Append a key/value pair to a string if the value is non-NULL,
+-  with an optional preceeding comma.
++  with an optional preceding comma.
+   @param           str                  The string to append to
+   @param           comma                Prepend a comma?
+--- a/sql/sql_yacc.cc
++++ b/sql/sql_yacc.cc
+@@ -35151,7 +35151,7 @@ yyreduce:
+             {
+               /*
+                 Not in trigger assigning value to new row,
+-                and option_type preceeding local variable is illegal.
++                and option_type preceding local variable is illegal.
+               */
+               my_parse_error(ER(ER_SYNTAX_ERROR));
+               MYSQL_YYABORT;
+--- a/sql/sql_yacc.yy
++++ b/sql/sql_yacc.yy
+@@ -14573,7 +14573,7 @@ opt_var_ident_type:
+         | SESSION_SYM '.' { $$=OPT_SESSION; }
+         ;
+-// Option values with preceeding option_type.
++// Option values with preceding option_type.
+ option_value_following_option_type:
+           internal_variable_name equal set_expr_or_default
+           {
+@@ -14590,7 +14590,7 @@ option_value_following_option_type:
+             {
+               /*
+                 Not in trigger assigning value to new row,
+-                and option_type preceeding local variable is illegal.
++                and option_type preceding local variable is illegal.
+               */
+               my_parse_error(ER(ER_SYNTAX_ERROR));
+               MYSQL_YYABORT;
+@@ -14598,7 +14598,7 @@ option_value_following_option_type:
+           }
+         ;
+-// Option values without preceeding option_type.
++// Option values without preceding option_type.
+ option_value_no_option_type:
+           internal_variable_name equal
+           {
+--- a/storage/myisam/mi_rnext.c
++++ b/storage/myisam/mi_rnext.c
+@@ -65,7 +65,7 @@ int mi_rnext(MI_INFO *info, uchar *buf,
+       Normally SQL layer would never request "search next" if
+       "search first" failed. But HANDLER may do anything.
+-      As mi_rnext() without preceeding mi_rkey()/mi_rfirst()
++      As mi_rnext() without preceding mi_rkey()/mi_rfirst()
+       equals to mi_rfirst(), we must restore original state
+       as if failing mi_rfirst() was not called.
+     */
diff --git a/mysql-wsrep-5.6/debian/po/POTFILES.in b/mysql-wsrep-5.6/debian/po/POTFILES.in
new file mode 100644 (file)
index 0000000..f9b5a05
--- /dev/null
@@ -0,0 +1 @@
+[type: gettext/rfc822deb] mysql-wsrep-server-5.6.templates
diff --git a/mysql-wsrep-5.6/debian/po/ar.po b/mysql-wsrep-5.6/debian/po/ar.po
new file mode 100644 (file)
index 0000000..4c371ff
--- /dev/null
@@ -0,0 +1,252 @@
+# translation of templates.po to Arabic
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Ossama M. Khayat <okhayat@yahoo.com>, 2007.
+msgid ""
+msgstr ""
+"Project-Id-Version: templates\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2007-05-01 13:04+0300\n"
+"Last-Translator: Ossama M. Khayat <okhayat@yahoo.com>\n"
+"Language-Team: Arabic <support@arabeyes.org>\n"
+"Language: ar\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+"Plural-Forms: nplurals=6; plural=n==1 ? 0 : n==0 ? 1 : n==2 ? 2: n%100>=3 && "
+"n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n"
+": n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n"
+": n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n"
+": n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n"
+": n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n"
+": n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n"
+": n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "هل فعلاً تريد التثبيط؟"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr "هناك ملف مسمى /var/lib/mysql/debian-*.flag موجود على هذا النظام."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+#, fuzzy
+#| msgid ""
+#| "Such file is an indication that a mysql-server package with a higher "
+#| "version has been installed earlier."
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"هذا الملف دلالة على أن نسخة أحدث من حزمة mysql-server تم تثبيتها مسبقاً."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"ليست هناك أية ضمانة أن النسخة التي تقوم بتثبيتها ستكون قادرة على استخدام "
+"قواعد البيانات الحالية."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "ملاحظة هامة لمستخدمي NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+#, fuzzy
+#| msgid ""
+#| "You should also check the permissions and the owner of the /var/lib/mysql "
+#| "directory:"
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr "عليك أيضاً أن تقوم بالتأكد من صلاحيات مالك الملف /var/lib/mysql: "
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "إزالة جميع قواعد بيانات MySQL؟"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr "الدليل /var/lib/mysql الذي يحتوي قواعد بيانات MySQL ستتم إزالته."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"إن كنت تقوم بإزالة حزمة MySQL كي تقوم لاحقاً بتثبيت نسخة أحدث أو إن كانت حزمة "
+"mysql-server مختلفة تستخدمها، فيجب إبقاء البيانات."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "تشغيل خادم MySQL عند الإقلاع؟"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"يمكن تشغيل خادم MySQL آلياً وقت الإقلاع أو يدوياً باستخدام الأمر '/etc/init.d/"
+"mysql start'."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "كلمة المرور الجديدة لمستخد \"root\" الخاص بـMySQL:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"مع أنه ليس إجبارياً، ولكن من المستحسن أن تقوم بتعيين كلمة مرور خاصة بمستخدم "
+"MySQL الإداري \"root\"."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+#, fuzzy
+#| msgid "If that field is left blank, the password will not be changed."
+msgid "If this field is left blank, the password will not be changed."
+msgstr "إن ترك الحقل فارغاً، فلن يتم تغيير كلمة المرور."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+#, fuzzy
+#| msgid "New password for the MySQL \"root\" user:"
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "كلمة المرور الجديدة لمستخد \"root\" الخاص بـMySQL:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "تعذر تعيين كلمة مرور للمستخدم \"root\" الخاص بـMySQL."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"حدث خطأ أثناء تعيين كلمة المرور لمستخدم MySQL الإداري. قد يكون هذا حدث بسبب "
+"أن حساب المستخدم له كلمة مرور معيّنة مسبقاً، أو بسبب مشكلة في الاتصال مع خادم "
+"MySQL."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "You should check the account's password after tha package installation."
+msgid "You should check the account's password after the package installation."
+msgstr "يجب عليك التحقق من كلمة مرور الحساب عقب تثبيت الحزمة."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for "
+#| "more information."
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"الرجاء قراءة الملف /usr/share/doc/mysql-server-5.6/README.Debian للمزيد من "
+"المعلومات."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+
+#~ msgid ""
+#~ "To use MySQL, the following entries for users and groups should be added "
+#~ "to the system:"
+#~ msgstr ""
+#~ "كي تستخدم MySQL، يجب إضافة المُدخلات التالية الخاصة بالمستخدمين والمجموعات "
+#~ "إلى النظام:"
+
+#~ msgid ""
+#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?"
+#~ msgstr ""
+#~ "هل تريد دعم اتصالات MySQL من الأجهزة التي تعمل على ديبيان \"sarge\" أو "
+#~ "أقدم؟"
+
+#~ msgid ""
+#~ "In old versions of MySQL clients on Debian, passwords were not stored "
+#~ "securely. This has been improved since then, however clients (such as "
+#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to "
+#~ "recent accounts or accounts whose password have been changed."
+#~ msgstr ""
+#~ "في إصدارات عملاء MySQL القديمة من ديبيان، لم تكن كلمات المرور تحفظ بشكل "
+#~ "آمن. ولقد حل هذه المشكلة بعدها، غير أن العملاء (مثل PHP) المتصلين من "
+#~ "أجهزة تعمل على ديبيان Sarge 3.1 لن يكونوا قادرين على الاتصال باستخدام "
+#~ "الحسابات الحديثة أو الحسابات التي تم تغيير كلمة مرورها."
diff --git a/mysql-wsrep-5.6/debian/po/ca.po b/mysql-wsrep-5.6/debian/po/ca.po
new file mode 100644 (file)
index 0000000..7b0721c
--- /dev/null
@@ -0,0 +1,227 @@
+# mysql-dfsg (debconf) translation to Catalan.
+# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+# Aleix Badia i Bosch <abadia@ica.es> 2004
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-dfsg-4.1\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2004-01-31 19:20GMT\n"
+"Last-Translator: Aleix Badia i Bosch <abadia@ica.es>\n"
+"Language-Team: Debian L10n Catalan <debian-l10n-catalan@lists.debian.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=ISO-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"Aquest fitxer indica que anteriorment s'ha instaŀlat un paquet mysql-server "
+"amb una versió posterior."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"No hi ha cap garantia que la versió que esteu instaŀlant actualment puga "
+"emprar les bases de dades actuals."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+#, fuzzy
+#| msgid "Important note for NIS/YP users!"
+msgid "Important note for NIS/YP users"
+msgstr "Nota important pels usuaris de NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Si empreu MySQL sota NIS/YP, heu d'afegir un compte d'usuari mysql al "
+"sistema local amb:"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"També hauríeu de comprovar els permisos i propietaris del directori /var/"
+"lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"El directori /var/lib/mysql que conté les bases de dades de MySQL està a "
+"punt deser suprimit."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Si esteu suprimint el paquet MySQL per a posteriorment instaŀlar una versió "
+"més recent, o si un paquet mysql-server diferent ja l'està emprant, les "
+"dades s'haurien de mantenir."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+#, fuzzy
+#| msgid "Should MySQL start on boot?"
+msgid "Start the MySQL server on boot?"
+msgstr "Voleu que el MySQL s'iniciï a l'arrencada ?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+#, fuzzy
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"El MySQL es pot executar automàticament a l'arrencada o manualment amb "
+"l'ordre «/etc/init.d/mysql start»."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr ""
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Tot i que no és requerida, és molt recomanable que establiu una "
+"contrasenya per a «root», l'usuari administratiu del MySQL."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr ""
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"S'ha produït un error en establir la contrasenya de l'usuari administratiu "
+"del MySQL. Això pot haver passat perquè el compte ja té una una "
+"contrasenya, o per un problema de comunicació amb el servidor de MySQL."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+"Hauríeu de comprovar la contrasenya del compte després de la instaŀlació "
+"del paquet."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for "
+#| "more information."
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Llegiu el fitxer /usr/share/doc/mysql-server-5.1/README.Debian per a obtenir "
+"més informació."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+"Les dos contrasenyes que heu introduït no són la mateixa. Proveu-ho de nou."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+
+#~ msgid ""
+#~ "MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the "
+#~ "new "
+#~ msgstr ""
+#~ "El MySQL-5.1 ja no implementa el clúster NDB. Migreu al nou paquet mysql-"
+#~ "cluster i suprimiu totes les línies que comencen per «ndb» de tots els "
+#~ "fitxers de configuració sota /etc/mysql/."
diff --git a/mysql-wsrep-5.6/debian/po/cs.po b/mysql-wsrep-5.6/debian/po/cs.po
new file mode 100644 (file)
index 0000000..a6be13b
--- /dev/null
@@ -0,0 +1,346 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-dfsg-5.6\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2007-05-01 13:01+0200\n"
+"Last-Translator: Miroslav Kure <kurem@debian.cz>\n"
+"Language-Team: Czech <debian-l10n-czech@lists.debian.org>\n"
+"Language: cs\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "Opravdu pokračovat v degradaci?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr "V systému existuje soubor /var/lib/mysql/debian-*.flag."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+#, fuzzy
+#| msgid ""
+#| "Such file is an indication that a mysql-server package with a higher "
+#| "version has been installed earlier."
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr "To znamená, že již byl nainstalován balík mysql-server s vyšší verzí."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"Neexistuje žádná záruka, že momentálně instalovaná verze bude umět pracovat "
+"se stávajícími databázemi."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Důležitá poznámka pro uživatele NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+#, fuzzy
+#| msgid ""
+#| "You should also check the permissions and the owner of the /var/lib/mysql "
+#| "directory:"
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Také byste měli zkontrolovat vlastníka a oprávnění adresáře /var/lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "Odstranit všechny MySQL databáze?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"Adresář /var/lib/mysql, ve kterém se nachází MySQL databáze, bude odstraněn."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Jestliže odstraňujete balík MySQL za účelem instalace novější verze MySQL, "
+"nebo pokud tato data souběžně využívá jiný balík mysql-server, měli byste "
+"data ponechat."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "Spustit MySQL server při startu systému?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"MySQL se může spouštět automaticky při startu systému, nebo ručně příkazem '/"
+"etc/init.d/mysql start'."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Nové heslo MySQL uživatele \"root\":"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Přestože to není nezbytné, je silně doporučeno nastavit heslo u "
+"správcovského MySQL účtu \"root\"."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+#, fuzzy
+#| msgid "If that field is left blank, the password will not be changed."
+msgid "If this field is left blank, the password will not be changed."
+msgstr "Ponecháte-li pole prázdné, heslo se nezmění."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+#, fuzzy
+#| msgid "New password for the MySQL \"root\" user:"
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Nové heslo MySQL uživatele \"root\":"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Nelze nastavit heslo MySQL uživatele \"root\""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Během nastavování hesla pro správcovského uživatele MySQL se vyskytla chyba. "
+"To se mohlo stát třeba proto, protože uživatel již měl heslo nastaveno, nebo "
+"protože nastal problém v komunikaci s MySQL serverem."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "You should check the account's password after tha package installation."
+msgid "You should check the account's password after the package installation."
+msgstr "Po instalaci balíku byste měli heslo ověřit."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for "
+#| "more information."
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Více informací naleznete v /usr/share/doc/mysql-server-5.6/README.Debian."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+
+#~ msgid ""
+#~ "To use MySQL, the following entries for users and groups should be added "
+#~ "to the system:"
+#~ msgstr ""
+#~ "Abyste mohli MySQL používat, musíte v systému založit následující "
+#~ "uživatele a skupiny:"
+
+#~ msgid "Cannot upgrade if ISAM tables are present!"
+#~ msgstr "Aktualizace nelze provést pokud jsou přítomny tabulky ISAM!"
+
+#~ msgid ""
+#~ "Recent versions of MySQL can no longer use the old ISAM table format and "
+#~ "it is necessary to convert your tables to e.g. MyISAM before upgrading by "
+#~ "using \"mysql_convert_table_format\" or \"ALTER TABLE x ENGINE=MyISAM\". "
+#~ "The installation of mysql-server-5.6 will now abort. In case your old "
+#~ "mysql-server-4.1 gets removed nevertheless just reinstall it to convert "
+#~ "those tables."
+#~ msgstr ""
+#~ "Poslední verze MySQL již nemohou používat starý formát tabulek ISAM a "
+#~ "před aktualizací je nutné převést tyto tabulky např. do formátu MyISAM "
+#~ "pomocí \"mysql_convert_table_format\" nebo \"ALTER TABLE x ENGINE=MyISAM"
+#~ "\". Instalace mysql-server-5.6 se nyní přeruší. V případě, že se mezitím "
+#~ "odinstaloval původní mysql-server-4.1, jednoduše jej znovu nainstalujte a "
+#~ "tabulky převeďte."
+
+#~ msgid ""
+#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?"
+#~ msgstr ""
+#~ "Podporovat MySQL připojení z počítačů používajících Debian Sarge nebo "
+#~ "starší?"
+
+#~ msgid ""
+#~ "In old versions of MySQL clients on Debian, passwords were not stored "
+#~ "securely. This has been improved since then, however clients (such as "
+#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to "
+#~ "recent accounts or accounts whose password have been changed."
+#~ msgstr ""
+#~ "Způsob, jakým se dříve ukládala hesla, nebyl příliš bezpečný. To se nyní "
+#~ "zlepšilo, ale nevýhodou je, že se klienti z Debianu 3.1 Sarge (např. PHP) "
+#~ "nebudou moci připojit na nové účty, nebo na účty, u nichž se heslo "
+#~ "změnilo."
+
+#~ msgid ""
+#~ "To use mysql you must install an equivalent user and group to the "
+#~ "following and ensure yourself that /var/lib/mysql has the right "
+#~ "permissions (the uid/gid may be different)."
+#~ msgstr ""
+#~ "Abyste mohli mysql používat, musíte do následujících souborů přidat "
+#~ "ekvivalentního uživatele a skupinu a zajistit, že /var/lib/mysql má "
+#~ "správná práva (uid/gid se mohou lišit)."
+
+#~ msgid "Remove the databases used by all MySQL versions?"
+#~ msgstr "Odstranit databáze používané všemi verzemi MySQL?"
+
+#~ msgid ""
+#~ "If you do not provide a password no changes will be made to the account."
+#~ msgstr "Nezadáte-li heslo, žádné změny se s účtem neprovedou."
+
+#~ msgid ""
+#~ "When installation finishes, you should verify that the account is "
+#~ "properly protected with a password (see README.Debian for more "
+#~ "information)."
+#~ msgstr ""
+#~ "Po skončení instalace byste měli ověřit, že je účet chráněn heslem (více "
+#~ "informací naleznete v souboru README.Debian)."
+
+#~ msgid "Update Hints"
+#~ msgstr "Poznámky k aktualizaci"
+
+#~ msgid ""
+#~ "You have to run \"mysql_upgrade\" after the upgrade, else tables can be  "
+#~ "corrupted! This script also enhances the privilege tables but is not  "
+#~ "supposed to give any user more rights that he had before,"
+#~ msgstr ""
+#~ "Po aktualizaci ještě musíte spustit \"mysql_upgrade\", protože jinak by "
+#~ "se tabulky mohly narušit! Tento skript také rozšiřuje tabulky privilegií, "
+#~ "ovšem neměl by uživatelům přidat více práv, než měli dosud."
+
+#~ msgid "Please also read http://www.mysql.com/doc/en/Upgrade.html"
+#~ msgstr "Také si přečtěte http://www.mysql.com/doc/en/Upgrade.html"
+
+#~ msgid ""
+#~ "MySQL will only install if you have a non-numeric hostname that is "
+#~ "resolvable via the /etc/hosts file. E.g. if the \"hostname\" command "
+#~ "returns \"myhostname\" then there must be a line like \"10.0.0.1 "
+#~ "myhostname\"."
+#~ msgstr ""
+#~ "MySQL se nainstaluje pouze v případě, že používáte nenumerické jméno "
+#~ "počítače, které se dá přeložit přes soubor /etc/hosts. Např. když příkaz "
+#~ "\"hostname\" vrátí \"diamond\", tak v /etc/hosts musí existovat obdobný "
+#~ "řádek jako \"10.0.0.1 diamond\"."
+
+#~ msgid ""
+#~ "A new mysql user \"debian-sys-maint\" will be created. This mysql account "
+#~ "is used in the start/stop and cron scripts. Don't delete."
+#~ msgstr ""
+#~ "Bude vytvořen nový mysql uživatel \"debian-sys-maint\". Tento mysql účet "
+#~ "se používá ve startovacích, ukončovacích a cronových skriptech. Nemažte "
+#~ "jej."
+
+#~ msgid ""
+#~ "Please remember to set a PASSWORD for the MySQL root user! If you use a /"
+#~ "root/.my.cnf, always write the \"user\" and the \"password\" lines in "
+#~ "there, never only the password!"
+#~ msgstr ""
+#~ "Nezapomeňte nastavit heslo pro účet administrátora MySQL! Používáte-li /"
+#~ "root/.my.cnf, vždy zde zadejte jak řádek \"user\", tak řádek \"password"
+#~ "\". Nikdy zde nezadávejte jenom heslo!"
+
+#~ msgid ""
+#~ "Should I remove the complete /var/lib/mysql directory tree which is used "
+#~ "by all MySQL versions, not necessarily only the one you are about to "
+#~ "purge?"
+#~ msgstr ""
+#~ "Mám odstranit kompletní adresářový strom /var/lib/mysql, který se používá "
+#~ "pro všechny verze MySQL, tedy ne nutně pouze pro verzi, kterou se "
+#~ "chystáte vyčistit?"
diff --git a/mysql-wsrep-5.6/debian/po/da.po b/mysql-wsrep-5.6/debian/po/da.po
new file mode 100644 (file)
index 0000000..94019aa
--- /dev/null
@@ -0,0 +1,222 @@
+# Danish translation mysql-5.1.
+# Copyright (C) 2010 mysql-5.1 & nedenstående oversættere.
+# This file is distributed under the same license as the mysql-5.1 package.
+# Claus Hindsgaul <claus_h@image.dk> 2005, 2006, 2007.
+# Joe Hansen <joedalton2@yahoo.dk>, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-5.1\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2010-10-07 05:26+0100\n"
+"Last-Translator: Joe Hansen <joedalton2@yahoo.dk>\n"
+"Language-Team: Danish <debian-l10n-danish@lists.debian.org> \n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "Ønsker du virkelig at fortsætte nedgraderingen?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr "Der er en fil med navnet /var/lib/mysql/debian-*.flag på dette system."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"Sådan en fil tyder på, at der tidligere har været installeret en højere "
+"version af mysql-server-pakken."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"Det kan ikke garanteres at den version, du er ved at installere, kan benytte "
+"data fra de eksisterende databaser."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Vigtig oplysning til NIS/YP-brugere"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Brug af MySQL under NIS/YP kræver at en mysql-brugerkonto tilføjes på det "
+"lokale system med:"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Du bør også tjekke rettighederne og ejerskabet af mappen /var/lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "Fjern alle MySQL-databaser?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"Mappen /var/lib/mysql, der indeholder MySQL-databaserne, er ved at blive "
+"fjernet."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Hvis du fjerner MySQL-pakken for senere at installere en nyere version, "
+"eller hvis en anden mysql-server-pakke allerede benytter den, bør dataene "
+"bevares."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "Start MySQL-serveren under systemopstart?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"MySQL-serveren kan enten startes op automatisk under systemopstarten, eller "
+"manuelt med kommandoen '/etc/init.d/mysql start'."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Ny adgangskode for MySQL's »rootbruger«:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Selvom det ikke kræves, anbefales det kraftigt, at du sætter en adgangskode "
+"for MySQL's administrationsbruger »root«."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr "Hvis du lader dette felt stå tomt, vil adgangskoden ikke blive ændret."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Gentag adgangskode for MySQL's »root-bruger«:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Kunne ikke sætte adgangskoden for MySQL's »root-bruger«"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Der opstod en fejl, da adgangskoden for MySQL's administrationsbruger blev "
+"forsøgt ændret. Dette kan være sket, fordi brugeren allerede har en "
+"adgangskode, eller fordi der var problemer med at kommunikere med MySQL-"
+"serveren."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr "Du bør tjekke kontoens adgangskode efter pakkeinstallationen."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for "
+#| "more information."
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Læs venligst filen /usr/share/doc/mysql-server-5.1/README.Debian for "
+"yderligere oplysninger."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr "Inddatafejl for adgangskode"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+"De to adgangskoder du indtastede var ikke de samme. Forsøg venligst igen."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr "NDB-cluster ser ud til at være i brug"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+#, fuzzy
+#| msgid ""
+#| "MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the "
+#| "new mysql-cluster package and remove all lines starting with \"ndb\" from "
+#| "all config files below /etc/mysql/."
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+"MySQL-5.1 tilbyder ikke længere NDB-clusterunderstøttelse. Migrer venligst "
+"til den nye pakke mysql-cluster og fjern alle linjer der starter med »ndb« "
+"fra alle konfigurationsfiler under /etc/mysql/."
diff --git a/mysql-wsrep-5.6/debian/po/de.po b/mysql-wsrep-5.6/debian/po/de.po
new file mode 100644 (file)
index 0000000..844f393
--- /dev/null
@@ -0,0 +1,230 @@
+# translation of mysql-dfsg-5.6_5.6.8-1_de.po to Deutsch
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans#
+#    Developers do not need to manually edit POT or PO files.
+#
+# Alwin Meschede <ameschede@gmx.de>, 2006, 2007.
+# Thomas Mueller <thomas.mueller@tmit.eu>, 2009.
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-dfsg 5.6.23-2\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2012-06-03 10:33+0200\n"
+"Last-Translator: Thomas Mueller <thomas.mueller@tmit.eu>\n"
+"Language-Team: german <debian-l10n-german@lists.debian.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+"Plural-Forms:  nplurals=2; plural=(n != 1);\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "Möchten Sie wirklich eine ältere Version einspielen?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr ""
+"Auf diesem System existiert eine Datei mit dem Namen /var/lib/mysql/debian-*."
+"flag"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"Diese Datei ist ein Hinweis darauf, dass früher ein MySQL-Server-Paket mit "
+"einer höheren Version installiert war."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"Es kann nicht garantiert werden, dass die gegenwärtig zu installierende "
+"Version dessen Daten benutzen kann."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Wichtige Anmerkung für NIS/YP-Benutzer!"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Falls MySQL mit NIS/YP genutzt wird, ist ein »mysql«-Benutzerkonto auf dem "
+"lokalen System notwendig:"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Sie sollten außerdem Besitzer und Zugriffsrechte des Verzeichnisses /var/lib/"
+"mysql überprüfen:"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "Alle MySQL-Datenbanken entfernen?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"Das Verzeichnis /var/lib/mysql mit den MySQL-Datenbanken soll entfernt "
+"werden."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Falls geplant ist, nur eine höhere Version von MySQL zu installieren oder "
+"ein anderes mysql-server-Paket dieses bereits benutzt, sollten die Daten "
+"behalten werden."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "Soll der MySQL-Server automatisch beim Booten starten?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"Der MySQL-Dienst kann entweder automatisch beim Systemstart oder manuell "
+"durch Eingabe des Befehls »/etc/init.d/mysql start« gestartet werden."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Neues Passwort für den MySQL »root«-Benutzer:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Obwohl es nicht zwingend erforderlich ist, wird nachdrücklich empfohlen für "
+"den administrativen MySQL »root«-Benutzer ein Passwort zu setzen."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr "Wenn dieses Feld freigelassen wird, wird das Passwort nicht geändert."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Wiederholen Sie das Passwort für den MySQL-»root«-Benutzer:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Konnte für den MySQL-»root«-Benutzer kein Passwort setzen"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Beim setzen des Passworts für den administrativen MySQL-Benutzer ist ein "
+"Fehler aufgetreten. Dies könnte daran liegen, dass der Benutzer bereits ein "
+"Passwort hat oder dass es ein Problem mit der Kommunikation mit dem MySQL-"
+"Server gibt."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+"Sie sollten das Passwort des administrativen Benutzers nach der "
+"Paketinstallation prüfen."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Für weitere Informationen lesen Sie /usr/share/doc/mysql-server-5.6/README."
+"Debian."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr "Passwort-Eingabefehler"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+"Die beiden von Ihnen eingegebenen Passwörter sind nicht identisch. Bitte "
+"erneut versuchen."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr "NDB-Cluster scheint gerade benutzt zu werden"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+"MySQL-5.6 bietet keine NDB-Clusterunterstützung mehr. Bitte migrieren Sie "
+"Ihr System zum neuen »mysql-cluster-server«-Paket und entfernen Sie alle "
+"Zeilen, die mit »ndb« beginnen aus allen Konfigurationsdateien im "
+"Verzeichnis /etc/mysql/."
diff --git a/mysql-wsrep-5.6/debian/po/es.po b/mysql-wsrep-5.6/debian/po/es.po
new file mode 100644 (file)
index 0000000..10f715c
--- /dev/null
@@ -0,0 +1,382 @@
+# mysql-5.6 translation to spanish
+# Copyright (C) 2005-2012 Software in the Public Interest, SPI Inc.
+# This file is distributed under the same license as the mysql-5.6 package.
+#
+# Changes:
+# - Initial translation
+#       Jesus Aneiros, 2006
+# - Updated
+#       Javier Fernandez-Sanguino, 2006-2012
+# - Revision
+#       Nacho Barrientos Arias
+#       Fernando Cerezal
+#       David Martínez Moreno
+#       Ricardo Mones
+#       Carlos Galisteo
+#       Javier Fernandez-Sanguino
+#       Fernando C. Estrada
+#
+#  Traductores, si no conoce el formato PO, merece la pena leer la 
+#  documentación de gettext, especialmente las secciones dedicadas a este
+#  formato, por ejemplo ejecutando:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+# Equipo de traducción al español, por favor lean antes de traducir
+# los siguientes documentos:
+#
+# - El proyecto de traducción de Debian al español
+#   http://www.debian.org/intl/spanish/
+#   especialmente las notas y normas de traducción en
+#   http://www.debian.org/intl/spanish/notas
+#
+# - La guía de traducción de po's de debconf:
+#   /usr/share/doc/po-debconf/README-trans
+#   o http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+# Si tiene dudas o consultas sobre esta traducción consulte con el último
+# traductor (campo Last-Translator) y ponga en copia a la lista de
+# traducción de Debian al español (<debian-l10n-spanish@lists.debian.org>)
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-5.6\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2012-06-17 09:49-0500\n"
+"Last-Translator: Javier Fernández-Sanguino <jfs@debian.org>\n"
+"Language-Team: Debian l10 Spanish <debian-l10n-spanish@lists.debian.org>\n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Virtaal 0.7.1\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "¿Desea realmente continuar con la desactualización?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr ""
+"Existe un fichero con el nombre /var/lib/mysql/debian-*.flag en este sistema."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"Este fichero indica que se instaló previamente una versión superior del "
+"paquete mysql-server."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"No se puede garantizar que la versión que está instalando pueda usar la base "
+"de datos actual."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Nota importante para los usuarios de NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Utilizar MySQL con NIS/YP requiere que una cuenta de usuario de mysql sea "
+"agregada en el sistema local como:"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"También debería comprobar los permisos y el propietario del directorio: /var/"
+"lib/mysql"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "¿Desea eliminar todas las bases de datos MySQL?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"El directorio /var/lib/mysql contiene bases de datos MySQL que van a "
+"eliminarse."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Debería mantener los datos si tiene planificado instalar una versión de "
+"MySQL más reciente o si hay un paquete «mysql-server» distinto que los está "
+"utilizando."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "¿Desea que el servidor MySQL se ejecute al iniciar el sistema?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"El servidor MySQL puede iniciarse en el momento de arranque del sistema o "
+"manualmente si escribe la orden «/etc/init.d/mysql start»."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Nueva contraseña para el usuario «root» de MySQL:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Se recomienda que configure una contraseña para el usuario "
+"«root» (administrador) de MySQL, aunque no es obligatorio."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr "No se modificará la contraseña si deja el espacio en blanco."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Nueva contraseña para el usuario «root» de MySQL:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "No se pudo fijar la contraseña para el usuario «root» de MySQL"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Se produjo un error mientras intentaba fijar la contraseña para el usuario "
+"administrador de MySQL. Esto puede haber sucedido porque la cuenta ya tenía "
+"una contraseña o porque se produjo un error de comunicación con el servidor "
+"MySQL."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+"Debería comprobar la contraseña de la cuenta después de la instalación del "
+"paquete."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Consulte /usr/share/doc/mysql-server-5.6/README.Debian para más información."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr "Se ha producido un error al introducir la contraseña"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+"Las dos contraseñas que ha introducido son distintas. Intente de nuevo."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr "NDB Cluster parece estar en uso"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+"MySQL-5.6 ya no brinda soporte para NDB Cluster. Migre al nuevo paquete "
+"mysql-cluster-server y elimine todas las líneas que empiecen con \"ndb\" de "
+"todos los ficheros de configuración bajo /etc/mysql/."
+
+#~ msgid ""
+#~ "To use MySQL, the following entries for users and groups should be added "
+#~ "to the system:"
+#~ msgstr ""
+#~ "Deben añadirse las siguientes entradas para usuarios y grupos en el "
+#~ "sistema para poder utilizar MySQL:"
+
+#~ msgid "Cannot upgrade if ISAM tables are present!"
+#~ msgstr "¡No se puede actualizar si ya hay tablas ISAM!"
+
+#~ msgid ""
+#~ "Recent versions of MySQL can no longer use the old ISAM table format and "
+#~ "it is necessary to convert your tables to e.g. MyISAM before upgrading by "
+#~ "using \"mysql_convert_table_format\" or \"ALTER TABLE x ENGINE=MyISAM\". "
+#~ "The installation of mysql-server-5.6 will now abort. In case your old "
+#~ "mysql-server-4.1 gets removed nevertheless just reinstall it to convert "
+#~ "those tables."
+#~ msgstr ""
+#~ "Las versiones recientes de MySQL ya no soportan el antiguo formato de "
+#~ "tabla ISAM. Antes de realizar la actualización es necesario convertir sus "
+#~ "tablas a por ejemplo, MyISAM, usando «mysql_convert_table_format» o "
+#~ "«ALTER TABLE x ENGINE=MyISAM». Se va a interrumpir ahora la instalación "
+#~ "de mysql-server-5.6. Si aún así su mysql-server-4.1 se elimina aún así, "
+#~ "puede reinstalarlo para convertir ese tipo de tablas."
+
+#~ msgid ""
+#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?"
+#~ msgstr ""
+#~ "¿Soportar las conexiones MySQL establecidadas desde sistemas que ejecutan "
+#~ "Debian Sarge o versiones anteriores?"
+
+#~ msgid ""
+#~ "In old versions of MySQL clients on Debian, passwords were not stored "
+#~ "securely. This has been improved since then, however clients (such as "
+#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to "
+#~ "recent accounts or accounts whose password have been changed."
+#~ msgstr ""
+#~ "No era muy segura la forma en la que se almacenaban las contraseñas en "
+#~ "versiones anteriores del cliente de MySQL en Debian. Este problema se ha "
+#~ "mejorado posteriormente con el inconveniente, sin embargo, de que "
+#~ "clientes (por ejemplo, PHP) en sistemas que ejecutan Debian 3.1 «Sarge» "
+#~ "no podrán conectarse a cuentas que son nuevas o a las que se le haya "
+#~ "cambiado la contraseña."
+
+#~ msgid ""
+#~ "To use mysql you must install an equivalent user and group to the "
+#~ "following and ensure yourself that /var/lib/mysql has the right "
+#~ "permissions (the uid/gid may be different)."
+#~ msgstr ""
+#~ "Para utilizar mysql debe instalar un usuario y grupo equivalente al "
+#~ "siguiente y asegurarse de que /var/lib/mysql tiene los permisos correctos "
+#~ "(los valores del «uid» y del «gid» pueden ser diferentes)."
+
+#~ msgid ""
+#~ "/etc/passwd:      mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false"
+#~ msgstr ""
+#~ "/etc/passwd:      mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false"
+
+#~ msgid "/etc/group:       mysql:x:101:"
+#~ msgstr "/etc/group:       mysql:x:101:"
+
+#~ msgid "/var/lib/mysql:   drwxr-xr-x   mysql    mysql"
+#~ msgstr "/var/lib/mysql:   drwxr-xr-x   mysql    mysql"
+
+#~ msgid "Remove the databases used by all MySQL versions?"
+#~ msgstr ""
+#~ "¿Eliminar las bases de datos utilizadas por todas las versiones de MySQL?"
+
+#~ msgid ""
+#~ "If you do not provide a password no changes will be made to the account."
+#~ msgstr ""
+#~ "No se hará ningún cambio en la cuenta si no introduce una contraseña."
+
+#~ msgid ""
+#~ "When installation finishes, you should verify that the account is "
+#~ "properly protected with a password (see README.Debian for more "
+#~ "information)."
+#~ msgstr ""
+#~ "Debería confirmar que la contraseña está correctamente protegida con una "
+#~ "contraseña cuando termine la instalación (consulte el fichero README."
+#~ "Debian si desea más información)."
+
+#~ msgid "Install Hints"
+#~ msgstr "Sugerencias para la instalación"
+
+#~ msgid ""
+#~ "On upgrades from MySQL 3.23, as shipped with Debian Woody, symlinks in "
+#~ "place of /var/lib/mysql or /var/log/mysql gets accidently removed and "
+#~ "have manually be restored."
+#~ msgstr ""
+#~ "Al actualizar a la versión de MySQL 3.23, la vrsión proporcionada en "
+#~ "Debian Woody, se eliminan de manera accidental, los enlaces simbólicos a "
+#~ "«/var/lib/mysql» o «/var/log/mysql» y tienen que restaurarse manualmente."
+
+#~ msgid ""
+#~ "MySQL will only install if you have a non-numeric hostname that is "
+#~ "resolvable via the /etc/hosts file. E.g. if the \"hostname\" command "
+#~ "returns \"myhostname\" then there must be a line like \"10.0.0.1 "
+#~ "myhostname\"."
+#~ msgstr ""
+#~ "Sólo se instalará MySQL si tiene un nombre de equipo que no sea una "
+#~ "dirección IP y pueda resolverse a través del fichero /etc/hosts. Por "
+#~ "ejemplo, si la orden «hostname» devuelve «MiNombreEquipo» entonces deberá "
+#~ "existir una línea «10.0.0.1 MiNombreEquipo» en dicho fichero."
+
+#~ msgid ""
+#~ "A new mysql user \"debian-sys-maint\" will be created. This mysql account "
+#~ "is used in the start/stop and cron scripts. Don't delete."
+#~ msgstr ""
+#~ "Se creará un nuevo usuario «debian-sys-maint». Esta cuenta de mysql se "
+#~ "utilizará en los scripts de inicio y parada y en los scripts «cron». No "
+#~ "la elimine."
+
+#~ msgid ""
+#~ "Please remember to set a PASSWORD for the MySQL root user! If you use a /"
+#~ "root/.my.cnf, always write the \"user\" and the \"password\" lines in "
+#~ "there, never only the password!"
+#~ msgstr ""
+#~ "¡Por favor, recuerde crear una CONTRASEÑA para el usuario «root» de "
+#~ "MySQL! ¡Si utiliza /root/.my.cnf debe escribir las líneas «user» y "
+#~ "«password» en dicho fichero, no incluya sólo la contraseña!"
+
+#~ msgid ""
+#~ "Should I remove the complete /var/lib/mysql directory tree which is used "
+#~ "by all MySQL versions, not necessarily only the one you are about to "
+#~ "purge?"
+#~ msgstr ""
+#~ "¿Debería eliminar el árbol de directorio /var/lib/mysql completo? Tenga "
+#~ "en cuenta que lo utilizan todas las versiones de MySQL y no sólo la que "
+#~ "está a punto de purgar."
diff --git a/mysql-wsrep-5.6/debian/po/eu.po b/mysql-wsrep-5.6/debian/po/eu.po
new file mode 100644 (file)
index 0000000..e9878c0
--- /dev/null
@@ -0,0 +1,236 @@
+# translation of eu.po to Euskara
+# Piarres BEobide <pi@beobide.net>, 2006.
+# Piarres Beobide <pi@beobide.net>, 2009.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+msgid ""
+msgstr ""
+"Project-Id-Version: eu\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2009-07-29 11:59+0200\n"
+"Last-Translator: Piarres Beobide <pi@beobide.net>\n"
+"Language-Team: Euskara <debian-l10n-eu@lists.debian.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "Benetan bertsio zaharragora itzuli nahi duzu?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr "Sisteman badago /var/lib/mysql/debian-*.flag izeneko fitxategi bat."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+#, fuzzy
+#| msgid ""
+#| "Such file is an indication that a mysql-server package with a higher "
+#| "version has been installed earlier."
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"Fitxategi honek aurretik bertsio berriagoko mysql-zerbitzari pakete bat "
+"instalatu dela adierazten du."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"Ezin da ziurtatu instalatzen ari zaren bertsio honek dauden datubaseak "
+"erabili ahal izango dituenik."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "NIS/YP erabiltzaileentzat ohar garrantzitsua"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+#, fuzzy
+#| msgid ""
+#| "You should also check the permissions and the owner of the /var/lib/mysql "
+#| "directory:"
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Honetaz gain /var/lib/mysql direktorioaren jabea eta baimenak egiaztatu "
+"beharko zenituzke:"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "Ezabatu MySQL datubase guztiak?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr "MySQL datubaseak dituen /var/lib/mysql direktorioa ezabatua izango da."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"MySQL paketea beranduago bertsio berriago bat instalatzeko kentzen ari "
+"bazara, edo beste mysql-server pakete bat berau erabiltzen ari bada, datuak "
+"mantendu egin beharko lirateke."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "Abioan MySQL zerbitzaria abiarazi?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"Sistema abioan MySQL automatikoki abiarazi daiteke edo eskuz '/etc/init.d/"
+"mysql start' eginaz."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "MySQL \"root\" erabiltzailearen pasahitz berria:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Derrigorrezkoa ez denean, oso gomendagarria da MySQL administratzaile \"root"
+"\" erabiltzaileari pasahitz bat ezartzea."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+#, fuzzy
+#| msgid "If that field is left blank, the password will not be changed."
+msgid "If this field is left blank, the password will not be changed."
+msgstr "Eremua hau zurian utziaz gero ez da pasahitza aldatuko."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Errepikatu MySQL \"root\" erabiltzailearen pasahitza:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Ezin da MySQL \"root\" erabiltzailearen pasahitza ezarri"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Errore bat gertatu da MySQL administratzaile kontuaren pasahitza ezartzean.  "
+"Hau erabiltzaileak dagoeneko pasahitz bat duelako edo MySQL "
+"zerbitzariarekiko konexioan erroreak daudelako gertatu daiteke."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+"Kontuaren pasahitza egiaztatu beharko zenuke paketea instalatu aurretik."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for "
+#| "more information."
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Mesedez irakurri /usr/share/doc/mysql-server-5.6/README.Debian fitxategia "
+"xehetasun gehiagorako."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr "Pasahitz sarrera errorea"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr "Idatzi dituzun bi pasahitzak ez dira berdina. Mesedez saiatu berriz."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr "Dirudienez NDB Cluster-a erabilia dago"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+#, fuzzy
+#| msgid ""
+#| "MySQL-5.6 has orphaned NDB Cluster support. Please migrate to the new "
+#| "mysql-cluster package and remove all lines starting with \"ndb\" from all "
+#| "config files below /etc/mysql/."
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+"MySQL-5.6-ek NDB cluster euskarri umezurtz bat behar du. Mesedez migratu "
+"mysql-cluster pakete berrira eta /etc/mysql/ azpiko konfigurazio fitxategi "
+"guztietan \"ndb\"-ez hasten diren lerro guztiak ezabatu."
+
+#~ msgid ""
+#~ "To use MySQL, the following entries for users and groups should be added "
+#~ "to the system:"
+#~ msgstr ""
+#~ "MySQL erabili ahal izateko, hurrengo erabiltzaile eta taldeak gehitu "
+#~ "behar dira sisteman:"
diff --git a/mysql-wsrep-5.6/debian/po/fr.po b/mysql-wsrep-5.6/debian/po/fr.po
new file mode 100644 (file)
index 0000000..9ced0c0
--- /dev/null
@@ -0,0 +1,242 @@
+# Translation of mysql-dfsg-* debconf templates to French
+# Copyright (C) 2004-2009 Debian French l10n team <debian-l10n-french@lists.debian.org>
+# This file is distributed under the same license as the mysql-dfsg-* packages.
+#
+# Translators:
+# Christian Perrier <bubulle@debian.org>, 2004, 2006, 2007, 2009, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: fr\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2012-05-22 08:30+0200\n"
+"Last-Translator: Christian Perrier <bubulle@debian.org>\n"
+"Language-Team: French <debian-l10n-french@lists.debian.org>\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"debian.org>\n"
+"X-Generator: Lokalize 1.2\n"
+"Plural-Forms: Plural-Forms: nplurals=2; plural=n>1;\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "Faut-il vraiment revenir à la version précédente ?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr "Un fichier /var/lib/mysql/debian-*.flag est présent sur ce système."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"Cela indique qu'une version plus récente du paquet mysql-server a été "
+"précédemment installée."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr "Il n'est pas garanti que cette version puisse en utiliser les données."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Note importante pour les utilisateurs NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"L'utilisation de MySQL avec NIS/YP impose l'ajout d'un compte local "
+"« mysql » avec la commande :"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Vous devez également vérifier le propriétaire et les permissions du "
+"répertoire /var/lib/mysql :"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "Faut-il supprimer toutes les bases de données MySQL ?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"Le répertoire /var/lib/mysql qui contient les bases de données de MySQL va "
+"être supprimé."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Si vous prévoyez d'installer une version plus récente de MySQL ou si un "
+"autre paquet mysql-server les utilise déjà, vous devriez les conserver."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "Faut-il lancer MySQL au démarrage ?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"MySQL peut être lancé soit au démarrage, soit en entrant la commande « /etc/"
+"init.d/mysql start »."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Nouveau mot de passe du superutilisateur de MySQL :"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Il est très fortement recommandé d'établir un mot de passe pour le compte "
+"d'administration de MySQL (« root »)."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr "Si ce champ est laissé vide, le mot de passe ne sera pas changé."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Confirmation du mot de passe du superutilisateur de MySQL :"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr ""
+"Impossible de changer le mot de passe de l'utilisateur « root » de MySQL"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Une erreur s'est produite lors du changement de mot de passe du compte "
+"d'administration. Un mot de passe existait peut-être déjà ou il n'a pas été "
+"possible de communiquer avec le serveur MySQL."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+"Vous devriez vérifier le mot de passe de ce compte après l'installation du "
+"paquet."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Veuillez consulter le fichier /usr/share/doc/mysql-server-5.6/README.Debian "
+"pour plus d'informations."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr "Erreur de saisie du mot de passe"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+"Le mot de passe et sa confirmation ne sont pas identiques. Veuillez "
+"recommencer."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr "Abandon de la gestion de NDB"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+"La version 5.6 de MySQL ne gère plus les grappes NDB. Vous devriez utiliser "
+"le paquet mysql-cluster-server et supprimer toutes les lignes commençant par "
+"« ndb » des fichiers de configuration situés dans /etc/mysql."
+
+#~ msgid ""
+#~ "To use MySQL, the following entries for users and groups should be added "
+#~ "to the system:"
+#~ msgstr ""
+#~ "Pour pouvoir utiliser MySQL, les utilisateurs et les groupes suivants "
+#~ "doivent être ajoutés au système :"
+
+#~ msgid ""
+#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?"
+#~ msgstr ""
+#~ "Gérer les connexions d'hôtes qui utilisent les versions Debian « sarge » "
+#~ "ou antérieures  ?"
+
+#~ msgid ""
+#~ "In old versions of MySQL clients on Debian, passwords were not stored "
+#~ "securely. This has been improved since then, however clients (such as "
+#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to "
+#~ "recent accounts or accounts whose password have been changed."
+#~ msgstr ""
+#~ "La méthode de stockage des mots de passe n'était pas très sûre dans les "
+#~ "version précédentes de ce paquet. Cette méthode a été améliorée mais les "
+#~ "modifications empêchent la connexion avec de nouveaux comptes ou des "
+#~ "comptes dont le mot de passe a été modifié, pour les clients (p. ex. PHP) "
+#~ "depuis des hôtes qui utilisent Debian 3.1 « sarge »."
diff --git a/mysql-wsrep-5.6/debian/po/gl.po b/mysql-wsrep-5.6/debian/po/gl.po
new file mode 100644 (file)
index 0000000..6bb1407
--- /dev/null
@@ -0,0 +1,249 @@
+# Galician translation of mysql-dfsg-5.6's debconf templates
+# This file is distributed under the same license as the mysql-dfsg-5.6 package.
+# Jacobo Tarrio <jtarrio@debian.org>, 2007.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-dfsg-5.6\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2007-04-20 09:44+0200\n"
+"Last-Translator: Jacobo Tarrio <jtarrio@debian.org>\n"
+"Language-Team: Galician <proxecto@trasno.net>\n"
+"Language: gl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "¿Quere pasar a unha versión anterior?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr "Neste sistema hai un ficheiro chamado /var/lib/mysql/debian-*.flag."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+#, fuzzy
+#| msgid ""
+#| "Such file is an indication that a mysql-server package with a higher "
+#| "version has been installed earlier."
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"Este ficheiro indica que antes se instalou un paquete mysql-server cunha "
+"versión superior."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"Non se pode garantir que a versión que está a instalar poida empregar as "
+"bases de datos actuais."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Nota importante para os usuarios de NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+#, fuzzy
+#| msgid ""
+#| "You should also check the permissions and the owner of the /var/lib/mysql "
+#| "directory:"
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Tamén debería comprobar os permisos e o propietario do directorio /var/lib/"
+"mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "¿Eliminar tódalas bases de datos de MySQL?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"Hase eliminar o directorio /var/lib/mysql, que contén as bases de datos de "
+"MySQL."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Se está a eliminar o paquete MySQL para instalar despois unha versión máis "
+"recente ou se xa hai un paquete mysql-server diferente a empregalo, debería "
+"conservar os datos."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "¿Iniciar o servidor MySQL co ordenador?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"Pódese iniciar automaticamente o servidor MySQL ao iniciar o ordenador, ou "
+"manualmente coa orde \"/etc/init.d/mysql start\"."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Novo contrasinal para o usuario \"root\" de MySQL:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Aínda que non é obrigatorio, recoméndase encarecidamente que estableza un "
+"contrasinal para o usuario administrativo \"root\" de MySQL."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+#, fuzzy
+#| msgid "If that field is left blank, the password will not be changed."
+msgid "If this field is left blank, the password will not be changed."
+msgstr "Se deixa o campo en branco, non se ha cambiar o contrasinal."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+#, fuzzy
+#| msgid "New password for the MySQL \"root\" user:"
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Novo contrasinal para o usuario \"root\" de MySQL:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Non se puido establecer o contrasinal do usuario \"root\" de MySQL"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Houbo un erro ao establecer o contrasinal do usuario administrativo de "
+"MySQL. Puido ocorrer porque o usuario xa teña un contrasinal ou debido a un "
+"problema de comunicacións co servidor MySQL."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "You should check the account's password after tha package installation."
+msgid "You should check the account's password after the package installation."
+msgstr "Debería comprobar o contrasinal da conta trala instalación do paquete."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for "
+#| "more information."
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Consulte o ficheiro /usr/share/doc/mysql-server-5.6/README.Debian para máis "
+"información."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+
+#~ msgid ""
+#~ "To use MySQL, the following entries for users and groups should be added "
+#~ "to the system:"
+#~ msgstr ""
+#~ "Para empregar MySQL deberían engadirse ao sistema as seguintes entradas "
+#~ "de usuarios e grupos:"
+
+#~ msgid ""
+#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?"
+#~ msgstr ""
+#~ "¿Soportar as conexións a MySQL de máquinas que empreguen Debian \"sarge\" "
+#~ "ou anterior?"
+
+#~ msgid ""
+#~ "In old versions of MySQL clients on Debian, passwords were not stored "
+#~ "securely. This has been improved since then, however clients (such as "
+#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to "
+#~ "recent accounts or accounts whose password have been changed."
+#~ msgstr ""
+#~ "Nas versións antigas dos clientes MySQL de Debian, os contrasinais non se "
+#~ "armacenaban de xeito seguro. Isto mellorouse desde aquela; nembargantes, "
+#~ "os clientes (tales coma PHP) das máquinas que executen Debian 3.1 Sarge "
+#~ "non se han poder conectar a contas recentes ou a contas nas que se "
+#~ "cambiara o contrasinal."
diff --git a/mysql-wsrep-5.6/debian/po/it.po b/mysql-wsrep-5.6/debian/po/it.po
new file mode 100644 (file)
index 0000000..b0567e5
--- /dev/null
@@ -0,0 +1,223 @@
+# Italian (it) translation of debconf templates for mysql-dfsg-5.6\r
+# Copyright (C) 2009 Software in the Public Interest\r
+# This file is distributed under the same license as the mysql-dfsg-5.6 package.\r
+# Luca Monducci <luca.mo@tiscali.it>, 2006 - 2009.\r
+# \r
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-dfsg-5.6 5.6.8 italian debconf templates\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2009-08-08 11:03+0200\n"
+"Last-Translator: Luca Monducci <luca.mo@tiscali.it>\n"
+"Language-Team: Italian <debian-l10n-italian@lists.debian.org>\n"
+"Language: it\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "Procedere realmente con l'abbassamento di versione?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr ""
+"Su questo sistema esiste un file con nome /var/lib/mysql/debian-*.flag."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"Quel file indica che in precedenza è stata installata una versione superiore "
+"del pacchetto mysql-server."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"Non è garantito che la versione che si sta installando sia in grado di usare "
+"i database presenti."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Nota importante per gli utenti NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Per usare MySQL con NIS/YP è necessario aggiungere al sistema locale un "
+"account utente per mysql con:"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Inoltre si devono verificare i permessi e la proprietà della directory /var/"
+"lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "Eliminare tutti i database MySQL?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"La directory /var/lib/mysql contenente i database di MySQL sta per essere "
+"eliminata."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Se si rimuove il pacchetto MySQL per poi installare una versione più recente "
+"oppure se sono già in uso da un altro pacchetto mysql-server, i dati non "
+"devono essere eliminati."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "Lanciare il server MySQL all'avvio?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"Il server MySQL può essere lanciato automaticamente all'avvio del sistema "
+"oppure manualmente con il comando «/etc/init.d/mysql start»."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Nuova password per l'utente «root» di MySQL:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Sebbene non sia obbligatoria, si raccomanda d'impostare una password per "
+"l'utente d'amministrazione «root» di MySQL."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr "Se questo campo è lasciato vuoto, la password non viene cambiata."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Ripetere la password per l'utente «root» di MySQL:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Impossibile impostare la password per l'utente «root» di MySQL"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Si è verificato un errore durante l'impostazione della password per l'utente "
+"d'amministrazione di MySQL. Questo può essere accaduto perché l'utente ha "
+"già una password oppure a causa di un problema di connessione con il server "
+"MySQL."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+"Al termine dell'installazione si deve verificare la password dell'account."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for "
+#| "more information."
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Per maggiori informazioni si consulti il file /usr/share/doc/mysql-"
+"server-5.6/README.Debian."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr "Errore di inserimento della password"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr "Le due password inserite sono diverse. Riprovare."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr "È in uso un cluster NDB"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+#, fuzzy
+#| msgid ""
+#| "MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the "
+#| "new mysql-cluster package and remove all lines starting with \"ndb\" from "
+#| "all config files below /etc/mysql/."
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+"MySQL-5.6 non fornisce più il supporto per i cluster NDB. Si dovrebbe "
+"migrare al nuovo pacchetto mysql-cluster e rimuovere tutte le righe che "
+"iniziano per \"ndb\" da tutti i file di configurazione sotto /etc/mysql/."
diff --git a/mysql-wsrep-5.6/debian/po/ja.po b/mysql-wsrep-5.6/debian/po/ja.po
new file mode 100644 (file)
index 0000000..796d5e3
--- /dev/null
@@ -0,0 +1,229 @@
+#
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'
+#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans
+#
+#    Developers do not need to manually edit POT or PO files.
+#
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-dfsg-5.6 5.6.8-1\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2009-09-01 08:25+0900\n"
+"Last-Translator: Hideki Yamane (Debian-JP) <henrich@debian.or.jp>\n"
+"Language-Team: Japanese <debian-japanese@lists.debian.org>\n"
+"Language: ja\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "本当にダウングレードを実行しますか?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr ""
+"このシステムには  /var/lib/mysql/debian-*.flag という名前のファイルが存在して"
+"います。"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"このファイルが意味するのは、以前により新しいバージョンの mysql-server パッ"
+"ケージがインストールされていたことを示します。"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"このデータベースを現在インストールしようとしているバージョンで使えるかどうか"
+"は保証できません。"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "NIS/YP ユーザへの重要な注意"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"NIS/YP 配下で MySQL を使うにはローカルのシステムに mysql のユーザアカウントを"
+"追加するのが必要です。"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr "/var/lib/mysql の所有者権限をチェックする必要もあります。"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "すべての MySQL データベースを削除しますか?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"MySQL データベースを含んでいるディレクトリ /var/lib/mysql を削除しようとして"
+"います。"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"後でより新しいバージョンのものをインストールしようとするために MySQL パッケー"
+"ジを削除しようとしている、あるいは別の mysql-server パッケージを既に使ってい"
+"る場合、データは保持する必要があります。"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "MySQL をシステム起動時に開始しますか?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"MySQL の起動方法について、システム起動時に自動的に開始するか、あるいは '/etc/"
+"init.d/mysql start' と手で入力して起動するかを選べます。"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "MySQL の \"root\" ユーザに対する新しいパスワード:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"強制ではありませんが、MySQL を管理する \"root\" ユーザのパスワードを設定する"
+"ことを強くお勧めします。"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr "この値を空のままにしておいた場合は、パスワードは変更されません。"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "MySQL の \"root\" ユーザに対する新しいパスワード:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "MySQL の \"root\" ユーザのパスワードを設定できません"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"MySQL の管理者ユーザに対してパスワードを設定しようとした際、エラーが発生しま"
+"した。これは既に管理者ユーザにパスワードが設定されていたか、MySQL サーバとの"
+"接続に問題があったためだと思われます。"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+"パッケージのインストール後、アカウントのパスワードを確認する必要があります。"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for "
+#| "more information."
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"詳細は /usr/share/doc/mysql-server-5.6/README.Debian を参照してください。"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr "パスワード入力エラー"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr "入力された二つのパスワードが一致しません。再入力してください。"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr "NDB クラスタが利用されているようです"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+#, fuzzy
+#| msgid ""
+#| "MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the "
+#| "new mysql-cluster package and remove all lines starting with \"ndb\" from "
+#| "all config files below /etc/mysql/."
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+"MySQL-5.6 では NDB クラスタのサポートを提供しなくなっています。新たな mysql-"
+"cluster パッケージに移行して、/etc/mysql 以下の設定ファイルすべてから「ndb」"
+"で始まる行を削除してください。"
diff --git a/mysql-wsrep-5.6/debian/po/nb.po b/mysql-wsrep-5.6/debian/po/nb.po
new file mode 100644 (file)
index 0000000..d3c9d0e
--- /dev/null
@@ -0,0 +1,297 @@
+# translation of mysql_nb.po to Norwegian Bokmål
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Bjørn Steensrud <bjornst@powertech.no>, 2007.
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql_nb\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2007-02-18 12:13+0100\n"
+"Last-Translator: Bjørn Steensrud <bjornst@powertech.no>\n"
+"Language-Team: Norwegian Bokmål <i18n-nb@lister.ping.uio.no>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.2\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+#, fuzzy
+#| msgid "Do you really want to downgrade?"
+msgid "Really proceed with downgrade?"
+msgstr "Er du sikker på at du vil nedgradere?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+#, fuzzy
+#| msgid ""
+#| "WARNING: The file /var/lib/mysql/debian-*.flag exists. This indicates "
+#| "that a mysql-server package with a higher version has been installed "
+#| "before. It can not be guaranteed that this version can use its data."
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"ADVARSEL: Fila /var/lib/mysql/debian-*.flag finnes. Dette viser at en mysql-"
+"server-pakke med et høyere versjonsnummer har vært installert før. Det kan "
+"ikke garanteres at denne versjonen kan bruke data fra den høyere versjonen."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+#, fuzzy
+#| msgid "Important note for NIS/YP users!"
+msgid "Important note for NIS/YP users"
+msgstr "Viktig merknad for NIS/YP-brukere!"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+#, fuzzy
+#| msgid ""
+#| "The script is about to remove the data directory /var/lib/mysql. If it is "
+#| "planned to just install a higher MySQL version or if a different mysql-"
+#| "server package is already using it, the data should be kept."
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Dette skriptet skal til å fjerne data-mappa /var/lib/mysql. Denne mappa bør "
+"beholdes hvis det bare skal installeres en høyere MySQL-versjon, eller hvis "
+"en annen mysql-server-pakke allerede bruker den."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+#, fuzzy
+#| msgid "Should MySQL start on boot?"
+msgid "Start the MySQL server on boot?"
+msgstr "Skal MySQL startes ved maskinoppstart?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+#, fuzzy
+#| msgid ""
+#| "The MySQL can start automatically on boot time or only if you manually "
+#| "type '/etc/init.d/mysql start'."
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"MySQL kan startes automatisk når maskinen starter, eller bare hvis du "
+"skriver «/etc/init.d/mysql start»."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+#, fuzzy
+#| msgid "New password for MySQL \"root\" user:"
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Nytt passord for MySQLs «root»-bruker:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+#, fuzzy
+#| msgid ""
+#| "It is highly recommended that you set a password for the MySQL "
+#| "administrative \"root\" user."
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Det anbefales sterkt at du oppgir et passord for den administrative «root»-"
+"brukeren i MySQl."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr ""
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+#, fuzzy
+#| msgid "New password for MySQL \"root\" user:"
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Nytt passord for MySQLs «root»-bruker:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid "Unable to set password for MySQL \"root\" user"
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Klarer ikke angi passord for MySQLs «root»-bruker"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "It seems an error occurred while setting the password for the MySQL "
+#| "administrative user.  This may have happened because the user already has "
+#| "a password, or because there was a problem communicating with the MySQL "
+#| "server."
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Det ser ut til at det oppsto en feil mens det ble satt et passord for MySQLs "
+"administrative bruker. Dette kan være fordi brukeren allerede har et "
+"passord, eller fordi det var et kommunikasjonsproblem med MySQL-tjeneren."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+
+#~ msgid ""
+#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?"
+#~ msgstr ""
+#~ "Skal MySQL-tilkoblinger støttes fra vertsmaskiner som kjører Debian "
+#~ "«sarge» eller eldre?"
+
+#, fuzzy
+#~| msgid ""
+#~| "The way passwords were stored was not very secure. This has been "
+#~| "improved with the drawback that clients (e.g. PHP) from hosts running "
+#~| "Debian 3.1 Sarge will not be able to connect to account which are new or "
+#~| "whose password have been changed. See /usr/share/doc/mysql-server-5.6/"
+#~| "README.Debian."
+#~ msgid ""
+#~ "In old versions of MySQL clients on Debian, passwords were not stored "
+#~ "securely. This has been improved since then, however clients (such as "
+#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to "
+#~ "recent accounts or accounts whose password have been changed."
+#~ msgstr ""
+#~ "Passord ble tidligere lagret på en lite sikker måte. Dette er nå "
+#~ "forbedret, med den ulempen at klienter (f.eks. PHP) fra verter som kjører "
+#~ "Debian 3.1 Sarge ikke vil kunne koble til en konto som er ny eller har "
+#~ "fått endret passordet. Se /usr/share/doc/mysql-server-5.6/README.Debian."
+
+#~ msgid ""
+#~ "To use mysql you must install an equivalent user and group to the "
+#~ "following and ensure yourself that /var/lib/mysql has the right "
+#~ "permissions (the uid/gid may be different)."
+#~ msgstr ""
+#~ "For å bruke MySQL må du installere en bruker og gruppe tilsvarende den "
+#~ "nedenfor og se til at /var/lib/mysql har riktige rettigheter (uid/gid kan "
+#~ "være forskjellig)."
+
+#~ msgid ""
+#~ "/etc/passwd:      mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false"
+#~ msgstr ""
+#~ "/etc/passwd:      mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false"
+
+#~ msgid "/etc/group:       mysql:x:101:"
+#~ msgstr "/etc/group:       mysql:x:101:"
+
+#~ msgid "/var/lib/mysql:   drwxr-xr-x   mysql    mysql"
+#~ msgstr "/var/lib/mysql:   drwxr-xr-x   mysql    mysql"
+
+#~ msgid "Remove the databases used by all MySQL versions?"
+#~ msgstr "Skal databasene brukt av alle MySQL-versjoner fjernes?"
+
+#~ msgid ""
+#~ "If you do not provide a password no changes will be made to the account."
+#~ msgstr ""
+#~ "Hvis du ikke oppgir et passord blir det ikke gjort noen endringer med "
+#~ "kontoen."
+
+#~ msgid ""
+#~ "When installation finishes, you should verify that the account is "
+#~ "properly protected with a password (see README.Debian for more "
+#~ "information)."
+#~ msgstr ""
+#~ "Når installasjonen er ferdig bør det sjekkes at kontoen er ordentlig "
+#~ "beskyttet med et passord (mer informasjon finnes i README.Debian)."
diff --git a/mysql-wsrep-5.6/debian/po/nl.po b/mysql-wsrep-5.6/debian/po/nl.po
new file mode 100644 (file)
index 0000000..8ddab3c
--- /dev/null
@@ -0,0 +1,219 @@
+# Dutch mysql-dfsg-5.6 po-debconf translation,
+# Copyright (C) 2006 THE PACKAGE'S COPYRIGHT HOLDER
+#
+# Vincent Zweije <zweije@xs4all.nl>, 2006.
+# Eric Spreen <erispre@gmail.com, 2010.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-5.6 5.6.6-1\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2012-05-23 10:26+0200\n"
+"Last-Translator: Jeroen Schot <schot@a-eskwadraat.nl>\n"
+"Language-Team: Debian l10n Dutch <debian-l10n-dutch@lists.debian.org>\n"
+"Language: nl\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "Wilt u echt een oude versie herstellen?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr ""
+"Er bestaat een bestand genaamd /var/lib/mysql/debian-*.flag op dit systeem."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"Zulk een bestand geeft aan dat er eerder een pakket mysql-server met een "
+"hogere versie is geïnstalleerd."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"Er is geen garantie dat de versie die u op dit moment installeert de huidige "
+"databases kan gebruiken."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Belangrijke opmerking voor gebruikers van NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Het gebruik van MySQL onder NIS/YP vereist dat een MySQL gebruikersaccount "
+"wordt toegevoegd aan het lokale systeem met:"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"U dient ook de permissies en eigenaren van de map /var/lib/mysql te "
+"controleren:"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "Wilt u alle MySQL-databases verwijderen?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"De map /var/lib/mysql die de MySQL-databases bevat staat op het punt om "
+"verwijderd te worden."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Als u het MySQL-pakket verwijdert om later een meer recente versie te "
+"installeren of als een ander mysql-server pakket het al gebruikt, zou de "
+"data behouden moeten worden."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "Moet MySQL starten als de computer start?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"De MySQL-server kan automatisch worden gestart bij het starten van de "
+"computer of slechts wanneer u '/etc/init.d/mysql start' handmatig uitvoert."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Nieuw wachtwoord voor de MySQL \"root\"-gebruiker:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Hoewel niet verplicht, wordt het sterk aangeraden een wachtwoord in te "
+"stellen voor de administratieve MySQL \"root\"-gebruiker."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr ""
+"Als dit veld leeg wordt gelaten, zal het wachtwoord niet worden veranderd."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Herhaal het wachtwoord voor de MySQL \"root\"-gebruiker:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Kan het wachtwoord voor de MySQL \"root\"-gebruiker niet instellen"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Er is een fout opgetreden bij het instellen van het wachtwoord voor de MySQL "
+"administratieve gebruiker. Dat kan komen doordat de gebruiker al een "
+"wachtwoord heeft, of omdat er een probleem was bij het communiceren met de "
+"MySQL-server."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+"U zou het wachtwoord van het account moeten controleren nadat het pakket is "
+"geïnstalleerd."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Leest u het bestand /usr/share/doc/mysql-server-5.6/README.Debian voor meer "
+"informatie."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr "Fout bij invoer wachtwoord"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+"De twee wachtwoorden die u hebt ingevoerd zijn niet gelijk. Probeert u het "
+"opnieuw."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr "De NDB-cluster lijkt in gebruik te zijn"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+"MySQL-5.6 biedt niet langer ondersteuning voor NDB Cluster. Migreer naar het "
+"nieuwe pakket mysql-cluster en verwijder alle regels die beginnen met \"ndb"
+"\" van alle configuratiebestanden onder /etc/mysql/."
diff --git a/mysql-wsrep-5.6/debian/po/pt.po b/mysql-wsrep-5.6/debian/po/pt.po
new file mode 100644 (file)
index 0000000..f142e86
--- /dev/null
@@ -0,0 +1,296 @@
+# Portuguese translation for mysql-dfsg-5.6's debconf messages
+# Copyright (C) 2006 Miguel Figueiredo <elmig@debianpt.org>
+# This file is distributed under the same license as the mysql-dfsg-5.6 package.
+# Miguel Figueiredo <elmig@debianpt.org>, 2012
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-dfsg-5.6\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2012-05-28 22:40+0100\n"
+"Last-Translator: Miguel Figueiredo <elmig@debianpt.org>\n"
+"Language-Team: Portuguese <traduz@debianpt.org>\n"
+"Language: pt\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "Deseja mesmo fazer downgrade?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr ""
+"Existe, neste sistema, um ficheiro chamado /var/lib/mysql/debian-*.flag."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"A existência de tal ficheiro é um indicador que anteriormente foi instalado "
+"um pacote mysql-server com um número de versão superior."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"Não existe nenhuma garantia que a versão que está actualmente a instalar "
+"seja capaz de utilizar as bases de dados actuais."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Nota importante para utilizadores de NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Utilizar MySQL com NIS/YP necessita que seja adicionada uma conta de "
+"utilizador de mysql ao sistema local com:"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Deve também verificar as permissões e o dono do directório /var/lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "Remover todas as bases de dados MySQL?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"O directório /var/lib/mysql que contém as bases de dados MySQL está prestes "
+"a ser removido."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Se está a remover o pacote MySQL de modo a posteriormente instalar uma "
+"versão mais recente ou se um pacote mysql-server já está os está a utilizar, "
+"os dados devem ser mantidos."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "Iniciar o servidor MySQL no arranque?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"O MySQL pode ser automaticamente lançado no arranque ou manualmente através "
+"do comando '/etc/init.d/mysql start'."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Nova palavra-passe para o utilizador \"root\" do MySQL:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Embora não seja obrigatório, é fortemente recomendado que defina uma palavra-"
+"passe para o utilizador administrativo \"root\" do MySQL."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr ""
+"Se este campo for deixado em branco, a palavra-passe não irá ser alterada."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Repita a palavra-passe para o utilizador \"root\" de MySQL:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr ""
+"Não foi possível definir a palavra-passe para o utilizador \"root\" do MySQL"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Ocorreu um erro enquanto era definida a palavra-passe para o utilizador "
+"administrativo do MySQL. Isto pode ter acontecido porque a conta já tem uma "
+"palavra-passe, ou porque ocorreu um problema ao comunicação com o servidor "
+"MySQL."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+"Você deve verificar a palavra-passe da conta após a instalação do pacote."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Para mais informações, por favor leia o ficheiro /usr/share/doc/mysql-"
+"server-5.6/README.Debian."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr "Erro de entrada da palavra-passe"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+"As duas palavras-passe que introduziu não são as mesmas. Por favor tente "
+"novamente."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr "NDB Cluster parece estar a ser utilizado"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+"MySQL-5.6 já não disponibiliza suporte para NDB Cluster. Por favor migre "
+"para o novo pacote mysql-cluster-server e remova todas as linhas que comecem "
+"por \"ndb\" em todos os ficheiros de configuração em /etc/mysql/."
+
+#~ msgid ""
+#~ "To use MySQL, the following entries for users and groups should be added "
+#~ "to the system:"
+#~ msgstr ""
+#~ "Para utilizar o MySQL, têm de ser acrescentadas as seguintes entradas "
+#~ "para os utilizadores e grupos:"
+
+#~ msgid "Cannot upgrade if ISAM tables are present!"
+#~ msgstr "Não é possível actualizar se estiverem presentes tabelas ISAM!"
+
+#~ msgid ""
+#~ "Recent versions of MySQL can no longer use the old ISAM table format and "
+#~ "it is necessary to convert your tables to e.g. MyISAM before upgrading by "
+#~ "using \"mysql_convert_table_format\" or \"ALTER TABLE x ENGINE=MyISAM\". "
+#~ "The installation of mysql-server-5.6 will now abort. In case your old "
+#~ "mysql-server-4.1 gets removed nevertheless just reinstall it to convert "
+#~ "those tables."
+#~ msgstr ""
+#~ "As versões recentes de MySQL já não podem utilizar o antigo formato de "
+#~ "tabelas ISAM e é por isso necessário converter as suas tabelas pra e.g. "
+#~ "MyISAM antes da actualização, utilizando \"mysql_convert_table_format\" "
+#~ "ou \"ALTER TABLE x ENGINE=MyISAM\". A instalação de mysql-server-5.6 irá "
+#~ "agora ser cancelada. Se o seu antigo mysql-server-4.1 for removido apenas "
+#~ "reinstale para converter essas tabelas."
+
+#~ msgid ""
+#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?"
+#~ msgstr ""
+#~ "Suportar ligações MySQL de máquinas que corram Debian \"sarge\" ou mais "
+#~ "antigos?"
+
+#~ msgid ""
+#~ "In old versions of MySQL clients on Debian, passwords were not stored "
+#~ "securely. This has been improved since then, however clients (such as "
+#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to "
+#~ "recent accounts or accounts whose password have been changed."
+#~ msgstr ""
+#~ "Nas versões antigas de clientes de MySQL em Debian, as palavras-passe não "
+#~ "eram guardadas de forma segura. Isto foi melhorado desde aí, no entanto "
+#~ "os clientes (como o PHP) de máquinas que corram Debian 3.1 Sarge não irão "
+#~ "conseguir ligar-se a contas novas ou cuja palavra-passe foi alterada."
+
+#~ msgid ""
+#~ "To use mysql you must install an equivalent user and group to the "
+#~ "following and ensure yourself that /var/lib/mysql has the right "
+#~ "permissions (the uid/gid may be different)."
+#~ msgstr ""
+#~ "Para utilizar mysql e instalar um utilizador e grupo equivalentes para o "
+#~ "seguinte e assegurar-se que /var/lib/mysql têm as permissões correctas (o "
+#~ "uid/gid podem ser diferentes)."
+
+#~ msgid ""
+#~ "/etc/passwd:      mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false"
+#~ msgstr ""
+#~ "/etc/passwd:      mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false"
+
+#~ msgid "/etc/group:       mysql:x:101:"
+#~ msgstr "/etc/group:       mysql:x:101:"
+
+#~ msgid "/var/lib/mysql:   drwxr-xr-x   mysql    mysql"
+#~ msgstr "/var/lib/mysql:   drwxr-xr-x   mysql    mysql"
+
+#~ msgid "Remove the databases used by all MySQL versions?"
+#~ msgstr "Remover as bases de dados utilizadas por todas as versões de MySQL?"
+
+#~ msgid ""
+#~ "If you do not provide a password no changes will be made to the account."
+#~ msgstr ""
+#~ "Se não disponibilizar uma password não serão feitas alterações nesta "
+#~ "conta."
+
+#~ msgid ""
+#~ "When installation finishes, you should verify that the account is "
+#~ "properly protected with a password (see README.Debian for more "
+#~ "information)."
+#~ msgstr ""
+#~ "Quando terminar a instalação, deve verificar se a conta está devidamente "
+#~ "protegida com uma password (para mais informações veja README.Debian)."
diff --git a/mysql-wsrep-5.6/debian/po/pt_BR.po b/mysql-wsrep-5.6/debian/po/pt_BR.po
new file mode 100644 (file)
index 0000000..e5fa5ee
--- /dev/null
@@ -0,0 +1,443 @@
+# Brazilian Portuguese (pt_BR) debconf template translation for
+# Debian's mysql-dfsg source package.
+# Debian-BR Project <debian-l10n-portuguese@lists.debian.org>
+# André Luís Lopes, <andrelop@debian.org> , 2004
+# André Luís Lopes, <andrelop@debian.org> , 2006
+# André Luís Lopes, <andrelop@debian.org> , 2007
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-dfsg-5.6\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2007-04-21 15:59-0300\n"
+"Last-Translator: André Luís Lopes <andrelop@debian.org>\n"
+"Language-Team: Debian-BR Project <debian-l10n-portuguese@lists.debian.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"pt_BR utf-8\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "Realmente proceder com o rebaixamento de versão?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr "Um arquivo de nome /var/lib/mysql/debian-*.flag existe no sistema."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+#, fuzzy
+#| msgid ""
+#| "Such file is an indication that a mysql-server package with a higher "
+#| "version has been installed earlier."
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"A presença de um arquivo como este é uma indicação de que um pacote mysql-"
+"server com um número de versão mais alto já foi instalado anteriormente."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"Não há garantias de que a versão que você está instalando no momento "
+"conseguirá utilizar as bases de dados existentes."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Aviso importante para usuários NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+#, fuzzy
+#| msgid ""
+#| "You should also check the permissions and the owner of the /var/lib/mysql "
+#| "directory:"
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Você deverá também checar as permissões e o dono do diretório /var/lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "Remover todas as bases de dados do MySQL?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"O diretório /var/lib/mysql, o qual contém as bases de dados do MySQL, está "
+"prestes a ser removido."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Caso você esteja removendo o pacote MySQL para posteriormente instalar uma "
+"versão mais recente ou, caso uma versão diferente do pacote mysql-server "
+"esteja sendo utilizada, os dados deverão ser mantidos."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "Iniciar o servidor MySQL junto a inicialização da máquina?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"O servidor MySQL pode ser iniciado automaticamente junto a inicialização da "
+"máquina ou manualmente com o comando '/etc/init.d/mysql start'."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Nova senha para o usuário \"root\" do MySQL:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Apesar de não ser mandatório, é altamente recomendado que você defina uma "
+"senha para o usuário administrativo \"root\" do MySQL."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+#, fuzzy
+#| msgid "If that field is left blank, the password will not be changed."
+msgid "If this field is left blank, the password will not be changed."
+msgstr "Caso este campo seja deixado em branco, a senha não sera mudada."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+#, fuzzy
+#| msgid "New password for the MySQL \"root\" user:"
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Nova senha para o usuário \"root\" do MySQL:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Impossível definir senha para o usuário \"root\" do MySQL"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Um erro ocorreu durante a definição da senha para o usuário administrativo "
+"do MySQL. Isso pode ter acontecido devido a esse usuário já possuir uma "
+"senha definida ou devido a ocorrência de um problema de comunicação com o "
+"servidor MySQL."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "You should check the account's password after tha package installation."
+msgid "You should check the account's password after the package installation."
+msgstr "Você deverá checar a senha dessa conta após a instalação deste pacote."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for "
+#| "more information."
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Por favor, leia o arquivo /usr/share/doc/mysql-server-5.6/README.Debian para "
+"maiores informações."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+
+#~ msgid ""
+#~ "To use MySQL, the following entries for users and groups should be added "
+#~ "to the system:"
+#~ msgstr ""
+#~ "Para utilizar o MySQL, as seguintes entradas para usuários e grupos devem "
+#~ "ser adicionadas ao sistema:"
+
+#~ msgid ""
+#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?"
+#~ msgstr ""
+#~ "Suportar conexões MySQL originadas de hosts executando o Debian \"sarge\" "
+#~ "ou mais antigos ?"
+
+#~ msgid ""
+#~ "In old versions of MySQL clients on Debian, passwords were not stored "
+#~ "securely. This has been improved since then, however clients (such as "
+#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to "
+#~ "recent accounts or accounts whose password have been changed."
+#~ msgstr ""
+#~ "Em versões antigas dos clientes MySQL no Debian, as senhas não eram "
+#~ "armazenadas de forma segura. Isto foi corrigido desde então, porém, "
+#~ "clientes (como o PHP) em hosts executando o Debian 3.1 Sarge não serão "
+#~ "capazes de conectar em contas recentes ou contas as quais as senhas "
+#~ "tenham sido modificadas."
+
+#~ msgid ""
+#~ "To use mysql you must install an equivalent user and group to the "
+#~ "following and ensure yourself that /var/lib/mysql has the right "
+#~ "permissions (the uid/gid may be different)."
+#~ msgstr ""
+#~ "Para utilizar o MySQL, você deve instalar um usuário e um grupo "
+#~ "equivalentes ao usuário e grupo a seguir para se certificar de que o "
+#~ "diretório /var/lib/mysql possua as permissões correctas (o uid/gid podem "
+#~ "ser diferentes)."
+
+#~ msgid ""
+#~ "/etc/passwd:      mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false"
+#~ msgstr ""
+#~ "/etc/passwd:      mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false"
+
+#~ msgid "/etc/group:       mysql:x:101:"
+#~ msgstr "/etc/group:       mysql:x:101:"
+
+#~ msgid "/var/lib/mysql:   drwxr-xr-x   mysql    mysql"
+#~ msgstr "/var/lib/mysql:   drwxr-xr-x   mysql    mysql"
+
+#~ msgid "Remove the databases used by all MySQL versions?"
+#~ msgstr "Remover as bases de dados utilizadas por todas as versões do MySQL?"
+
+#~ msgid ""
+#~ "If you do not provide a password no changes will be made to the account."
+#~ msgstr ""
+#~ "Caso você não forneça uma senha, nenhuma mudança será feita na conta."
+
+#~ msgid ""
+#~ "When installation finishes, you should verify that the account is "
+#~ "properly protected with a password (see README.Debian for more "
+#~ "information)."
+#~ msgstr ""
+#~ "Quando a instalação finalizar, você deverá verificar se a conta está "
+#~ "apropriadamente protegida com uma senha (consulte o arquivo README.Debian "
+#~ "para maiores informações)."
+
+#~ msgid "internal"
+#~ msgstr "interno"
+
+#~ msgid "Only internally used."
+#~ msgstr "Somente utilizado internamente."
+
+#, fuzzy
+#~ msgid "Update Hints"
+#~ msgstr "Dicas de atualização"
+
+#, fuzzy
+#~ msgid ""
+#~ "Rarely, e.g. on new major versions, the privilege system is improved. To "
+#~ "make use of it mysql_fix_privilege_tables must be executed manually. The "
+#~ "script is not supposed to give any user more rights that he had before,"
+#~ msgstr ""
+#~ "Raramente, por exemplo, em novas versões maiores, o sistema de "
+#~ "privilégios é melhorado. Para fazer uso disso, o script "
+#~ "mysql_fix_privilege_tables deve ser executado manualmente. O script não "
+#~ "atribuirá a nenhum usuário mais direitos do que os mesmos já possuíam "
+#~ "anteriormente."
+
+#~ msgid "Please also read http://www.mysql.com/doc/en/Upgrade.html"
+#~ msgstr "Por favor, leia http://www.mysql.com/doc/en/Upgrade.html"
+
+#, fuzzy
+#~ msgid "Install Hints"
+#~ msgstr "Dicas de instalação"
+
+#, fuzzy
+#~ msgid ""
+#~ "MySQL will only install if you have a non-numeric hostname that is "
+#~ "resolvable via the /etc/hosts file. E.g. if the \"hostname\" command "
+#~ "returns \"myhostname\" then there must be a line like \"10.0.0.1 "
+#~ "myhostname\"."
+#~ msgstr ""
+#~ "O MySQL será instalado somente caso você possua um nome de host NÃO "
+#~ "NUMÉRICO que possa ser resolvido através do arquivo /etc/hosts, ou seja, "
+#~ "caso o comando \"hostname\" retorne \"myhostname\", uma linha como "
+#~ "\"10.0.0.1 myhostname\" deverá existir no arquivo /etc/hosts."
+
+#~ msgid ""
+#~ "A new mysql user \"debian-sys-maint\" will be created. This mysql account "
+#~ "is used in the start/stop and cron scripts. Don't delete."
+#~ msgstr ""
+#~ "Um novo usuário MySQL de nome \"debian-sys-maint\" será criado. Essa "
+#~ "conta MySQL é utilizada pelos scripts de inicialização/parada e pelos "
+#~ "scripts cron. Não remova esse usuário."
+
+#, fuzzy
+#~ msgid ""
+#~ "Please remember to set a PASSWORD for the MySQL root user! If you use a /"
+#~ "root/.my.cnf, always write the \"user\" and the \"password\" lines in "
+#~ "there, never only the password!"
+#~ msgstr ""
+#~ "Por favor, lembre-se de definir uma SENHA para o usuário root do MySQL ! "
+#~ "Caso você utilize um arquivo /root/.my.cnf, sempre inclua as linhas \"user"
+#~ "\" e \"password\" nesse arquivo, nunca somente a senha ! Consulte o "
+#~ "arquivo /usr/share/doc/mysql-server/README.Debian para mais informações."
+
+#~ msgid ""
+#~ "Should I remove all databases below /var/lib/mysql as you are purging the "
+#~ "mysql-server package?"
+#~ msgstr ""
+#~ "Todas as base de dados sob o diretório /var/lib/mysql devem ser removidas "
+#~ "quando você remover o pacote pacote mysql-server ?"
+
+#~ msgid ""
+#~ "Networking is disabled by default for security reasons. You can enable it "
+#~ "by commenting out the skip-networking option in /etc/mysql/my.cnf."
+#~ msgstr ""
+#~ "O suporte ao funcionamento em rede está desativado por padrão por "
+#~ "questões de segurança. Você poderá ativá-lo comentando a opção 'skip-"
+#~ "networking' no arquivo /etc/mysql/my.cnf."
+
+#~ msgid "security and update notice"
+#~ msgstr "aviso de segurança e actualização"
+
+#~ msgid ""
+#~ "Should I remove everything below /var/lib/mysql when you purge the mysql-"
+#~ "server package with the \"dpkg --purge mysql-server\" command (i.e. "
+#~ "remove everything including the configuration) somewhen? (default is not)"
+#~ msgstr ""
+#~ "Devo remover tudo abaixo de /var/lib/mysql quando fizer o purge do pacote "
+#~ "mysql-server com o comando \"dpkg --purge mysql-server\" (ou seja, "
+#~ "remover tudo incluíndo a configuração)? (o padrão é não remover)"
+
+#~ msgid "Make MySQL reachable via network?"
+#~ msgstr "Fazer com que o MySQL seja acessível via rede?"
+
+#~ msgid ""
+#~ "Should MySQL listen on a network reachable TCP port? This is not "
+#~ "necessary for use on a single computer and could be a security problem."
+#~ msgstr ""
+#~ "O MySQL deve aguardar ligações numa porta TCP acessível via rede? Isto "
+#~ "não é necessário para uso num único computador e pode ser um problema de "
+#~ "segurança."
+
+#~ msgid "Enable chroot mode?"
+#~ msgstr "Activar o modo chroot?"
+
+#~ msgid ""
+#~ "MySQL is able to jail itself into the /var/lib/mysql_jail directory so "
+#~ "that users cannot modify any files outside this directory. This improves "
+#~ "resistence against crackers, too, as they are not able to modify system "
+#~ "files."
+#~ msgstr ""
+#~ "O MySQL é capaz de se prender no diretório /var/lib/mysql_jail, assim os "
+#~ "utilizadores não poderão modificar ficheiros fora deste directório. Isto "
+#~ "aumenta também a resistência contra crackers, pois eles não poderão "
+#~ "modificar arquivos de sistema."
+
+#~ msgid "Please run mysql_fix_privilege_tables !"
+#~ msgstr "Por favor execute mysql_fix_privilege_tables !"
+
+#~ msgid ""
+#~ "I will ensure secure permissions of /var/lib/mysql by replacing GIDs "
+#~ "other than root and mysql with mysql."
+#~ msgstr ""
+#~ "Permissões seguras para o diretório /var/lib/mysql serão asseguradas "
+#~ "substituíndo GIDs diferentes de root e mysql por mysql."
+
+#~ msgid ""
+#~ "Instructions how to enable SSL support are in /usr/share/doc/mysql-server/"
+#~ msgstr ""
+#~ "Instruções sobre como activar o suporte de SSL estão disponíveis no "
+#~ "directório /usr/share/doc/mysql-server/."
+
+#, fuzzy
+#~ msgid "mysql_fix_privileges_tables should be executed"
+#~ msgstr "mysql_fix_privileges_tables será executado"
+
+#, fuzzy
+#~ msgid ""
+#~ "The latest MySQL versions have an enhanced, more fine grained, privilege "
+#~ "system. To make use of it, some new fields must be added to the tables "
+#~ "in  the \"mysql\" database. This will not happen automatically."
+#~ msgstr ""
+#~ "As últimas versões do MySQL possuem um sistema de privilégios melhorado e "
+#~ "mais refinado. Para utilizá-lo, alguns novos campos devem ser adicionados "
+#~ "as tabelas na base de dados \"mysql\". Isto é feito pelo script "
+#~ "mysql_fix_privileges_tables durante esta actualização independente do "
+#~ "servidor estar a correr ou não !"
+
+#~ msgid ""
+#~ "This script is not supposed to give any user more rights that he had "
+#~ "before, if you encounter such a case, please contact me."
+#~ msgstr ""
+#~ "Este script não deverá fornecer mais direitos a um utilizador além dos "
+#~ "quais ele já possua anteriormente. SE encontrar um caso desses, por favor "
+#~ "entre em contacto com o mantainer deste pacote Debian."
diff --git a/mysql-wsrep-5.6/debian/po/ro.po b/mysql-wsrep-5.6/debian/po/ro.po
new file mode 100644 (file)
index 0000000..0e48225
--- /dev/null
@@ -0,0 +1,319 @@
+# Romanian translation of mysql-dfsg.
+# Copyright (C) 2006 THE mysql-dfsg'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the mysql-dfsg package.
+#
+# Stan Ioan-Eugen <stan.ieugen@gmail.com>, 2006.
+msgid ""
+msgstr ""
+"Project-Id-Version: po-debconf://mysql-dfsg\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2006-12-20 21:27+0200\n"
+"Last-Translator: stan ioan-eugen <stan.ieugen@gmail.com>\n"
+"Language-Team: romanian <debian-l10n-romanian@lists.debian.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: KBabel 1.11.4\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+#, fuzzy
+#| msgid "Do you really want to downgrade?"
+msgid "Really proceed with downgrade?"
+msgstr "Sunteţi sigur că doriţi să instalaţi o versiune mai veche?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+#, fuzzy
+#| msgid ""
+#| "WARNING: The file /var/lib/mysql/debian-*.flag exists. This indicates "
+#| "that a mysql-server package with a higher version has been installed "
+#| "before. It can not be guaranteed that this version can use its data."
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"AVERTISMENT: Fişierul /var/lib/mysql/debian-*.flag există. Acest lucru "
+"indică faptul că anterior a fost instalată o versiune nouă a pachetului "
+"mysql-server. Nu se poate garanta că versiunea instalată acum poate folosi "
+"datele versiunii instalate anterior."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+#, fuzzy
+#| msgid "Important note for NIS/YP users!"
+msgid "Important note for NIS/YP users"
+msgstr "Notă importantă pentru utilizatorii NIS/YP!"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+#, fuzzy
+#| msgid ""
+#| "The script is about to remove the data directory /var/lib/mysql. If it is "
+#| "planned to just install a higher MySQL version or if a different mysql-"
+#| "server package is already using it, the data should be kept."
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Scriptul urmează să şteargă directorul de date /var/lib/mysql. Dacă plănuiţi "
+"doar să instalaţi o versiune nouă MySQL sau datele sunt folosite de către un "
+"alt pachet mysql-server, atunci ar trebui păstraţi datele."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+#, fuzzy
+#| msgid "Should MySQL start on boot?"
+msgid "Start the MySQL server on boot?"
+msgstr "Doriţi ca MySQL să pornească la initializarea sistemului?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+#, fuzzy
+#| msgid ""
+#| "The MySQL can start automatically on boot time or only if you manually "
+#| "type '/etc/init.d/mysql start'."
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"MySQL poate porni automat la iniţializarea sistemului sau doar dacă rulaţi "
+"comanda „/etc/init.d/mysql start”."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+#, fuzzy
+#| msgid "New password for MySQL \"root\" user:"
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Noua parolă pentru utilizatorul „root” al MySQL:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+#, fuzzy
+#| msgid ""
+#| "It is highly recommended that you set a password for the MySQL "
+#| "administrative \"root\" user."
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Este recomandat să stabiliţi o parolă pentru utilizatorul administrativ "
+"„root” al MySQL."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr ""
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+#, fuzzy
+#| msgid "New password for MySQL \"root\" user:"
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Noua parolă pentru utilizatorul „root” al MySQL:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid "Unable to set password for MySQL \"root\" user"
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Nu s-a putut stabili parola pentru utilizatorul „root” al MySQL"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "It seems an error occurred while setting the password for the MySQL "
+#| "administrative user.  This may have happened because the user already has "
+#| "a password, or because there was a problem communicating with the MySQL "
+#| "server."
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Se pare că a intervenit o eroare în stabilirea parolei pentru utilizatorul "
+"administrativ al MySQL. Acest lucru se poate întâmpla dacă utilizatorul are "
+"deja o parolă, sau a existat o problemă în comunicarea cu serverul MySQL."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+
+#~ msgid "Cannot upgrade if ISAM tables are present!"
+#~ msgstr "Nu se poate face actualizarea dacă sunt prezente tabele ISAM!"
+
+#~ msgid ""
+#~ "Recent versions of MySQL can no longer use the old ISAM table format and "
+#~ "it is necessary to convert your tables to e.g. MyISAM before upgrading by "
+#~ "using \"mysql_convert_table_format\" or \"ALTER TABLE x ENGINE=MyISAM\". "
+#~ "The installation of mysql-server-5.6 will now abort. In case your old "
+#~ "mysql-server-4.1 gets removed nevertheless just reinstall it to convert "
+#~ "those tables."
+#~ msgstr ""
+#~ "Versiunile recente MySQL nu mai pot folosi vechiul format de tabele ISAM "
+#~ "şieste necesar să convertiţi tabelele dumneavoastră de ex. la formatul "
+#~ "MyISAM înainte de a face actualizarea folosind comanda "
+#~ "„mysql_convert_table_format” sau „ALTER TABLE x ENGINE=MyISAM”. "
+#~ "Instalarea mysql-server-5.6 va eşua. În caz că ştergeţiversiunea "
+#~ "anterioară mysql-server-4.1 va trebui reinstalată pentru a converti "
+#~ "tabelele."
+
+#~ msgid ""
+#~ "Support MySQL connections from hosts running Debian \"sarge\" or older?"
+#~ msgstr ""
+#~ "Suportaţi conexiuni MySQL de la staţii ce rulează sistemul Debian „sarge” "
+#~ "sau mai vechi?"
+
+#, fuzzy
+#~| msgid ""
+#~| "The way passwords were stored was not very secure. This has been "
+#~| "improved with the drawback that clients (e.g. PHP) from hosts running "
+#~| "Debian 3.1 Sarge will not be able to connect to account which are new or "
+#~| "whose password have been changed. See /usr/share/doc/mysql-server-5.6/"
+#~| "README.Debian."
+#~ msgid ""
+#~ "In old versions of MySQL clients on Debian, passwords were not stored "
+#~ "securely. This has been improved since then, however clients (such as "
+#~ "PHP) from hosts running Debian 3.1 Sarge will not be able to connect to "
+#~ "recent accounts or accounts whose password have been changed."
+#~ msgstr ""
+#~ "Modul în care erau păstrate parolele nu era foarte sigur. Acest lucru a "
+#~ "fost îmbunătăţitcu dezajantajul că clienţii (de ex. PHP) de pe staţii ce "
+#~ "rulează sistemul Debian 3.1 Sargenu se vor putea conecta la conturi noi "
+#~ "sau ale căror parole au fost schimbate. Citiţi /usr/share/doc/mysql-"
+#~ "server-5.6/README.Debian."
+
+#~ msgid ""
+#~ "To use mysql you must install an equivalent user and group to the "
+#~ "following and ensure yourself that /var/lib/mysql has the right "
+#~ "permissions (the uid/gid may be different)."
+#~ msgstr ""
+#~ "Pentru a folosi mysql trebuie să adăugaţi un utilizator şi grup "
+#~ "echivalent şi să vă asiguraţi că /var/lib/mysql are permisiunile "
+#~ "stabilite corect (uid/gid pot aveavalori diferite)."
+
+#~ msgid ""
+#~ "/etc/passwd:      mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false"
+#~ msgstr ""
+#~ "/etc/passwd:\tmysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false"
+
+#~ msgid "/etc/group:       mysql:x:101:"
+#~ msgstr "/etc/group:\tmysql:x:101:"
+
+#~ msgid "/var/lib/mysql:   drwxr-xr-x   mysql    mysql"
+#~ msgstr "/var/lib/mysql:\tdrwxr-xr-x\tmysql\tmysql"
+
+#~ msgid "Remove the databases used by all MySQL versions?"
+#~ msgstr "Doriţi să ştergeţi bazele de date folosite de toate versiune MySQL?"
+
+#~ msgid ""
+#~ "If you do not provide a password no changes will be made to the account."
+#~ msgstr ""
+#~ "Dacă nu introduceţi nici o parolă, nici o schimbare nu va fi luată în "
+#~ "considerare."
+
+#~ msgid ""
+#~ "When installation finishes, you should verify that the account is "
+#~ "properly protected with a password (see README.Debian for more "
+#~ "information)."
+#~ msgstr ""
+#~ "După finalizarea instalării, ar trebui să verificaţi dacă contul este "
+#~ "protejat cu o parolă (citiţi fişierul README.Debian pentru informaţii "
+#~ "suplimentare)."
diff --git a/mysql-wsrep-5.6/debian/po/ru.po b/mysql-wsrep-5.6/debian/po/ru.po
new file mode 100644 (file)
index 0000000..59fbe33
--- /dev/null
@@ -0,0 +1,220 @@
+# translation of ru.po to Russian
+# Russian messages:
+#    Translators, if you are not familiar with the PO format, gettext
+#    documentation is worth reading, especially sections dedicated to
+#    this format, e.g. by running:
+#         info -n '(gettext)PO Files'
+#         info -n '(gettext)Header Entry'#
+#    Some information specific to po-debconf are available at
+#            /usr/share/doc/po-debconf/README-trans
+#         or http://www.debian.org/intl/l10n/po-debconf/README-trans#
+#    Developers do not need to manually edit POT or PO files.
+#
+# Ilgiz Kalmetev <translator@ilgiz.pp.ru>, 2003.
+# Yuriy Talakan' <yt@amur.elektra.ru>, 2005, 2006.
+# Yuriy Talakan' <yt@drsk.ru>, 2007.
+# Yuri Kozlov <yuray@komyakino.ru>, 2009, 2012.
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-dfsg-5.6 5.6.8-1\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2012-05-23 21:14+0400\n"
+"Last-Translator: Yuri Kozlov <yuray@komyakino.ru>\n"
+"Language-Team: Russian <debian-l10n-russian@lists.debian.org>\n"
+"Language: ru\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Lokalize 1.2\n"
+"Plural-Forms:  nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
+"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "Действительно установить более старую версию?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr "В системе найден файл /var/lib/mysql/debian-*.flag."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"Это означает, что ранее уже был установлен пакет mysql-server более новой "
+"версии."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"Нет гарантий, что версия, которая устанавливается сейчас, будет способна "
+"работать с имеющимися базами данных."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Важное замечание для пользователей NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Использование MySQL в NIS/YP требует добавления учётной записи mysql в "
+"локальную систему с:"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr "Также проверьте права доступа и владельца каталога /var/lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "Удалить все базы данных MySQL?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"Запрос на удаление каталога /var/lib/mysql, содержащий базы данных MySQL."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Если вы удаляете пакет MySQL для установки более новой версии MySQL, или "
+"есть другие пакеты mysql-server, использующие этот каталог, то данные лучше "
+"сохранить."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "Запускать MySQL при загрузке системы?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"Сервер MySQL можно запускать автоматически при загрузке системы или вручную "
+"по команде '/etc/init.d/mysql start'."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Новый пароль для MySQL пользователя «root»:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Хотя и необязательно, но настоятельно рекомендуется установить пароль для "
+"административного пользователя MySQL «root»."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr "Если оставить поле пустым, то пароль изменён не будет."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Повторите ввод пароля для MySQL пользователя «root»:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Невозможно задать пароль MySQL пользователю «root»"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"В процессе задания пароля административного MySQL пользователя произошла "
+"ошибка. Это могло произойти, если у пользователя уже был задан пароль, или "
+"из-за проблем соединения с сервером MySQL."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr "Проверьте пароль учётной записи после установки пакета."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr "Подробности см. в файле /usr/share/doc/mysql-server-5.6/README.Debian."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr "Ошибка ввода пароля"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr "Два введённых пароля не одинаковы. Повторите ввод."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr "NDB Cluster уже используется"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+"MySQL-5.6 больше не поддерживает NDB Cluster. Переходите на новый пакет "
+"mysql-cluster-server и удалите все строки, начинающиеся с «ndb», из всех "
+"файлов настройки в каталоге /etc/mysql/."
diff --git a/mysql-wsrep-5.6/debian/po/sk.po b/mysql-wsrep-5.6/debian/po/sk.po
new file mode 100644 (file)
index 0000000..630a9a1
--- /dev/null
@@ -0,0 +1,219 @@
+# Slovak translations for mysql-5.1 package
+# Slovenské preklady pre balík mysql-5.1.
+# Copyright (C) 2011 THE mysql-5.1'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the mysql-5.1 package.
+# Slavko <linux@slavino.sk>, 2011.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-5.1 5.1.49-3\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2011-01-04 12:55+0100\n"
+"Last-Translator: Slavko <linux@slavino.sk>\n"
+"Language-Team: Slovak <nomail>\n"
+"Language: sk\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "Naozaj pokračovať v znížení verzie?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr "Súbor s menom /var/lib/mysql/debian-*.flag už v systéme existuje."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"Takýto súbor udáva, že už bol predtým nainštalovaný balík mysql-server s "
+"vyššou verziou."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"Neexistuje žiadna záruka, že aktuálne inštalovaná verzia dokáže pracovať s "
+"existujúcimi databázami."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Dôležitá poznámka pre používateľov NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Používanie MySQL pod NIS/YP vyžaduje aby bol používateľský účet mysql "
+"pridaný do lokálneho systému pomocou:"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Mali by ste tiež skontrolovať vlastníctvo a práva k adresáru /var/lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "Odstrániť všetky databázy MySQL?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"Adresár /var/lib/mysql, ktorý obsahuje databázy MySQL, bude odstránený."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Ak odstraňujete balík MySQL kvôli neskoršej inštalácii najnovšej verzie "
+"alebo ak ich používa aj iný balík mysql-server, mali by ste údaje ponechať."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "Spúšťať MySQL server pri štarte systému?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"MySQL server môže byť automaticky spúšťaný pri štarte systému alebo manuálne "
+"príkazom „/etc/init.d/mysql start”."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Nové heslo MySQL používateľa „root”:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Hoci to nie je vyslovene nutné, je silne odporúčané nastaviť heslo "
+"správcovského MySQL účtu \"root\"."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr "Ak toto pole ponecháte prázdne, heslo nebude zmenené."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Zopakujte heslo MySQL používateľa „root“:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Nemožno nastaviť heslo MySQL používateľa „root“"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Pri nastavovaní hesla správcu MySQL nastala chyba. Toto môže nastať, ak už "
+"účet má nastavené heslo alebo kvôli problémom pri komunikácii s MySQL "
+"serverom."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr "Po inštalácii balíka by ste mali skontrolovať heslo účtu."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+#, fuzzy
+#| msgid ""
+#| "Please read the /usr/share/doc/mysql-server-5.1/README.Debian file for "
+#| "more information."
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Ďalšie podrobností nájdete v súbore /usr/share/doc/mysql-server-5.1/README."
+"Debian."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr "Chyba pri zadávaní hesla"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr "Heslá, ktoré ste zadali sa nezhodujú. Skúste prosím znova."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr "Vyzerá to, že používate NDB Cluster"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+#, fuzzy
+#| msgid ""
+#| "MySQL-5.1 no longer provides NDB Cluster support. Please migrate to the "
+#| "new mysql-cluster package and remove all lines starting with \"ndb\" from "
+#| "all config files below /etc/mysql/."
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+"MySQL-5.1 už nepodporuje NDB Cluster. Použite prosím nový balík mysql-"
+"cluster a zo všetkých konfiguračných súborov v /etc/mysql/ odstráňte všetky "
+"riadky, ktoré začínajú na „ndb”."
diff --git a/mysql-wsrep-5.6/debian/po/sv.po b/mysql-wsrep-5.6/debian/po/sv.po
new file mode 100644 (file)
index 0000000..ebbb497
--- /dev/null
@@ -0,0 +1,220 @@
+# Translation of mysql-5.6 debconf template to Swedish\r
+# Copyright (C) 2009, 2012 Martin Bagge <brother@bsnet.se>\r
+# This file is distributed under the same license as the mysql-5.6 package.\r
+# \r
+# Andreas Henriksson <andreas@fatal.se>, 2007\r
+# Martin Bagge <brother@bsnet.se>, 2009, 2012\r
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-dfsg-5.6 5.0.21-3\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2012-05-30 00:29+0100\n"
+"Last-Translator: Martin Bagge / brother <brother@bsnet.se>\n"
+"Language-Team: Swedish <debian-l10n-swedish@lists.debian.org>\n"
+"Language: sv\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Poedit-Language: Swedish\n"
+"X-Poedit-Country: Sweden\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr "Vill du verkligen genomföra nedgraderingen?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr "En fil med namnet /var/lib/mysql/debian-*.flag hittades i systemet."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+"En sådan fil är en indikation på att paketet mysql-server med ett högre "
+"versionsnummer har installerats tidigare."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+"Det finns ingen garanti för att den version som du håller på att installera "
+"kommer att kunna använda de aktuella databaserna."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Viktig information för NIS/YP-användare"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"För att kunna använda MySQL under NIS/YP måste ett användarkonto för MySQL "
+"läggas till i systemet."
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Du bör också kontrollera rättigheterna och ägaren av katalogen /var/lib/"
+"mysql."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr "Ta bort alla MySQL-databaser?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+"Katalogen /var/lib/mysql som innehåller MySQL-databaser kommer att tas bort."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Om avinstallationen av MySQL-paketet görs för att senare kunna installera en "
+"nyare version eller om en annan MySQL-server redan använder filerna ska de "
+"inte raderas."
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr "Ska MySQL startas vid systemets uppstart?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"MySQL-servern kan startas vid systemets uppstart eller manuellt med "
+"kommandot \"/etc/init.d/mysql start\"."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr "Nytt lösenord för MySQLs \"root\"-användare:"
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+"Det är inte obligatoriskt men starkt rekommenderat att du sätter ett "
+"lösenord för MySQLs administrativa \"root\"-användare."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr "Om detta fält lämnas tom kommer lösenordet inte att ändras."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr "Repetera lösenordet för MySQLs \"root\"-användare:"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr "Kunde inte sätta lösenord för MySQLs \"root\"-användare"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+"Ett fel uppstod när det skulle sättas ett lösenord för MySQLs administrativa "
+"användare (\"root\"). Detta kan ha skett för att användaren redan har ett "
+"lösenord satt, eller på grund av problem med att kommunicera med MySQL-"
+"servern."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr "Du bör kontrollera kontots lösenord efter installationen av paketet."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+"Läs filen /usr/share/doc/mysql-server-5.6/README.Debian för mer information."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr "Fel vid inmatning av lösenord"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr "De två lösenorden du angav stämde inte överrens. Prova igen."
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr "NDB-kluster används inte"
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+"Stödet för NDB-kluster har tagits bort i MySQL-5.6. Migrera till det nya "
+"paketet mysql-cluster-server  och ta bort alla rader som inleds med \"ndb\" "
+"från alla inställlningsfiler i /etc/mysql/."
+
+#~ msgid ""
+#~ "To use MySQL, the following entries for users and groups should be added "
+#~ "to the system:"
+#~ msgstr ""
+#~ "För att använda MySQL måste följande användare och grupper läggas till i "
+#~ "systemet:"
diff --git a/mysql-wsrep-5.6/debian/po/templates.pot b/mysql-wsrep-5.6/debian/po/templates.pot
new file mode 100644 (file)
index 0000000..f9b2dca
--- /dev/null
@@ -0,0 +1,187 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-wsrep-5.6\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid "Start the MySQL server on boot?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr ""
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr ""
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
diff --git a/mysql-wsrep-5.6/debian/po/tr.po b/mysql-wsrep-5.6/debian/po/tr.po
new file mode 100644 (file)
index 0000000..f721a65
--- /dev/null
@@ -0,0 +1,342 @@
+# Turkish translation of mysql-server.
+# This file is distributed under the same license as the mysql-server package.
+# Gürkan Aslan <gurkan@iaslan.com>, 2004
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mysql-dfsg-4.1\n"
+"Report-Msgid-Bugs-To: mysql-wsrep-5.6@packages.debian.org\n"
+"POT-Creation-Date: 2014-11-23 01:05+0200\n"
+"PO-Revision-Date: 2004-06-05 08:53+0300\n"
+"Last-Translator: Gürkan Aslan <gurkan@iaslan.com>\n"
+"Language-Team: Turkish <debian-l10n-turkish@lists.debian.org>\n"
+"Language: tr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms:  nplurals=1; plural=0;\n"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "Really proceed with downgrade?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid "A file named /var/lib/mysql/debian-*.flag exists on this system."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"Such a file is an indication that a mysql-server package with a higher "
+"version has been installed previously."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:2001
+msgid ""
+"There is no guarantee that the version you're currently installing will be "
+"able to use the current databases."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+#, fuzzy
+#| msgid "Important note for NIS/YP users!"
+msgid "Important note for NIS/YP users"
+msgstr "NIS/YP kullanıcıları için önemli not!"
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"Using MySQL under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid "Remove all MySQL databases?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MySQL databases is about to "
+"be removed."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:4001
+msgid ""
+"If you're removing the MySQL package in order to later install a more recent "
+"version or if a different mysql-server package is already using it, the data "
+"should be kept."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+#, fuzzy
+#| msgid "Should MySQL start on boot?"
+msgid "Start the MySQL server on boot?"
+msgstr "MySQL açılış sırasında başlatılsın mı?"
+
+#. Type: boolean
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:5001
+#, fuzzy
+msgid ""
+"The MySQL server can be launched automatically at boot time or manually with "
+"the '/etc/init.d/mysql start' command."
+msgstr ""
+"MySQL açılış sırasında veya '/etc/init.d/mysql start' komutunu vermeniz "
+"halinde elle başlatılabilir. Eğer açılışta otomatik olarak başlatılmasını "
+"istiyorsanız burada 'evet'i seçin."
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "New password for the MySQL \"root\" user:"
+msgstr ""
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid ""
+"While not mandatory, it is highly recommended that you set a password for "
+"the MySQL administrative \"root\" user."
+msgstr ""
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:6001
+msgid "If this field is left blank, the password will not be changed."
+msgstr ""
+
+#. Type: password
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:7001
+msgid "Repeat password for the MySQL \"root\" user:"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "Unable to set password for the MySQL \"root\" user"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"An error occurred while setting the password for the MySQL administrative "
+"user. This may have happened because the account already has a password, or "
+"because of a communication problem with the MySQL server."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid "You should check the account's password after the package installation."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:8001
+msgid ""
+"Please read the /usr/share/doc/mysql-server-5.6/README.Debian file for more "
+"information."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "Password input error"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:9001
+msgid "The two passwords you entered were not the same. Please try again."
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid "NDB Cluster seems to be in use"
+msgstr ""
+
+#. Type: error
+#. Description
+#: ../mysql-wsrep-server-5.6.templates:10001
+msgid ""
+"MySQL-5.6 no longer provides NDB Cluster support. Please migrate to the new "
+"mysql-cluster-server package and remove all lines starting with \"ndb\" from "
+"all config files below /etc/mysql/."
+msgstr ""
+
+#~ msgid ""
+#~ "To use mysql you must install an equivalent user and group to the "
+#~ "following and ensure yourself that /var/lib/mysql has the right "
+#~ "permissions (the uid/gid may be different)."
+#~ msgstr ""
+#~ "Mysql'i kullanmak için aşağıdakiyle eşdeğer bir kullanıcı ve grup "
+#~ "tanımlamalı, ve /var/lib/mysql izinlerinin uygun şekilde ayarlandığından "
+#~ "emin olmalısınız (uid/gid farklı olabilir)."
+
+#~ msgid ""
+#~ "/etc/passwd:      mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false"
+#~ msgstr ""
+#~ "/etc/passwd:      mysql:x:100:101:MySQL Server:/var/lib/mysql:/bin/false"
+
+#~ msgid "/etc/group:       mysql:x:101:"
+#~ msgstr "/etc/group:       mysql:x:101:"
+
+#~ msgid "/var/lib/mysql:   drwxr-xr-x   mysql    mysql"
+#~ msgstr "/var/lib/mysql:   drwxr-xr-x   mysql    mysql"
+
+#, fuzzy
+#~ msgid "Please also read http://www.mysql.com/doc/en/Upgrade.html"
+#~ msgstr "Lütfen http://www.mysql.com/doc/en/Upgrade.html belgesini okuyun"
+
+#, fuzzy
+#~ msgid ""
+#~ "MySQL will only install if you have a non-numeric hostname that is "
+#~ "resolvable via the /etc/hosts file. E.g. if the \"hostname\" command "
+#~ "returns \"myhostname\" then there must be a line like \"10.0.0.1 "
+#~ "myhostname\"."
+#~ msgstr ""
+#~ "MySQL sadece /etc/hosts dosyası yoluyla çözülebilir NUMERİK OLMAYAN bir "
+#~ "makine adına sahipseniz kurulacaktır. Örneğin, eğer \"hostname\" komutu "
+#~ "\"makinem\" ismini döndürüyorsa, bu dosya içinde \"10.0.0.1 makinem\" "
+#~ "gibi bir satır olmalıdır."
+
+#, fuzzy
+#~ msgid ""
+#~ "A new mysql user \"debian-sys-maint\" will be created. This mysql account "
+#~ "is used in the start/stop and cron scripts. Don't delete."
+#~ msgstr ""
+#~ "Yeni mysql kullanıcısı \"debian-sys-maint\" yaratılacak. Bu hesap, "
+#~ "başlangıç betiklerinde ve cron içinde kullanılıyor. Bu hesabı silmeyin."
+
+#, fuzzy
+#~ msgid ""
+#~ "Please remember to set a PASSWORD for the MySQL root user! If you use a /"
+#~ "root/.my.cnf, always write the \"user\" and the \"password\" lines in "
+#~ "there, never only the password!"
+#~ msgstr ""
+#~ "Lütfen MySQL root kullanıcısı için bir PAROLA girmeyi unutmayın! Eğer /"
+#~ "root/.my.cnf kullanıyorsanız, \"user\" ve \"password\" satırlarını her "
+#~ "zaman buraya ekleyin, sadece parolayı değil! Daha fazla bilgi için /usr/"
+#~ "share/doc/mysql-server/README.Debian dosyasını okuyun."
+
+#, fuzzy
+#~ msgid ""
+#~ "Should I remove all databases below /var/lib/mysql as you are purging the "
+#~ "mysql-server package?"
+#~ msgstr ""
+#~ "mysql-server paketi kaldırıldıktan sonra bütün veritabanları silinsin mi?"
+
+#~ msgid ""
+#~ "Networking is disabled by default for security reasons. You can enable it "
+#~ "by commenting out the skip-networking option in /etc/mysql/my.cnf."
+#~ msgstr ""
+#~ "Ağ, öntanımlı olarak güvenlik gerekçeleriyle devre dışı bırakıldı. Bu "
+#~ "özelliği /etc/mysql/my.cnf dosyası içindeki \"skip-networking\" "
+#~ "seçeneğini kaldırarak etkinleştirebilirsiniz."
+
+#~ msgid "security and update notice"
+#~ msgstr "güvenlik ve güncelleme duyurusu"
+
+#~ msgid ""
+#~ "Should I remove everything below /var/lib/mysql when you purge the mysql-"
+#~ "server package with the \"dpkg --purge mysql-server\" command (i.e. "
+#~ "remove everything including the configuration) somewhen? (default is not)"
+#~ msgstr ""
+#~ "mysql-server paketini temizlemek için \"dpkg --purge mysql-server\" "
+#~ "komutunu kullandığınızda (yani yapılandırma dahil herşeyi silmek) /var/"
+#~ "lib/mysql altındaki herşeyi sileyim mi? (öntanımlı cevap hayır'dır)."
+
+#~ msgid "Please run mysql_fix_privilege_tables !"
+#~ msgstr "Lütfen mysql_fix_privilege_tables komutunu çalıştırın!"
+
+#~ msgid ""
+#~ "I will ensure secure permissions of /var/lib/mysql by replacing GIDs "
+#~ "other than root and mysql with mysql."
+#~ msgstr ""
+#~ "/var/lib/mysql'in izinlerinin güvenli olmasını sağlamak amacıyla, buna "
+#~ "ait GID'leri root ve mysql'den farklı olacak şekilde değiştireceğim."
+
+#~ msgid ""
+#~ "Instructions how to enable SSL support are in /usr/share/doc/mysql-server/"
+#~ msgstr ""
+#~ "SSL desteğini nasıl etkinleştirebileceğinize ilişkin talimatlar /usr/"
+#~ "share/doc/mysql-server/ içinde."
+
+#~ msgid "mysql_fix_privileges_tables will be executed"
+#~ msgstr "mysql_fix_privileges_tables çalıştırılacak"
+
+#~ msgid ""
+#~ "The latest MySQL versions have an enhanced, more fine grained, privilege "
+#~ "system. To make use of it, some new fields must be added to the tables "
+#~ "in  the \"mysql\" database. This is done by the "
+#~ "mysql_fix_privilege_tables script during this upgrade regardless of if "
+#~ "the server is currently running or not!"
+#~ msgstr ""
+#~ "En son MySQL sürümleri zenginleştirilmiş, daha ayrıntılandırılmış bir "
+#~ "ayrıcalık (privilege) sistemine sahiptir. Yeni sistemi kullanmak için, "
+#~ "\"mysql\" veritabanındaki tablolara bazı yeni alanlar eklenmelidir. Bu "
+#~ "işlem, sunucunun çalışıp çalışmamasına bağlı olmaksızın "
+#~ "mysql_fix_privilege_tables betiği tarafından bu yükseltme sırasında "
+#~ "yapılır."
+
+#~ msgid ""
+#~ "This script is not supposed to give any user more rights that he had "
+#~ "before, if you encounter such a case, please contact me."
+#~ msgstr ""
+#~ "Bu betiğin hiç bir kullanıcıya öncekinden daha fazla hak kazandırmadığı "
+#~ "varsayılıyor. Eğer bunun aksinde bir durumla karşılaşırsanız, lütfen "
+#~ "benimle bağlantıya geçin."
+
+#~ msgid "Make MySQL reachable via network?"
+#~ msgstr "MySQL network üzerinden ulaşılabilir olsun mu?"
+
+#~ msgid ""
+#~ "Should MySQL listen on a network reachable TCP port? This is not "
+#~ "necessary for use on a single computer and could be a security problem."
+#~ msgstr ""
+#~ "MySQL ağ üzerinde ulaşılabilen bir TCP portunu dinlesin mi? Tek olan bir "
+#~ "bilgisayar için bu ayar gerekli değildir ve bir güvenlik sorunu "
+#~ "oluşturabilir."
+
+#~ msgid "Enable chroot mode?"
+#~ msgstr "chroot kipi etkinleştirilsin mi?"
+
+#~ msgid ""
+#~ "MySQL is able to jail itself into the /var/lib/mysql_jail directory so "
+#~ "that users cannot modify any files outside this directory. This improves "
+#~ "resistence against crackers, too, as they are not able to modify system "
+#~ "files."
+#~ msgstr ""
+#~ "MySQL kendini /var/lib/mysql_jail dizinine hapsederek kullanıcıların bu "
+#~ "dizin dışındaki hiç bir dosyayı değiştirmemesini sağlayabilir. Bu "
+#~ "düzenleme, sistem dosyalarını değiştirmelerini engelleyeceğinden, "
+#~ "cracker'lara karşı dayanıklılığı arttırır."
diff --git a/mysql-wsrep-5.6/debian/rules b/mysql-wsrep-5.6/debian/rules
new file mode 100755 (executable)
index 0000000..9b64bc2
--- /dev/null
@@ -0,0 +1,231 @@
+#!/usr/bin/make -f
+
+export DH_VERBOSE=1
+
+# enable Debian Hardening
+# see: https://wiki.debian.org/Hardening
+export DEB_BUILD_MAINT_OPTIONS = hardening=+all,-pie
+DPKG_EXPORT_BUILDFLAGS = 1
+include /usr/share/dpkg/buildflags.mk
+
+ARCH := $(shell dpkg-architecture -qDEB_BUILD_ARCH)
+ARCH_OS := $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS)
+BUILDDIR := builddir
+BUILDDIR_PIC := builddir-pic
+builddir = $(if $(findstring -pic,$@),$(BUILDDIR_PIC),$(BUILDDIR))
+DEBVERSION := $(shell dpkg-parsechangelog | awk '/^Version: / { print $$2 }' | sed 's/^.*-//' )
+DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+DEB_BUILD_GNU_SYSTEM ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_SYSTEM)
+DEB_HOST_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_SOURCE_PACKAGE ?= $(strip $(shell egrep '^Source: ' debian/control | cut -f 2 -d ':'))
+DEB_VERSION ?= $(shell dpkg-parsechangelog | egrep '^Version:' | cut -f 2 -d ' ')
+DEB_NOEPOCH_VERSION ?= $(shell echo $(DEB_VERSION) | cut -d: -f2-)
+DEB_UPSTREAM_VERSION ?= $(shell echo $(DEB_NOEPOCH_VERSION) | sed 's/-[^-]*$$//')
+DEB_UPSTREAM_VERSION_MAJOR_MINOR := $(shell echo $(DEB_UPSTREAM_VERSION) | sed -r -n 's/^([0-9]+\.[0-9]+).*/\1/p')
+DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
+DISTRIBUTION := $(shell lsb_release -i -s)
+EXPORTED_SOURCE_TARBALL := debian/mysql-source-5.6.tar.gz
+TESTSUITE_FAIL_CMD:=true
+TMP := $(CURDIR)/debian/tmp/
+USE_ASSEMBLER:=--enable-assembler
+
+
+export MYSQL_BUILD_CC=$(DEB_HOST_GNU_TYPE)-gcc
+export MYSQL_BUILD_CXX=$(DEB_HOST_GNU_TYPE)-g++
+
+
+ifneq (,$(filter $(ARCH), i386 kfreebsd-i386 hurd-i386))
+       TAOCRYPT_OPT="-DTAOCRYPT_DISABLE_X86ASM"
+endif
+
+# make test-bt is the testsuite run by the MySQL build team
+# before a release, but it is long
+MAKE_TEST_TARGET:=test-mtr
+ifneq ($(findstring fulltest,$(DEB_BUILD_OPTIONS)),)
+    MAKE_TEST_TARGET:=test-bt
+endif
+ifeq ($(ARCH_OS),hurd)
+# Tests not fully working under Hurd
+# See http://bugs.mysql.com/bug.php?id=64685
+    MAKE_TEST_TARGET:=test
+endif
+
+
+# This causes seg11 crashes if LDAP is used for groups in /etc/nsswitch.conf
+# so it is disabled by default although, according to MySQL, it brings >10%
+# performance gain if enabled. See #299382.
+ifeq ($(STATIC_MYSQLD), 1)
+    USE_STATIC_MYSQLD:=--with-mysqld-ldflags=-all-static
+endif
+
+override_dh_auto_clean:
+       @echo "RULES.$@"
+       dh_testdir
+       dh_testroot
+       [ ! -d mysql-test/var ] || rm -rf mysql-test/var
+       rm -rf $(BUILDDIR) $(BUILDDIR_PIC) .pc
+       debconf-updatepo
+       rm -f $(EXPORTED_SOURCE_TARBALL)
+       rm -f cmake/os/GNU.cmake
+
+override_dh_prep:
+
+override_dh_auto_configure: configure-stamp
+
+configure-pic-stamp: FORCE_FPIC_CFLAGS=-fPIC
+configure-pic-stamp: FORCE_FPIC=-DWITH_PIC=On
+
+configure-stamp configure-pic-stamp:
+       @echo "RULES.$@"
+       dh_testdir
+       ( test -d $(builddir) || mkdir $(builddir) ) && cd $(builddir) && \
+       sh -c  'PATH=$${MYSQL_BUILD_PATH:-"/usr/local/bin:/usr/bin:/bin"} \
+               CC=$${MYSQL_BUILD_CC:-gcc} \
+               CFLAGS=$${MYSQL_BUILD_CFLAGS:-"-O2 -DBIG_JOINS=1 ${FORCE_FPIC_CFLAGS} -fno-strict-aliasing ${TAOCRYPT_OPT}"} \
+               CXX=$${MYSQL_BUILD_CXX:-g++} \
+               CXXFLAGS=$${MYSQL_BUILD_CXXFLAGS:-"-O3 -DBIG_JOINS=1 -felide-constructors -fpermissive ${FORCE_FPIC_CFLAGS} -fno-strict-aliasing ${TAOCRYPT_OPT}"} \
+               cmake -DCMAKE_INSTALL_PREFIX=/usr \
+               -DCMAKE_VERBOSE_MAKEFILE=ON \
+               $(FORCE_FPIC) \
+               -DMYSQL_UNIX_ADDR=/var/run/mysqld/mysqld.sock \
+               -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+               -DWITH_WSREP=1 \
+               -DWITH_LIBWRAP=ON \
+               -DWITH_ZLIB=system \
+               -DWITH_EDITLINE=system \
+               $(USE_STATIC_MYSQLD) \
+               -DWITH_SSL=system \
+               -DCOMPILATION_COMMENT="($(DISTRIBUTION))" \
+               -DMYSQL_SERVER_SUFFIX="-$(DEBVERSION)" \
+               -DSYSTEM_TYPE="debian-$(DEB_BUILD_GNU_SYSTEM)" \
+               -DINSTALL_LAYOUT=RPM \
+               -DINSTALL_LIBDIR=lib/$(DEB_HOST_MULTIARCH) \
+               -DINSTALL_PLUGINDIR=lib/mysql/plugin \
+               -DWITH_EMBEDDED_SERVER=ON \
+               -DWITH_ARCHIVE_STORAGE_ENGINE=ON \
+               -DWITH_BLACKHOLE_STORAGE_ENGINE=ON \
+               -DWITH_FEDERATED_STORAGE_ENGINE=ON \
+               -DWITH_EXTRA_CHARSETS=all ..'
+       touch $@
+
+override_dh_auto_build: build-stamp
+
+build-stamp:
+       @echo "RULES.$@"
+       [ -f $(EXPORTED_SOURCE_TARBALL) ] || tar -zcf $(EXPORTED_SOURCE_TARBALL) \
+       --exclude=debian . \
+       --transform="s,^\./,mysql-5.6/,"
+       cd $(builddir) && $(MAKE)
+       touch $@
+
+build-pic-stamp:
+       # Don't call this section from dh_auto_build as
+       # linmysqld does not exsist in mysql-wsrep
+       @echo "RULES.$@"
+       cd $(builddir) && $(MAKE) -C scripts
+       cd $(builddir) && $(MAKE) -C libmysqld
+       touch $@
+
+override_dh_auto_test:
+       @echo "RULES.$@"
+ifeq ($(findstring nocheck,$(DEB_BUILD_OPTIONS)),)
+       cp unittest/unit.pl $(builddir)/unittest/
+       cp -r mysql-test/* $(builddir)/mysql-test/
+       cp -r sql/share/* $(builddir)/sql/share/
+       cp -r scripts/*sql $(builddir)/scripts/
+       cd $(builddir) && $(MAKE) $(MAKE_TEST_TARGET) || $(TESTSUITE_FAIL_CMD) ;
+endif
+
+override_dh_auto_install: auto_install-stamp
+
+auto_install-stamp:
+       @echo "RULES.$@"
+       dh_testdir
+       dh_testroot
+       # make install (trailing slash needed for innobase)
+       cd $(builddir) && $(MAKE) install DESTDIR=$(TMP)/
+       # install libmysqld built with -FPIC
+       install -d -m 0755 -o root -g root $(TMP)/usr/lib/mysql
+       # linmysqld does not exsist in mysql-wsrep
+       # install -m 0644 -o root -g root $(BUILDDIR_PIC)/libmysqld/libmysqld.a $(TMP)/usr/lib/mysql/libmysqld_pic.a
+       ## mysql_config won't report the -fPIC, so give libmysqld-pic users a way to get their flags
+       # install -m 0755 -o root -g root $(BUILDDIR_PIC)/scripts/mysql_config $(TMP)/usr/bin/mysql_config_pic
+       mkdir -p $(TMP)/usr/share/doc/mysql-server-5.6
+       install -m 0644 Docs/README-wsrep $(TMP)/usr/share/doc/mysql-server-5.6
+       nm -n $(BUILDDIR)/sql/mysqld |gzip -9 > $(TMP)/usr/share/doc/mysql-server-5.6/mysqld.sym.gz
+       install -m 0644 support-files/wsrep.cnf $(TMP)/usr/share/mysql
+       # This seems to be the only safe place to fix permissions issues
+        # not handled by dh_fixperms.
+       mkdir -p $(TMP)/etc/mysql/conf.d/
+       touch $(TMP)/etc/mysql/conf.d/.keepme
+       install -D -m 0755 $(builddir)/support-files/mysql.server $(TMP)/etc/init.d/mysql
+       install -m 0755 debian/additions/echo_stderr $(TMP)/usr/share/mysql/
+       install -m 0755 debian/additions/debian-start $(TMP)/etc/mysql/
+       install -m 0755 debian/additions/debian-start.inc.sh $(TMP)/usr/share/mysql/
+       install -m 0644 debian/additions/mysql_config_pic.1 $(TMP)/usr/share/man/man1
+       install -m 0644 debian/additions/mysql_embedded.1 $(TMP)/usr/share/man/man1
+       install -m 0644 debian/additions/debian_create_root_user.sql $(TMP)/usr/share/mysql/
+       # install AppArmor profile
+       install -D -m 644 debian/apparmor-profile $(TMP)/etc/apparmor.d/usr.sbin.mysqld
+       chmod 0755 $(TMP)/usr/share/mysql-test/std_data/checkDBI_DBD-mysql.pl
+       # install Apport hook
+       install -D -m 644 debian/mysql-server-5.6.py $(TMP)/usr/share/apport/package-hooks/source_mysql-5.6.py
+       # chmod 0644 $(TMP)/usr/share/mysql/*.ini
+       chmod 0644 $(TMP)/usr/bin/mysqlaccess.conf
+       touch $@
+
+# Use the --fail-missing to check for stuff that we should be installing
+#       Exclusion                                       Package         Type
+#       usr/share/man/                                  various         man
+#       usr/share/mysql/magic                           M-server-5.6    example
+#       usr/bin/mysqlaccess.conf                        M-client-5.6    example
+#       usr/lib/mysql/plugin/daemon_example.ini         M-server-5.6    example
+#       usr/share/mysql/my-                             M-server-5.6    example
+# The following exclusions have been inherited from pre short form
+# debian/rules days.
+#        usr/share/mysql/mi_test_all
+#        usr/share/mysql/mysql-log-rotate
+#        usr/share/mysql/mysql.server
+#        usr/share/mysql/binary-configure
+# NOTE(james-page) usr/include -> end can be dropped when 5.6 becomes default
+# NOTE(james-page) skip --fail-missing until package is complete 5.5 replacement
+#override_dh_install:
+#      dh_install --fail-missing                       \
+#        -Xusr/share/man/                                \
+#        -Xusr/share/info/mysql.info                     \
+#        -Xusr/share/mysql/magic                         \
+#        -Xusr/share/mysql/solaris/postinstall-solaris   \
+#        -Xusr/lib/mysql/plugin/daemon_example.ini       \
+#        -Xusr/bin/mysqlaccess.conf                      \
+#        -Xusr/share/mysql/mi_test_all                   \
+#        -Xusr/share/mysql/mysql-log-rotate              \
+#        -Xusr/share/mysql/mysql.server                  \
+#        -Xusr/share/mysql/binary-configure              \
+#        -Xusr/share/mysql/my-                           \
+#        -Xusr/include                                   \
+#        -Xusr/bin/mysql_config                          \
+#        -Xusr/share/aclocal/mysql.m4                    \
+#        -Xlibmysql
+
+override_dh_installlogrotate-arch:
+       dh_installlogrotate --name mysql-server
+       dh_apparmor -pmysql-server-5.6 --profile-name=usr.sbin.mysqld
+
+# Start mysql in runlevel 19 before 20 where apache, proftpd etc gets
+# started which might depend on a running database server.
+override_dh_installinit-arch:
+       dh_installinit --name=mysql -- defaults 19 21
+
+override_dh_installcron-arch:
+       dh_installcron --name mysql-server
+
+override_dh_strip:
+       @echo "Notice: not stripping debug symbols from any binaries"
+
+binary:        binary-indep binary-arch
+
+get-orig-source:
+       uscan --force-download --verbose
+
+%:
+       dh $@ --parallel
diff --git a/mysql-wsrep-5.6/debian/source.lintian-overrides b/mysql-wsrep-5.6/debian/source.lintian-overrides
new file mode 100644 (file)
index 0000000..c48b90c
--- /dev/null
@@ -0,0 +1,7 @@
+# The mysql-server-5.6.postrm script handles 
+# what debhelper normally would.
+# This is apparently related to #526464.
+maintainer-script-lacks-debhelper-token debian/mysql-server-5.6.postrm
+# Probably best to keep the debhelper version low in
+# case someone needs to backport
+package-needs-versioned-debhelper-build-depends 9
diff --git a/mysql-wsrep-5.6/debian/source/format b/mysql-wsrep-5.6/debian/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/mysql-wsrep-5.6/debian/tests/build b/mysql-wsrep-5.6/debian/tests/build
new file mode 100755 (executable)
index 0000000..e88bd22
--- /dev/null
@@ -0,0 +1,35 @@
+#!/bin/sh
+# autopkgtest check: Build and run a program against libmysqlclient, to verify that the
+# headers and pkg-config file are installed correctly
+# (C) 2012 Canonical Ltd.
+# Author: Daniel Kessel <d.kessel@gmx.de>
+
+echo "test 'build' starting"
+set -e
+
+WORKDIR=$(mktemp -d)
+trap "rm -rf $WORKDIR" 0 INT QUIT ABRT PIPE TERM
+cd $WORKDIR
+
+cat <<EOF > libmysqltest.c
+#include <stdio.h>
+#include <mysql.h>
+
+int main()
+{
+    if (mysql_library_init(0, NULL, NULL)) {
+        fprintf(stderr, "failed to initialize mysql client library\n");
+       return 1;
+    }
+
+    mysql_library_end();
+    return 0;
+}
+EOF
+
+echo "building..."
+gcc -o libmysqltest libmysqltest.c `/usr/bin/mysql_config --cflags --libs` -Wall -Werror
+echo "build: OK"
+[ -x libmysqltest ]
+./libmysqltest
+echo "run: OK"
diff --git a/mysql-wsrep-5.6/debian/tests/control b/mysql-wsrep-5.6/debian/tests/control
new file mode 100644 (file)
index 0000000..ba148bb
--- /dev/null
@@ -0,0 +1,3 @@
+Tests: smoke upstream
+Depends: mysql-testsuite-5.6
+Restrictions: allow-stderr needs-root breaks-testbed
diff --git a/mysql-wsrep-5.6/debian/tests/smoke b/mysql-wsrep-5.6/debian/tests/smoke
new file mode 100644 (file)
index 0000000..58afe8b
--- /dev/null
@@ -0,0 +1,59 @@
+#!/bin/sh
+set -ex
+
+# dep8 smoke test for mysql-server
+# Author: Robie Basak <robie.basak at canonical.com>
+#
+# This test should be declared in debian/tests/control with a dependency
+# on the package that provides a configured MySQL server (eg.
+# mysql-server-5.6).
+#
+# This test should be declared in debian/tests/control with the
+# following restrictions:
+#
+# needs-root (needed to reset the root mysql password)
+# breaks-testbed (because it resets the root mysql password)
+# allow-stderr
+#
+# This test:
+#
+# 1) Configures packaged mysql server root password with maintainer
+# scripts.
+#
+# 2) Creates a test database and test user as the root user.
+#
+# 3) Creates a test table and checks it appears to operate normally
+# using the test user and test database.
+
+debconf-set-selections <<EOT
+mysql-server-5.6 mysql-server/root_password password rootpassword
+mysql-server-5.6 mysql-server/root_password_again password rootpassword
+EOT
+
+DEBIAN_FRONTEND=noninteractive dpkg-reconfigure mysql-server-5.6
+
+mysql --user=root --password=rootpassword <<EOT
+CREATE DATABASE testdatabase;
+CREATE USER 'testuser'@'localhost' identified by 'testpassword';
+GRANT ALL ON testdatabase.* TO 'testuser'@'localhost';
+EOT
+
+mysql --user=testuser --password=testpassword testdatabase <<EOT
+CREATE TABLE foo (bar INTEGER);
+INSERT INTO foo (bar) VALUES (41);
+EOT
+
+result=`echo 'SELECT bar+1 FROM foo;'|mysql --batch --skip-column-names --user=testuser --password=testpassword testdatabase`
+if [ "$result" != "42" ]; then
+       echo "Unexpected result" >&2
+       exit 1
+fi
+
+mysql --user=testuser --password=testpassword testdatabase <<EOT
+DROP TABLE foo;
+EOT
+
+mysql --user=root --password=rootpassword <<EOT
+DROP DATABASE testdatabase;
+DROP USER 'testuser'@'localhost';
+EOT
diff --git a/mysql-wsrep-5.6/debian/tests/upstream b/mysql-wsrep-5.6/debian/tests/upstream
new file mode 100755 (executable)
index 0000000..0a8b952
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+# autopkgtest check: Build and run the upstream test suite.
+# (C) 2012 Canonical Ltd.
+# Author: Daniel Kessel <d.kessel@gmx.de>
+
+# running the mysql testsuite as described in:
+# https://bugs.launchpad.net/ubuntu/+source/mysql-5.5/+bug/959683
+
+echo "running test 'testsuite'"
+set -e
+
+SKIP_TEST_LST="/tmp/skip-test.lst"
+WORKDIR=$(mktemp -d)
+trap "rm -rf $WORKDIRi $SKIP_TEST_LST" 0 INT QUIT ABRT PIPE TERM
+cd $WORKDIR
+
+mkdir var
+mkdir tmp
+
+echo "using vardir: $WORKDIR/var"
+echo "using tmpdir: $WORKDIR/tmp"
+
+echo "Setting up skip-tests-list"
+cat > $SKIP_TEST_LST << EOF
+binlog.binlog_server_start_options : Requires writable /usr
+main.ctype_uca : Requires writable /usr
+EOF
+
+cd /usr/lib/mysql-testsuite
+echo "starting mysql-test-tun.pl..."
+./mysql-test-run.pl --force --vardir=$WORKDIR/var --tmpdir=$WORKDIR/tmp \
+    --comment=normal --timer --skip-ndbcluster --report-features \
+    --skip-test-list=$SKIP_TEST_LST $@ 2>&1
+echo "run: OK"
diff --git a/mysql-wsrep-5.6/debian/watch b/mysql-wsrep-5.6/debian/watch
new file mode 100644 (file)
index 0000000..9e04cd9
--- /dev/null
@@ -0,0 +1,3 @@
+# See debian/README.source for more information about the DFSG repacking here.
+version=3
+http://mysql.mirrors.pair.com/Downloads/MySQL-5.6/mysql-([\d\.]+).tar.gz
index d55717a8e9d56825b4527c48a4d03b1dd144952a..958dedf07c09da3b367b47f7a3136f185fd64d15 100644 (file)
 #ifndef _lf_h
 #define _lf_h
 
-#include <my_atomic.h>
+#include "my_global.h"
+#include "my_atomic.h"
+#include "my_sys.h"
+#include "hash.h"
 
 C_MODE_START
 
@@ -111,13 +114,12 @@ typedef struct {
 typedef struct {
   void * volatile pin[LF_PINBOX_PINS];
   LF_PINBOX *pinbox;
-  void  **stack_ends_here;
   void  *purgatory;
   uint32 purgatory_count;
   uint32 volatile link;
 /* we want sizeof(LF_PINS) to be 64 to avoid false sharing */
-#if SIZEOF_INT*2+SIZEOF_CHARP*(LF_PINBOX_PINS+3) != 64
-  char pad[64-sizeof(uint32)*2-sizeof(void*)*(LF_PINBOX_PINS+3)];
+#if SIZEOF_INT*2+SIZEOF_CHARP*(LF_PINBOX_PINS+2) != 64
+  char pad[64-sizeof(uint32)*2-sizeof(void*)*(LF_PINBOX_PINS+2)];
 #endif
 } LF_PINS;
 
@@ -211,15 +213,6 @@ lock_wrap(lf_alloc_new, void *,
           (pins),
           &pins->pinbox->pinarray.lock)
 
-C_MODE_END
-
-/*
-  extendible hash, lf_hash.c
-*/
-#include <hash.h>
-
-C_MODE_START
-
 #define LF_HASH_UNIQUE 1
 
 /* lf_hash overhead per element (that is, sizeof(LF_SLIST) */
index 2feaa69f623cd356d3fa8fe46ff43987d3987ac3..66d6d918ef96e556697b2621b10f7e45e3798420 100644 (file)
@@ -25,6 +25,7 @@ extern const char *my_defaults_extra_file;
 extern const char *my_defaults_group_suffix;
 extern const char *my_defaults_file;
 extern my_bool my_getopt_use_args_separator;
+extern my_bool my_defaults_read_login_file;
 
 /* Define the type of function to be passed to process_default_option_files */
 typedef int (*Process_option_func)(void *ctx, const char *group_name,
index 956221aadd9b2f84d027490d2a01b588b5e2b37b..7dd8a8f606f4aa2ca47aacd28c19d9fa8a4d48ea 100644 (file)
@@ -853,7 +853,6 @@ struct st_my_thread_var
   my_bool init;
   struct st_my_thread_var *next,**prev;
   void *opt_info;
-  void  *stack_ends_here;
 #ifndef DBUG_OFF
   void *dbug;
   char name[THREAD_NAME_SIZE+1];
index 75e516b5267a6d111ca572b4c91cd201b8520698..fa1203b46ce8cc87aad6ea56f84e5125da605791 100644 (file)
@@ -713,7 +713,6 @@ extern size_t cleanup_dirname(char * to,const char *from);
 extern size_t system_filename(char * to,const char *from);
 extern size_t unpack_filename(char * to,const char *from);
 extern char * intern_filename(char * to,const char *from);
-extern char * directory_file_name(char * dst, const char *src);
 extern int pack_filename(char * to, const char *name, size_t max_length);
 extern char * my_path(char * to,const char *progname,
                         const char *own_pathname_part);
index 1cfe8b2a7296b6732f49f8b3136a7a150520705d..ef98cc9f3155024c686289df9c583a1c5e8b1874 100644 (file)
@@ -429,8 +429,16 @@ if (`SELECT UPPER(LEFT($engine_type, 3)) != 'NDB'`)
   # they are declared without DEFAULT clause.
 
   sync_slave_with_master;
+  --replace_column 4 CURRENT_TIMESTAMP
   select * from t9;
 
+  # Bug #22916743 RBR DOES NOT USE DEFAULT CURRENT_TIMESTAMP FOR EXTRA COLUMN
+  # ON SLAVE
+  --let $assert_text= The values of column 'd' should have non-zero timetsamp.
+  --let $assert_cond= [SELECT COUNT(*) AS Val FROM t9 WHERE d = "0000-00-00 00:00:00", Val, 1] = 0
+  --source include/assert.inc
+  # End of test for Bug #22916743
+
   # todo: fix Bug #43992 slave sql thread can't tune own sql_mode ...
   # and add/restore waiting for stop test
 
index 2661ffadea0944839fce919fdfeaa447f5f42971..79bb82cae7e1747664a7cab864065f4057ae42bb 100644 (file)
@@ -107,7 +107,7 @@ DROP DATABASE hotcopy_save;
 --replace_result $MYSQLD_DATADIR MYSQLD_DATADIR
 --list_files $MYSQLD_DATADIR/hotcopy_save
 --replace_result $MASTER_MYSOCK MASTER_MYSOCK
---error 9,11,110,2304
+--error 9,11,110,2304,255
 --exec $MYSQLHOTCOPY --quiet -S $MASTER_MYSOCK -u root hotcopy_test hotcopy_save
 --replace_result $MASTER_MYSOCK MASTER_MYSOCK
 --exec $MYSQLHOTCOPY --quiet --allowold -S $MASTER_MYSOCK -u root hotcopy_test hotcopy_save
index 4af980810137955a0948571ba9557af1b707a030..7dc8ba29473e415795845ae2f27b763a5c692ecc 100644 (file)
@@ -47,3 +47,4 @@ innodb_engine      plugin/innodb_memcached/innodb_memcache INNODB_ENGINE
 validate_password  plugin/password_validation VALIDATE_PASSWORD validate_password
 mysql_no_login     plugin/mysql_no_login      MYSQL_NO_LOGIN    mysql_no_login
 test_udf_services  plugin/udf_services TESTUDFSERVICES
+connection_control  plugin/connection_control   CONNECTION_CONTROL_PLUGIN    connection_control
index e8c01f0524404f267783508dd3fe513b3f2a8294..8e6e1fb33c7fa712ad10f082a4a173a20bc37e82 100644 (file)
@@ -1836,4 +1836,67 @@ CREATE TABLE t1 (
 
 SELECT 1 FROM t1 WHERE a <> 'a' OR a <> "";
 
-DROP TABLE t1;
\ No newline at end of file
+DROP TABLE t1;
+
+--echo #
+--echo # Bug #23259872: OPTIMIZER CHOOSES TO USE NON PRIMARY
+--echo #                INDEX, EVEN THOUGH COST IS HIGHER
+--echo #
+
+CREATE TABLE `giant_table` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `one_id` int(11) NOT NULL,
+  `other_id` bigint(20) NOT NULL DEFAULT '0',
+  `some_other_id` int(11) DEFAULT 0 NOT NULL,
+  `something` double NOT NULL DEFAULT '0',
+  `comment` text COLLATE utf8_unicode_ci,
+  `flags` int(11) NOT NULL DEFAULT '0',
+  `time_created` int(11) NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  KEY `time_created` (`time_created`),
+  KEY `some_other_id` (`some_other_id`),
+  KEY `one_other_idx` (`one_id`,`other_id`),
+  KEY `other_id` (`other_id`,`time_created`)
+) ENGINE=InnoDB AUTO_INCREMENT=101651329
+DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;
+
+CREATE TABLE t1 (c1 INT);
+INSERT INTO t1 VALUES (66136540), (68983250), (89627210), (77869520),
+                      (82543190), (67538270), (77282760), (77908170),
+                      (70923370), (68066360);
+DELIMITER $;
+CREATE PROCEDURE p()
+BEGIN
+SET @x = 1;
+REPEAT
+
+INSERT INTO giant_table(id,one_id)
+  SELECT c1 + @x, 0
+  FROM t1
+  WHERE c1 IN (66136540, 68985250, 89627210, 77869520 , 82543190, 67538270,
+               77282760, 77908170, 70923370, 68066360);
+SET @x =  @x + 1;
+
+UNTIL @x > 30 END REPEAT;
+END $
+DELIMITER ;$
+
+CALL p();
+SELECT count(*) FROM giant_table;
+
+INSERT INTO giant_table (id,one_id) VALUES (66136539, 0), (68983258,1),
+                                           (89628210,1), (77869520,2);
+INSERT INTO giant_table (id,one_id, some_other_id) VALUES(84673401, 0, 1),
+                                                         (61069031, 1, 1);
+
+EXPLAIN SELECT id, something, comment, time_created, one_id, other_id,
+               some_other_id, flags
+FROM giant_table
+WHERE id IN (66136539, 68983258, 89628210, 77869520, 82543198, 67538272,
+             84673401, 61069031, 68214385, 77282865, 76991297, 64569216,
+             89481638, 74534074, 70396537, 80076375, 63308530, 77908270,
+             70923271, 68066180)
+  AND (giant_table.flags & 0x01) = 0 AND giant_table.some_other_id = 0;
+
+DROP PROCEDURE p;
+DROP TABLE giant_table, t1;
index 8fad94712781931bb34e5c42cbb5f345d30370a6..41fc1bf6642fb8a356d9101974342641b1687594 100755 (executable)
@@ -163,7 +163,7 @@ our $opt_vs_config = $ENV{'MTR_VS_CONFIG'};
 
 # If you add a new suite, please check TEST_DIRS in Makefile.am.
 #
-my $DEFAULT_SUITES= "main,sys_vars,binlog,federated,rpl,innodb,innodb_fts,innodb_zip,perfschema,funcs_1,opt_trace,parts,auth_sec";
+my $DEFAULT_SUITES= "main,sys_vars,binlog,federated,rpl,innodb,innodb_fts,innodb_zip,perfschema,funcs_1,opt_trace,parts,auth_sec,connection_control";
 my $opt_suites;
 
 our $opt_verbose= 0;  # Verbose output, enable with --verbose
index c16757684d186502a96c5b21cedc152d19707f1d..96cb248677ce74246dbc406c77ef4da575f8bce4 100644 (file)
@@ -2578,3 +2578,56 @@ t1       CREATE TABLE `t1` (
   PRIMARY KEY (`fld1`)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8
 DROP TABLE t1;
+#
+# Bug#19635706
+# Verify that it is possible to add a unique key to a not-NULL POINT 
+# column and that this key is promoted to primary key
+# 
+CREATE TABLE t1(a INT NOT NULL, b POINT NOT NULL) ENGINE=INNODB;
+SHOW CREATE TABLE t1;
+Table  Create Table
+t1     CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` point NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+ALTER TABLE t1 ADD UNIQUE INDEX (b);
+# Note that SHOW CREATE TABLE does not list b as a primary key, 
+# even though it was promoted. This appears to be the case also 
+# for other column types.
+SHOW CREATE TABLE t1;
+Table  Create Table
+t1     CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` point NOT NULL,
+  UNIQUE KEY `b` (`b`(25))
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+ALTER TABLE t1 ADD UNIQUE INDEX (a);
+SHOW CREATE TABLE t1;
+Table  Create Table
+t1     CREATE TABLE `t1` (
+  `a` int(11) NOT NULL,
+  `b` point NOT NULL,
+  UNIQUE KEY `b` (`b`(25)),
+  UNIQUE KEY `a` (`a`)
+) ENGINE=InnoDB DEFAULT CHARSET=latin1
+# Verify that the expected indices have been created by Innodb
+SELECT T.NAME AS TABLE_NAME, I.NAME AS INDEX_NAME, 
+CASE I.TYPE 
+WHEN 0 THEN 'Secondary' 
+WHEN 1 THEN 'Clustered' 
+WHEN 2 THEN 'Unique' 
+WHEN 3 THEN 'Primary' 
+WHEN 32 THEN 'Full text' 
+WHEN 64 THEN 'Spatial' 
+ELSE 'Unknown' 
+END AS INDEX_TYPE, 
+F.NAME AS FIELD_NAME, F.POS AS FIELD_POS FROM 
+INFORMATION_SCHEMA.INNODB_SYS_TABLES AS T JOIN 
+INFORMATION_SCHEMA.INNODB_SYS_INDEXES AS I JOIN 
+INFORMATION_SCHEMA.INNODB_SYS_FIELDS AS F 
+ON I.INDEX_ID = F.INDEX_ID AND I.TABLE_ID = T.TABLE_ID 
+WHERE T.NAME = 'test/t1';
+TABLE_NAME     INDEX_NAME      INDEX_TYPE      FIELD_NAME      FIELD_POS
+test/t1        b       Primary b       0
+test/t1        a       Unique  a       0
+DROP TABLE t1;
index de19254071560b640cc45393878941d22f52ba5e..102cfee05df612f894d3c69c833cbeb8efd776dc 100644 (file)
@@ -1,10 +1,10 @@
 drop database if exists events_test;
 create database events_test;
 use events_test;
-create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
+create event e_26 on schedule at '2038-01-19 03:14:07' disable do set @a = 5;
 select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
 db     name    body    definer convert_tz(execute_at, 'UTC', 'SYSTEM') on_completion
-events_test    e_26    set @a = 5      root@localhost  2017-01-01 00:00:00     DROP
+events_test    e_26    set @a = 5      root@localhost  2038-01-19 03:14:07     DROP
 drop event e_26;
 create event e_26 on schedule at NULL disable do set @a = 5;
 ERROR HY000: Incorrect AT value: 'NULL'
index ba5c763fbda4ce538a9b3637615472e3d6053aae..8ccc1a3da3de80600b9c3833b1a7e1979af1172a 100644 (file)
@@ -507,7 +507,7 @@ DROP TABLE t1;
 # Bug#11765139  58069: LOAD DATA INFILE: VALGRIND REPORTS INVALID MEMORY READS AND WRITES WITH U
 #
 CREATE TABLE t1(f1 INT);
-SELECT 0xE1C330 INTO OUTFILE 't1.dat';
+SELECT 0xE1BB30 INTO OUTFILE 't1.dat';
 LOAD DATA INFILE 't1.dat' IGNORE INTO TABLE t1 CHARACTER SET utf8;
 DROP TABLE t1;
 #
@@ -532,27 +532,3 @@ FIELDS TERMINATED BY 't' LINES TERMINATED BY '';
 Got one of the listed errors
 SET @@sql_mode= @old_mode;
 DROP TABLE t1;
-
-#
-#  Bug#23080148 - Backport of Bug#20683959.
-#  Bug#20683959 LOAD DATA INFILE IGNORES A SPECIFIC ROW SILENTLY
-#               UNDER DB CHARSET IS UTF8.
-#
-CREATE DATABASE d1 CHARSET latin1;
-USE d1;
-CREATE TABLE t1 (val TEXT);
-LOAD DATA INFILE '../../std_data/bug20683959loaddata.txt' INTO TABLE t1;
-SELECT COUNT(*) FROM t1;
-COUNT(*)
-1
-SELECT HEX(val) FROM t1;
-HEX(val)
-C38322525420406E696F757A656368756E3A20E98198E2889AF58081AEE7B99DE4B88AE383A3E7B99DE69690F58087B3E7B9A7EFBDA8E7B99DEFBDB3E7B99DE78999E880B3E7B8BAEFBDAAE7B9A7E89699E296A1E7B8BAE4BBA3EFBD8CE7B8BAEFBDA9E7B8B2E2889AE38184E7B99DEFBDB3E7B99DE4B88AE383A3E7B99DE69690F58087B3E7B9A7EFBDA8E7B99DEFBDB3E7B99DE5B3A8EFBD84E8ABA0EFBDA8E89C89F580948EE599AAE7B8BAEFBDAAE7B8BAE9A198EFBDA9EFBDB1E7B9A7E581B5E289A0E7B8BAEFBDBEE7B9A7E9A194EFBDA9E882B4EFBDA5EFBDB5E980A7F5808B96E28693E99EABE38287E58F99E7B8BAE58AB1E28691E7B8BAF5808B9AE7828AE98095EFBDB1E7B8BAEFBDAFE7B8B2E288ABE6A89FE89EB3E6BA98F58081ADE88EA0EFBDBAE98095E6BA98F58081AEE89D93EFBDBAE8AD9BEFBDACE980A7F5808B96E28693E7B8BAF580918EE288AAE7B8BAE4B88AEFBC9EE7B8BAE4B99DE28691E7B8BAF5808B96EFBCA0E88DB3E6A68AEFBDB9EFBDB3E981B2E5B3A8E296A1E7B8BAE7A4BCE7828AE88DB3E6A68AEFBDB0EFBDBDE7B8BAA0E7B8BAE88B93EFBDBEE5B899EFBC9E
-CREATE DATABASE d2 CHARSET utf8;
-USE d2;
-CREATE TABLE t1 (val TEXT);
-LOAD DATA INFILE '../../std_data/bug20683959loaddata.txt' INTO TABLE t1;
-ERROR HY000: Invalid utf8 character string: 'Ã"RT @niouzechun: \9058\221A'
-DROP TABLE d1.t1, d2.t1;
-DROP DATABASE d1;
-DROP DATABASE d2;
index f1acfc7370908120bc669c170a08f3d3050fcb27..9ddc45723b24bedbee73497cf3671dfb619197e8 100644 (file)
@@ -267,3 +267,9 @@ mysqld is alive
 # normally.
 mysqld is alive
 #### End of test ####
+#
+# Bug #24557925: MYSQL_CONFIG_EDITOR CAN MAKE SERVER UNBOOTABLE
+#
+# Restarting the server. Should work
+# Cleanup
+# End of 5.6 tests
index 26a4524ceaff5f1d73d244ad7a08cc111caf511f..8ffb219f03f3b697648fcb4ea735771d9160612f 100644 (file)
@@ -43,6 +43,8 @@ DROP TABLE t1, t2;
 # test.t1 have partitions in mysqltest2-directory!
 # user root:
 CREATE USER mysqltest_1@localhost;
+# Need FILE permission to use external datadir or indexdir.
+GRANT FILE ON *.* TO mysqltest_1@localhost;
 CREATE DATABASE mysqltest2;
 USE mysqltest2;
 CREATE TABLE t1 (a INT) ENGINE = MyISAM;
index a4b2c4acd778afaa5f863beac444db5153f83b29..6d074eb21af576426e74979ba5eddd35a713916a 100644 (file)
@@ -2494,4 +2494,60 @@ KEY(a(1))
 SELECT 1 FROM t1 WHERE a <> 'a' OR a <> "";
 1
 DROP TABLE t1;
+#
+# Bug #23259872: OPTIMIZER CHOOSES TO USE NON PRIMARY
+#                INDEX, EVEN THOUGH COST IS HIGHER
+#
+CREATE TABLE `giant_table` (
+`id` int(11) NOT NULL AUTO_INCREMENT,
+`one_id` int(11) NOT NULL,
+`other_id` bigint(20) NOT NULL DEFAULT '0',
+`some_other_id` int(11) DEFAULT 0 NOT NULL,
+`something` double NOT NULL DEFAULT '0',
+`comment` text COLLATE utf8_unicode_ci,
+`flags` int(11) NOT NULL DEFAULT '0',
+`time_created` int(11) NOT NULL DEFAULT '0',
+PRIMARY KEY (`id`),
+KEY `time_created` (`time_created`),
+KEY `some_other_id` (`some_other_id`),
+KEY `one_other_idx` (`one_id`,`other_id`),
+KEY `other_id` (`other_id`,`time_created`)
+) ENGINE=InnoDB AUTO_INCREMENT=101651329
+DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;
+CREATE TABLE t1 (c1 INT);
+INSERT INTO t1 VALUES (66136540), (68983250), (89627210), (77869520),
+(82543190), (67538270), (77282760), (77908170),
+(70923370), (68066360);
+CREATE PROCEDURE p()
+BEGIN
+SET @x = 1;
+REPEAT
+INSERT INTO giant_table(id,one_id)
+SELECT c1 + @x, 0
+FROM t1
+WHERE c1 IN (66136540, 68985250, 89627210, 77869520 , 82543190, 67538270,
+77282760, 77908170, 70923370, 68066360);
+SET @x =  @x + 1;
+UNTIL @x > 30 END REPEAT;
+END $
+CALL p();
+SELECT count(*) FROM giant_table;
+count(*)
+270
+INSERT INTO giant_table (id,one_id) VALUES (66136539, 0), (68983258,1),
+(89628210,1), (77869520,2);
+INSERT INTO giant_table (id,one_id, some_other_id) VALUES(84673401, 0, 1),
+(61069031, 1, 1);
+EXPLAIN SELECT id, something, comment, time_created, one_id, other_id,
+some_other_id, flags
+FROM giant_table
+WHERE id IN (66136539, 68983258, 89628210, 77869520, 82543198, 67538272,
+84673401, 61069031, 68214385, 77282865, 76991297, 64569216,
+89481638, 74534074, 70396537, 80076375, 63308530, 77908270,
+70923271, 68066180)
+AND (giant_table.flags & 0x01) = 0 AND giant_table.some_other_id = 0;
+id     select_type     table   type    possible_keys   key     key_len ref     rows    Extra
+1      SIMPLE  giant_table     range   PRIMARY,some_other_id   some_other_id   8       NULL    20      Using index condition; Using where; Using MRR
+DROP PROCEDURE p;
+DROP TABLE giant_table, t1;
 set optimizer_switch=default;
index 361fcb0d6f15be10c4bbed06f4d007a801f0eaa7..c8e857cbed3828f352b8a76bc0d4a07304684608 100644 (file)
@@ -2494,4 +2494,60 @@ KEY(a(1))
 SELECT 1 FROM t1 WHERE a <> 'a' OR a <> "";
 1
 DROP TABLE t1;
+#
+# Bug #23259872: OPTIMIZER CHOOSES TO USE NON PRIMARY
+#                INDEX, EVEN THOUGH COST IS HIGHER
+#
+CREATE TABLE `giant_table` (
+`id` int(11) NOT NULL AUTO_INCREMENT,
+`one_id` int(11) NOT NULL,
+`other_id` bigint(20) NOT NULL DEFAULT '0',
+`some_other_id` int(11) DEFAULT 0 NOT NULL,
+`something` double NOT NULL DEFAULT '0',
+`comment` text COLLATE utf8_unicode_ci,
+`flags` int(11) NOT NULL DEFAULT '0',
+`time_created` int(11) NOT NULL DEFAULT '0',
+PRIMARY KEY (`id`),
+KEY `time_created` (`time_created`),
+KEY `some_other_id` (`some_other_id`),
+KEY `one_other_idx` (`one_id`,`other_id`),
+KEY `other_id` (`other_id`,`time_created`)
+) ENGINE=InnoDB AUTO_INCREMENT=101651329
+DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;
+CREATE TABLE t1 (c1 INT);
+INSERT INTO t1 VALUES (66136540), (68983250), (89627210), (77869520),
+(82543190), (67538270), (77282760), (77908170),
+(70923370), (68066360);
+CREATE PROCEDURE p()
+BEGIN
+SET @x = 1;
+REPEAT
+INSERT INTO giant_table(id,one_id)
+SELECT c1 + @x, 0
+FROM t1
+WHERE c1 IN (66136540, 68985250, 89627210, 77869520 , 82543190, 67538270,
+77282760, 77908170, 70923370, 68066360);
+SET @x =  @x + 1;
+UNTIL @x > 30 END REPEAT;
+END $
+CALL p();
+SELECT count(*) FROM giant_table;
+count(*)
+270
+INSERT INTO giant_table (id,one_id) VALUES (66136539, 0), (68983258,1),
+(89628210,1), (77869520,2);
+INSERT INTO giant_table (id,one_id, some_other_id) VALUES(84673401, 0, 1),
+(61069031, 1, 1);
+EXPLAIN SELECT id, something, comment, time_created, one_id, other_id,
+some_other_id, flags
+FROM giant_table
+WHERE id IN (66136539, 68983258, 89628210, 77869520, 82543198, 67538272,
+84673401, 61069031, 68214385, 77282865, 76991297, 64569216,
+89481638, 74534074, 70396537, 80076375, 63308530, 77908270,
+70923271, 68066180)
+AND (giant_table.flags & 0x01) = 0 AND giant_table.some_other_id = 0;
+id     select_type     table   type    possible_keys   key     key_len ref     rows    Extra
+1      SIMPLE  giant_table     range   PRIMARY,some_other_id   some_other_id   8       NULL    20      Using index condition; Using where
+DROP PROCEDURE p;
+DROP TABLE giant_table, t1;
 set optimizer_switch=default;
index 1550bcf0ac7d41008e9a1288d308e9603905fb9d..fd0d00c719f3aa9288c4e7020dd339bb129beb6c 100644 (file)
@@ -2494,4 +2494,60 @@ KEY(a(1))
 SELECT 1 FROM t1 WHERE a <> 'a' OR a <> "";
 1
 DROP TABLE t1;
+#
+# Bug #23259872: OPTIMIZER CHOOSES TO USE NON PRIMARY
+#                INDEX, EVEN THOUGH COST IS HIGHER
+#
+CREATE TABLE `giant_table` (
+`id` int(11) NOT NULL AUTO_INCREMENT,
+`one_id` int(11) NOT NULL,
+`other_id` bigint(20) NOT NULL DEFAULT '0',
+`some_other_id` int(11) DEFAULT 0 NOT NULL,
+`something` double NOT NULL DEFAULT '0',
+`comment` text COLLATE utf8_unicode_ci,
+`flags` int(11) NOT NULL DEFAULT '0',
+`time_created` int(11) NOT NULL DEFAULT '0',
+PRIMARY KEY (`id`),
+KEY `time_created` (`time_created`),
+KEY `some_other_id` (`some_other_id`),
+KEY `one_other_idx` (`one_id`,`other_id`),
+KEY `other_id` (`other_id`,`time_created`)
+) ENGINE=InnoDB AUTO_INCREMENT=101651329
+DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;
+CREATE TABLE t1 (c1 INT);
+INSERT INTO t1 VALUES (66136540), (68983250), (89627210), (77869520),
+(82543190), (67538270), (77282760), (77908170),
+(70923370), (68066360);
+CREATE PROCEDURE p()
+BEGIN
+SET @x = 1;
+REPEAT
+INSERT INTO giant_table(id,one_id)
+SELECT c1 + @x, 0
+FROM t1
+WHERE c1 IN (66136540, 68985250, 89627210, 77869520 , 82543190, 67538270,
+77282760, 77908170, 70923370, 68066360);
+SET @x =  @x + 1;
+UNTIL @x > 30 END REPEAT;
+END $
+CALL p();
+SELECT count(*) FROM giant_table;
+count(*)
+270
+INSERT INTO giant_table (id,one_id) VALUES (66136539, 0), (68983258,1),
+(89628210,1), (77869520,2);
+INSERT INTO giant_table (id,one_id, some_other_id) VALUES(84673401, 0, 1),
+(61069031, 1, 1);
+EXPLAIN SELECT id, something, comment, time_created, one_id, other_id,
+some_other_id, flags
+FROM giant_table
+WHERE id IN (66136539, 68983258, 89628210, 77869520, 82543198, 67538272,
+84673401, 61069031, 68214385, 77282865, 76991297, 64569216,
+89481638, 74534074, 70396537, 80076375, 63308530, 77908270,
+70923271, 68066180)
+AND (giant_table.flags & 0x01) = 0 AND giant_table.some_other_id = 0;
+id     select_type     table   type    possible_keys   key     key_len ref     rows    Extra
+1      SIMPLE  giant_table     range   PRIMARY,some_other_id   some_other_id   8       NULL    20      Using index condition; Using where; Using MRR
+DROP PROCEDURE p;
+DROP TABLE giant_table, t1;
 set optimizer_switch=default;
index 6c612d0884c731e2e55f9121fff6560e00e1b293..1b97592744c5347b1c6c971c8ca155746c5da98c 100644 (file)
@@ -2494,4 +2494,60 @@ KEY(a(1))
 SELECT 1 FROM t1 WHERE a <> 'a' OR a <> "";
 1
 DROP TABLE t1;
+#
+# Bug #23259872: OPTIMIZER CHOOSES TO USE NON PRIMARY
+#                INDEX, EVEN THOUGH COST IS HIGHER
+#
+CREATE TABLE `giant_table` (
+`id` int(11) NOT NULL AUTO_INCREMENT,
+`one_id` int(11) NOT NULL,
+`other_id` bigint(20) NOT NULL DEFAULT '0',
+`some_other_id` int(11) DEFAULT 0 NOT NULL,
+`something` double NOT NULL DEFAULT '0',
+`comment` text COLLATE utf8_unicode_ci,
+`flags` int(11) NOT NULL DEFAULT '0',
+`time_created` int(11) NOT NULL DEFAULT '0',
+PRIMARY KEY (`id`),
+KEY `time_created` (`time_created`),
+KEY `some_other_id` (`some_other_id`),
+KEY `one_other_idx` (`one_id`,`other_id`),
+KEY `other_id` (`other_id`,`time_created`)
+) ENGINE=InnoDB AUTO_INCREMENT=101651329
+DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;
+CREATE TABLE t1 (c1 INT);
+INSERT INTO t1 VALUES (66136540), (68983250), (89627210), (77869520),
+(82543190), (67538270), (77282760), (77908170),
+(70923370), (68066360);
+CREATE PROCEDURE p()
+BEGIN
+SET @x = 1;
+REPEAT
+INSERT INTO giant_table(id,one_id)
+SELECT c1 + @x, 0
+FROM t1
+WHERE c1 IN (66136540, 68985250, 89627210, 77869520 , 82543190, 67538270,
+77282760, 77908170, 70923370, 68066360);
+SET @x =  @x + 1;
+UNTIL @x > 30 END REPEAT;
+END $
+CALL p();
+SELECT count(*) FROM giant_table;
+count(*)
+270
+INSERT INTO giant_table (id,one_id) VALUES (66136539, 0), (68983258,1),
+(89628210,1), (77869520,2);
+INSERT INTO giant_table (id,one_id, some_other_id) VALUES(84673401, 0, 1),
+(61069031, 1, 1);
+EXPLAIN SELECT id, something, comment, time_created, one_id, other_id,
+some_other_id, flags
+FROM giant_table
+WHERE id IN (66136539, 68983258, 89628210, 77869520, 82543198, 67538272,
+84673401, 61069031, 68214385, 77282865, 76991297, 64569216,
+89481638, 74534074, 70396537, 80076375, 63308530, 77908270,
+70923271, 68066180)
+AND (giant_table.flags & 0x01) = 0 AND giant_table.some_other_id = 0;
+id     select_type     table   type    possible_keys   key     key_len ref     rows    Extra
+1      SIMPLE  giant_table     range   PRIMARY,some_other_id   some_other_id   8       NULL    20      Using where; Using MRR
+DROP PROCEDURE p;
+DROP TABLE giant_table, t1;
 set optimizer_switch=default;
index decf2550f9ac7a056dc5662495fc2e372a6fa56e..901968354a4a6eadf0506555d0222fb4143f8337 100644 (file)
@@ -2494,4 +2494,60 @@ KEY(a(1))
 SELECT 1 FROM t1 WHERE a <> 'a' OR a <> "";
 1
 DROP TABLE t1;
+#
+# Bug #23259872: OPTIMIZER CHOOSES TO USE NON PRIMARY
+#                INDEX, EVEN THOUGH COST IS HIGHER
+#
+CREATE TABLE `giant_table` (
+`id` int(11) NOT NULL AUTO_INCREMENT,
+`one_id` int(11) NOT NULL,
+`other_id` bigint(20) NOT NULL DEFAULT '0',
+`some_other_id` int(11) DEFAULT 0 NOT NULL,
+`something` double NOT NULL DEFAULT '0',
+`comment` text COLLATE utf8_unicode_ci,
+`flags` int(11) NOT NULL DEFAULT '0',
+`time_created` int(11) NOT NULL DEFAULT '0',
+PRIMARY KEY (`id`),
+KEY `time_created` (`time_created`),
+KEY `some_other_id` (`some_other_id`),
+KEY `one_other_idx` (`one_id`,`other_id`),
+KEY `other_id` (`other_id`,`time_created`)
+) ENGINE=InnoDB AUTO_INCREMENT=101651329
+DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;
+CREATE TABLE t1 (c1 INT);
+INSERT INTO t1 VALUES (66136540), (68983250), (89627210), (77869520),
+(82543190), (67538270), (77282760), (77908170),
+(70923370), (68066360);
+CREATE PROCEDURE p()
+BEGIN
+SET @x = 1;
+REPEAT
+INSERT INTO giant_table(id,one_id)
+SELECT c1 + @x, 0
+FROM t1
+WHERE c1 IN (66136540, 68985250, 89627210, 77869520 , 82543190, 67538270,
+77282760, 77908170, 70923370, 68066360);
+SET @x =  @x + 1;
+UNTIL @x > 30 END REPEAT;
+END $
+CALL p();
+SELECT count(*) FROM giant_table;
+count(*)
+270
+INSERT INTO giant_table (id,one_id) VALUES (66136539, 0), (68983258,1),
+(89628210,1), (77869520,2);
+INSERT INTO giant_table (id,one_id, some_other_id) VALUES(84673401, 0, 1),
+(61069031, 1, 1);
+EXPLAIN SELECT id, something, comment, time_created, one_id, other_id,
+some_other_id, flags
+FROM giant_table
+WHERE id IN (66136539, 68983258, 89628210, 77869520, 82543198, 67538272,
+84673401, 61069031, 68214385, 77282865, 76991297, 64569216,
+89481638, 74534074, 70396537, 80076375, 63308530, 77908270,
+70923271, 68066180)
+AND (giant_table.flags & 0x01) = 0 AND giant_table.some_other_id = 0;
+id     select_type     table   type    possible_keys   key     key_len ref     rows    Extra
+1      SIMPLE  giant_table     range   PRIMARY,some_other_id   some_other_id   8       NULL    20      Using where
+DROP PROCEDURE p;
+DROP TABLE giant_table, t1;
 set optimizer_switch=default;
index ef718a40b2debd972e7b95f0e1ea6176d6b82684..7989cb29c23a06acc13293e4e1945debe793ca2e 100644 (file)
@@ -2493,4 +2493,60 @@ KEY(a(1))
 SELECT 1 FROM t1 WHERE a <> 'a' OR a <> "";
 1
 DROP TABLE t1;
+#
+# Bug #23259872: OPTIMIZER CHOOSES TO USE NON PRIMARY
+#                INDEX, EVEN THOUGH COST IS HIGHER
+#
+CREATE TABLE `giant_table` (
+`id` int(11) NOT NULL AUTO_INCREMENT,
+`one_id` int(11) NOT NULL,
+`other_id` bigint(20) NOT NULL DEFAULT '0',
+`some_other_id` int(11) DEFAULT 0 NOT NULL,
+`something` double NOT NULL DEFAULT '0',
+`comment` text COLLATE utf8_unicode_ci,
+`flags` int(11) NOT NULL DEFAULT '0',
+`time_created` int(11) NOT NULL DEFAULT '0',
+PRIMARY KEY (`id`),
+KEY `time_created` (`time_created`),
+KEY `some_other_id` (`some_other_id`),
+KEY `one_other_idx` (`one_id`,`other_id`),
+KEY `other_id` (`other_id`,`time_created`)
+) ENGINE=InnoDB AUTO_INCREMENT=101651329
+DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci ;
+CREATE TABLE t1 (c1 INT);
+INSERT INTO t1 VALUES (66136540), (68983250), (89627210), (77869520),
+(82543190), (67538270), (77282760), (77908170),
+(70923370), (68066360);
+CREATE PROCEDURE p()
+BEGIN
+SET @x = 1;
+REPEAT
+INSERT INTO giant_table(id,one_id)
+SELECT c1 + @x, 0
+FROM t1
+WHERE c1 IN (66136540, 68985250, 89627210, 77869520 , 82543190, 67538270,
+77282760, 77908170, 70923370, 68066360);
+SET @x =  @x + 1;
+UNTIL @x > 30 END REPEAT;
+END $
+CALL p();
+SELECT count(*) FROM giant_table;
+count(*)
+270
+INSERT INTO giant_table (id,one_id) VALUES (66136539, 0), (68983258,1),
+(89628210,1), (77869520,2);
+INSERT INTO giant_table (id,one_id, some_other_id) VALUES(84673401, 0, 1),
+(61069031, 1, 1);
+EXPLAIN SELECT id, something, comment, time_created, one_id, other_id,
+some_other_id, flags
+FROM giant_table
+WHERE id IN (66136539, 68983258, 89628210, 77869520, 82543198, 67538272,
+84673401, 61069031, 68214385, 77282865, 76991297, 64569216,
+89481638, 74534074, 70396537, 80076375, 63308530, 77908270,
+70923271, 68066180)
+AND (giant_table.flags & 0x01) = 0 AND giant_table.some_other_id = 0;
+id     select_type     table   type    possible_keys   key     key_len ref     rows    Extra
+1      SIMPLE  giant_table     range   PRIMARY,some_other_id   some_other_id   8       NULL    20      Using where
+DROP PROCEDURE p;
+DROP TABLE giant_table, t1;
 set optimizer_switch=default;
diff --git a/mysql-wsrep-5.6/mysql-test/std_data/bug20683959loaddata.txt b/mysql-wsrep-5.6/mysql-test/std_data/bug20683959loaddata.txt
deleted file mode 100644 (file)
index 1878cc7..0000000
+++ /dev/null
@@ -1 +0,0 @@
\83"RT @niouzechun: é\81\98â\88\9aõ\80\81®ç¹\9dä¸\8aã\83£ç¹\9dæ\96\90õ\80\87³ç¹§ï½¨ç¹\9dï½³ç¹\9dç\89\99è\80³ç¸ºï½ªç¹§è\96\99â\96¡ç¸ºä»£ï½\8c縺ゥ縲â\88\9aã\81\84ç¹\9dï½³ç¹\9dä¸\8aã\83£ç¹\9dæ\96\90õ\80\87³ç¹§ï½¨ç¹\9dï½³ç¹\9d峨ï½\84諠ィè\9c\89õ\80\94\8eå\99ªç¸ºï½ªç¸ºé¡\98ゥア繧å\81µâ\89 ç¸ºï½¾ç¹§é¡\94ゥè\82´ï½¥ï½µé\80§õ\80\8b\96â\86\93é\9e«ã\82\87å\8f\99縺å\8a±â\86\91縺õ\80\8b\9aç\82\8aé\80\95ア縺ッ縲â\88«æ¨\9fè\9e³æº\98õ\80\81­è\8e ï½ºé\80\95æº\98õ\80\81®è\9d\93コè­\9bャé\80§õ\80\8b\96â\86\93縺õ\80\91\8eâ\88ªç¸ºä¸\8aï¼\9e縺ä¹\9dâ\86\91縺õ\80\8b\96ï¼ è\8d³æ¦\8aケウé\81²å³¨â\96¡ç¸ºç¤¼ç\82\8aè\8d³æ¦\8aース縺 ç¸ºè\8b\93ï½¾å¸\99ï¼\9e
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/check_connection_delay.inc b/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/check_connection_delay.inc
new file mode 100644 (file)
index 0000000..20b69bd
--- /dev/null
@@ -0,0 +1,44 @@
+# Following variables should be set:
+# $USER                 Name of the user
+# $PASSWORD             Password to be supplied
+# $SUCCESS              Whether a successful connection is expected or not
+# $DELAY_STATS           Expected value of Connection_control_delay_generated
+# $USE_AUTH_PLUGIN      Whether an authentication plugin is to be used or not
+# $CLIENT_AUTH_PLUGIN   Authentication plugin
+
+connection default;
+disable_query_log;
+disable_result_log;
+
+if ($SUCCESS == 0)
+{
+  --echo # Connection attempt should fail.
+  if ($USE_AUTH_PLUGIN == 0)
+  {
+    --error 1
+    --exec $MYSQL -u$USER -p$PASSWORD -e "SELECT 1;" 2>&1
+  }
+  if ($USE_AUTH_PLUGIN == 1)
+  {
+    --error 1
+    --exec $MYSQL -u$USER $CLIENT_AUTH_PLUGIN -p$PASSWORD -e "SELECT 1;" 2>&1
+  }
+}
+
+if ($SUCCESS != 0)
+{
+  --echo # Connection attempt should succeed.
+    if ($USE_AUTH_PLUGIN == 0)
+  {
+    --exec $MYSQL -u$USER -p$PASSWORD -e "SELECT 1;" 2>&1
+  }
+  if ($USE_AUTH_PLUGIN == 1)
+  {
+    --exec $MYSQL -u$USER $CLIENT_AUTH_PLUGIN -p$PASSWORD -e "SELECT 1;" 2>&1
+  }
+}
+
+enable_result_log;
+--echo Connection_control_delay_generated should be $DELAY_STATS
+SHOW STATUS LIKE 'Connection_control_delay_generated';
+enable_query_log;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/cleanup_proxy_accounts.inc b/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/cleanup_proxy_accounts.inc
new file mode 100644 (file)
index 0000000..5cf2c57
--- /dev/null
@@ -0,0 +1,24 @@
+disable_query_log;
+disable_result_log;
+# Revoke proxy grants
+REVOKE PROXY ON proxied@localhost FROM u1@localhost, u2@localhost, u3@localhost;
+
+# Drop proxy users
+DROP USER u1@localhost, u2@localhost, u3@localhost;
+
+# Drop proxied user
+DROP USER proxied@localhost;
+
+# Uninstall test_plugin_server
+UNINSTALL PLUGIN test_plugin_server;
+
+# Remove plugin library
+let $auth_plugin_path= `SELECT SUBSTR('$PLUGIN_AUTH_OPT/$PLUGIN_AUTH', 14)`;
+let $connection_control_plugin_path= `SELECT SUBSTR('$CONNECTION_CONTROL_PLUGIN_OPT/$PLUGIN_AUTH', 14)`;
+
+if ($auth_plugin_path != $connection_control_plugin_path)
+{
+  --remove_file $connection_control_plugin_path
+}
+enable_result_log;
+enable_query_log;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/have_connection_control_plugin.inc b/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/have_connection_control_plugin.inc
new file mode 100644 (file)
index 0000000..e316487
--- /dev/null
@@ -0,0 +1,22 @@
+disable_query_log;
+#
+# Check if server has support for loading plugin
+#
+if (`SELECT @@have_dynamic_loading != 'YES'`) {
+  --skip The connection_control plugin requires dynamic loading
+}
+
+#
+# Check if the variable CONNECTION_CONTROL_PLUGIN is set
+#
+if (!$CONNECTION_CONTROL_PLUGIN) {
+  --skip The connection_control plugin requires the environment variable \$CONNECTION_CONTROL_PLUGIN to be set (normally done by mtr)
+}
+
+#
+# Check if --plugin-dir was setup for null_audit_db
+#
+if (`SELECT CONCAT('--plugin-dir=', REPLACE(@@plugin_dir, '\\\\', '/')) != '$CONNECTION_CONTROL_PLUGIN_OPT/'`) {
+  --skip The connection_control plugin requires that --plugin-dir is set to the connection_control plugin dir (either the .opt file does not contain \$CONNECTION_CONTROL_PLUGIN_OPT or another plugin is in use)
+}
+enable_query_log;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/have_test_plugin.inc b/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/have_test_plugin.inc
new file mode 100644 (file)
index 0000000..a60d3a9
--- /dev/null
@@ -0,0 +1,16 @@
+disable_query_log;
+#
+# Check if server has support for loading plugin
+#
+if (`SELECT @@have_dynamic_loading != 'YES'`) {
+  --skip The connection_control plugin requires dynamic loading
+}
+
+#
+# Check if the variable PLUGIN_AUTH is set
+#
+if (!$PLUGIN_AUTH) {
+  --skip The connection_control plugin requires the environment variable \$PLUGIN_AUTH to be set (normally done by mtr)
+}
+
+enable_query_log;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/install_connection_control_plugin.inc b/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/install_connection_control_plugin.inc
new file mode 100644 (file)
index 0000000..2249b35
--- /dev/null
@@ -0,0 +1,5 @@
+# Install connection_control plugin
+--replace_result $CONNECTION_CONTROL_PLUGIN CONNECTION_CONTROL_LIB
+eval INSTALL PLUGIN connection_control SONAME '$CONNECTION_CONTROL_PLUGIN';
+--replace_result $CONNECTION_CONTROL_PLUGIN CONNECTION_CONTROL_LIB
+eval INSTALL PLUGIN connection_control_failed_login_attempts SONAME '$CONNECTION_CONTROL_PLUGIN'; 
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/set_after_marker.inc b/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/set_after_marker.inc
new file mode 100644 (file)
index 0000000..be69c58
--- /dev/null
@@ -0,0 +1,10 @@
+# set after marker
+# $SERVER_RESPONSE_TIME [IN] Expected delay
+disable_query_log;
+disable_result_log;
+SET @after= TIMESTAMP(current_time());
+SET @server_response_time= TIMESTAMPDIFF(SECOND, @before, @after);
+enable_result_log;
+
+--eval SELECT @server_response_time >= $SERVER_RESPONSE_TIME
+enable_query_log;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/set_before_marker.inc b/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/set_before_marker.inc
new file mode 100644 (file)
index 0000000..52d84a9
--- /dev/null
@@ -0,0 +1,6 @@
+# Set before marker
+disable_query_log;
+disable_result_log;
+SET @before= TIMESTAMP(current_time());
+enable_result_log;
+enable_query_log;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/setup_proxy_accounts.inc b/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/setup_proxy_accounts.inc
new file mode 100644 (file)
index 0000000..2a0b884
--- /dev/null
@@ -0,0 +1,26 @@
+disable_query_log;
+disable_result_log;
+# Copy PLUGIN_AUTH library to CONNECTION_CONTROL_OPT location
+let $auth_plugin_path= `SELECT SUBSTR('$PLUGIN_AUTH_OPT/$PLUGIN_AUTH', 14)`;
+let $connection_control_plugin_path= `SELECT SUBSTR('$CONNECTION_CONTROL_PLUGIN_OPT/$PLUGIN_AUTH', 14)`;
+
+if ($auth_plugin_path != $connection_control_plugin_path)
+{
+  --error 0, 1
+  --remove_file $connection_control_plugin_path
+  --copy_file $auth_plugin_path $connection_control_plugin_path
+}
+# Install test_plugin_server
+eval INSTALL PLUGIN test_plugin_server SONAME '$PLUGIN_AUTH';
+
+# Create proxied@localhost
+CREATE USER proxied@localhost IDENTIFIED BY 'proxied_password';
+
+# Create u1@localhost, u2@localhost, u3@localhst
+CREATE USER u1@localhost IDENTIFIED WITH test_plugin_server AS 'proxied';
+CREATE USER u2@localhost IDENTIFIED WITH test_plugin_server AS 'proxied';
+CREATE USER u3@localhost IDENTIFIED WITH test_plugin_server AS 'proxied';
+
+GRANT PROXY ON proxied@localhost TO u1@localhost, u2@localhost, u3@localhost;
+enable_result_log;
+enable_query_log;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/uninstall_connection_control_plugin.inc b/mysql-wsrep-5.6/mysql-test/suite/connection_control/inc/uninstall_connection_control_plugin.inc
new file mode 100644 (file)
index 0000000..540e124
--- /dev/null
@@ -0,0 +1,5 @@
+# Uninstall connection_control plugin
+--disable_warnings
+UNINSTALL PLUGIN connection_control;
+--enable_warnings
+UNINSTALL PLUGIN connection_control_failed_login_attempts;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_anonymous_user.result b/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_anonymous_user.result
new file mode 100644 (file)
index 0000000..efdae6e
--- /dev/null
@@ -0,0 +1,60 @@
+# Connection delay tests for valid user accounts
+
+# ----------------------------------------------------------------------
+
+# Setup
+# Install connection_control plugin
+INSTALL PLUGIN connection_control SONAME 'CONNECTION_CONTROL_LIB';
+INSTALL PLUGIN connection_control_failed_login_attempts SONAME 'CONNECTION_CONTROL_LIB';
+# Create anonymous user
+CREATE USER ''@'localhost';
+# Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+SET @saved_max_delay = @@global.connection_control_max_connection_delay;
+# Set small values for connection_control variables
+SET @@global.connection_control_failed_connections_threshold = 3;
+SET @global.connection_control_max_connection_delay = 1000;
+
+# ----------------------------------------------------------------------
+
+# Following attempts will not experience any delay in server respose
+# Connection attempt should fail.
+Connection_control_delay_generated should be 0
+Variable_name  Value
+Connection_control_delay_generated     0
+# Connection attempt should fail.
+Connection_control_delay_generated should be 0
+Variable_name  Value
+Connection_control_delay_generated     0
+# Connection attempt should fail.
+Connection_control_delay_generated should be 0
+Variable_name  Value
+Connection_control_delay_generated     0
+
+# Following attempts will experience delay in server respose
+# Connection attempt should fail.
+Connection_control_delay_generated should be 1
+Variable_name  Value
+Connection_control_delay_generated     1
+# Connection attempt should fail.
+Connection_control_delay_generated should be 2
+Variable_name  Value
+Connection_control_delay_generated     2
+# Connection attempt should fail.
+Connection_control_delay_generated should be 3
+Variable_name  Value
+Connection_control_delay_generated     3
+
+# ----------------------------------------------------------------------
+
+# Cleanup
+# Restore original values of conenction_control variables
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+SET @@global.connection_control_max_connection_delay = @saved_max_delay;
+# Drop anonymous user
+DROP USER ''@'localhost';
+# Uninstall connection_control plugin
+UNINSTALL PLUGIN connection_control;
+UNINSTALL PLUGIN connection_control_failed_login_attempts;
+
+# ----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_info_schema_view.result b/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_info_schema_view.result
new file mode 100644 (file)
index 0000000..d90034a
--- /dev/null
@@ -0,0 +1,140 @@
+# Connection delay tests for valid user accounts
+
+# ----------------------------------------------------------------------
+
+# Setup
+# Install connection_control plugin
+INSTALL PLUGIN connection_control SONAME 'CONNECTION_CONTROL_LIB';
+INSTALL PLUGIN connection_control_failed_login_attempts SONAME 'CONNECTION_CONTROL_LIB';
+# Create user accounts for testing
+CREATE USER u1@localhost IDENTIFIED BY 'abcd';
+CREATE USER u2@localhost IDENTIFIED BY 'abcd';
+CREATE USER u3@localhost IDENTIFIED BY 'abcd';
+# Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+# Avoid triggering delay
+SET @@global.connection_control_failed_connections_threshold = 100;
+
+# ----------------------------------------------------------------------
+
+connect(localhost,u1,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: NO)
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: YES)
+connect(localhost,u2,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u2'@'localhost' (using password: YES)
+# connection_control_failed_login_attempts should contain entries
+# for u1@localhost and u2@localhost
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+USERHOST       FAILED_ATTEMPTS
+'u1'@'localhost'       2
+'u2'@'localhost'       1
+connect(localhost,u3,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u3'@'localhost' (using password: NO)
+connect(localhost,u2,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u2'@'localhost' (using password: YES)
+connect(localhost,u3,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u3'@'localhost' (using password: YES)
+# connection_control_failed_login_attempts should contain entries
+# for u1@localhost, u2@localhost and u3@localhost
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+USERHOST       FAILED_ATTEMPTS
+'u1'@'localhost'       2
+'u2'@'localhost'       2
+'u3'@'localhost'       2
+connect(localhost,u2,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u2'@'localhost' (using password: NO)
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: YES)
+connect(localhost,u3,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u3'@'localhost' (using password: YES)
+# failed connection counts should have increased for all users
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+USERHOST       FAILED_ATTEMPTS
+'u1'@'localhost'       3
+'u2'@'localhost'       3
+'u3'@'localhost'       3
+connect(localhost,u2,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u2'@'localhost' (using password: NO)
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: YES)
+connect(localhost,u3,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u3'@'localhost' (using password: YES)
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: YES)
+connect(localhost,u3,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u3'@'localhost' (using password: YES)
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: YES)
+# Try various queries
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts
+WHERE USERHOST = '\'u1\'@\'localhost\'';
+USERHOST       FAILED_ATTEMPTS
+'u1'@'localhost'       6
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts
+WHERE USERHOST LIKE '%u2%';
+USERHOST       FAILED_ATTEMPTS
+'u2'@'localhost'       4
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts
+WHERE FAILED_ATTEMPTS > 4;
+USERHOST       FAILED_ATTEMPTS
+'u1'@'localhost'       6
+'u3'@'localhost'       5
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts
+WHERE FAILED_ATTEMPTS > 5;
+USERHOST       FAILED_ATTEMPTS
+'u1'@'localhost'       6
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts
+WHERE FAILED_ATTEMPTS < 5;
+USERHOST       FAILED_ATTEMPTS
+'u2'@'localhost'       4
+# After successful login, corresponding entry should disappear
+# from the view
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+USERHOST       FAILED_ATTEMPTS
+'u3'@'localhost'       5
+# A user without privileges should not be able to any information
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+USERHOST       FAILED_ATTEMPTS
+connect(localhost,u1,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: NO)
+connect(localhost,u3,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u3'@'localhost' (using password: YES)
+connect(localhost,u2,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u2'@'localhost' (using password: YES)
+# Subsequent failed attempts should put entries back in the view
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+USERHOST       FAILED_ATTEMPTS
+'u1'@'localhost'       1
+'u2'@'localhost'       1
+'u3'@'localhost'       1
+connect(localhost,u4,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u4'@'localhost' (using password: NO)
+connect(localhost,u5,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u5'@'localhost' (using password: YES)
+connect(localhost,u6,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u6'@'localhost' (using password: YES)
+# Attempts by invalid accounts should be shown in the view
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+USERHOST       FAILED_ATTEMPTS
+'u1'@'localhost'       1
+'u2'@'localhost'       1
+'u3'@'localhost'       1
+'u4'@'localhost'       1
+'u5'@'localhost'       1
+'u6'@'localhost'       1
+
+# ----------------------------------------------------------------------
+
+# Cleanup
+# Restore original values of conenction_control variables
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+# Remove user accounts created for the test
+DROP USER u1@localhost;
+DROP USER u2@localhost;
+DROP USER u3@localhost;
+# Uninstall connection_control plugin
+UNINSTALL PLUGIN connection_control;
+UNINSTALL PLUGIN connection_control_failed_login_attempts;
+
+# ----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_invalid_users.result b/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_invalid_users.result
new file mode 100644 (file)
index 0000000..ba4e346
--- /dev/null
@@ -0,0 +1,102 @@
+# Connection delay tests for valid user accounts
+
+# ----------------------------------------------------------------------
+
+# Setup
+# Install connection_control plugin
+INSTALL PLUGIN connection_control SONAME 'CONNECTION_CONTROL_LIB';
+INSTALL PLUGIN connection_control_failed_login_attempts SONAME 'CONNECTION_CONTROL_LIB';
+# Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+SET @saved_max_delay = @@global.connection_control_max_connection_delay;
+# Set small values for connection_control variables
+SET @@global.connection_control_failed_connections_threshold = 3;
+SET @@global.connection_control_max_connection_delay = 1000;
+
+# ----------------------------------------------------------------------
+
+# Following attempts will not experience any delay in server respose
+# Connection attempt should fail.
+Connection_control_delay_generated should be 0
+Variable_name  Value
+Connection_control_delay_generated     0
+# Connection attempt should fail.
+Connection_control_delay_generated should be 0
+Variable_name  Value
+Connection_control_delay_generated     0
+# Connection attempt should fail.
+Connection_control_delay_generated should be 0
+Variable_name  Value
+Connection_control_delay_generated     0
+# Connection attempt should fail.
+Connection_control_delay_generated should be 0
+Variable_name  Value
+Connection_control_delay_generated     0
+# Connection attempt should fail.
+Connection_control_delay_generated should be 0
+Variable_name  Value
+Connection_control_delay_generated     0
+# Connection attempt should fail.
+Connection_control_delay_generated should be 0
+Variable_name  Value
+Connection_control_delay_generated     0
+# Connection attempt should fail.
+Connection_control_delay_generated should be 0
+Variable_name  Value
+Connection_control_delay_generated     0
+# Connection attempt should fail.
+Connection_control_delay_generated should be 0
+Variable_name  Value
+Connection_control_delay_generated     0
+# Connection attempt should fail.
+Connection_control_delay_generated should be 0
+Variable_name  Value
+Connection_control_delay_generated     0
+
+# Following attempts will experience delay in server respose
+# Connection attempt should fail.
+Connection_control_delay_generated should be 1
+Variable_name  Value
+Connection_control_delay_generated     1
+# Connection attempt should fail.
+Connection_control_delay_generated should be 2
+Variable_name  Value
+Connection_control_delay_generated     2
+# Connection attempt should fail.
+Connection_control_delay_generated should be 3
+Variable_name  Value
+Connection_control_delay_generated     3
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+USERHOST       FAILED_ATTEMPTS
+'u1'@'localhost'       4
+'u2'@'localhost'       4
+'u3'@'localhost'       4
+# Connection attempt should fail.
+Connection_control_delay_generated should be 4
+Variable_name  Value
+Connection_control_delay_generated     4
+# Connection attempt should fail.
+Connection_control_delay_generated should be 5
+Variable_name  Value
+Connection_control_delay_generated     5
+# Connection attempt should fail.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+USERHOST       FAILED_ATTEMPTS
+'u1'@'localhost'       5
+'u2'@'localhost'       5
+'u3'@'localhost'       5
+
+# ----------------------------------------------------------------------
+
+# Cleanup
+# Restore original values of conenction_control variables
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+SET @@global.connection_control_max_connection_delay = @saved_max_delay;
+# Uninstall connection_control plugin
+UNINSTALL PLUGIN connection_control;
+UNINSTALL PLUGIN connection_control_failed_login_attempts;
+
+# ----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_min_max.result b/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_min_max.result
new file mode 100644 (file)
index 0000000..54783da
--- /dev/null
@@ -0,0 +1,82 @@
+# Connection delay tests for valid user accounts
+
+# ----------------------------------------------------------------------
+
+# Setup
+# Install connection_control plugin
+INSTALL PLUGIN connection_control SONAME 'CONNECTION_CONTROL_LIB';
+INSTALL PLUGIN connection_control_failed_login_attempts SONAME 'CONNECTION_CONTROL_LIB';
+# Create user account for testing
+CREATE USER u1 IDENTIFIED BY 'abcd';
+# Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+SET @saved_max_delay = @@global.connection_control_max_connection_delay;
+SET @saved_min_delay = @@global.connection_control_min_connection_delay;
+# Set small values for connection_control variables
+SET @@global.connection_control_failed_connections_threshold = 3;
+SET @@global.connection_control_max_connection_delay = 4000;
+SET @@global.connection_control_min_connection_delay = 2000;
+
+# ----------------------------------------------------------------------
+
+# Make enough failed attempts to trigger delays
+connect(localhost,u1,,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+
+# Following attempts will experience delay in server respose
+# Connection attempt should fail.
+Connection_control_delay_generated should be 1
+Variable_name  Value
+Connection_control_delay_generated     1
+@server_response_time >= 2
+1
+# Connection attempt should fail.
+Connection_control_delay_generated should be 2
+Variable_name  Value
+Connection_control_delay_generated     2
+@server_response_time >= 2
+1
+# Connection attempt should fail.
+Connection_control_delay_generated should be 3
+Variable_name  Value
+Connection_control_delay_generated     3
+@server_response_time >= 3
+1
+# Connection attempt should fail.
+Connection_control_delay_generated should be 4
+Variable_name  Value
+Connection_control_delay_generated     4
+@server_response_time >= 4
+1
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 5
+Variable_name  Value
+Connection_control_delay_generated     5
+@server_response_time >= 4
+1
+
+# Following attempts will not experience any delay in server respose
+# Connection attempt should fail.
+Connection_control_delay_generated should be 5
+Variable_name  Value
+Connection_control_delay_generated     5
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 5
+Variable_name  Value
+Connection_control_delay_generated     5
+
+# ----------------------------------------------------------------------
+
+# Cleanup
+# Restore original values of conenction_control variables
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+SET @@global.connection_control_max_connection_delay = @saved_max_delay;
+SET @@global.connection_control_min_connection_delay = @saved_min_delay;
+# Remove user account created for the test
+DROP USER u1;
+# Uninstall connection_control plugin
+UNINSTALL PLUGIN connection_control;
+UNINSTALL PLUGIN connection_control_failed_login_attempts;
+
+# ----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_proxy_users.result b/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_proxy_users.result
new file mode 100644 (file)
index 0000000..4ac930f
--- /dev/null
@@ -0,0 +1,97 @@
+#-----------------------------------------------------------------------
+# Setup
+# Install connection_control plugin
+INSTALL PLUGIN connection_control SONAME 'CONNECTION_CONTROL_LIB';
+INSTALL PLUGIN connection_control_failed_login_attempts SONAME 'CONNECTION_CONTROL_LIB';
+# Do proxy setup
+CALL mtr.add_suppression("Plugin test_plugin_server reported: 'Wrong password supplied for proxied'");
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+SET @saved_max_delay = @@global.connection_control_max_connection_delay;
+SET @saved_min_delay= @@global.connection_control_min_connection_delay;
+SET @@global.connection_control_failed_connections_threshold = 3;
+SET @@global.connection_control_max_connection_delay = 4000;
+SET @@global.connection_control_min_connection_delay = 2000;
+#-----------------------------------------------------------------------
+# Case 1 : Testss for valid user accounts
+# Make enough failed attempts to trigger delays
+connect(localhost,u1,,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u2,efgh,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u3,,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u2,haha,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u3,efgh,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u2,,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u3,efgh,test,MASTER_PORT,MASTER_SOCKET);
+# Following attempts will experience delay in server respose
+# Connection attempt should fail.
+Connection_control_delay_generated should be 1
+Variable_name  Value
+Connection_control_delay_generated     1
+@server_response_time >= 2
+1
+# Connection attempt should fail.
+Connection_control_delay_generated should be 2
+Variable_name  Value
+Connection_control_delay_generated     2
+@server_response_time >= 2
+1
+# Connection attempt should fail.
+Connection_control_delay_generated should be 3
+Variable_name  Value
+Connection_control_delay_generated     3
+@server_response_time >= 2
+1
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 4
+Variable_name  Value
+Connection_control_delay_generated     4
+@server_response_time >= 2
+1
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 5
+Variable_name  Value
+Connection_control_delay_generated     5
+@server_response_time >= 2
+1
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+@server_response_time >= 2
+1
+# Following attempts will not experience any delay in server respose
+# Connection attempt should fail.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+# Connection attempt should fail.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+# Connection attempt should fail.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+#-----------------------------------------------------------------------
+# Cleanup
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+SET @@global.connection_control_max_connection_delay = @saved_max_delay;
+SET @@global.connection_control_min_connection_delay = @saved_min_delay;
+# Remove user accounts
+# Uninstall connection_control plugin
+UNINSTALL PLUGIN connection_control;
+UNINSTALL PLUGIN connection_control_failed_login_attempts;
+#-----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_valid_users.result b/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/connection_delay_valid_users.result
new file mode 100644 (file)
index 0000000..1ab98a5
--- /dev/null
@@ -0,0 +1,114 @@
+# Connection delay tests for valid user accounts
+
+# ----------------------------------------------------------------------
+
+# Setup
+# Install connection_control plugin
+INSTALL PLUGIN connection_control SONAME 'CONNECTION_CONTROL_LIB';
+INSTALL PLUGIN connection_control_failed_login_attempts SONAME 'CONNECTION_CONTROL_LIB';
+# Create user accounts for testing
+CREATE USER u1 IDENTIFIED BY 'abcd';
+CREATE USER u2 IDENTIFIED BY 'abcd';
+CREATE USER u3 IDENTIFIED BY 'abcd';
+# Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+SET @saved_max_delay = @@global.connection_control_max_connection_delay;
+SET @saved_min_delay= @@global.connection_control_min_connection_delay;
+# Set small values for connection_control variables
+SET @@global.connection_control_failed_connections_threshold = 3;
+SET @@global.connection_control_max_connection_delay = 4000;
+SET @@global.connection_control_min_connection_delay = 2000;
+
+# ----------------------------------------------------------------------
+
+# Make enough failed attempts to trigger delays
+connect(localhost,u1,,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u2,efgh,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u3,,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u2,haha,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u3,efgh,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u2,,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+connect(localhost,u3,efgh,test,MASTER_PORT,MASTER_SOCKET);
+
+# Following attempts will experience delay in server respose
+# Connection attempt should fail.
+Connection_control_delay_generated should be 1
+Variable_name  Value
+Connection_control_delay_generated     1
+@server_response_time >= 2
+1
+# Connection attempt should fail.
+Connection_control_delay_generated should be 2
+Variable_name  Value
+Connection_control_delay_generated     2
+@server_response_time >= 2
+1
+# Connection attempt should fail.
+Connection_control_delay_generated should be 3
+Variable_name  Value
+Connection_control_delay_generated     3
+@server_response_time >= 2
+1
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 4
+Variable_name  Value
+Connection_control_delay_generated     4
+@server_response_time >= 2
+1
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 5
+Variable_name  Value
+Connection_control_delay_generated     5
+@server_response_time >= 2
+1
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+@server_response_time >= 2
+1
+
+# Following attempts will not experience any delay in server respose
+# Connection attempt should fail.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+# Connection attempt should fail.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+# Connection attempt should fail.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+# Connection attempt should succeed.
+Connection_control_delay_generated should be 6
+Variable_name  Value
+Connection_control_delay_generated     6
+
+# ----------------------------------------------------------------------
+
+# Cleanup
+# Restore original values of conenction_control variables
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+SET @@global.connection_control_max_connection_delay = @saved_max_delay;
+SET @@global.connection_control_min_connection_delay = @saved_min_delay;
+# Remove user accounts created for the test
+DROP USER u1;
+DROP USER u2;
+DROP USER u3;
+# Uninstall connection_control plugin
+UNINSTALL PLUGIN connection_control;
+UNINSTALL PLUGIN connection_control_failed_login_attempts;
+
+# ----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/status_variables.result b/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/status_variables.result
new file mode 100644 (file)
index 0000000..dd5cc67
--- /dev/null
@@ -0,0 +1,97 @@
+# Connection delay tests for valid user accounts
+
+# ----------------------------------------------------------------------
+
+# Setup
+# Install connection_control plugin
+INSTALL PLUGIN connection_control SONAME 'CONNECTION_CONTROL_LIB';
+INSTALL PLUGIN connection_control_failed_login_attempts SONAME 'CONNECTION_CONTROL_LIB';
+# Create user accounts for testing
+CREATE USER u1@localhost IDENTIFIED BY 'abcd';
+CREATE USER u2@localhost IDENTIFIED BY 'abcd';
+CREATE USER u3@localhost IDENTIFIED BY 'abcd';
+# Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+SET @saved_max_delay= @@global.connection_control_max_connection_delay;
+# Set small threshold
+SET @@global.connection_control_failed_connections_threshold = 1;
+# Set small max delay
+SET @@global.connection_control_max_connection_delay = 1000;
+
+# ----------------------------------------------------------------------
+
+connect(localhost,u1,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: NO)
+connect(localhost,u3,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u3'@'localhost' (using password: YES)
+connect(localhost,u2,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u2'@'localhost' (using password: YES)
+# Check  Connection_control_delay_generated - Should be 0
+SHOW STATUS LIKE 'Connection_control_delay_generated';
+Variable_name  Value
+Connection_control_delay_generated     0
+connect(localhost,u1,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: NO)
+connect(localhost,u2,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u2'@'localhost' (using password: YES)
+connect(localhost,u3,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u3'@'localhost' (using password: YES)
+connect(localhost,u2,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u2'@'localhost' (using password: NO)
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: YES)
+connect(localhost,u3,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u3'@'localhost' (using password: YES)
+# Check Connection_control_delay_generated - Should be 6
+SHOW STATUS LIKE 'Connection_control_delay_generated';
+Variable_name  Value
+Connection_control_delay_generated     6
+connect(localhost,u2,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u2'@'localhost' (using password: NO)
+connect(localhost,u1,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: YES)
+connect(localhost,u3,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u3'@'localhost' (using password: YES)
+# Check Connection_control_delay_generated - Should be 9
+SHOW STATUS LIKE 'Connection_control_delay_generated';
+Variable_name  Value
+Connection_control_delay_generated     9
+# Successful connection but delays would still be generated
+# Should be 12
+SHOW STATUS LIKE 'Connection_control_delay_generated';
+Variable_name  Value
+Connection_control_delay_generated     12
+# Setting failed connection threshold should reset delay statistics
+SET @@global.connection_control_failed_connections_threshold = 1;
+connect(localhost,u1,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: NO)
+connect(localhost,u3,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u3'@'localhost' (using password: YES)
+connect(localhost,u2,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u2'@'localhost' (using password: YES)
+connect(localhost,u1,,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u1'@'localhost' (using password: NO)
+connect(localhost,u3,haha,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u3'@'localhost' (using password: YES)
+connect(localhost,u2,efgh,test,MASTER_PORT,MASTER_SOCKET);
+ERROR 28000: Access denied for user 'u2'@'localhost' (using password: YES)
+# Check Connection_control_delay_generated - Should be 3
+SHOW STATUS LIKE 'Connection_control_delay_generated';
+Variable_name  Value
+Connection_control_delay_generated     3
+
+# ----------------------------------------------------------------------
+
+# Cleanup
+# Restore original values of conenction_control variables
+SET @@global.connection_control_max_connection_delay= @saved_max_delay;
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+# Remove user accounts created for the test
+DROP USER u1@localhost;
+DROP USER u2@localhost;
+DROP USER u3@localhost;
+# Uninstall connection_control plugin
+UNINSTALL PLUGIN connection_control;
+UNINSTALL PLUGIN connection_control_failed_login_attempts;
+
+# ----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/system_variables.result b/mysql-wsrep-5.6/mysql-test/suite/connection_control/r/system_variables.result
new file mode 100644 (file)
index 0000000..8c91262
--- /dev/null
@@ -0,0 +1,290 @@
+#-----------------------------------------------------------------------
+# Setup
+# Install connection_control plugin
+INSTALL PLUGIN connection_control SONAME 'CONNECTION_CONTROL_LIB';
+INSTALL PLUGIN connection_control_failed_login_attempts SONAME 'CONNECTION_CONTROL_LIB';
+CREATE USER no_privs@localhost IDENTIFIED BY 'abcd';
+#-----------------------------------------------------------------------
+# Case 1 : connection_control_failed_connections_threshold
+SHOW GRANTS;
+Grants for root@localhost
+GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION
+GRANT PROXY ON ''@'' TO 'root'@'localhost' WITH GRANT OPTION
+SET @saved_value = @@global.connection_control_failed_connections_threshold;
+SELECT @saved_value;
+@saved_value
+3
+SET @@global.connection_control_failed_connections_threshold = @saved_value;
+# 1.1 : Setting connection_control_failed_connections_threshold to valid
+#       value
+SET @@global.connection_control_failed_connections_threshold = 20;
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+20
+SET @@global.connection_control_failed_connections_threshold = 2000;
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+2000
+SET @@global.connection_control_failed_connections_threshold = 2147483647;
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+2147483647
+SET @@global.connection_control_failed_connections_threshold = DEFAULT;
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+3
+# 1.2 : Setting connection_control_failed_connections_threshold to
+#       invalid value
+SET @@global.connection_control_failed_connections_threshold = NULL;
+ERROR 42000: Incorrect argument type to variable 'connection_control_failed_connections_threshold'
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+3
+SET @@global.connection_control_failed_connections_threshold = `SELECT * FROM mysql.user`;
+ERROR 42000: Incorrect argument type to variable 'connection_control_failed_connections_threshold'
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+3
+SET @@global.connection_control_failed_connections_threshold = -20;
+ERROR 42000: Variable 'connection_control_failed_connections_threshold' can't be set to the value of '-20'
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+3
+SET @@global.connection_control_failed_connections_threshold = 9223372036854775808;
+ERROR 42000: Variable 'connection_control_failed_connections_threshold' can't be set to the value of '9223372036854775808'
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+3
+SET @@global.connection_control_failed_connections_threshold = -9223372036854775808;
+ERROR 42000: Variable 'connection_control_failed_connections_threshold' can't be set to the value of '-9223372036854775808'
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+3
+# Switch to conn_no_privs
+# 1.3 : Use no_privs@localhost to set
+#       connection_control_failed_connections_threshold to valid value
+SET @@global.connection_control_failed_connections_threshold = 2147483647;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+3
+SET @@global.connection_control_failed_connections_threshold = DEFAULT;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+3
+# 1.4 : Use no_privs@localhost to set
+#       connection_control_failed_connections_threshold to invalid value
+SET @@global.connection_control_failed_connections_threshold = NULL;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+3
+SET @@global.connection_control_failed_connections_threshold = 9223372036854775808;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+3
+SET @@global.connection_control_failed_connections_threshold = @saved_value;
+SELECT @@global.connection_control_failed_connections_threshold;
+@@global.connection_control_failed_connections_threshold
+3
+#-----------------------------------------------------------------------
+# Case 2 : connection_control_min_connection_delay
+SET @saved_value= @@global.connection_control_min_connection_delay;
+SELECT @saved_value;
+@saved_value
+1000
+# 2.1 : Setting connection_control_min_connection_delay to valid
+#       value
+SET @@global.connection_control_min_connection_delay = 20000;
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+20000
+SET @@global.connection_control_min_connection_delay = 2000;
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+2000
+SET @@global.connection_control_min_connection_delay = 2147483647;
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+2147483647
+SET @@global.connection_control_min_connection_delay = DEFAULT;
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+# 2.2 : Setting connection_control_min_connection_delay to
+#       invalid value
+SET @@global.connection_control_min_connection_delay = NULL;
+ERROR 42000: Incorrect argument type to variable 'connection_control_min_connection_delay'
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+SET @@global.connection_control_min_connection_delay = `SELECT * FROM mysql.user`;
+ERROR 42000: Incorrect argument type to variable 'connection_control_min_connection_delay'
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+SET @@global.connection_control_min_connection_delay = -20;
+ERROR 42000: Variable 'connection_control_min_connection_delay' can't be set to the value of '-20'
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+SET @@global.connection_control_min_connection_delay = 9223372036854775808;
+ERROR 42000: Variable 'connection_control_min_connection_delay' can't be set to the value of '9223372036854775808'
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+SET @@global.connection_control_min_connection_delay = -9223372036854775808;
+ERROR 42000: Variable 'connection_control_min_connection_delay' can't be set to the value of '-9223372036854775808'
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+SET@@global.connection_control_min_connection_delay = 20;
+ERROR 42000: Variable 'connection_control_min_connection_delay' can't be set to the value of '20'
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+# Switch to conn_no_privs
+# 2.3 : Use no_privs@localhost to set
+#       connection_control_min_connection_delay to valid value
+SET @@global.connection_control_min_connection_delay = 2147483647;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+SET @@global.connection_control_min_connection_delay = DEFAULT;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+# 2.4 : Use no_privs@localhost to set
+#       connection_control_min_connection_delay to invalid value
+SET @@global.connection_control_min_connection_delay = NULL;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+SET @@global.connection_control_min_connection_delay = 9223372036854775808;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+# Switch to default connection
+# 2.5 : Setting connection_control_min_connection_delay to a value
+#       greater than connection_control_max_connection_delay
+SET @saved_max_delay= @@global.connection_control_max_connection_delay;
+SET @@global.connection_control_max_connection_delay= 10000;
+SET @@global.connection_control_min_connection_delay= 11000;
+ERROR 42000: Variable 'connection_control_min_connection_delay' can't be set to the value of '11000'
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+SET @@global.connection_control_max_connection_delay= @saved_max_delay;
+SET @@global.connection_control_min_connection_delay = @saved_value;
+SELECT @@global.connection_control_min_connection_delay;
+@@global.connection_control_min_connection_delay
+1000
+#-----------------------------------------------------------------------
+# Case 3 : connection_control_max_connection_delay
+SET @saved_value= @@global.connection_control_max_connection_delay;
+SELECT @saved_value;
+@saved_value
+2147483647
+# 3.1 : Setting connection_control_max_connection_delay to valid
+#       value
+SET @@global.connection_control_max_connection_delay = 20000;
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+20000
+SET @@global.connection_control_max_connection_delay = 2000;
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2000
+SET @@global.connection_control_max_connection_delay = 2147483647;
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+SET @@global.connection_control_max_connection_delay = DEFAULT;
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+# 3.2 : Setting connection_control_max_connection_delay to
+#       invalid value
+SET @@global.connection_control_max_connection_delay = NULL;
+ERROR 42000: Incorrect argument type to variable 'connection_control_max_connection_delay'
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+SET @@global.connection_control_max_connection_delay = `SELECT * FROM mysql.user`;
+ERROR 42000: Incorrect argument type to variable 'connection_control_max_connection_delay'
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+SET @@global.connection_control_max_connection_delay = -20;
+ERROR 42000: Variable 'connection_control_max_connection_delay' can't be set to the value of '-20'
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+SET @@global.connection_control_max_connection_delay = 9223372036854775808;
+ERROR 42000: Variable 'connection_control_max_connection_delay' can't be set to the value of '9223372036854775808'
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+SET @@global.connection_control_max_connection_delay = -9223372036854775808;
+ERROR 42000: Variable 'connection_control_max_connection_delay' can't be set to the value of '-9223372036854775808'
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+SET @@global.connection_control_max_connection_delay = 20;
+ERROR 42000: Variable 'connection_control_max_connection_delay' can't be set to the value of '20'
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+# Switch to conn_no_privs
+# 3.3 : Use no_privs@localhost to set
+#       connection_control_max_connection_delay to valid value
+SET @@global.connection_control_max_connection_delay = 2147483647;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+SET @@global.connection_control_max_connection_delay = DEFAULT;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+# 3.4 : Use no_privs@localhost to set
+#       connection_control_max_connection_delay to invalid value
+SET @@global.connection_control_max_connection_delay = NULL;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+SET @@global.connection_control_max_connection_delay = 9223372036854775808;
+ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) for this operation
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+# Switch to default connection
+# 3.5 : Setting connection_control_min_connection_delay to a value
+#       greater than connection_control_max_connection_delay
+SET @saved_min_delay= @@global.connection_control_min_connection_delay;
+SET @@global.connection_control_min_connection_delay= 11000;
+SET @@global.connection_control_max_connection_delay= 10000;
+ERROR 42000: Variable 'connection_control_max_connection_delay' can't be set to the value of '10000'
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+SET @@global.connection_control_min_connection_delay= @saved_min_delay;
+SET @@global.connection_control_max_connection_delay = @saved_value;
+SELECT @@global.connection_control_max_connection_delay;
+@@global.connection_control_max_connection_delay
+2147483647
+#-----------------------------------------------------------------------
+# Cleanup
+DROP USER no_privs@localhost;
+# Uninstall connection_control plugin
+UNINSTALL PLUGIN connection_control;
+UNINSTALL PLUGIN connection_control_failed_login_attempts;
+#-----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_anonymous_user-master.opt b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_anonymous_user-master.opt
new file mode 100644 (file)
index 0000000..f12184b
--- /dev/null
@@ -0,0 +1 @@
+$CONNECTION_CONTROL_PLUGIN_OPT
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_anonymous_user.test b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_anonymous_user.test
new file mode 100644 (file)
index 0000000..0d84d00
--- /dev/null
@@ -0,0 +1,101 @@
+# Skip the test in embedded mode
+--source include/not_embedded.inc
+
+# Make sure that connection_control plugin can be loaded
+--source ../inc/have_connection_control_plugin.inc
+
+# Save the initial number of concurrent sessions
+--source include/count_sessions.inc
+
+--echo # Connection delay tests for valid user accounts
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Setup
+--echo # Install connection_control plugin
+--source ../inc/install_connection_control_plugin.inc
+
+--echo # Create anonymous user
+CREATE USER ''@'localhost';
+
+--echo # Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+SET @saved_max_delay = @@global.connection_control_max_connection_delay;
+
+-- echo # Set small values for connection_control variables
+SET @@global.connection_control_failed_connections_threshold = 3;
+SET @global.connection_control_max_connection_delay = 1000;
+
+# We don't need to use client side authentication plugin for this test.
+let $USE_AUTH_PLUGIN= 0;
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Following attempts will not experience any delay in server respose
+
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=0;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u2;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=0;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u3;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=0;
+--source ../inc/check_connection_delay.inc
+
+--echo
+--echo # Following attempts will experience delay in server respose
+
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=1;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u2;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=2;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u3;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=3;
+--source ../inc/check_connection_delay.inc
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Cleanup
+
+connection default;
+
+--echo # Restore original values of conenction_control variables
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+SET @@global.connection_control_max_connection_delay = @saved_max_delay;
+
+--echo # Drop anonymous user
+DROP USER ''@'localhost';
+
+--echo # Uninstall connection_control plugin
+--source ../inc/uninstall_connection_control_plugin.inc
+
+# Wait till all disconnects are completed.
+--source include/wait_until_count_sessions.inc
+
+--echo
+--echo # ----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_info_schema_view-master.opt b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_info_schema_view-master.opt
new file mode 100644 (file)
index 0000000..f12184b
--- /dev/null
@@ -0,0 +1 @@
+$CONNECTION_CONTROL_PLUGIN_OPT
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_info_schema_view.test b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_info_schema_view.test
new file mode 100644 (file)
index 0000000..0f8c3f9
--- /dev/null
@@ -0,0 +1,198 @@
+# Skip the test in embedded mode
+--source include/not_embedded.inc
+
+# Make sure that connection_control plugin can be loaded
+--source ../inc/have_connection_control_plugin.inc
+
+# Save the initial number of concurrent sessions
+--source include/count_sessions.inc
+
+--echo # Connection delay tests for valid user accounts
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Setup
+--echo # Install connection_control plugin
+--source ../inc/install_connection_control_plugin.inc
+
+--echo # Create user accounts for testing
+CREATE USER u1@localhost IDENTIFIED BY 'abcd';
+CREATE USER u2@localhost IDENTIFIED BY 'abcd';
+CREATE USER u3@localhost IDENTIFIED BY 'abcd';
+
+--echo # Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+
+-- echo # Avoid triggering delay
+SET @@global.connection_control_failed_connections_threshold = 100;
+
+# We don't need to use client side authentication plugin for this test.
+let $USE_AUTH_PLUGIN= 0;
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,efgh,,,,);
+
+-- echo # connection_control_failed_login_attempts should contain entries
+-- echo # for u1@localhost and u2@localhost
+
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,efgh,,,,);
+
+-- echo # connection_control_failed_login_attempts should contain entries
+-- echo # for u1@localhost, u2@localhost and u3@localhost
+
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,efgh,,,,);
+
+-- echo # failed connection counts should have increased for all users
+
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,efgh,,,,);
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,efgh,,,,);
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+
+-- echo # Try various queries
+
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts
+  WHERE USERHOST = '\'u1\'@\'localhost\'';
+  
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts
+  WHERE USERHOST LIKE '%u2%';
+
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts
+  WHERE FAILED_ATTEMPTS > 4;
+
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts
+  WHERE FAILED_ATTEMPTS > 5;
+
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts
+  WHERE FAILED_ATTEMPTS < 5;
+  
+connect(con_u1, localhost, u1,abcd,,,,);
+connect(con_u2, localhost, u2,abcd,,,,);
+connection default;
+--disconnect con_u1
+--disconnect con_u2
+
+--echo # After successful login, corresponding entry should disappear
+--echo # from the view
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+
+connect(con_u3, localhost, u3,abcd,,,,);
+--echo # A user without privileges should not be able to any information
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+
+connection default;
+--disconnect con_u3
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,efgh,,,,);
+
+-- echo # Subsequent failed attempts should put entries back in the view
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u4, localhost, u4,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u5, localhost, u5,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u6, localhost, u6,efgh,,,,);
+
+-- echo # Attempts by invalid accounts should be shown in the view
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Cleanup
+
+connection default;
+
+--echo # Restore original values of conenction_control variables
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+
+--echo # Remove user accounts created for the test
+DROP USER u1@localhost;
+DROP USER u2@localhost;
+DROP USER u3@localhost;
+
+--echo # Uninstall connection_control plugin
+--source ../inc/uninstall_connection_control_plugin.inc
+
+# Wait till all disconnects are completed.
+--source include/wait_until_count_sessions.inc
+
+--echo
+--echo # ----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_invalid_users-master.opt b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_invalid_users-master.opt
new file mode 100644 (file)
index 0000000..f12184b
--- /dev/null
@@ -0,0 +1 @@
+$CONNECTION_CONTROL_PLUGIN_OPT
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_invalid_users.test b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_invalid_users.test
new file mode 100644 (file)
index 0000000..f0933c0
--- /dev/null
@@ -0,0 +1,156 @@
+# Skip the test in embedded mode
+--source include/not_embedded.inc
+
+# Make sure that connection_control plugin can be loaded
+--source ../inc/have_connection_control_plugin.inc
+
+# Save the initial number of concurrent sessions
+--source include/count_sessions.inc
+
+--echo # Connection delay tests for valid user accounts
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Setup
+--echo # Install connection_control plugin
+--source ../inc/install_connection_control_plugin.inc
+
+--echo # Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+SET @saved_max_delay = @@global.connection_control_max_connection_delay;
+
+-- echo # Set small values for connection_control variables
+SET @@global.connection_control_failed_connections_threshold = 3;
+SET @@global.connection_control_max_connection_delay = 1000;
+
+# We don't need to use client side authentication plugin for this test.
+let $USE_AUTH_PLUGIN= 0;
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Following attempts will not experience any delay in server respose
+
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=0;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u2;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=0;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u3;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=0;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=0;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u2;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=0;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u3;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=0;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=0;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u2;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=0;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u3;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=0;
+--source ../inc/check_connection_delay.inc
+
+--echo
+--echo # Following attempts will experience delay in server respose
+
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=1;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u2;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=2;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u3;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=3;
+--source ../inc/check_connection_delay.inc
+
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+
+let $USER=u3;
+let $PASSWORD=abcd;
+let $SUCCESS=0;
+let $DELAY_STATS=4;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u2;
+let $PASSWORD=abcd;
+let $SUCCESS=0;
+let $DELAY_STATS=5;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u1;
+let $PASSWORD=abcd;
+let $SUCCESS=0;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+--sorted_result
+SELECT * FROM INFORMATION_SCHEMA.connection_control_failed_login_attempts;
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Cleanup
+
+connection default;
+
+--echo # Restore original values of conenction_control variables
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+SET @@global.connection_control_max_connection_delay = @saved_max_delay;
+
+
+--echo # Uninstall connection_control plugin
+--source ../inc/uninstall_connection_control_plugin.inc
+
+# Wait till all disconnects are completed.
+--source include/wait_until_count_sessions.inc
+
+--echo
+--echo # ----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_min_max-master.opt b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_min_max-master.opt
new file mode 100644 (file)
index 0000000..f12184b
--- /dev/null
@@ -0,0 +1 @@
+$CONNECTION_CONTROL_PLUGIN_OPT
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_min_max.test b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_min_max.test
new file mode 100644 (file)
index 0000000..40bb0f3
--- /dev/null
@@ -0,0 +1,152 @@
+# Skip the test in embedded mode
+--source include/not_embedded.inc
+
+# Make sure that connection_control plugin can be loaded
+--source ../inc/have_connection_control_plugin.inc
+
+# Save the initial number of concurrent sessions
+--source include/count_sessions.inc
+
+--echo # Connection delay tests for valid user accounts
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Setup
+--echo # Install connection_control plugin
+--source ../inc/install_connection_control_plugin.inc
+
+--echo # Create user account for testing
+CREATE USER u1 IDENTIFIED BY 'abcd';
+
+--echo # Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+SET @saved_max_delay = @@global.connection_control_max_connection_delay;
+SET @saved_min_delay = @@global.connection_control_min_connection_delay;
+
+-- echo # Set small values for connection_control variables
+SET @@global.connection_control_failed_connections_threshold = 3;
+SET @@global.connection_control_max_connection_delay = 4000;
+SET @@global.connection_control_min_connection_delay = 2000;
+
+# We don't need to use client side authentication plugin for this test.
+let $USE_AUTH_PLUGIN= 0;
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Make enough failed attempts to trigger delays
+
+disable_result_log;
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+
+enable_result_log;
+
+--echo
+--echo # Following attempts will experience delay in server respose
+
+# Trying with invalid passwords
+
+--source ../inc/set_before_marker.inc
+
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=1;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+--source ../inc/set_before_marker.inc
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=2;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+--source ../inc/set_before_marker.inc
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=3;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 3;
+--source ../inc/set_after_marker.inc
+
+--source ../inc/set_before_marker.inc
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=4;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 4;
+--source ../inc/set_after_marker.inc
+
+# Trying with valid passwords
+
+--source ../inc/set_before_marker.inc
+let $USER=u1;
+let $PASSWORD=abcd;
+let $SUCCESS=1;
+let $DELAY_STATS=5;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 4;
+--source ../inc/set_after_marker.inc
+
+--echo
+--echo # Following attempts will not experience any delay in server respose
+
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=5;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u1;
+let $PASSWORD=abcd;
+let $SUCCESS=1;
+let $DELAY_STATS=5;
+--source ../inc/check_connection_delay.inc
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Cleanup
+
+connection default;
+
+--echo # Restore original values of conenction_control variables
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+SET @@global.connection_control_max_connection_delay = @saved_max_delay;
+SET @@global.connection_control_min_connection_delay = @saved_min_delay;
+
+--echo # Remove user account created for the test
+DROP USER u1;
+
+--echo # Uninstall connection_control plugin
+--source ../inc/uninstall_connection_control_plugin.inc
+
+# Wait till all disconnects are completed.
+--source include/wait_until_count_sessions.inc
+
+--echo
+--echo # ----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_proxy_users-master.opt b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_proxy_users-master.opt
new file mode 100644 (file)
index 0000000..f12184b
--- /dev/null
@@ -0,0 +1 @@
+$CONNECTION_CONTROL_PLUGIN_OPT
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_proxy_users.test b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_proxy_users.test
new file mode 100644 (file)
index 0000000..77b6e1e
--- /dev/null
@@ -0,0 +1,203 @@
+# Skip the test in embedded mode
+--source include/not_embedded.inc
+
+# Make sure that connection_control plugin can be loaded
+--source ../inc/have_connection_control_plugin.inc
+--source ../inc/have_test_plugin.inc
+
+# Save the initial number of concurrent sessions
+--source include/count_sessions.inc
+
+--echo #-----------------------------------------------------------------------
+--echo # Setup
+--echo # Install connection_control plugin
+--source ../inc/install_connection_control_plugin.inc
+--echo # Do proxy setup
+--source ../inc/setup_proxy_accounts.inc
+
+# Suppress error messages from test_plugin_server
+CALL mtr.add_suppression("Plugin test_plugin_server reported: 'Wrong password supplied for proxied'");
+
+# Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+SET @saved_max_delay = @@global.connection_control_max_connection_delay;
+SET @saved_min_delay= @@global.connection_control_min_connection_delay;
+
+# Set a small values for connection_control variables
+SET @@global.connection_control_failed_connections_threshold = 3;
+SET @@global.connection_control_max_connection_delay = 4000;
+SET @@global.connection_control_min_connection_delay = 2000;
+
+# We will use client side authentication plugin for this test.
+let $USE_AUTH_PLUGIN= 1;
+let $CLIENT_AUTH_PLUGIN= $PLUGIN_AUTH_OPT;
+
+--echo #-----------------------------------------------------------------------
+
+--echo # Case 1 : Testss for valid user accounts
+
+--echo # Make enough failed attempts to trigger delays
+
+disable_result_log;
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u2,efgh,,,,);
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u3,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u2,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u3,efgh,,,,);
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u2,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u3,efgh,,,,);
+
+enable_result_log;
+
+--echo # Following attempts will experience delay in server respose
+
+# Trying with invalid passwords
+
+--source ../inc/set_before_marker.inc
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=1;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+--source ../inc/set_before_marker.inc
+let $USER=u2;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=2;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+--source ../inc/set_before_marker.inc
+let $USER=u3;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=3;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+# Trying with valid passwords
+# Even though u1@localhost, u2@localhost and u3@localhost are
+# proxying same user - proxied@localhost, we will not use
+# proxied@localohst for recording failed attempts information.
+# Rather, we will rely on proxying users' data.
+# So each of the following should get delay of 2 seconds
+# or more.
+
+--source ../inc/set_before_marker.inc
+let $USER=u3;
+let $PASSWORD=proxied;
+let $SUCCESS=1;
+let $DELAY_STATS=4;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+--source ../inc/set_before_marker.inc
+let $USER=u2;
+let $PASSWORD=proxied;
+let $SUCCESS=1;
+let $DELAY_STATS=5;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+--source ../inc/set_before_marker.inc
+let $USER=u1;
+let $PASSWORD=proxied;
+let $SUCCESS=1;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+
+--echo # Following attempts will not experience any delay in server respose
+
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u2;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u3;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u1;
+let $PASSWORD=proxied;
+let $SUCCESS=1;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u2;
+let $PASSWORD=proxied;
+let $SUCCESS=1;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u3;
+let $PASSWORD=proxied;
+let $SUCCESS=1;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+--echo #-----------------------------------------------------------------------
+--echo # Cleanup
+
+connection default;
+
+# Restore original values of conenction_control variables
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+SET @@global.connection_control_max_connection_delay = @saved_max_delay;
+SET @@global.connection_control_min_connection_delay = @saved_min_delay;
+
+--echo # Remove user accounts
+--source ../inc/cleanup_proxy_accounts.inc
+--echo # Uninstall connection_control plugin
+--source ../inc/uninstall_connection_control_plugin.inc
+
+# Wait till all disconnects are completed.
+--source include/wait_until_count_sessions.inc
+--echo #-----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_valid_users-master.opt b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_valid_users-master.opt
new file mode 100644 (file)
index 0000000..f12184b
--- /dev/null
@@ -0,0 +1 @@
+$CONNECTION_CONTROL_PLUGIN_OPT
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_valid_users.test b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/connection_delay_valid_users.test
new file mode 100644 (file)
index 0000000..ded7c18
--- /dev/null
@@ -0,0 +1,209 @@
+# Skip the test in embedded mode
+--source include/not_embedded.inc
+
+# Make sure that connection_control plugin can be loaded
+--source ../inc/have_connection_control_plugin.inc
+
+# Save the initial number of concurrent sessions
+--source include/count_sessions.inc
+
+--echo # Connection delay tests for valid user accounts
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Setup
+--echo # Install connection_control plugin
+--source ../inc/install_connection_control_plugin.inc
+
+--echo # Create user accounts for testing
+CREATE USER u1 IDENTIFIED BY 'abcd';
+CREATE USER u2 IDENTIFIED BY 'abcd';
+CREATE USER u3 IDENTIFIED BY 'abcd';
+
+--echo # Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+SET @saved_max_delay = @@global.connection_control_max_connection_delay;
+SET @saved_min_delay= @@global.connection_control_min_connection_delay;
+
+-- echo # Set small values for connection_control variables
+SET @@global.connection_control_failed_connections_threshold = 3;
+SET @@global.connection_control_max_connection_delay = 4000;
+SET @@global.connection_control_min_connection_delay = 2000;
+
+# We don't need to use client side authentication plugin for this test.
+let $USE_AUTH_PLUGIN= 0;
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Make enough failed attempts to trigger delays
+
+disable_result_log;
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,efgh,,,,);
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,efgh,,,,);
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,efgh,,,,);
+
+enable_result_log;
+
+--echo
+--echo # Following attempts will experience delay in server respose
+
+# Trying with invalid passwords
+
+--source ../inc/set_before_marker.inc
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=1;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+--source ../inc/set_before_marker.inc
+let $USER=u2;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=2;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+--source ../inc/set_before_marker.inc
+let $USER=u3;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=3;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+# Trying with valid passwords
+
+--source ../inc/set_before_marker.inc
+let $USER=u3;
+let $PASSWORD=abcd;
+let $SUCCESS=1;
+let $DELAY_STATS=4;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+--source ../inc/set_before_marker.inc
+let $USER=u2;
+let $PASSWORD=abcd;
+let $SUCCESS=1;
+let $DELAY_STATS=5;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+--source ../inc/set_before_marker.inc
+let $USER=u1;
+let $PASSWORD=abcd;
+let $SUCCESS=1;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+let $SERVER_RESPONSE_TIME= 2;
+--source ../inc/set_after_marker.inc
+
+--echo
+--echo # Following attempts will not experience any delay in server respose
+
+let $USER=u1;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u2;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u3;
+let $PASSWORD=hoho;
+let $SUCCESS=0;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u1;
+let $PASSWORD=abcd;
+let $SUCCESS=1;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u2;
+let $PASSWORD=abcd;
+let $SUCCESS=1;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+let $USER=u3;
+let $PASSWORD=abcd;
+let $SUCCESS=1;
+let $DELAY_STATS=6;
+--source ../inc/check_connection_delay.inc
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Cleanup
+
+connection default;
+
+--echo # Restore original values of conenction_control variables
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+SET @@global.connection_control_max_connection_delay = @saved_max_delay;
+SET @@global.connection_control_min_connection_delay = @saved_min_delay;
+
+--echo # Remove user accounts created for the test
+DROP USER u1;
+DROP USER u2;
+DROP USER u3;
+
+--echo # Uninstall connection_control plugin
+--source ../inc/uninstall_connection_control_plugin.inc
+
+# Wait till all disconnects are completed.
+--source include/wait_until_count_sessions.inc
+
+--echo
+--echo # ----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/status_variables-master.opt b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/status_variables-master.opt
new file mode 100644 (file)
index 0000000..f12184b
--- /dev/null
@@ -0,0 +1 @@
+$CONNECTION_CONTROL_PLUGIN_OPT
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/status_variables.test b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/status_variables.test
new file mode 100644 (file)
index 0000000..f3f3ad0
--- /dev/null
@@ -0,0 +1,152 @@
+# Skip the test in embedded mode
+--source include/not_embedded.inc
+
+# Make sure that connection_control plugin can be loaded
+--source ../inc/have_connection_control_plugin.inc
+
+# Save the initial number of concurrent sessions
+--source include/count_sessions.inc
+
+--echo # Connection delay tests for valid user accounts
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Setup
+--echo # Install connection_control plugin
+--source ../inc/install_connection_control_plugin.inc
+
+--echo # Create user accounts for testing
+CREATE USER u1@localhost IDENTIFIED BY 'abcd';
+CREATE USER u2@localhost IDENTIFIED BY 'abcd';
+CREATE USER u3@localhost IDENTIFIED BY 'abcd';
+
+--echo # Save original values of connection_control variables
+SET @saved_connections_threshold = @@global.connection_control_failed_connections_threshold;
+SET @saved_max_delay= @@global.connection_control_max_connection_delay;
+
+-- echo # Set small threshold
+SET @@global.connection_control_failed_connections_threshold = 1;
+-- echo # Set small max delay
+SET @@global.connection_control_max_connection_delay = 1000;
+
+# We don't need to use client side authentication plugin for this test.
+let $USE_AUTH_PLUGIN= 0;
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,efgh,,,,);
+
+--echo # Check  Connection_control_delay_generated - Should be 0
+SHOW STATUS LIKE 'Connection_control_delay_generated';
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,efgh,,,,);
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,efgh,,,,);
+
+--echo # Check Connection_control_delay_generated - Should be 6
+SHOW STATUS LIKE 'Connection_control_delay_generated';
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,efgh,,,,);
+
+--echo # Check Connection_control_delay_generated - Should be 9
+SHOW STATUS LIKE 'Connection_control_delay_generated';
+
+connect(con_u1, localhost, u1,abcd,,,,);
+connect(con_u2, localhost, u2,abcd,,,,);
+connect(con_u3, localhost, u3,abcd,,,,);
+connection default;
+--disconnect con_u1
+--disconnect con_u2
+--disconnect con_u3
+
+--echo # Successful connection but delays would still be generated
+--echo # Should be 12
+SHOW STATUS LIKE 'Connection_control_delay_generated';
+
+--echo # Setting failed connection threshold should reset delay statistics
+SET @@global.connection_control_failed_connections_threshold = 1;
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,efgh,,,,);
+
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u1, localhost, u1,,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u3, localhost, u3,haha,,,,);
+--replace_result $MASTER_MYSOCK MASTER_SOCKET $MASTER_MYPORT MASTER_PORT
+--error ER_ACCESS_DENIED_ERROR
+connect(fail_con_u2, localhost, u2,efgh,,,,);
+
+--echo # Check Connection_control_delay_generated - Should be 3
+SHOW STATUS LIKE 'Connection_control_delay_generated';
+
+--echo
+--echo # ----------------------------------------------------------------------
+--echo
+
+--echo # Cleanup
+
+connection default;
+
+--echo # Restore original values of conenction_control variables
+SET @@global.connection_control_max_connection_delay= @saved_max_delay;
+SET @@global.connection_control_failed_connections_threshold = @saved_connections_threshold;
+
+--echo # Remove user accounts created for the test
+DROP USER u1@localhost;
+DROP USER u2@localhost;
+DROP USER u3@localhost;
+
+--echo # Uninstall connection_control plugin
+--source ../inc/uninstall_connection_control_plugin.inc
+
+# Wait till all disconnects are completed.
+--source include/wait_until_count_sessions.inc
+
+--echo
+--echo # ----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/system_variables-master.opt b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/system_variables-master.opt
new file mode 100644 (file)
index 0000000..f12184b
--- /dev/null
@@ -0,0 +1 @@
+$CONNECTION_CONTROL_PLUGIN_OPT
diff --git a/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/system_variables.test b/mysql-wsrep-5.6/mysql-test/suite/connection_control/t/system_variables.test
new file mode 100644 (file)
index 0000000..b83e4d7
--- /dev/null
@@ -0,0 +1,281 @@
+# Skip the test in embedded mode
+--source include/not_embedded.inc
+
+# Make sure that connection_control plugin can be loaded
+--source ../inc/have_connection_control_plugin.inc
+
+# Save the initial number of concurrent sessions
+--source include/count_sessions.inc
+
+--echo #-----------------------------------------------------------------------
+--echo # Setup
+--echo # Install connection_control plugin
+--source ../inc/install_connection_control_plugin.inc
+CREATE USER no_privs@localhost IDENTIFIED BY 'abcd';
+connect(conn_no_privs, localhost, no_privs, abcd,,,,);
+connection default;
+--echo #-----------------------------------------------------------------------
+
+--echo # Case 1 : connection_control_failed_connections_threshold
+SHOW GRANTS;
+SET @saved_value = @@global.connection_control_failed_connections_threshold;
+SELECT @saved_value;
+SET @@global.connection_control_failed_connections_threshold = @saved_value;
+
+--echo # 1.1 : Setting connection_control_failed_connections_threshold to valid
+--echo #       value
+
+SET @@global.connection_control_failed_connections_threshold = 20;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+SET @@global.connection_control_failed_connections_threshold = 2000;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+SET @@global.connection_control_failed_connections_threshold = 2147483647;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+SET @@global.connection_control_failed_connections_threshold = DEFAULT;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+--echo # 1.2 : Setting connection_control_failed_connections_threshold to
+--echo #       invalid value
+
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.connection_control_failed_connections_threshold = NULL;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.connection_control_failed_connections_threshold = `SELECT * FROM mysql.user`;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.connection_control_failed_connections_threshold = -20;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.connection_control_failed_connections_threshold = 9223372036854775808;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.connection_control_failed_connections_threshold = -9223372036854775808;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+--echo # Switch to conn_no_privs
+connection conn_no_privs;
+--echo # 1.3 : Use no_privs@localhost to set
+--echo #       connection_control_failed_connections_threshold to valid value
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET @@global.connection_control_failed_connections_threshold = 2147483647;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET @@global.connection_control_failed_connections_threshold = DEFAULT;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+--echo # 1.4 : Use no_privs@localhost to set
+--echo #       connection_control_failed_connections_threshold to invalid value
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET @@global.connection_control_failed_connections_threshold = NULL;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET @@global.connection_control_failed_connections_threshold = 9223372036854775808;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+connection default;
+
+SET @@global.connection_control_failed_connections_threshold = @saved_value;
+SELECT @@global.connection_control_failed_connections_threshold;
+
+--echo #-----------------------------------------------------------------------
+
+--echo # Case 2 : connection_control_min_connection_delay
+
+SET @saved_value= @@global.connection_control_min_connection_delay;
+SELECT @saved_value;
+
+--echo # 2.1 : Setting connection_control_min_connection_delay to valid
+--echo #       value
+
+SET @@global.connection_control_min_connection_delay = 20000;
+SELECT @@global.connection_control_min_connection_delay;
+
+SET @@global.connection_control_min_connection_delay = 2000;
+SELECT @@global.connection_control_min_connection_delay;
+
+SET @@global.connection_control_min_connection_delay = 2147483647;
+SELECT @@global.connection_control_min_connection_delay;
+
+SET @@global.connection_control_min_connection_delay = DEFAULT;
+SELECT @@global.connection_control_min_connection_delay;
+
+--echo # 2.2 : Setting connection_control_min_connection_delay to
+--echo #       invalid value
+
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.connection_control_min_connection_delay = NULL;
+SELECT @@global.connection_control_min_connection_delay;
+
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.connection_control_min_connection_delay = `SELECT * FROM mysql.user`;
+SELECT @@global.connection_control_min_connection_delay;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.connection_control_min_connection_delay = -20;
+SELECT @@global.connection_control_min_connection_delay;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.connection_control_min_connection_delay = 9223372036854775808;
+SELECT @@global.connection_control_min_connection_delay;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.connection_control_min_connection_delay = -9223372036854775808;
+SELECT @@global.connection_control_min_connection_delay;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET@@global.connection_control_min_connection_delay = 20;
+SELECT @@global.connection_control_min_connection_delay;
+
+--echo # Switch to conn_no_privs
+connection conn_no_privs;
+--echo # 2.3 : Use no_privs@localhost to set
+--echo #       connection_control_min_connection_delay to valid value
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET @@global.connection_control_min_connection_delay = 2147483647;
+SELECT @@global.connection_control_min_connection_delay;
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET @@global.connection_control_min_connection_delay = DEFAULT;
+SELECT @@global.connection_control_min_connection_delay;
+
+--echo # 2.4 : Use no_privs@localhost to set
+--echo #       connection_control_min_connection_delay to invalid value
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET @@global.connection_control_min_connection_delay = NULL;
+SELECT @@global.connection_control_min_connection_delay;
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET @@global.connection_control_min_connection_delay = 9223372036854775808;
+SELECT @@global.connection_control_min_connection_delay;
+
+--echo # Switch to default connection
+connection default;
+--echo # 2.5 : Setting connection_control_min_connection_delay to a value
+--echo #       greater than connection_control_max_connection_delay
+
+SET @saved_max_delay= @@global.connection_control_max_connection_delay;
+SET @@global.connection_control_max_connection_delay= 10000;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.connection_control_min_connection_delay= 11000;
+SELECT @@global.connection_control_min_connection_delay;
+
+SET @@global.connection_control_max_connection_delay= @saved_max_delay;
+
+SET @@global.connection_control_min_connection_delay = @saved_value;
+SELECT @@global.connection_control_min_connection_delay;
+
+--echo #-----------------------------------------------------------------------
+
+--echo # Case 3 : connection_control_max_connection_delay
+
+SET @saved_value= @@global.connection_control_max_connection_delay;
+SELECT @saved_value;
+
+--echo # 3.1 : Setting connection_control_max_connection_delay to valid
+--echo #       value
+
+SET @@global.connection_control_max_connection_delay = 20000;
+SELECT @@global.connection_control_max_connection_delay;
+
+SET @@global.connection_control_max_connection_delay = 2000;
+SELECT @@global.connection_control_max_connection_delay;
+
+SET @@global.connection_control_max_connection_delay = 2147483647;
+SELECT @@global.connection_control_max_connection_delay;
+
+SET @@global.connection_control_max_connection_delay = DEFAULT;
+SELECT @@global.connection_control_max_connection_delay;
+
+--echo # 3.2 : Setting connection_control_max_connection_delay to
+--echo #       invalid value
+
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.connection_control_max_connection_delay = NULL;
+SELECT @@global.connection_control_max_connection_delay;
+
+--error ER_WRONG_TYPE_FOR_VAR
+SET @@global.connection_control_max_connection_delay = `SELECT * FROM mysql.user`;
+SELECT @@global.connection_control_max_connection_delay;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.connection_control_max_connection_delay = -20;
+SELECT @@global.connection_control_max_connection_delay;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.connection_control_max_connection_delay = 9223372036854775808;
+SELECT @@global.connection_control_max_connection_delay;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.connection_control_max_connection_delay = -9223372036854775808;
+SELECT @@global.connection_control_max_connection_delay;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.connection_control_max_connection_delay = 20;
+SELECT @@global.connection_control_max_connection_delay;
+
+--echo # Switch to conn_no_privs
+connection conn_no_privs;
+--echo # 3.3 : Use no_privs@localhost to set
+--echo #       connection_control_max_connection_delay to valid value
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET @@global.connection_control_max_connection_delay = 2147483647;
+SELECT @@global.connection_control_max_connection_delay;
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET @@global.connection_control_max_connection_delay = DEFAULT;
+SELECT @@global.connection_control_max_connection_delay;
+
+--echo # 3.4 : Use no_privs@localhost to set
+--echo #       connection_control_max_connection_delay to invalid value
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET @@global.connection_control_max_connection_delay = NULL;
+SELECT @@global.connection_control_max_connection_delay;
+
+--error ER_SPECIFIC_ACCESS_DENIED_ERROR
+SET @@global.connection_control_max_connection_delay = 9223372036854775808;
+SELECT @@global.connection_control_max_connection_delay;
+
+--echo # Switch to default connection
+connection default;
+--echo # 3.5 : Setting connection_control_min_connection_delay to a value
+--echo #       greater than connection_control_max_connection_delay
+
+SET @saved_min_delay= @@global.connection_control_min_connection_delay;
+SET @@global.connection_control_min_connection_delay= 11000;
+
+--error ER_WRONG_VALUE_FOR_VAR
+SET @@global.connection_control_max_connection_delay= 10000;
+SELECT @@global.connection_control_max_connection_delay;
+
+SET @@global.connection_control_min_connection_delay= @saved_min_delay;
+
+SET @@global.connection_control_max_connection_delay = @saved_value;
+SELECT @@global.connection_control_max_connection_delay;
+
+--echo #-----------------------------------------------------------------------
+--echo # Cleanup
+disconnect conn_no_privs;
+DROP USER no_privs@localhost;
+--echo # Uninstall connection_control plugin
+--source ../inc/uninstall_connection_control_plugin.inc
+
+# Wait till all disconnects are completed.
+--source include/wait_until_count_sessions.inc
+--echo #-----------------------------------------------------------------------
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/r/GAL-480.result b/mysql-wsrep-5.6/mysql-test/suite/galera/r/GAL-480.result
new file mode 100644 (file)
index 0000000..b762e07
--- /dev/null
@@ -0,0 +1,39 @@
+CREATE TABLE t1 (f1 CHAR(10), f0 integer) ENGINE=InnoDB;
+FLUSH TABLE t1 FOR EXPORT;
+UNLOCK TABLES;
+ALTER TABLE t1 DROP COLUMN f1;
+SET SESSION wsrep_osu_method='RSU';
+ALTER TABLE t1 ADD COLUMN f1 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f1;
+ALTER TABLE t1 ADD COLUMN f2 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f2;
+ALTER TABLE t1 ADD COLUMN f3 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f3;
+ALTER TABLE t1 ADD COLUMN f4 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f4;
+ALTER TABLE t1 ADD COLUMN f5 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f5;
+ALTER TABLE t1 ADD COLUMN f6 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f6;
+ALTER TABLE t1 ADD COLUMN f7 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f7;
+ALTER TABLE t1 ADD COLUMN f8 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f8;
+ALTER TABLE t1 ADD COLUMN f9 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f9;
+ALTER TABLE t1 ADD COLUMN f10 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f10;
+ALTER TABLE t1 ADD COLUMN f11 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f11;
+ALTER TABLE t1 ADD COLUMN f12 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f12;
+ALTER TABLE t1 ADD COLUMN f13 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f13;
+ALTER TABLE t1 ADD COLUMN f14 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f14;
+ALTER TABLE t1 ADD COLUMN f15 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f15;
+ALTER TABLE t1 ADD COLUMN f16 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f16;
+SET SESSION wsrep_osu_method='TOI';
+DROP TABLE t1;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328A.result b/mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328A.result
new file mode 100644 (file)
index 0000000..daed246
--- /dev/null
@@ -0,0 +1,21 @@
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO t1 (f1) VALUES (1);
+CREATE TABLE t2 (f1 CHAR(20)) ENGINE=InnoDB;
+CREATE PROCEDURE proc_update ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+UPDATE t1 SET f2 = LEFT(MD5(RAND()), 4);
+END WHILE;
+END|
+CALL proc_update();;
+SET SESSION wsrep_retry_autocommit = 0;
+have_successes
+1
+have_deadlocks
+1
+Got one of the listed errors
+DROP PROCEDURE proc_update;
+DROP TABLE t1, t2;
+CALL mtr.add_suppression("conflict state 3 after post commit");
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328B.result b/mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328B.result
new file mode 100644 (file)
index 0000000..7809889
--- /dev/null
@@ -0,0 +1,17 @@
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO t1 (f1) VALUES (1);
+CREATE TABLE t2 (f1 CHAR(20)) ENGINE=InnoDB;
+CREATE PROCEDURE proc_update ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+UPDATE t1 SET f2 = LEFT(MD5(RAND()), 4);
+END WHILE;
+END|
+CALL proc_update();;
+SET SESSION wsrep_retry_autocommit = 0;
+Got one of the listed errors
+DROP PROCEDURE proc_update;
+DROP TABLE t1, t2;
+CALL mtr.add_suppression("conflict state 3 after post commit");
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328C.result b/mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328C.result
new file mode 100644 (file)
index 0000000..5cd74f0
--- /dev/null
@@ -0,0 +1,17 @@
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO t1 (f1) VALUES (1);
+CREATE TABLE t2 (f1 CHAR(20)) ENGINE=InnoDB;
+CREATE PROCEDURE proc_update ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+UPDATE t1 SET f2 = LEFT(MD5(RAND()), 4);
+END WHILE;
+END|
+CALL proc_update();;
+SET SESSION wsrep_retry_autocommit = 10000;
+Got one of the listed errors
+DROP PROCEDURE proc_update;
+DROP TABLE t1, t2;
+CALL mtr.add_suppression("conflict state 3 after post commit");
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328D.result b/mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328D.result
new file mode 100644 (file)
index 0000000..f6d055d
--- /dev/null
@@ -0,0 +1,15 @@
+CREATE TABLE t1 (i INT) ENGINE = InnoDB;
+INSERT INTO t1 (i) VALUES(1);
+CREATE TABLE t2 (i INT) ENGINE = InnoDB;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+SELECT * FROM t1 WHERE i = 1 LOCK IN SHARE MODE;
+i
+1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT IGNORE INTO t2 SELECT * FROM t1 WHERE i = 1 FOR UPDATE;;
+DELETE FROM t1 WHERE i = 1;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+DROP TABLE t1, t2;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328E.result b/mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-328E.result
new file mode 100644 (file)
index 0000000..5829559
--- /dev/null
@@ -0,0 +1,15 @@
+create table t1 (i int primary key, j int) engine=innodb;
+create table t2 (i int primary key, j int) engine=innodb;
+insert into t1 values (1,0);
+insert into t2 values (2,0);
+set autocommit=off;
+start transaction;
+update t1 set j=1 where i=1;
+set autocommit=off;
+start transaction;
+begin;
+update t2 set j=1 where i=2;
+insert into t1 select * from t2;;
+insert into t2 select * from t1;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+DROP TABLE t1, t2;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-329.result b/mysql-wsrep-5.6/mysql-test/suite/galera/r/MW-329.result
new file mode 100644 (file)
index 0000000..655d8e9
--- /dev/null
@@ -0,0 +1,20 @@
+CREATE TABLE t1 (f1 INTEGER, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO t1 (f1) VALUES (1),(65535);
+FLUSH STATUS;
+SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays';
+VARIABLE_VALUE = 0
+1
+CREATE PROCEDURE proc_insert ()
+BEGIN
+DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+SET SESSION wsrep_sync_wait = 0;
+WHILE 1 DO
+INSERT INTO t1 (f1) VALUES (FLOOR( 1 + RAND( ) * 65535 ));
+END WHILE;
+END|
+CALL proc_insert();;
+SELECT VARIABLE_VALUE > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays';
+VARIABLE_VALUE > 0
+1
+DROP PROCEDURE proc_insert;
+DROP TABLE t1;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db.result b/mysql-wsrep-5.6/mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db.result
new file mode 100644 (file)
index 0000000..27bebf2
--- /dev/null
@@ -0,0 +1,182 @@
+RESET MASTER;
+RESET MASTER;
+RESET MASTER;
+START SLAVE USER='root';
+Warnings:
+Note   1759    Sending passwords in plain text without SSL/TLS is extremely insecure.
+CREATE SCHEMA test1;
+CREATE SCHEMA test2;
+USE test1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY,f2 CHAR(5) DEFAULT 'abc') ENGINE=InnoDB;
+USE test2;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY,f2 CHAR(5) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO test1.t1 (f1) VALUES (1);
+INSERT INTO test2.t1 (f1) VALUES (1);
+INSERT INTO test1.t1 (f1) VALUES (2);
+INSERT INTO test2.t1 (f1) VALUES (2);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+UPDATE test2.t1 SET test2.t1.f2 = 'cde';
+UPDATE test1.t1, test2.t1 SET test1.t1.f2 = 'klm', test2.t1.f2 = 'xyz';
+DELETE test1.t1, test2.t1 FROM test1.t1 INNER JOIN test2.t1 WHERE test1.t1.f1 = test2.t1.f1 AND test1.t1.f1 = 3;
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO test2.t1 (f1) VALUES (999);
+INSERT INTO test2.t1 (f1) VALUES (9999);
+COMMIT;
+START TRANSACTION;
+INSERT INTO test1.t1 (f1) VALUES (111);
+INSERT INTO test1.t1 (f1) VALUES (222);
+COMMIT;
+START TRANSACTION;
+INSERT INTO test1.t1 (f1) VALUES (333);
+INSERT INTO test2.t1 (f1) VALUES (99999);
+COMMIT;
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
+Log_name       Pos     Event_type      Server_id       End_log_pos     Info
+mysqld-bin.000001      120     Previous_gtids  2       151     
+mysqld-bin.000001      151     Gtid    1       199     SET @@SESSION.GTID_NEXT= '<effective_uuid>:1'
+mysqld-bin.000001      199     Query   1       294     CREATE SCHEMA test1
+mysqld-bin.000001      294     Gtid    1       342     SET @@SESSION.GTID_NEXT= '<effective_uuid>:2'
+mysqld-bin.000001      342     Query   1       415     BEGIN
+mysqld-bin.000001      415     Query   1       489     COMMIT
+mysqld-bin.000001      489     Gtid    1       537     SET @@SESSION.GTID_NEXT= '<effective_uuid>:3'
+mysqld-bin.000001      537     Query   1       692     use `test1`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY,f2 CHAR(5) DEFAULT 'abc') ENGINE=InnoDB
+mysqld-bin.000001      692     Gtid    1       740     SET @@SESSION.GTID_NEXT= '<effective_uuid>:4'
+mysqld-bin.000001      740     Query   1       813     BEGIN
+mysqld-bin.000001      813     Query   1       887     COMMIT
+mysqld-bin.000001      887     Gtid    1       935     SET @@SESSION.GTID_NEXT= '<effective_uuid>:5'
+mysqld-bin.000001      935     Query   1       998     BEGIN
+mysqld-bin.000001      998     Table_map       1       1047    table_id: ### (test1.t1)
+mysqld-bin.000001      1047    Write_rows      1       1091    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      1091    Xid     1       1122    COMMIT /* xid=### */
+mysqld-bin.000001      1122    Gtid    1       1170    SET @@SESSION.GTID_NEXT= '<effective_uuid>:6'
+mysqld-bin.000001      1170    Query   1       1233    BEGIN
+mysqld-bin.000001      1233    Query   1       1297    COMMIT
+mysqld-bin.000001      1297    Gtid    1       1345    SET @@SESSION.GTID_NEXT= '<effective_uuid>:7'
+mysqld-bin.000001      1345    Query   1       1408    BEGIN
+mysqld-bin.000001      1408    Table_map       1       1457    table_id: ### (test1.t1)
+mysqld-bin.000001      1457    Write_rows      1       1501    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      1501    Xid     1       1532    COMMIT /* xid=### */
+mysqld-bin.000001      1532    Gtid    1       1580    SET @@SESSION.GTID_NEXT= '<effective_uuid>:8'
+mysqld-bin.000001      1580    Query   1       1643    BEGIN
+mysqld-bin.000001      1643    Query   1       1707    COMMIT
+mysqld-bin.000001      1707    Gtid    1       1755    SET @@SESSION.GTID_NEXT= '<effective_uuid>:9'
+mysqld-bin.000001      1755    Query   1       1818    BEGIN
+mysqld-bin.000001      1818    Table_map       1       1867    table_id: ### (test1.t1)
+mysqld-bin.000001      1867    Write_rows      1       1911    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      1911    Xid     1       1942    COMMIT /* xid=### */
+mysqld-bin.000001      1942    Gtid    1       1990    SET @@SESSION.GTID_NEXT= '<effective_uuid>:10'
+mysqld-bin.000001      1990    Query   1       2053    BEGIN
+mysqld-bin.000001      2053    Query   1       2117    COMMIT
+mysqld-bin.000001      2117    Gtid    1       2165    SET @@SESSION.GTID_NEXT= '<effective_uuid>:11'
+mysqld-bin.000001      2165    Query   1       2228    BEGIN
+mysqld-bin.000001      2228    Query   1       2292    COMMIT
+mysqld-bin.000001      2292    Gtid    1       2340    SET @@SESSION.GTID_NEXT= '<effective_uuid>:12'
+mysqld-bin.000001      2340    Query   1       2403    BEGIN
+mysqld-bin.000001      2403    Table_map       1       2452    table_id: ### (test1.t1)
+mysqld-bin.000001      2452    Update_rows     1       2542    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      2542    Xid     1       2573    COMMIT /* xid=### */
+mysqld-bin.000001      2573    Gtid    1       2621    SET @@SESSION.GTID_NEXT= '<effective_uuid>:13'
+mysqld-bin.000001      2621    Query   1       2684    BEGIN
+mysqld-bin.000001      2684    Table_map       1       2733    table_id: ### (test1.t1)
+mysqld-bin.000001      2733    Delete_rows     1       2777    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      2777    Xid     1       2808    COMMIT /* xid=### */
+mysqld-bin.000001      2808    Gtid    1       2856    SET @@SESSION.GTID_NEXT= '<effective_uuid>:14'
+mysqld-bin.000001      2856    Query   1       2919    BEGIN
+mysqld-bin.000001      2919    Query   1       2983    COMMIT
+mysqld-bin.000001      2983    Gtid    1       3031    SET @@SESSION.GTID_NEXT= '<effective_uuid>:15'
+mysqld-bin.000001      3031    Query   1       3094    BEGIN
+mysqld-bin.000001      3094    Table_map       1       3143    table_id: ### (test1.t1)
+mysqld-bin.000001      3143    Write_rows      1       3187    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      3187    Table_map       1       3236    table_id: ### (test1.t1)
+mysqld-bin.000001      3236    Write_rows      1       3280    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      3280    Xid     1       3311    COMMIT /* xid=### */
+mysqld-bin.000001      3311    Gtid    1       3359    SET @@SESSION.GTID_NEXT= '<effective_uuid>:16'
+mysqld-bin.000001      3359    Query   1       3422    BEGIN
+mysqld-bin.000001      3422    Table_map       1       3471    table_id: ### (test1.t1)
+mysqld-bin.000001      3471    Write_rows      1       3515    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      3515    Xid     1       3546    COMMIT /* xid=### */
+gtid_executed_equal
+1
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
+Log_name       Pos     Event_type      Server_id       End_log_pos     Info
+mysqld-bin.000001      120     Previous_gtids  3       151     
+mysqld-bin.000001      151     Gtid    1       199     SET @@SESSION.GTID_NEXT= '<effective_uuid>:1'
+mysqld-bin.000001      199     Query   1       294     CREATE SCHEMA test1
+mysqld-bin.000001      294     Gtid    1       342     SET @@SESSION.GTID_NEXT= '<effective_uuid>:2'
+mysqld-bin.000001      342     Query   1       415     BEGIN
+mysqld-bin.000001      415     Query   1       489     COMMIT
+mysqld-bin.000001      489     Gtid    1       537     SET @@SESSION.GTID_NEXT= '<effective_uuid>:3'
+mysqld-bin.000001      537     Query   1       692     use `test1`; CREATE TABLE t1 (f1 INTEGER PRIMARY KEY,f2 CHAR(5) DEFAULT 'abc') ENGINE=InnoDB
+mysqld-bin.000001      692     Gtid    1       740     SET @@SESSION.GTID_NEXT= '<effective_uuid>:4'
+mysqld-bin.000001      740     Query   1       813     BEGIN
+mysqld-bin.000001      813     Query   1       887     COMMIT
+mysqld-bin.000001      887     Gtid    1       935     SET @@SESSION.GTID_NEXT= '<effective_uuid>:5'
+mysqld-bin.000001      935     Query   1       998     BEGIN
+mysqld-bin.000001      998     Table_map       1       1047    table_id: ### (test1.t1)
+mysqld-bin.000001      1047    Write_rows      1       1091    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      1091    Xid     1       1122    COMMIT /* xid=### */
+mysqld-bin.000001      1122    Gtid    1       1170    SET @@SESSION.GTID_NEXT= '<effective_uuid>:6'
+mysqld-bin.000001      1170    Query   1       1233    BEGIN
+mysqld-bin.000001      1233    Query   1       1297    COMMIT
+mysqld-bin.000001      1297    Gtid    1       1345    SET @@SESSION.GTID_NEXT= '<effective_uuid>:7'
+mysqld-bin.000001      1345    Query   1       1408    BEGIN
+mysqld-bin.000001      1408    Table_map       1       1457    table_id: ### (test1.t1)
+mysqld-bin.000001      1457    Write_rows      1       1501    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      1501    Xid     1       1532    COMMIT /* xid=### */
+mysqld-bin.000001      1532    Gtid    1       1580    SET @@SESSION.GTID_NEXT= '<effective_uuid>:8'
+mysqld-bin.000001      1580    Query   1       1643    BEGIN
+mysqld-bin.000001      1643    Query   1       1707    COMMIT
+mysqld-bin.000001      1707    Gtid    1       1755    SET @@SESSION.GTID_NEXT= '<effective_uuid>:9'
+mysqld-bin.000001      1755    Query   1       1818    BEGIN
+mysqld-bin.000001      1818    Table_map       1       1867    table_id: ### (test1.t1)
+mysqld-bin.000001      1867    Write_rows      1       1911    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      1911    Xid     1       1942    COMMIT /* xid=### */
+mysqld-bin.000001      1942    Gtid    1       1990    SET @@SESSION.GTID_NEXT= '<effective_uuid>:10'
+mysqld-bin.000001      1990    Query   1       2053    BEGIN
+mysqld-bin.000001      2053    Query   1       2117    COMMIT
+mysqld-bin.000001      2117    Gtid    1       2165    SET @@SESSION.GTID_NEXT= '<effective_uuid>:11'
+mysqld-bin.000001      2165    Query   1       2228    BEGIN
+mysqld-bin.000001      2228    Query   1       2292    COMMIT
+mysqld-bin.000001      2292    Gtid    1       2340    SET @@SESSION.GTID_NEXT= '<effective_uuid>:12'
+mysqld-bin.000001      2340    Query   1       2403    BEGIN
+mysqld-bin.000001      2403    Table_map       1       2452    table_id: ### (test1.t1)
+mysqld-bin.000001      2452    Update_rows     1       2542    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      2542    Xid     1       2573    COMMIT /* xid=### */
+mysqld-bin.000001      2573    Gtid    1       2621    SET @@SESSION.GTID_NEXT= '<effective_uuid>:13'
+mysqld-bin.000001      2621    Query   1       2684    BEGIN
+mysqld-bin.000001      2684    Table_map       1       2733    table_id: ### (test1.t1)
+mysqld-bin.000001      2733    Delete_rows     1       2777    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      2777    Xid     1       2808    COMMIT /* xid=### */
+mysqld-bin.000001      2808    Gtid    1       2856    SET @@SESSION.GTID_NEXT= '<effective_uuid>:14'
+mysqld-bin.000001      2856    Query   1       2919    BEGIN
+mysqld-bin.000001      2919    Query   1       2983    COMMIT
+mysqld-bin.000001      2983    Gtid    1       3031    SET @@SESSION.GTID_NEXT= '<effective_uuid>:15'
+mysqld-bin.000001      3031    Query   1       3094    BEGIN
+mysqld-bin.000001      3094    Table_map       1       3143    table_id: ### (test1.t1)
+mysqld-bin.000001      3143    Write_rows      1       3187    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      3187    Table_map       1       3236    table_id: ### (test1.t1)
+mysqld-bin.000001      3236    Write_rows      1       3280    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      3280    Xid     1       3311    COMMIT /* xid=### */
+mysqld-bin.000001      3311    Gtid    1       3359    SET @@SESSION.GTID_NEXT= '<effective_uuid>:16'
+mysqld-bin.000001      3359    Query   1       3422    BEGIN
+mysqld-bin.000001      3422    Table_map       1       3471    table_id: ### (test1.t1)
+mysqld-bin.000001      3471    Write_rows      1       3515    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      3515    Xid     1       3546    COMMIT /* xid=### */
+include/diff_servers.inc [servers=2 3]
+SELECT COUNT(*) = 2 FROM test1.t1 WHERE f1 IN (1,2);
+COUNT(*) = 2
+1
+SELECT COUNT(*) = 3 FROM test1.t1 WHERE f1 IN (111,222,333);
+COUNT(*) = 3
+1
+SELECT COUNT(*) = 2 FROM test1.t1 WHERE f2 = 'klm';
+COUNT(*) = 2
+1
+USE test2;
+ERROR 42000: Unknown database 'test2'
+DROP SCHEMA test1;
+DROP SCHEMA test2;
+STOP SLAVE;
+RESET SLAVE ALL;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db_cc.result b/mysql-wsrep-5.6/mysql-test/suite/galera/r/galera_as_slave_gtid_replicate_do_db_cc.result
new file mode 100644 (file)
index 0000000..c968312
--- /dev/null
@@ -0,0 +1,295 @@
+RESET MASTER;
+RESET MASTER;
+RESET MASTER;
+START SLAVE USER='root';
+Warnings:
+Note   1759    Sending passwords in plain text without SSL/TLS is extremely insecure.
+CREATE SCHEMA test1;
+CREATE SCHEMA test2;
+USE test1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+USE test2;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+INSERT INTO test1.t1 (f1) VALUES (1);
+INSERT INTO test2.t1 (f1) VALUES (1);
+INSERT INTO test1.t1 (f1) VALUES (2);
+INSERT INTO test2.t1 (f1) VALUES (2);
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+SET SESSION wsrep_on=OFF;
+include/wait_for_slave_sql_error.inc [errno=1047]
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+INSERT INTO test1.t1 (f1) VALUES (5);
+INSERT INTO test2.t1 (f1) VALUES (5);
+SET SESSION wsrep_on=ON;
+INSERT INTO test1.t1 (f1) VALUES (6);
+INSERT INTO test2.t1 (f1) VALUES (6);
+START SLAVE;
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
+Log_name       Pos     Event_type      Server_id       End_log_pos     Info
+mysqld-bin.000001      120     Previous_gtids  2       151     
+mysqld-bin.000001      151     Gtid    1       199     SET @@SESSION.GTID_NEXT= '<effective_uuid>:1'
+mysqld-bin.000001      199     Query   1       294     CREATE SCHEMA test1
+mysqld-bin.000001      294     Gtid    1       342     SET @@SESSION.GTID_NEXT= '<effective_uuid>:2'
+mysqld-bin.000001      342     Query   1       415     BEGIN
+mysqld-bin.000001      415     Query   1       489     COMMIT
+mysqld-bin.000001      489     Gtid    1       537     SET @@SESSION.GTID_NEXT= '<effective_uuid>:3'
+mysqld-bin.000001      537     Query   1       655     use `test1`; CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB
+mysqld-bin.000001      655     Gtid    1       703     SET @@SESSION.GTID_NEXT= '<effective_uuid>:4'
+mysqld-bin.000001      703     Query   1       776     BEGIN
+mysqld-bin.000001      776     Query   1       850     COMMIT
+mysqld-bin.000001      850     Gtid    1       898     SET @@SESSION.GTID_NEXT= '<effective_uuid>:5'
+mysqld-bin.000001      898     Query   1       961     BEGIN
+mysqld-bin.000001      961     Table_map       1       1007    table_id: ### (test1.t1)
+mysqld-bin.000001      1007    Write_rows      1       1047    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      1047    Xid     1       1078    COMMIT /* xid=### */
+mysqld-bin.000001      1078    Gtid    1       1126    SET @@SESSION.GTID_NEXT= '<effective_uuid>:6'
+mysqld-bin.000001      1126    Query   1       1189    BEGIN
+mysqld-bin.000001      1189    Query   1       1253    COMMIT
+mysqld-bin.000001      1253    Gtid    1       1301    SET @@SESSION.GTID_NEXT= '<effective_uuid>:7'
+mysqld-bin.000001      1301    Query   1       1364    BEGIN
+mysqld-bin.000001      1364    Table_map       1       1410    table_id: ### (test1.t1)
+mysqld-bin.000001      1410    Write_rows      1       1450    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      1450    Xid     1       1481    COMMIT /* xid=### */
+mysqld-bin.000001      1481    Gtid    1       1529    SET @@SESSION.GTID_NEXT= '<effective_uuid>:8'
+mysqld-bin.000001      1529    Query   1       1592    BEGIN
+mysqld-bin.000001      1592    Query   1       1656    COMMIT
+mysqld-bin.000001      1656    Gtid    1       1704    SET @@SESSION.GTID_NEXT= '<effective_uuid>:9'
+mysqld-bin.000001      1704    Query   1       1767    BEGIN
+mysqld-bin.000001      1767    Table_map       1       1813    table_id: ### (test1.t1)
+mysqld-bin.000001      1813    Write_rows      1       1853    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      1853    Xid     1       1884    COMMIT /* xid=### */
+mysqld-bin.000001      1884    Gtid    1       1932    SET @@SESSION.GTID_NEXT= '<effective_uuid>:10'
+mysqld-bin.000001      1932    Query   1       1995    BEGIN
+mysqld-bin.000001      1995    Query   1       2059    COMMIT
+mysqld-bin.000001      2059    Gtid    1       2107    SET @@SESSION.GTID_NEXT= '<effective_uuid>:11'
+mysqld-bin.000001      2107    Query   1       2170    BEGIN
+mysqld-bin.000001      2170    Table_map       1       2216    table_id: ### (test1.t1)
+mysqld-bin.000001      2216    Write_rows      1       2256    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      2256    Xid     1       2287    COMMIT /* xid=### */
+mysqld-bin.000001      2287    Gtid    1       2335    SET @@SESSION.GTID_NEXT= '<effective_uuid>:12'
+mysqld-bin.000001      2335    Query   1       2398    BEGIN
+mysqld-bin.000001      2398    Query   1       2462    COMMIT
+mysqld-bin.000001      2462    Gtid    1       2510    SET @@SESSION.GTID_NEXT= '<effective_uuid>:13'
+mysqld-bin.000001      2510    Query   1       2573    BEGIN
+mysqld-bin.000001      2573    Table_map       1       2619    table_id: ### (test1.t1)
+mysqld-bin.000001      2619    Write_rows      1       2659    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      2659    Xid     1       2690    COMMIT /* xid=### */
+mysqld-bin.000001      2690    Gtid    1       2738    SET @@SESSION.GTID_NEXT= '<effective_uuid>:14'
+mysqld-bin.000001      2738    Query   1       2801    BEGIN
+mysqld-bin.000001      2801    Query   1       2865    COMMIT
+mysqld-bin.000001      2865    Gtid    1       2913    SET @@SESSION.GTID_NEXT= '<effective_uuid>:15'
+mysqld-bin.000001      2913    Query   1       2976    BEGIN
+mysqld-bin.000001      2976    Table_map       1       3022    table_id: ### (test1.t1)
+mysqld-bin.000001      3022    Write_rows      1       3062    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      3062    Xid     1       3093    COMMIT /* xid=### */
+mysqld-bin.000001      3093    Gtid    1       3141    SET @@SESSION.GTID_NEXT= '<effective_uuid>:16'
+mysqld-bin.000001      3141    Query   1       3204    BEGIN
+mysqld-bin.000001      3204    Query   1       3268    COMMIT
+mysqld-bin.000001      3268    Gtid    1       3316    SET @@SESSION.GTID_NEXT= '<effective_uuid>:17'
+mysqld-bin.000001      3316    Query   1       3379    BEGIN
+mysqld-bin.000001      3379    Table_map       1       3425    table_id: ### (test1.t1)
+mysqld-bin.000001      3425    Write_rows      1       3465    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      3465    Xid     1       3496    COMMIT /* xid=### */
+mysqld-bin.000001      3496    Gtid    1       3544    SET @@SESSION.GTID_NEXT= '<effective_uuid>:18'
+mysqld-bin.000001      3544    Query   1       3607    BEGIN
+mysqld-bin.000001      3607    Query   1       3671    COMMIT
+mysqld-bin.000001      3671    Gtid    1       3719    SET @@SESSION.GTID_NEXT= '<effective_uuid>:19'
+mysqld-bin.000001      3719    Query   1       3782    BEGIN
+mysqld-bin.000001      3782    Table_map       1       3828    table_id: ### (test1.t1)
+mysqld-bin.000001      3828    Write_rows      1       3868    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      3868    Xid     1       3899    COMMIT /* xid=### */
+mysqld-bin.000001      3899    Gtid    1       3947    SET @@SESSION.GTID_NEXT= '<effective_uuid>:20'
+mysqld-bin.000001      3947    Query   1       4010    BEGIN
+mysqld-bin.000001      4010    Query   1       4074    COMMIT
+mysqld-bin.000001      4074    Gtid    1       4122    SET @@SESSION.GTID_NEXT= '<effective_uuid>:21'
+mysqld-bin.000001      4122    Query   1       4185    BEGIN
+mysqld-bin.000001      4185    Table_map       1       4231    table_id: ### (test1.t1)
+mysqld-bin.000001      4231    Write_rows      1       4271    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      4271    Xid     1       4302    COMMIT /* xid=### */
+mysqld-bin.000001      4302    Gtid    1       4350    SET @@SESSION.GTID_NEXT= '<effective_uuid>:22'
+mysqld-bin.000001      4350    Query   1       4413    BEGIN
+mysqld-bin.000001      4413    Query   1       4477    COMMIT
+mysqld-bin.000001      4477    Gtid    1       4525    SET @@SESSION.GTID_NEXT= '<effective_uuid>:23'
+mysqld-bin.000001      4525    Query   1       4588    BEGIN
+mysqld-bin.000001      4588    Table_map       1       4634    table_id: ### (test1.t1)
+mysqld-bin.000001      4634    Write_rows      1       4674    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      4674    Xid     1       4705    COMMIT /* xid=### */
+mysqld-bin.000001      4705    Gtid    1       4753    SET @@SESSION.GTID_NEXT= '<effective_uuid>:24'
+mysqld-bin.000001      4753    Query   1       4816    BEGIN
+mysqld-bin.000001      4816    Query   1       4880    COMMIT
+mysqld-bin.000001      4880    Gtid    1       4928    SET @@SESSION.GTID_NEXT= '<effective_uuid>:25'
+mysqld-bin.000001      4928    Query   1       4991    BEGIN
+mysqld-bin.000001      4991    Table_map       1       5037    table_id: ### (test1.t1)
+mysqld-bin.000001      5037    Write_rows      1       5077    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      5077    Xid     1       5108    COMMIT /* xid=### */
+mysqld-bin.000001      5108    Gtid    1       5156    SET @@SESSION.GTID_NEXT= '<effective_uuid>:26'
+mysqld-bin.000001      5156    Query   1       5219    BEGIN
+mysqld-bin.000001      5219    Query   1       5283    COMMIT
+mysqld-bin.000001      5283    Gtid    1       5331    SET @@SESSION.GTID_NEXT= '<effective_uuid>:27'
+mysqld-bin.000001      5331    Query   1       5394    BEGIN
+mysqld-bin.000001      5394    Table_map       1       5440    table_id: ### (test1.t1)
+mysqld-bin.000001      5440    Write_rows      1       5480    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      5480    Xid     1       5511    COMMIT /* xid=### */
+mysqld-bin.000001      5511    Gtid    1       5559    SET @@SESSION.GTID_NEXT= '<effective_uuid>:28'
+mysqld-bin.000001      5559    Query   1       5622    BEGIN
+mysqld-bin.000001      5622    Query   1       5686    COMMIT
+mysqld-bin.000001      5686    Gtid    1       5734    SET @@SESSION.GTID_NEXT= '<effective_uuid>:29'
+mysqld-bin.000001      5734    Query   1       5797    BEGIN
+mysqld-bin.000001      5797    Table_map       1       5843    table_id: ### (test1.t1)
+mysqld-bin.000001      5843    Write_rows      1       5883    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      5883    Xid     1       5914    COMMIT /* xid=### */
+mysqld-bin.000001      5914    Gtid    1       5962    SET @@SESSION.GTID_NEXT= '<effective_uuid>:30'
+mysqld-bin.000001      5962    Query   1       6025    BEGIN
+mysqld-bin.000001      6025    Query   1       6089    COMMIT
+USE test2;
+ERROR 42000: Unknown database 'test2'
+gtid_executed_equal
+1
+USE test2;
+ERROR 42000: Unknown database 'test2'
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
+Log_name       Pos     Event_type      Server_id       End_log_pos     Info
+mysqld-bin.000001      120     Previous_gtids  4       151     
+mysqld-bin.000001      151     Gtid    1       199     SET @@SESSION.GTID_NEXT= '<effective_uuid>:1'
+mysqld-bin.000001      199     Query   1       294     CREATE SCHEMA test1
+mysqld-bin.000001      294     Gtid    1       342     SET @@SESSION.GTID_NEXT= '<effective_uuid>:2'
+mysqld-bin.000001      342     Query   1       415     BEGIN
+mysqld-bin.000001      415     Query   1       489     COMMIT
+mysqld-bin.000001      489     Gtid    1       537     SET @@SESSION.GTID_NEXT= '<effective_uuid>:3'
+mysqld-bin.000001      537     Query   1       655     use `test1`; CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB
+mysqld-bin.000001      655     Gtid    1       703     SET @@SESSION.GTID_NEXT= '<effective_uuid>:4'
+mysqld-bin.000001      703     Query   1       776     BEGIN
+mysqld-bin.000001      776     Query   1       850     COMMIT
+mysqld-bin.000001      850     Gtid    1       898     SET @@SESSION.GTID_NEXT= '<effective_uuid>:5'
+mysqld-bin.000001      898     Query   1       961     BEGIN
+mysqld-bin.000001      961     Table_map       1       1007    table_id: ### (test1.t1)
+mysqld-bin.000001      1007    Write_rows      1       1047    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      1047    Xid     1       1078    COMMIT /* xid=### */
+mysqld-bin.000001      1078    Gtid    1       1126    SET @@SESSION.GTID_NEXT= '<effective_uuid>:6'
+mysqld-bin.000001      1126    Query   1       1189    BEGIN
+mysqld-bin.000001      1189    Query   1       1253    COMMIT
+mysqld-bin.000001      1253    Gtid    1       1301    SET @@SESSION.GTID_NEXT= '<effective_uuid>:7'
+mysqld-bin.000001      1301    Query   1       1364    BEGIN
+mysqld-bin.000001      1364    Table_map       1       1410    table_id: ### (test1.t1)
+mysqld-bin.000001      1410    Write_rows      1       1450    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      1450    Xid     1       1481    COMMIT /* xid=### */
+mysqld-bin.000001      1481    Gtid    1       1529    SET @@SESSION.GTID_NEXT= '<effective_uuid>:8'
+mysqld-bin.000001      1529    Query   1       1592    BEGIN
+mysqld-bin.000001      1592    Query   1       1656    COMMIT
+mysqld-bin.000001      1656    Gtid    1       1704    SET @@SESSION.GTID_NEXT= '<effective_uuid>:9'
+mysqld-bin.000001      1704    Query   1       1767    BEGIN
+mysqld-bin.000001      1767    Table_map       1       1813    table_id: ### (test1.t1)
+mysqld-bin.000001      1813    Write_rows      1       1853    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      1853    Xid     1       1884    COMMIT /* xid=### */
+mysqld-bin.000001      1884    Gtid    1       1932    SET @@SESSION.GTID_NEXT= '<effective_uuid>:10'
+mysqld-bin.000001      1932    Query   1       1995    BEGIN
+mysqld-bin.000001      1995    Query   1       2059    COMMIT
+mysqld-bin.000001      2059    Gtid    1       2107    SET @@SESSION.GTID_NEXT= '<effective_uuid>:11'
+mysqld-bin.000001      2107    Query   1       2170    BEGIN
+mysqld-bin.000001      2170    Table_map       1       2216    table_id: ### (test1.t1)
+mysqld-bin.000001      2216    Write_rows      1       2256    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      2256    Xid     1       2287    COMMIT /* xid=### */
+mysqld-bin.000001      2287    Gtid    1       2335    SET @@SESSION.GTID_NEXT= '<effective_uuid>:12'
+mysqld-bin.000001      2335    Query   1       2398    BEGIN
+mysqld-bin.000001      2398    Query   1       2462    COMMIT
+mysqld-bin.000001      2462    Gtid    1       2510    SET @@SESSION.GTID_NEXT= '<effective_uuid>:13'
+mysqld-bin.000001      2510    Query   1       2573    BEGIN
+mysqld-bin.000001      2573    Table_map       1       2619    table_id: ### (test1.t1)
+mysqld-bin.000001      2619    Write_rows      1       2659    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      2659    Xid     1       2690    COMMIT /* xid=### */
+mysqld-bin.000001      2690    Gtid    1       2738    SET @@SESSION.GTID_NEXT= '<effective_uuid>:14'
+mysqld-bin.000001      2738    Query   1       2801    BEGIN
+mysqld-bin.000001      2801    Query   1       2865    COMMIT
+mysqld-bin.000001      2865    Gtid    1       2913    SET @@SESSION.GTID_NEXT= '<effective_uuid>:15'
+mysqld-bin.000001      2913    Query   1       2976    BEGIN
+mysqld-bin.000001      2976    Table_map       1       3022    table_id: ### (test1.t1)
+mysqld-bin.000001      3022    Write_rows      1       3062    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      3062    Xid     1       3093    COMMIT /* xid=### */
+mysqld-bin.000001      3093    Gtid    1       3141    SET @@SESSION.GTID_NEXT= '<effective_uuid>:16'
+mysqld-bin.000001      3141    Query   1       3204    BEGIN
+mysqld-bin.000001      3204    Query   1       3268    COMMIT
+mysqld-bin.000001      3268    Gtid    1       3316    SET @@SESSION.GTID_NEXT= '<effective_uuid>:17'
+mysqld-bin.000001      3316    Query   1       3379    BEGIN
+mysqld-bin.000001      3379    Table_map       1       3425    table_id: ### (test1.t1)
+mysqld-bin.000001      3425    Write_rows      1       3465    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      3465    Xid     1       3496    COMMIT /* xid=### */
+mysqld-bin.000001      3496    Gtid    1       3544    SET @@SESSION.GTID_NEXT= '<effective_uuid>:18'
+mysqld-bin.000001      3544    Query   1       3607    BEGIN
+mysqld-bin.000001      3607    Query   1       3671    COMMIT
+mysqld-bin.000001      3671    Gtid    1       3719    SET @@SESSION.GTID_NEXT= '<effective_uuid>:19'
+mysqld-bin.000001      3719    Query   1       3782    BEGIN
+mysqld-bin.000001      3782    Table_map       1       3828    table_id: ### (test1.t1)
+mysqld-bin.000001      3828    Write_rows      1       3868    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      3868    Xid     1       3899    COMMIT /* xid=### */
+mysqld-bin.000001      3899    Gtid    1       3947    SET @@SESSION.GTID_NEXT= '<effective_uuid>:20'
+mysqld-bin.000001      3947    Query   1       4010    BEGIN
+mysqld-bin.000001      4010    Query   1       4074    COMMIT
+mysqld-bin.000001      4074    Gtid    1       4122    SET @@SESSION.GTID_NEXT= '<effective_uuid>:21'
+mysqld-bin.000001      4122    Query   1       4185    BEGIN
+mysqld-bin.000001      4185    Table_map       1       4231    table_id: ### (test1.t1)
+mysqld-bin.000001      4231    Write_rows      1       4271    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      4271    Xid     1       4302    COMMIT /* xid=### */
+mysqld-bin.000001      4302    Gtid    1       4350    SET @@SESSION.GTID_NEXT= '<effective_uuid>:22'
+mysqld-bin.000001      4350    Query   1       4413    BEGIN
+mysqld-bin.000001      4413    Query   1       4477    COMMIT
+mysqld-bin.000001      4477    Gtid    1       4525    SET @@SESSION.GTID_NEXT= '<effective_uuid>:23'
+mysqld-bin.000001      4525    Query   1       4588    BEGIN
+mysqld-bin.000001      4588    Table_map       1       4634    table_id: ### (test1.t1)
+mysqld-bin.000001      4634    Write_rows      1       4674    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      4674    Xid     1       4705    COMMIT /* xid=### */
+mysqld-bin.000001      4705    Gtid    1       4753    SET @@SESSION.GTID_NEXT= '<effective_uuid>:24'
+mysqld-bin.000001      4753    Query   1       4816    BEGIN
+mysqld-bin.000001      4816    Query   1       4880    COMMIT
+mysqld-bin.000001      4880    Gtid    1       4928    SET @@SESSION.GTID_NEXT= '<effective_uuid>:25'
+mysqld-bin.000001      4928    Query   1       4991    BEGIN
+mysqld-bin.000001      4991    Table_map       1       5037    table_id: ### (test1.t1)
+mysqld-bin.000001      5037    Write_rows      1       5077    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      5077    Xid     1       5108    COMMIT /* xid=### */
+mysqld-bin.000001      5108    Gtid    1       5156    SET @@SESSION.GTID_NEXT= '<effective_uuid>:26'
+mysqld-bin.000001      5156    Query   1       5219    BEGIN
+mysqld-bin.000001      5219    Query   1       5283    COMMIT
+mysqld-bin.000001      5283    Gtid    1       5331    SET @@SESSION.GTID_NEXT= '<effective_uuid>:27'
+mysqld-bin.000001      5331    Query   1       5394    BEGIN
+mysqld-bin.000001      5394    Table_map       1       5440    table_id: ### (test1.t1)
+mysqld-bin.000001      5440    Write_rows      1       5480    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      5480    Xid     1       5511    COMMIT /* xid=### */
+mysqld-bin.000001      5511    Gtid    1       5559    SET @@SESSION.GTID_NEXT= '<effective_uuid>:28'
+mysqld-bin.000001      5559    Query   1       5622    BEGIN
+mysqld-bin.000001      5622    Query   1       5686    COMMIT
+mysqld-bin.000001      5686    Gtid    1       5734    SET @@SESSION.GTID_NEXT= '<effective_uuid>:29'
+mysqld-bin.000001      5734    Query   1       5797    BEGIN
+mysqld-bin.000001      5797    Table_map       1       5843    table_id: ### (test1.t1)
+mysqld-bin.000001      5843    Write_rows      1       5883    table_id: ### flags: STMT_END_F
+mysqld-bin.000001      5883    Xid     1       5914    COMMIT /* xid=### */
+mysqld-bin.000001      5914    Gtid    1       5962    SET @@SESSION.GTID_NEXT= '<effective_uuid>:30'
+mysqld-bin.000001      5962    Query   1       6025    BEGIN
+mysqld-bin.000001      6025    Query   1       6089    COMMIT
+DROP SCHEMA test1;
+DROP SCHEMA test2;
+STOP SLAVE;
+RESET SLAVE ALL;
+CALL mtr.add_suppression("GTID replication failed");
+CALL mtr.add_suppression("Slave SQL: Error in Xid_log_event: Commit could not be completed");
+CALL mtr.add_suppression("Slave SQL: Node has dropped from cluster, Error_code: 1047");
+CALL mtr.add_suppression("TO isolation failed for");
+CALL mtr.add_suppression("Slave SQL: Error 'Deadlock found when trying to get lock; try restarting transaction' on query");
+CALL mtr.add_suppression("Slave SQL: Error 'WSREP has not yet prepared node for application use' on query");
+CALL mtr.add_suppression("Slave: WSREP has not yet prepared node for application use Error_code: 1047");
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/r/galera_wsrep_log_conficts.result b/mysql-wsrep-5.6/mysql-test/suite/galera/r/galera_wsrep_log_conficts.result
new file mode 100644 (file)
index 0000000..b535c64
--- /dev/null
@@ -0,0 +1,18 @@
+CREATE TABLE t1 (
+f1 VARCHAR(255) PRIMARY KEY
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+INSERT INTO t1 VALUES ('abc');
+SELECT f1 = 'abc' FROM t1;
+f1 = 'abc'
+1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+UPDATE t1 SET f1 = 'klm';
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+UPDATE t1 SET f1 = 'xyz';
+COMMIT;
+COMMIT;
+ERROR 40001: Deadlock found when trying to get lock; try restarting transaction
+include/assert_grep.inc [cluster conflict due to high priority abort for threads]
+DROP TABLE t1;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/GAL-480.test b/mysql-wsrep-5.6/mysql-test/suite/galera/t/GAL-480.test
new file mode 100644 (file)
index 0000000..c2b34f2
--- /dev/null
@@ -0,0 +1,46 @@
+--source include/galera_cluster.inc
+
+--connection node_1
+CREATE TABLE t1 (f1 CHAR(10), f0 integer) ENGINE=InnoDB;
+
+FLUSH TABLE t1 FOR EXPORT;
+UNLOCK TABLES;
+
+ALTER TABLE t1 DROP COLUMN f1;
+
+SET SESSION wsrep_osu_method='RSU';
+ALTER TABLE t1 ADD COLUMN f1 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f1;
+ALTER TABLE t1 ADD COLUMN f2 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f2;
+ALTER TABLE t1 ADD COLUMN f3 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f3;
+ALTER TABLE t1 ADD COLUMN f4 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f4;
+ALTER TABLE t1 ADD COLUMN f5 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f5;
+ALTER TABLE t1 ADD COLUMN f6 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f6;
+ALTER TABLE t1 ADD COLUMN f7 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f7;
+ALTER TABLE t1 ADD COLUMN f8 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f8;
+ALTER TABLE t1 ADD COLUMN f9 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f9;
+ALTER TABLE t1 ADD COLUMN f10 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f10;
+ALTER TABLE t1 ADD COLUMN f11 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f11;
+ALTER TABLE t1 ADD COLUMN f12 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f12;
+ALTER TABLE t1 ADD COLUMN f13 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f13;
+ALTER TABLE t1 ADD COLUMN f14 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f14;
+ALTER TABLE t1 ADD COLUMN f15 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f15;
+ALTER TABLE t1 ADD COLUMN f16 CHAR(10);
+ALTER TABLE t1 DROP COLUMN f16;
+
+SET SESSION wsrep_osu_method='TOI';
+DROP TABLE t1;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328-footer.inc b/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328-footer.inc
new file mode 100644 (file)
index 0000000..5b736df
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# Cleanup for MW-328 tests
+# 
+
+--connection node_1
+--disable_query_log
+--eval KILL CONNECTION $sp_connection_id
+--enable_query_log
+
+--connection node_1X
+--error 2013,1317
+--reap
+
+--connection node_1
+DROP PROCEDURE proc_update;
+DROP TABLE t1, t2;
+
+CALL mtr.add_suppression("conflict state 3 after post commit");
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328-header.inc b/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328-header.inc
new file mode 100644 (file)
index 0000000..f0a6cca
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# Initialization for MW-328 tests
+#
+
+CREATE TABLE t1 (f1 INTEGER AUTO_INCREMENT PRIMARY KEY, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+INSERT INTO t1 (f1) VALUES (1);
+
+CREATE TABLE t2 (f1 CHAR(20)) ENGINE=InnoDB;
+
+#
+# Have some random updates going on against t1
+#
+
+DELIMITER |;
+CREATE PROCEDURE proc_update ()
+BEGIN
+        DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+        SET SESSION wsrep_sync_wait = 0;
+        WHILE 1 DO
+                UPDATE t1 SET f2 = LEFT(MD5(RAND()), 4);
+        END WHILE;
+END|
+
+DELIMITER ;|
+
+--connect node_1X, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1X
+--let $sp_connection_id = `SELECT CONNECTION_ID()`
+--send CALL proc_update();
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328A.test b/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328A.test
new file mode 100644 (file)
index 0000000..836dd08
--- /dev/null
@@ -0,0 +1,55 @@
+#
+# MW-328 Fix unnecessary/silent BF aborts
+# 
+
+#
+# Attempt to insert into t2 and check if insert actually inserted rows if 
+# a success was reported.
+#
+
+--source include/galera_cluster.inc
+--source suite/galera/t/MW-328-header.inc
+
+--connection node_2
+--let $count = 100
+--let $successes = 0
+--let $deadlocks = 0
+
+SET SESSION wsrep_retry_autocommit = 0;
+
+--disable_query_log
+
+while ($count)
+{
+  TRUNCATE TABLE t2;
+
+  --error 0,1213
+  INSERT IGNORE INTO t2 SELECT f2 FROM t1;
+  if ($mysql_errno != 1213) {
+    --inc $successes
+    if (`SELECT COUNT(*) = 0 FROM t2`) {
+      --die No rows arrived in table t2
+    }
+  }
+
+  if ($mysql_errno == 1213) {
+    --inc $deadlocks
+      
+  }
+
+  --dec $count
+}
+
+--enable_query_log
+
+#
+# Check that the test produced both deadlocks and successes
+#
+
+--disable_query_log
+--eval SELECT $successes > 0 AS have_successes
+--eval SELECT $deadlocks > 0 AS have_deadlocks
+--enable_query_log
+
+
+--source suite/galera/t/MW-328-footer.inc
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328B.test b/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328B.test
new file mode 100644 (file)
index 0000000..11969dd
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# MW-328 Fix unnecessary/silent BF aborts
+# 
+
+#
+# Make sure an unrelated SELECT following a BF-aborted query never 
+# gets the deadlock error
+#
+
+--source include/galera_cluster.inc
+--source suite/galera/t/MW-328-header.inc
+
+--connection node_2
+--let $count = 100
+
+SET SESSION wsrep_retry_autocommit = 0;
+
+--disable_query_log
+
+while ($count)
+{
+  --error 0,1213
+  INSERT IGNORE INTO t2 SELECT f2 FROM t1;
+
+  --disable_result_log
+  --error 0
+  SELECT 1 FROM DUAL;
+  --enable_result_log
+
+  --dec $count
+}
+
+--enable_query_log
+
+--source suite/galera/t/MW-328-footer.inc
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328C.test b/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328C.test
new file mode 100644 (file)
index 0000000..7241dfb
--- /dev/null
@@ -0,0 +1,35 @@
+#
+# MW-328 Fix unnecessary/silent BF aborts
+# 
+
+#
+# Make sure that a high value of wsrep_retry_autocommit
+# masks all deadlock errors
+#
+
+--source include/galera_cluster.inc
+--source suite/galera/t/MW-328-header.inc
+
+--connection node_2
+--let $count = 100
+
+SET SESSION wsrep_retry_autocommit = 10000;
+
+--disable_query_log
+
+while ($count)
+{
+  --error 0
+  INSERT IGNORE INTO t2 SELECT f2 FROM t1;
+
+  --disable_result_log
+  --error 0
+  SELECT 1 FROM DUAL;
+  --enable_result_log
+
+  --dec $count
+}
+
+--enable_query_log
+
+--source suite/galera/t/MW-328-footer.inc
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328D.test b/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328D.test
new file mode 100644 (file)
index 0000000..e8a22f2
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# MW-328 Fix unnecessary/silent BF aborts
+#
+
+#
+# Test that non-Galera deadlock error still behaves as expected
+#
+
+--source include/galera_cluster.inc
+
+CREATE TABLE t1 (i INT) ENGINE = InnoDB;
+INSERT INTO t1 (i) VALUES(1);
+
+CREATE TABLE t2 (i INT) ENGINE = InnoDB;
+
+# Create a deadlock situation
+
+--connection node_1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+SELECT * FROM t1 WHERE i = 1 LOCK IN SHARE MODE;
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+--send INSERT IGNORE INTO t2 SELECT * FROM t1 WHERE i = 1 FOR UPDATE;
+
+--connection node_1
+--sleep 2
+DELETE FROM t1 WHERE i = 1;
+COMMIT;
+
+# We expect that ER_LOCK_DEADLOCK will be delivered even though it was a INSERT INGORE statement
+--connection node_1a
+--error ER_LOCK_DEADLOCK
+--reap
+
+DROP TABLE t1, t2;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328E.test b/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-328E.test
new file mode 100644 (file)
index 0000000..34b17be
--- /dev/null
@@ -0,0 +1,40 @@
+#
+# MW-328 Fix unnecessary/silent BF aborts
+#
+
+#
+# Test that non-Galera deadlock error still behaves as expected (case #2)
+#
+
+--source include/galera_cluster.inc
+
+create table t1 (i int primary key, j int) engine=innodb;
+create table t2 (i int primary key, j int) engine=innodb;
+
+insert into t1 values (1,0);
+insert into t2 values (2,0);
+
+set autocommit=off;
+start transaction;
+update t1 set j=1 where i=1;
+
+--connect node_1a, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1a
+set autocommit=off;
+start transaction;
+begin;
+update t2 set j=1 where i=2;
+
+--connection node_1
+# Hang expected here
+--send insert into t1 select * from t2;
+
+--sleep 2
+--connection node_1a
+--error ER_LOCK_DEADLOCK
+insert into t2 select * from t1;
+
+--connection node_1
+--reap
+
+DROP TABLE t1, t2;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-329-master.opt b/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-329-master.opt
new file mode 100644 (file)
index 0000000..6565a6a
--- /dev/null
@@ -0,0 +1 @@
+--wsrep-retry-autocommit=0
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-329.test b/mysql-wsrep-5.6/mysql-test/suite/galera/t/MW-329.test
new file mode 100644 (file)
index 0000000..445f879
--- /dev/null
@@ -0,0 +1,81 @@
+#
+# #MW-329 Fix incorrect affected rows count after replay
+#
+
+--source include/galera_cluster.inc
+
+CREATE TABLE t1 (f1 INTEGER, f2 CHAR(20) DEFAULT 'abc') ENGINE=InnoDB;
+
+# We start with a populated table
+INSERT INTO t1 (f1) VALUES (1),(65535);
+
+# Clear the wsrep_local_replays counter
+
+FLUSH STATUS;
+SELECT VARIABLE_VALUE = 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays';
+
+#
+# Run concurrent INSERTs 
+#
+
+DELIMITER |;
+CREATE PROCEDURE proc_insert ()
+BEGIN
+        DECLARE CONTINUE HANDLER FOR SQLEXCEPTION BEGIN END;
+        SET SESSION wsrep_sync_wait = 0;
+        WHILE 1 DO
+               INSERT INTO t1 (f1) VALUES (FLOOR( 1 + RAND( ) * 65535 ));
+        END WHILE;
+END|
+DELIMITER ;|
+
+--connect node_1b, 127.0.0.1, root, , test, $NODE_MYPORT_1
+--connection node_1b
+--let $connection_id = `SELECT CONNECTION_ID()`
+--send CALL proc_insert();
+
+#
+# Run concurrent UPDATEs. We expect that each UPDATE will report that
+# some rows were matched and updated
+#
+
+--connection node_2
+--let $count = 10
+while ($count)
+{
+       --let $signature = `SELECT LEFT(MD5(RAND()), 10)`
+       --disable_query_log
+       --error 0,ER_LOCK_DEADLOCK
+       --eval UPDATE t1 SET f2 = '$signature'
+       --enable_query_log
+       --let $row_count = `SELECT ROW_COUNT()`
+       if (`SELECT @@error_count = 0`) {
+               if (`SELECT $row_count = 0`) {
+                       --die ROW_COUNT() = 0
+               }
+       }
+       --dec $count
+}
+
+#
+# Confirm that some transaction replays occurred
+#
+
+SELECT VARIABLE_VALUE > 0 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_local_replays';
+
+#
+# Terminate the stored procedure
+#
+
+--connection node_1
+--disable_query_log
+--eval KILL CONNECTION $connection_id
+--enable_query_log
+
+--connection node_1b
+--error 0,2013,1317
+--reap
+
+--connection node_1
+DROP PROCEDURE proc_insert;
+DROP TABLE t1;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.cnf b/mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.cnf
new file mode 100644 (file)
index 0000000..56102fb
--- /dev/null
@@ -0,0 +1,16 @@
+!include ../galera_2nodes_as_slave.cnf
+
+[mysqld]
+gtid-mode=ON
+log-bin=mysqld-bin
+log-slave-updates
+enforce-gtid-consistency
+binlog-format=ROW
+
+[mysqld.2]
+replicate-do-db=test1
+replicate-wild-do-table=test1.%
+
+[mysqld.3]
+replicate-do-db=test1
+replicate-wild-do-table=test1.%
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.test b/mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db.test
new file mode 100644 (file)
index 0000000..5f3fbd5
--- /dev/null
@@ -0,0 +1,146 @@
+#
+# Test Galera as a slave to a MySQL master using GTIDs
+#
+
+--source include/have_innodb.inc
+--source include/have_log_bin.inc
+
+# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--source include/galera_cluster.inc
+
+--connection node_1
+RESET MASTER;
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_3
+RESET MASTER;
+
+--connection node_2
+RESET MASTER;
+--disable_query_log
+--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_1;
+--enable_query_log
+START SLAVE USER='root';
+
+--connection node_1
+CREATE SCHEMA test1;
+CREATE SCHEMA test2;
+USE test1;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY,f2 CHAR(5) DEFAULT 'abc') ENGINE=InnoDB;
+USE test2;
+CREATE TABLE t1 (f1 INTEGER PRIMARY KEY,f2 CHAR(5) DEFAULT 'abc') ENGINE=InnoDB;
+
+#
+# First , some autocommit stuff
+#
+
+# Simple inserts
+
+INSERT INTO test1.t1 (f1) VALUES (1);
+INSERT INTO test2.t1 (f1) VALUES (1);
+
+INSERT INTO test1.t1 (f1) VALUES (2);
+INSERT INTO test2.t1 (f1) VALUES (2);
+
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+
+# Update that only covers test2.t1
+
+UPDATE test2.t1 SET test2.t1.f2 = 'cde';
+
+# Multi-table UPDATE
+
+UPDATE test1.t1, test2.t1 SET test1.t1.f2 = 'klm', test2.t1.f2 = 'xyz';
+
+# Multi-table DELETE
+
+DELETE test1.t1, test2.t1 FROM test1.t1 INNER JOIN test2.t1 WHERE test1.t1.f1 = test2.t1.f1 AND test1.t1.f1 = 3;
+
+#
+# Multi-statement transactions
+#
+
+# Transaction which is not replicated at all
+
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+INSERT INTO test2.t1 (f1) VALUES (999);
+INSERT INTO test2.t1 (f1) VALUES (9999);
+COMMIT;
+
+# Transaction that is completely replicated
+START TRANSACTION;
+INSERT INTO test1.t1 (f1) VALUES (111);
+INSERT INTO test1.t1 (f1) VALUES (222);
+COMMIT;
+
+# Transaction that is partially replicated
+
+START TRANSACTION;
+INSERT INTO test1.t1 (f1) VALUES (333);
+INSERT INTO test2.t1 (f1) VALUES (99999);
+COMMIT;
+
+#
+# Make sure binary logs and gtid_executed strings are equal
+#
+
+--sleep 2
+--connection node_2
+--let $effective_uuid = `SELECT LEFT(@@global.gtid_executed, 36)`
+--let $gtid_executed_node2 = `SELECT @@global.gtid_executed;`
+
+--replace_result $effective_uuid <effective_uuid>
+--replace_regex /xid=[0-9]+/xid=###/ /table_id: [0-9]+/table_id: ###/
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
+
+--connection node_3
+
+--disable_query_log
+--eval SELECT '$gtid_executed_node2' = @@global.gtid_executed AS gtid_executed_equal;
+--enable_query_log
+
+--replace_result $effective_uuid <effective_uuid>
+--replace_regex /xid=[0-9]+/xid=###/ /table_id: [0-9]+/table_id: ###/
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
+
+#
+# Final consistency checks
+# 
+
+--let $diff_servers = 2 3
+--source include/diff_servers.inc
+
+--connection node_3
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+SELECT COUNT(*) = 2 FROM test1.t1 WHERE f1 IN (1,2);
+SELECT COUNT(*) = 3 FROM test1.t1 WHERE f1 IN (111,222,333);
+SELECT COUNT(*) = 2 FROM test1.t1 WHERE f2 = 'klm';
+
+--error 1049
+USE test2;
+
+#
+# Cleanup
+#
+
+--connection node_1
+DROP SCHEMA test1;
+DROP SCHEMA test2;
+
+--sleep 1
+
+--connection node_3
+--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+STOP SLAVE;
+RESET SLAVE ALL;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db_cc.cnf b/mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db_cc.cnf
new file mode 100644 (file)
index 0000000..2669da8
--- /dev/null
@@ -0,0 +1,16 @@
+!include ../galera_3nodes_as_slave.cnf
+
+[mysqld]
+gtid-mode=ON
+log-bin=mysqld-bin
+log-slave-updates
+enforce-gtid-consistency
+binlog-format=ROW
+
+[mysqld.2]
+replicate-do-db=test1
+replicate-wild-do-table=test1.%
+
+[mysqld.3]
+replicate-do-db=test1
+replicate-wild-do-table=test1.%
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db_cc.test b/mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_as_slave_gtid_replicate_do_db_cc.test
new file mode 100644 (file)
index 0000000..0324c8d
--- /dev/null
@@ -0,0 +1,168 @@
+#
+# Test the case where a Galera slave to async replication goes non-prim while
+# a stream of replication events including filtered events is arriving
+#
+
+--source include/have_innodb.inc
+--source include/have_log_bin.inc
+--source include/big_test.inc
+
+# As node #1 is not a Galera node, we connect to node #2 in order to run include/galera_cluster.inc
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--source include/galera_cluster.inc
+
+--connection node_1
+RESET MASTER;
+
+--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
+--connection node_3
+RESET MASTER;
+
+--connection node_2
+RESET MASTER;
+
+--connection node_2
+--disable_query_log
+--eval CHANGE MASTER TO MASTER_HOST='127.0.0.1', MASTER_PORT=$NODE_MYPORT_1;
+--enable_query_log
+START SLAVE USER='root';
+
+--connection node_1
+CREATE SCHEMA test1;
+CREATE SCHEMA test2;
+USE test1;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+USE test2;
+CREATE TABLE t1 (f1 INTEGER) ENGINE=InnoDB;
+
+INSERT INTO test1.t1 (f1) VALUES (1);
+INSERT INTO test2.t1 (f1) VALUES (1);
+
+INSERT INTO test1.t1 (f1) VALUES (2);
+INSERT INTO test2.t1 (f1) VALUES (2);
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+--let $wait_condition = SELECT COUNT(*) = 2 FROM test1.t1;
+--source include/wait_condition.inc
+
+SET GLOBAL wsrep_provider_options='gmcast.isolate=1';
+
+--connection node_1
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+INSERT INTO test1.t1 (f1) VALUES (3);
+INSERT INTO test2.t1 (f1) VALUES (3);
+
+--connection node_2
+SET SESSION wsrep_on=OFF;
+--let $wait_condition = SELECT VARIABLE_VALUE = 'non-Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+
+--let $slave_sql_errno = 1047
+--source include/wait_for_slave_sql_error.inc
+
+--connection node_1
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+INSERT INTO test1.t1 (f1) VALUES (4);
+INSERT INTO test2.t1 (f1) VALUES (4);
+
+--connection node_2
+SET GLOBAL wsrep_provider_options='gmcast.isolate=0';
+
+--connection node_1
+INSERT INTO test1.t1 (f1) VALUES (5);
+INSERT INTO test2.t1 (f1) VALUES (5);
+
+--connection node_2
+--let $wait_condition = SELECT VARIABLE_VALUE = 'Primary' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_cluster_status';
+--source include/wait_condition.inc
+SET SESSION wsrep_on=ON;
+--let $wait_condition = SELECT VARIABLE_VALUE = 'ON' FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE variable_name = 'wsrep_ready';
+--source include/wait_condition.inc
+
+--connection node_1
+INSERT INTO test1.t1 (f1) VALUES (6);
+INSERT INTO test2.t1 (f1) VALUES (6);
+
+--connection node_2
+START SLAVE;
+
+#
+# Consistency checks
+#
+
+--sleep 2
+--connection node_2
+--let $wait_condition = SELECT COUNT(DISTINCT f1) = 6 FROM test1.t1;
+--source include/wait_condition.inc
+
+--connection node_3
+--let $wait_condition = SELECT COUNT(DISTINCT f1) = 6 FROM test1.t1;
+--source include/wait_condition.inc
+
+--connection node_2
+--let $gtid_executed_node2 = `SELECT @@global.gtid_executed;`
+--let $effective_uuid = `SELECT LEFT(@@global.gtid_executed, 36)`
+
+--replace_result $effective_uuid <effective_uuid>
+--replace_regex /xid=[0-9]+/xid=###/ /table_id: [0-9]+/table_id: ###/
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
+
+--error 1049
+USE test2;
+
+--connection node_3
+
+--disable_query_log
+--eval SELECT '$gtid_executed_node2' = @@global.gtid_executed AS gtid_executed_equal;
+--enable_query_log
+
+--error 1049
+USE test2;
+
+--replace_result $effective_uuid <effective_uuid>
+--replace_regex /xid=[0-9]+/xid=###/ /table_id: [0-9]+/table_id: ###/
+SHOW BINLOG EVENTS IN 'mysqld-bin.000001' FROM 120;
+
+#
+# Cleanup
+#
+
+--connection node_1
+DROP SCHEMA test1;
+DROP SCHEMA test2;
+
+--sleep 1
+
+--connection node_3
+--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+--connection node_2
+--let $wait_condition = SELECT COUNT(*) = 0 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 't1';
+--source include/wait_condition.inc
+
+--connection node_2
+STOP SLAVE;
+RESET SLAVE ALL;
+CALL mtr.add_suppression("GTID replication failed");
+CALL mtr.add_suppression("Slave SQL: Error in Xid_log_event: Commit could not be completed");
+CALL mtr.add_suppression("Slave SQL: Node has dropped from cluster, Error_code: 1047");
+CALL mtr.add_suppression("TO isolation failed for");
+CALL mtr.add_suppression("Slave SQL: Error 'Deadlock found when trying to get lock; try restarting transaction' on query");
+CALL mtr.add_suppression("Slave SQL: Error 'WSREP has not yet prepared node for application use' on query");
+CALL mtr.add_suppression("Slave: WSREP has not yet prepared node for application use Error_code: 1047");
index 7d684cef67d562c7d9793ab3cda13646d48afcc8..b4bf5f0217137b0b65cf17d601aca46abd1579ed 100644 (file)
@@ -1,9 +1,8 @@
 !include ../galera_2nodes.cnf
 
 [mysqld]
-#wsrep_sst_method=xtrabackup-v2
-#wsrep_sst_auth="root:"
-#wsrep_debug=ON
+wsrep_sst_method=xtrabackup-v2
+wsrep_sst_auth="root:"
 
 [mysqld.1]
 wsrep_provider_options='base_port=@mysqld.1.#galera_port;gcache.size=1;pc.ignore_sb=true'
index 251450f70992e3a54a89a6b891127a2f21fae0cd..30ce9bc4ceb45e6087fdcc55984021bc202315da 100644 (file)
@@ -1,6 +1,6 @@
 #
 # Test that autoincrement works correctly while the cluster membership
-# is changing and IST takes place.
+# is changing and SST takes place.
 #
 
 --source include/big_test.inc
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_wsrep_log_conficts-master.opt b/mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_wsrep_log_conficts-master.opt
new file mode 100644 (file)
index 0000000..930c483
--- /dev/null
@@ -0,0 +1 @@
+--wsrep_log_conflicts=ON
diff --git a/mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_wsrep_log_conficts.test b/mysql-wsrep-5.6/mysql-test/suite/galera/t/galera_wsrep_log_conficts.test
new file mode 100644 (file)
index 0000000..3af08cb
--- /dev/null
@@ -0,0 +1,55 @@
+#
+# Test --wsrep_log_conflicts=ON
+#
+
+--source include/galera_cluster.inc
+--source include/have_innodb.inc
+
+CREATE TABLE t1 (
+       f1 VARCHAR(255) PRIMARY KEY
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+INSERT INTO t1 VALUES ('abc');
+
+--connection node_2
+SELECT f1 = 'abc' FROM t1;
+
+#
+# Provoke a conflict
+#
+
+--connection node_1
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+UPDATE t1 SET f1 = 'klm';
+
+--connection node_2
+SET AUTOCOMMIT=OFF;
+START TRANSACTION;
+UPDATE t1 SET f1 = 'xyz';
+
+--connection node_1
+COMMIT;
+
+--connect node_2a, 127.0.0.1, root, , test, $NODE_MYPORT_2
+--connection node_2a
+--let $wait_condition = SELECT f1 = 'klm' FROM t1;
+--source include/wait_condition.inc
+
+--connection node_2
+--error ER_LOCK_DEADLOCK
+COMMIT;
+
+#
+# We can not really check the log output very much because it is quite variable
+#
+
+--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err
+--let $assert_only_after = CURRENT_TEST
+
+--let $assert_text = cluster conflict due to high priority abort for threads
+--let $assert_select = cluster conflict due to high priority abort for threads
+--let $assert_match = cluster conflict due to high priority abort for threads
+--source include/assert_grep.inc
+
+DROP TABLE t1;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/innodb/r/autoinc_debug.result b/mysql-wsrep-5.6/mysql-test/suite/innodb/r/autoinc_debug.result
new file mode 100644 (file)
index 0000000..b607109
--- /dev/null
@@ -0,0 +1,94 @@
+CREATE TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY)ENGINE=INNODB;
+# SETTING auto_increment_increment IN CONNECTION DEFAULT
+SET AUTO_INCREMENT_INCREMENT = 1;
+INSERT INTO t1 VALUES(NULL);
+SELECT * FROM t1;
+id
+1
+SHOW CREATE TABLE t1;
+Table  Create Table
+t1     CREATE TABLE `t1` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
+# SETTING auto_increment_increment IN CONNECTION1
+SET AUTO_INCREMENT_INCREMENT = 2;
+SET DEBUG_SYNC= 'ib_after_row_insert SIGNAL opened WAIT_FOR flushed1';
+INSERT INTO t1 VALUES(NULL);
+SET AUTO_INCREMENT_INCREMENT = 2;
+SET DEBUG_SYNC= 'now WAIT_FOR opened';
+SET DEBUG_SYNC= 'ib_after_row_insert_step SIGNAL flushed1 WAIT_FOR opened1';
+insert into t1 values(NULL);
+# CONNECTION default
+SELECT * FROM t1;
+id
+1
+3
+SHOW CREATE TABLE t1;
+Table  Create Table
+t1     CREATE TABLE `t1` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
+SET DEBUG_SYNC= 'now SIGNAL opened1';
+# CONNECTION con1
+SELECT * FROM t1;
+id
+1
+3
+5
+SHOW CREATE TABLE t1;
+Table  Create Table
+t1     CREATE TABLE `t1` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1
+DROP TABLE t1;
+CREATE TABLE t1(id INT AUTO_INCREMENT PRIMARY KEY)ENGINE=INNODB;
+# SETTING auto_increment_increment IN CONNECTION DEFAULT
+SET AUTO_INCREMENT_INCREMENT = 1;
+INSERT INTO t1 VALUES(NULL);
+SELECT * FROM t1;
+id
+1
+SHOW CREATE TABLE t1;
+Table  Create Table
+t1     CREATE TABLE `t1` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1
+SET DEBUG_SYNC = 'now SIGNAL flushed';
+# SETTING auto_increment_increment in connection1
+SET AUTO_INCREMENT_INCREMENT = 2;
+SET DEBUG_SYNC= 'now WAIT_FOR flushed';
+SET DEBUG_SYNC= 'ib_after_row_insert SIGNAL opened WAIT_FOR flushed1';
+INSERT INTO t1 values(NULL);
+# CONNECTION DEFAULT
+SET DEBUG_SYNC= 'now WAIT_FOR opened';
+SET DEBUG_SYNC= 'ib_after_row_insert_step SIGNAL flushed1 WAIT_FOR opened1';
+INSERT INTO t1 VALUES(NULL);
+# CONNECTION con1
+SELECT * FROM t1;
+id
+1
+3
+SHOW CREATE TABLE t1;
+Table  Create Table
+t1     CREATE TABLE `t1` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
+SET DEBUG_SYNC= 'now SIGNAL opened1';
+# CONNECTION default
+SELECT * FROM t1;
+id
+1
+3
+5
+SHOW CREATE TABLE t1;
+Table  Create Table
+t1     CREATE TABLE `t1` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1
+DROP TABLE t1;
index caa28131649d4f4cf2ae1c35d76fefd9cd85bb91..0957eedd5f9ffcff3aeaf20de316a9450420bbef 100644 (file)
@@ -153,6 +153,7 @@ id  LEFT(bfield,20)
 21     aaaaaaaaaaaaaaaaaaaa
 22     bbbbbbbbbbbbbbbbbbbb
 23     cccccccccccccccccccc
+SET GLOBAL innodb_fast_shutdown=0;
 "test misc 1"
 "test misc 2"
 "test misc 3"
index 0f5edd5e65f949d9a6645356d597c21652eb312b..4662d2dbd67bbc7457e4df0462c528b50af0392f 100644 (file)
@@ -2568,7 +2568,7 @@ EXPLAIN SELECT * FROM t1 WHERE f1 IN
 3784744,4180925,4559596,3963734,3856391,4494153)
 AND f5 = 'abcdefghijklmnopwrst' AND f2 = 1221457 AND f4 = 0 ;
 id     select_type     table   type    possible_keys   key     key_len ref     rows    Extra
-1      SIMPLE  t1      ref     PRIMARY,idx1,idx2       idx1    60      const,const,const       18      Using index condition
+1      SIMPLE  t1      range   PRIMARY,idx1,idx2       idx1    64      NULL    18      Using index condition
 DROP TABLE t1;
 #
 # Bug#51431 Wrong sort order after import of dump file
diff --git a/mysql-wsrep-5.6/mysql-test/suite/innodb/r/innodb_stats_del_mark.result b/mysql-wsrep-5.6/mysql-test/suite/innodb/r/innodb_stats_del_mark.result
new file mode 100644 (file)
index 0000000..0362ef8
--- /dev/null
@@ -0,0 +1,93 @@
+#
+# Bug 23333990 PERSISTENT INDEX STATISTICS UPDATE BEFORE
+#              TRANSACTION IS COMMITTED
+#
+"Test 1:- Uncommited delete test"
+CREATE TABLE t1 (id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+val INT UNSIGNED NOT NULL,
+INDEX (val)) ENGINE=INNODB
+STATS_PERSISTENT=1,STATS_AUTO_RECALC=1;
+INSERT INTO t1 (val) VALUES (4);
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+SELECT COUNT(*) FROM t1;
+COUNT(*)
+262144
+Connection 1
+START TRANSACTION;
+DELETE FROM t1;
+SELECT COUNT(*) FROM t1;
+Connection Default
+analyze table t1;
+Table  Op      Msg_type        Msg_text
+test.t1        analyze status  OK
+Test correctly estimates the number of rows as > 20000
+even when in other uncommmited transaction
+all rows have been deleted.
+Connection 1
+COUNT(*)
+0
+commit;
+Connection deafult
+Test 2:- Insert and rollback test
+CREATE TABLE t2 (id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+val INT UNSIGNED NOT NULL,
+INDEX (val)) ENGINE=INNODB
+STATS_PERSISTENT=1,STATS_AUTO_RECALC=1;
+Connection 1
+START TRANSACTION;
+INSERT INTO t2 (val) VALUES (4);
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+SELECT COUNT(*) FROM t2;
+Connection default
+select count(*) from t2;
+count(*)
+0
+analyze table t2;
+Table  Op      Msg_type        Msg_text
+test.t2        analyze status  OK
+Test correctly estimates the number of rows as > 20000
+even when in other uncommited transaction
+many rows are inserted.
+Connection 1
+COUNT(*)
+262144
+Rollback the insert
+rollback;
+Connection default
+Test correctly estimates the number of rows as 1
+after rollback.
+DROP TABLE t1,t2;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/innodb/t/autoinc_debug.test b/mysql-wsrep-5.6/mysql-test/suite/innodb/t/autoinc_debug.test
new file mode 100644 (file)
index 0000000..96568d3
--- /dev/null
@@ -0,0 +1,89 @@
+--source include/have_innodb.inc
+--source include/not_embedded.inc
+--source include/have_debug.inc
+
+# Two parallel connection with autoinc column after restart.
+
+CREATE TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY)ENGINE=INNODB;
+
+--echo # SETTING auto_increment_increment IN CONNECTION DEFAULT
+SET AUTO_INCREMENT_INCREMENT = 1;
+INSERT INTO t1 VALUES(NULL);
+SELECT * FROM t1;
+SHOW CREATE TABLE t1;
+
+--source include/restart_mysqld.inc
+
+--echo # SETTING auto_increment_increment IN CONNECTION1
+SET AUTO_INCREMENT_INCREMENT = 2;
+
+SET DEBUG_SYNC= 'ib_after_row_insert SIGNAL opened WAIT_FOR flushed1';
+
+SEND INSERT INTO t1 VALUES(NULL);
+
+connect(con1, localhost, root,,);
+SET AUTO_INCREMENT_INCREMENT = 2;
+SET DEBUG_SYNC= 'now WAIT_FOR opened';
+SET DEBUG_SYNC= 'ib_after_row_insert_step SIGNAL flushed1 WAIT_FOR opened1';
+send insert into t1 values(NULL);
+
+--echo # CONNECTION default
+connection default;
+reap;
+SELECT * FROM t1;
+SHOW CREATE TABLE t1;
+SET DEBUG_SYNC= 'now SIGNAL opened1';
+
+--echo # CONNECTION con1
+connection con1;
+reap;
+SELECT * FROM t1;
+SHOW CREATE TABLE t1;
+connection default;
+disconnect con1;
+
+DROP TABLE t1;
+
+# Two parallel connection with autoinc column without restart.
+
+CREATE TABLE t1(id INT AUTO_INCREMENT PRIMARY KEY)ENGINE=INNODB;
+
+--echo # SETTING auto_increment_increment IN CONNECTION DEFAULT
+SET AUTO_INCREMENT_INCREMENT = 1;
+INSERT INTO t1 VALUES(NULL);
+SELECT * FROM t1;
+SHOW CREATE TABLE t1;
+SET DEBUG_SYNC = 'now SIGNAL flushed';
+
+connect(con1, localhost, root,,);
+
+--echo # SETTING auto_increment_increment in connection1
+SET AUTO_INCREMENT_INCREMENT = 2;
+
+SET DEBUG_SYNC= 'now WAIT_FOR flushed';
+SET DEBUG_SYNC= 'ib_after_row_insert SIGNAL opened WAIT_FOR flushed1';
+
+send INSERT INTO t1 values(NULL);
+
+--echo # CONNECTION DEFAULT
+connection default;
+
+SET DEBUG_SYNC= 'now WAIT_FOR opened';
+SET DEBUG_SYNC= 'ib_after_row_insert_step SIGNAL flushed1 WAIT_FOR opened1';
+
+send INSERT INTO t1 VALUES(NULL);
+
+--echo # CONNECTION con1
+connection con1;
+reap;
+SELECT * FROM t1;
+SHOW CREATE TABLE t1;
+SET DEBUG_SYNC= 'now SIGNAL opened1';
+
+--echo # CONNECTION default
+connection default;
+reap;
+SELECT * FROM t1;
+SHOW CREATE TABLE t1;
+disconnect con1;
+DROP TABLE t1;
index e90f9f1cd43139b251f7fc684fb1bda423ecda08..45eebdb54e436001c89e4ada8ac067716abd1722 100644 (file)
@@ -45,3 +45,4 @@ innodb-lock-inherit-read_commited :  Cannot execute statement: impossible to wri
 innodb-index-debug : Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT
 flush-hang : Unsafe statement written to the binary log
 innodb_deadlock_with_autoinc : Test uses autoinc_lock_mode = 0
+innodb_stats_del_mark : Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.
index 252f86493a84334f56c66c5fbd94896b0928c01c..91c2a141300de70b5d04f6557f42f0883981afb7 100644 (file)
@@ -198,6 +198,7 @@ let SEARCH_FILE= $MYSQLTEST_VARDIR/log/my_restart.err;
 let $args=--loose-console > $SEARCH_FILE 2>&1;
 
 # Stop the server
+SET GLOBAL innodb_fast_shutdown=0;
 let $restart_file= $MYSQLTEST_VARDIR/tmp/mysqld.1.expect;
 --exec echo "wait" > $restart_file
 --shutdown_server
diff --git a/mysql-wsrep-5.6/mysql-test/suite/innodb/t/innodb_stats_del_mark-master.opt b/mysql-wsrep-5.6/mysql-test/suite/innodb/t/innodb_stats_del_mark-master.opt
new file mode 100644 (file)
index 0000000..145ee2b
--- /dev/null
@@ -0,0 +1 @@
+--innodb_stats_include_delete_marked=on
diff --git a/mysql-wsrep-5.6/mysql-test/suite/innodb/t/innodb_stats_del_mark.test b/mysql-wsrep-5.6/mysql-test/suite/innodb/t/innodb_stats_del_mark.test
new file mode 100644 (file)
index 0000000..9f0a5c1
--- /dev/null
@@ -0,0 +1,130 @@
+--echo #
+--echo # Bug 23333990  PERSISTENT INDEX STATISTICS UPDATE BEFORE
+--echo #               TRANSACTION IS COMMITTED
+--echo #
+
+--source include/big_test.inc
+--source include/not_valgrind.inc
+
+--echo "Test 1:- Uncommited delete test"
+CREATE TABLE t1 (id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+                val INT UNSIGNED NOT NULL,
+                INDEX (val)) ENGINE=INNODB
+                STATS_PERSISTENT=1,STATS_AUTO_RECALC=1;
+
+
+INSERT INTO t1 (val) VALUES (4);
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+INSERT INTO t1 (val) SELECT VAL from t1;
+SELECT COUNT(*) FROM t1;
+
+connect(con1, localhost, root,,);
+
+--echo Connection 1
+connection con1;
+START TRANSACTION;
+DELETE FROM t1;
+send SELECT COUNT(*) FROM t1;
+
+--echo Connection Default
+connection default;
+# To make test determinstic in case stats calculation is not
+# triggered we will call analyze table
+analyze table t1;
+let $row_count= query_get_value(EXPLAIN SELECT * FROM t1 WHERE val=4, rows,1);
+if ($row_count > 20000)
+{
+--echo Test correctly estimates the number of rows as > 20000
+--echo even when in other uncommmited transaction
+--echo all rows have been deleted.
+}
+
+if ($row_count < 20000)
+{
+--echo FAIL row count is $row_count
+}
+--echo Connection 1
+connection con1;
+reap;
+commit;
+
+--echo Connection deafult
+connection default;
+
+--echo Test 2:- Insert and rollback test
+CREATE TABLE t2 (id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+                val INT UNSIGNED NOT NULL,
+                INDEX (val)) ENGINE=INNODB
+                STATS_PERSISTENT=1,STATS_AUTO_RECALC=1;
+
+--echo Connection 1
+connection con1;
+
+START TRANSACTION;
+
+INSERT INTO t2 (val) VALUES (4);
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+INSERT INTO t2 (val) SELECT VAL from t2;
+send SELECT COUNT(*) FROM t2;
+
+--echo Connection default
+connection default;
+select count(*) from t2;
+analyze table t2;
+let $row_count= query_get_value(EXPLAIN SELECT * FROM t2 WHERE val=4, rows,1);
+if ($row_count > 20000)
+{
+--echo Test correctly estimates the number of rows as > 20000
+--echo even when in other uncommited transaction
+--echo many rows are inserted.
+}
+
+--echo Connection 1
+connection con1;
+reap;
+--echo Rollback the insert
+rollback;
+
+--echo Connection default
+connection default;
+let $row_count= query_get_value(EXPLAIN SELECT * FROM t2 WHERE val=4, rows,1);
+if ($row_count <= 1)
+{
+--echo Test correctly estimates the number of rows as $row_count
+--echo after rollback.
+}
+
+disconnect con1;
+DROP TABLE t1,t2;
index 9fe571cdee527d6460844ba1b6bb9497993a62fb..dc8e4db5163f9076f35228845bafa2300c272763 100644 (file)
@@ -335,3 +335,34 @@ WHERE
 HAVING  alias1.col_int_nokey  IN ( SELECT 2 FROM DUAL ) ;
 
 DROP TABLE t1,t2,t3,t4;
+
+--echo #
+--echo # Bug #23259872: OPTIMIZER CHOOSES TO USE NON PRIMARY
+--echo #                INDEX, EVEN THOUGH COST IS HIGHER
+--echo #
+
+CREATE TABLE t1 (
+  a TINYTEXT NOT NULL,
+  b TINYINT(3) UNSIGNED NOT NULL,
+  PRIMARY KEY (a(32),b),
+  KEY b_idx(b)
+) ENGINE=INNODB;
+INSERT INTO t1 VALUES ('a',1),('a',2),('a',3),('b',1),('b',4),('c',1),('d',1),
+                      ('c',4),('d',3),('e',2),('f',2);
+
+SET @optimizer_switch_saved=@@session.optimizer_switch;
+SET @@session.optimizer_switch=default;
+SET optimizer_trace="enabled=on";
+
+# Uses "access_type_changed" to use range over ref despite b_idx not being the
+# cheapest in range.
+EXPLAIN SELECT * FROM t1 WHERE a IN ('a', 'b') AND b = 2;
+
+# Output of table_scan in test_quick_select is not always reliable.
+--replace_regex /"rows": 12/"rows": 11/ /"cost": 5.5/"cost": 5.3/
+SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+
+SET optimizer_trace="enabled=off";
+SET @@session.optimizer_switch=@optimizer_switch_saved;
+
+DROP TABLE t1;
index f2f9af7ddce901e70185a819c7a487b6d0c2a062..08da7b99a674781734cc7bb79a3f5e47709371d0 100644 (file)
@@ -2435,3 +2435,311 @@ AND alias1.col_int_key = alias2.pk
 HAVING  alias1.col_int_nokey  IN ( SELECT 2 FROM DUAL ) ;
 field1 field2  field3  field4
 DROP TABLE t1,t2,t3,t4;
+#
+# Bug #23259872: OPTIMIZER CHOOSES TO USE NON PRIMARY
+#                INDEX, EVEN THOUGH COST IS HIGHER
+#
+CREATE TABLE t1 (
+a TINYTEXT NOT NULL,
+b TINYINT(3) UNSIGNED NOT NULL,
+PRIMARY KEY (a(32),b),
+KEY b_idx(b)
+) ENGINE=INNODB;
+INSERT INTO t1 VALUES ('a',1),('a',2),('a',3),('b',1),('b',4),('c',1),('d',1),
+('c',4),('d',3),('e',2),('f',2);
+SET @optimizer_switch_saved=@@session.optimizer_switch;
+SET @@session.optimizer_switch=default;
+SET optimizer_trace="enabled=on";
+EXPLAIN SELECT * FROM t1 WHERE a IN ('a', 'b') AND b = 2;
+id     select_type     table   type    possible_keys   key     key_len ref     rows    Extra
+1      SIMPLE  t1      range   PRIMARY,b_idx   b_idx   35      NULL    2       Using index condition; Using where
+SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+QUERY  TRACE   MISSING_BYTES_BEYOND_MAX_MEM_SIZE       INSUFFICIENT_PRIVILEGES
+EXPLAIN SELECT * FROM t1 WHERE a IN ('a', 'b') AND b = 2       {
+  "steps": [
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+          {
+            "expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where ((`t1`.`a` in ('a','b')) and (`t1`.`b` = 2))"
+          }
+        ] /* steps */
+      } /* join_preparation */
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "((`t1`.`a` in ('a','b')) and (`t1`.`b` = 2))",
+              "steps": [
+                {
+                  "transformation": "equality_propagation",
+                  "resulting_condition": "((`t1`.`a` in ('a','b')) and multiple equal(2, `t1`.`b`))"
+                },
+                {
+                  "transformation": "constant_propagation",
+                  "resulting_condition": "((`t1`.`a` in ('a','b')) and multiple equal(2, `t1`.`b`))"
+                },
+                {
+                  "transformation": "trivial_condition_removal",
+                  "resulting_condition": "((`t1`.`a` in ('a','b')) and multiple equal(2, `t1`.`b`))"
+                }
+              ] /* steps */
+            } /* condition_processing */
+          },
+          {
+            "table_dependencies": [
+              {
+                "table": "`t1`",
+                "row_may_be_null": false,
+                "map_bit": 0,
+                "depends_on_map_bits": [
+                ] /* depends_on_map_bits */
+              }
+            ] /* table_dependencies */
+          },
+          {
+            "ref_optimizer_key_uses": [
+              {
+                "table": "`t1`",
+                "field": "b",
+                "equals": "2",
+                "null_rejecting": false
+              }
+            ] /* ref_optimizer_key_uses */
+          },
+          {
+            "rows_estimation": [
+              {
+                "table": "`t1`",
+                "range_analysis": {
+                  "table_scan": {
+                    "rows": 11,
+                    "cost": 5.3
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "PRIMARY",
+                      "usable": true,
+                      "key_parts": [
+                        "a",
+                        "b"
+                      ] /* key_parts */
+                    },
+                    {
+                      "index": "b_idx",
+                      "usable": true,
+                      "key_parts": [
+                        "b",
+                        "a"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "setup_range_conditions": [
+                  ] /* setup_range_conditions */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "PRIMARY",
+                        "ranges": [
+                          "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2",
+                          "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2"
+                        ] /* ranges */,
+                        "index_dives_for_eq_ranges": true,
+                        "rowid_ordered": true,
+                        "using_mrr": false,
+                        "index_only": false,
+                        "rows": 2,
+                        "cost": 2.41,
+                        "chosen": true
+                      },
+                      {
+                        "index": "b_idx",
+                        "ranges": [
+                          "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value",
+                          "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value"
+                        ] /* ranges */,
+                        "index_dives_for_eq_ranges": true,
+                        "rowid_ordered": false,
+                        "using_mrr": false,
+                        "index_only": false,
+                        "rows": 2,
+                        "cost": 4.41,
+                        "chosen": false,
+                        "cause": "cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_roworder_intersect": {
+                      "usable": false,
+                      "cause": "too_few_roworder_scans"
+                    } /* analyzing_roworder_intersect */
+                  } /* analyzing_range_alternatives */,
+                  "chosen_range_access_summary": {
+                    "range_access_plan": {
+                      "type": "range_scan",
+                      "index": "PRIMARY",
+                      "rows": 2,
+                      "ranges": [
+                        "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2",
+                        "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2"
+                      ] /* ranges */
+                    } /* range_access_plan */,
+                    "rows_for_plan": 2,
+                    "cost_for_plan": 2.41,
+                    "chosen": true
+                  } /* chosen_range_access_summary */
+                } /* range_analysis */
+              }
+            ] /* rows_estimation */
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "plan_prefix": [
+                ] /* plan_prefix */,
+                "table": "`t1`",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "ref",
+                      "index": "b_idx",
+                      "rows": 2,
+                      "cost": 2.4,
+                      "chosen": true
+                    },
+                    {
+                      "access_type": "range",
+                      "rows": 2,
+                      "cost": 2.81,
+                      "chosen": false
+                    }
+                  ] /* considered_access_paths */
+                } /* best_access_path */,
+                "cost_for_plan": 2.4,
+                "rows_for_plan": 2,
+                "chosen": true
+              }
+            ] /* considered_execution_plans */
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "((`t1`.`b` = 2) and (`t1`.`a` in ('a','b')))",
+              "attached_conditions_computation": [
+                {
+                  "rerunning_range_optimizer_for_single_index": [
+                    {
+                      "table_scan": {
+                        "rows": 11,
+                        "cost": 5.3
+                      } /* table_scan */,
+                      "potential_range_indices": [
+                        {
+                          "index": "PRIMARY",
+                          "usable": false,
+                          "cause": "not_applicable"
+                        },
+                        {
+                          "index": "b_idx",
+                          "usable": true,
+                          "key_parts": [
+                            "b",
+                            "a"
+                          ] /* key_parts */
+                        }
+                      ] /* potential_range_indices */,
+                      "setup_range_conditions": [
+                      ] /* setup_range_conditions */,
+                      "group_index_range": {
+                        "chosen": false,
+                        "cause": "not_group_by_or_distinct"
+                      } /* group_index_range */,
+                      "analyzing_range_alternatives": {
+                        "range_scan_alternatives": [
+                          {
+                            "index": "b_idx",
+                            "ranges": [
+                              "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value",
+                              "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value"
+                            ] /* ranges */,
+                            "index_dives_for_eq_ranges": true,
+                            "rowid_ordered": false,
+                            "using_mrr": false,
+                            "index_only": false,
+                            "rows": 2,
+                            "cost": 4.41,
+                            "chosen": true
+                          }
+                        ] /* range_scan_alternatives */,
+                        "analyzing_roworder_intersect": {
+                          "usable": false,
+                          "cause": "too_few_roworder_scans"
+                        } /* analyzing_roworder_intersect */
+                      } /* analyzing_range_alternatives */,
+                      "chosen_range_access_summary": {
+                        "range_access_plan": {
+                          "type": "range_scan",
+                          "index": "b_idx",
+                          "rows": 2,
+                          "ranges": [
+                            "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value",
+                            "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value"
+                          ] /* ranges */
+                        } /* range_access_plan */,
+                        "rows_for_plan": 2,
+                        "cost_for_plan": 4.41,
+                        "chosen": true
+                      } /* chosen_range_access_summary */
+                    } /* range_analysis */
+                  ] /* rerunning_range_optimizer_for_single_index */
+                },
+                {
+                  "access_type_changed": {
+                    "table": "`t1`",
+                    "index": "b_idx",
+                    "old_type": "ref",
+                    "new_type": "range",
+                    "cause": "uses_more_keyparts"
+                  } /* access_type_changed */
+                }
+              ] /* attached_conditions_computation */,
+              "attached_conditions_summary": [
+                {
+                  "table": "`t1`",
+                  "attached": "((`t1`.`b` = 2) and (`t1`.`a` in ('a','b')))"
+                }
+              ] /* attached_conditions_summary */
+            } /* attaching_conditions_to_tables */
+          },
+          {
+            "refine_plan": [
+              {
+                "table": "`t1`",
+                "pushed_index_condition": "(`t1`.`b` = 2)",
+                "table_condition_attached": "(`t1`.`a` in ('a','b'))",
+                "access_type": "range"
+              }
+            ] /* refine_plan */
+          }
+        ] /* steps */
+      } /* join_optimization */
+    },
+    {
+      "join_explain": {
+        "select#": 1,
+        "steps": [
+        ] /* steps */
+      } /* join_explain */
+    }
+  ] /* steps */
+}      0       0
+SET optimizer_trace="enabled=off";
+SET @@session.optimizer_switch=@optimizer_switch_saved;
+DROP TABLE t1;
index 19f93e641db6b4cf78f71bc0eafa34bafab22051..1143d39622f9f69be246f29358b7d16ec1818d2c 100644 (file)
@@ -1895,3 +1895,311 @@ AND alias1.col_int_key = alias2.pk
 HAVING  alias1.col_int_nokey  IN ( SELECT 2 FROM DUAL ) ;
 field1 field2  field3  field4
 DROP TABLE t1,t2,t3,t4;
+#
+# Bug #23259872: OPTIMIZER CHOOSES TO USE NON PRIMARY
+#                INDEX, EVEN THOUGH COST IS HIGHER
+#
+CREATE TABLE t1 (
+a TINYTEXT NOT NULL,
+b TINYINT(3) UNSIGNED NOT NULL,
+PRIMARY KEY (a(32),b),
+KEY b_idx(b)
+) ENGINE=INNODB;
+INSERT INTO t1 VALUES ('a',1),('a',2),('a',3),('b',1),('b',4),('c',1),('d',1),
+('c',4),('d',3),('e',2),('f',2);
+SET @optimizer_switch_saved=@@session.optimizer_switch;
+SET @@session.optimizer_switch=default;
+SET optimizer_trace="enabled=on";
+EXPLAIN SELECT * FROM t1 WHERE a IN ('a', 'b') AND b = 2;
+id     select_type     table   type    possible_keys   key     key_len ref     rows    Extra
+1      SIMPLE  t1      range   PRIMARY,b_idx   b_idx   35      NULL    2       Using index condition; Using where
+SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+QUERY  TRACE   MISSING_BYTES_BEYOND_MAX_MEM_SIZE       INSUFFICIENT_PRIVILEGES
+EXPLAIN SELECT * FROM t1 WHERE a IN ('a', 'b') AND b = 2       {
+  "steps": [
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+          {
+            "expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where ((`t1`.`a` in ('a','b')) and (`t1`.`b` = 2))"
+          }
+        ] /* steps */
+      } /* join_preparation */
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "((`t1`.`a` in ('a','b')) and (`t1`.`b` = 2))",
+              "steps": [
+                {
+                  "transformation": "equality_propagation",
+                  "resulting_condition": "((`t1`.`a` in ('a','b')) and multiple equal(2, `t1`.`b`))"
+                },
+                {
+                  "transformation": "constant_propagation",
+                  "resulting_condition": "((`t1`.`a` in ('a','b')) and multiple equal(2, `t1`.`b`))"
+                },
+                {
+                  "transformation": "trivial_condition_removal",
+                  "resulting_condition": "((`t1`.`a` in ('a','b')) and multiple equal(2, `t1`.`b`))"
+                }
+              ] /* steps */
+            } /* condition_processing */
+          },
+          {
+            "table_dependencies": [
+              {
+                "table": "`t1`",
+                "row_may_be_null": false,
+                "map_bit": 0,
+                "depends_on_map_bits": [
+                ] /* depends_on_map_bits */
+              }
+            ] /* table_dependencies */
+          },
+          {
+            "ref_optimizer_key_uses": [
+              {
+                "table": "`t1`",
+                "field": "b",
+                "equals": "2",
+                "null_rejecting": false
+              }
+            ] /* ref_optimizer_key_uses */
+          },
+          {
+            "rows_estimation": [
+              {
+                "table": "`t1`",
+                "range_analysis": {
+                  "table_scan": {
+                    "rows": 11,
+                    "cost": 5.3
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "PRIMARY",
+                      "usable": true,
+                      "key_parts": [
+                        "a",
+                        "b"
+                      ] /* key_parts */
+                    },
+                    {
+                      "index": "b_idx",
+                      "usable": true,
+                      "key_parts": [
+                        "b",
+                        "a"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "setup_range_conditions": [
+                  ] /* setup_range_conditions */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "PRIMARY",
+                        "ranges": [
+                          "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2",
+                          "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2"
+                        ] /* ranges */,
+                        "index_dives_for_eq_ranges": true,
+                        "rowid_ordered": true,
+                        "using_mrr": false,
+                        "index_only": false,
+                        "rows": 2,
+                        "cost": 2.41,
+                        "chosen": true
+                      },
+                      {
+                        "index": "b_idx",
+                        "ranges": [
+                          "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value",
+                          "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value"
+                        ] /* ranges */,
+                        "index_dives_for_eq_ranges": true,
+                        "rowid_ordered": false,
+                        "using_mrr": false,
+                        "index_only": false,
+                        "rows": 2,
+                        "cost": 4.41,
+                        "chosen": false,
+                        "cause": "cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_roworder_intersect": {
+                      "usable": false,
+                      "cause": "too_few_roworder_scans"
+                    } /* analyzing_roworder_intersect */
+                  } /* analyzing_range_alternatives */,
+                  "chosen_range_access_summary": {
+                    "range_access_plan": {
+                      "type": "range_scan",
+                      "index": "PRIMARY",
+                      "rows": 2,
+                      "ranges": [
+                        "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2",
+                        "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2"
+                      ] /* ranges */
+                    } /* range_access_plan */,
+                    "rows_for_plan": 2,
+                    "cost_for_plan": 2.41,
+                    "chosen": true
+                  } /* chosen_range_access_summary */
+                } /* range_analysis */
+              }
+            ] /* rows_estimation */
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "plan_prefix": [
+                ] /* plan_prefix */,
+                "table": "`t1`",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "ref",
+                      "index": "b_idx",
+                      "rows": 2,
+                      "cost": 2.4,
+                      "chosen": true
+                    },
+                    {
+                      "access_type": "range",
+                      "rows": 2,
+                      "cost": 2.81,
+                      "chosen": false
+                    }
+                  ] /* considered_access_paths */
+                } /* best_access_path */,
+                "cost_for_plan": 2.4,
+                "rows_for_plan": 2,
+                "chosen": true
+              }
+            ] /* considered_execution_plans */
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "((`t1`.`b` = 2) and (`t1`.`a` in ('a','b')))",
+              "attached_conditions_computation": [
+                {
+                  "rerunning_range_optimizer_for_single_index": [
+                    {
+                      "table_scan": {
+                        "rows": 11,
+                        "cost": 5.3
+                      } /* table_scan */,
+                      "potential_range_indices": [
+                        {
+                          "index": "PRIMARY",
+                          "usable": false,
+                          "cause": "not_applicable"
+                        },
+                        {
+                          "index": "b_idx",
+                          "usable": true,
+                          "key_parts": [
+                            "b",
+                            "a"
+                          ] /* key_parts */
+                        }
+                      ] /* potential_range_indices */,
+                      "setup_range_conditions": [
+                      ] /* setup_range_conditions */,
+                      "group_index_range": {
+                        "chosen": false,
+                        "cause": "not_group_by_or_distinct"
+                      } /* group_index_range */,
+                      "analyzing_range_alternatives": {
+                        "range_scan_alternatives": [
+                          {
+                            "index": "b_idx",
+                            "ranges": [
+                              "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value",
+                              "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value"
+                            ] /* ranges */,
+                            "index_dives_for_eq_ranges": true,
+                            "rowid_ordered": false,
+                            "using_mrr": false,
+                            "index_only": false,
+                            "rows": 2,
+                            "cost": 4.41,
+                            "chosen": true
+                          }
+                        ] /* range_scan_alternatives */,
+                        "analyzing_roworder_intersect": {
+                          "usable": false,
+                          "cause": "too_few_roworder_scans"
+                        } /* analyzing_roworder_intersect */
+                      } /* analyzing_range_alternatives */,
+                      "chosen_range_access_summary": {
+                        "range_access_plan": {
+                          "type": "range_scan",
+                          "index": "b_idx",
+                          "rows": 2,
+                          "ranges": [
+                            "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value",
+                            "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value"
+                          ] /* ranges */
+                        } /* range_access_plan */,
+                        "rows_for_plan": 2,
+                        "cost_for_plan": 4.41,
+                        "chosen": true
+                      } /* chosen_range_access_summary */
+                    } /* range_analysis */
+                  ] /* rerunning_range_optimizer_for_single_index */
+                },
+                {
+                  "access_type_changed": {
+                    "table": "`t1`",
+                    "index": "b_idx",
+                    "old_type": "ref",
+                    "new_type": "range",
+                    "cause": "uses_more_keyparts"
+                  } /* access_type_changed */
+                }
+              ] /* attached_conditions_computation */,
+              "attached_conditions_summary": [
+                {
+                  "table": "`t1`",
+                  "attached": "((`t1`.`b` = 2) and (`t1`.`a` in ('a','b')))"
+                }
+              ] /* attached_conditions_summary */
+            } /* attaching_conditions_to_tables */
+          },
+          {
+            "refine_plan": [
+              {
+                "table": "`t1`",
+                "pushed_index_condition": "(`t1`.`b` = 2)",
+                "table_condition_attached": "(`t1`.`a` in ('a','b'))",
+                "access_type": "range"
+              }
+            ] /* refine_plan */
+          }
+        ] /* steps */
+      } /* join_optimization */
+    },
+    {
+      "join_explain": {
+        "select#": 1,
+        "steps": [
+        ] /* steps */
+      } /* join_explain */
+    }
+  ] /* steps */
+}      0       0
+SET optimizer_trace="enabled=off";
+SET @@session.optimizer_switch=@optimizer_switch_saved;
+DROP TABLE t1;
index f2f9af7ddce901e70185a819c7a487b6d0c2a062..08da7b99a674781734cc7bb79a3f5e47709371d0 100644 (file)
@@ -2435,3 +2435,311 @@ AND alias1.col_int_key = alias2.pk
 HAVING  alias1.col_int_nokey  IN ( SELECT 2 FROM DUAL ) ;
 field1 field2  field3  field4
 DROP TABLE t1,t2,t3,t4;
+#
+# Bug #23259872: OPTIMIZER CHOOSES TO USE NON PRIMARY
+#                INDEX, EVEN THOUGH COST IS HIGHER
+#
+CREATE TABLE t1 (
+a TINYTEXT NOT NULL,
+b TINYINT(3) UNSIGNED NOT NULL,
+PRIMARY KEY (a(32),b),
+KEY b_idx(b)
+) ENGINE=INNODB;
+INSERT INTO t1 VALUES ('a',1),('a',2),('a',3),('b',1),('b',4),('c',1),('d',1),
+('c',4),('d',3),('e',2),('f',2);
+SET @optimizer_switch_saved=@@session.optimizer_switch;
+SET @@session.optimizer_switch=default;
+SET optimizer_trace="enabled=on";
+EXPLAIN SELECT * FROM t1 WHERE a IN ('a', 'b') AND b = 2;
+id     select_type     table   type    possible_keys   key     key_len ref     rows    Extra
+1      SIMPLE  t1      range   PRIMARY,b_idx   b_idx   35      NULL    2       Using index condition; Using where
+SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+QUERY  TRACE   MISSING_BYTES_BEYOND_MAX_MEM_SIZE       INSUFFICIENT_PRIVILEGES
+EXPLAIN SELECT * FROM t1 WHERE a IN ('a', 'b') AND b = 2       {
+  "steps": [
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+          {
+            "expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where ((`t1`.`a` in ('a','b')) and (`t1`.`b` = 2))"
+          }
+        ] /* steps */
+      } /* join_preparation */
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "((`t1`.`a` in ('a','b')) and (`t1`.`b` = 2))",
+              "steps": [
+                {
+                  "transformation": "equality_propagation",
+                  "resulting_condition": "((`t1`.`a` in ('a','b')) and multiple equal(2, `t1`.`b`))"
+                },
+                {
+                  "transformation": "constant_propagation",
+                  "resulting_condition": "((`t1`.`a` in ('a','b')) and multiple equal(2, `t1`.`b`))"
+                },
+                {
+                  "transformation": "trivial_condition_removal",
+                  "resulting_condition": "((`t1`.`a` in ('a','b')) and multiple equal(2, `t1`.`b`))"
+                }
+              ] /* steps */
+            } /* condition_processing */
+          },
+          {
+            "table_dependencies": [
+              {
+                "table": "`t1`",
+                "row_may_be_null": false,
+                "map_bit": 0,
+                "depends_on_map_bits": [
+                ] /* depends_on_map_bits */
+              }
+            ] /* table_dependencies */
+          },
+          {
+            "ref_optimizer_key_uses": [
+              {
+                "table": "`t1`",
+                "field": "b",
+                "equals": "2",
+                "null_rejecting": false
+              }
+            ] /* ref_optimizer_key_uses */
+          },
+          {
+            "rows_estimation": [
+              {
+                "table": "`t1`",
+                "range_analysis": {
+                  "table_scan": {
+                    "rows": 11,
+                    "cost": 5.3
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "PRIMARY",
+                      "usable": true,
+                      "key_parts": [
+                        "a",
+                        "b"
+                      ] /* key_parts */
+                    },
+                    {
+                      "index": "b_idx",
+                      "usable": true,
+                      "key_parts": [
+                        "b",
+                        "a"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "setup_range_conditions": [
+                  ] /* setup_range_conditions */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "PRIMARY",
+                        "ranges": [
+                          "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2",
+                          "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2"
+                        ] /* ranges */,
+                        "index_dives_for_eq_ranges": true,
+                        "rowid_ordered": true,
+                        "using_mrr": false,
+                        "index_only": false,
+                        "rows": 2,
+                        "cost": 2.41,
+                        "chosen": true
+                      },
+                      {
+                        "index": "b_idx",
+                        "ranges": [
+                          "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value",
+                          "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value"
+                        ] /* ranges */,
+                        "index_dives_for_eq_ranges": true,
+                        "rowid_ordered": false,
+                        "using_mrr": false,
+                        "index_only": false,
+                        "rows": 2,
+                        "cost": 4.41,
+                        "chosen": false,
+                        "cause": "cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_roworder_intersect": {
+                      "usable": false,
+                      "cause": "too_few_roworder_scans"
+                    } /* analyzing_roworder_intersect */
+                  } /* analyzing_range_alternatives */,
+                  "chosen_range_access_summary": {
+                    "range_access_plan": {
+                      "type": "range_scan",
+                      "index": "PRIMARY",
+                      "rows": 2,
+                      "ranges": [
+                        "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2",
+                        "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2"
+                      ] /* ranges */
+                    } /* range_access_plan */,
+                    "rows_for_plan": 2,
+                    "cost_for_plan": 2.41,
+                    "chosen": true
+                  } /* chosen_range_access_summary */
+                } /* range_analysis */
+              }
+            ] /* rows_estimation */
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "plan_prefix": [
+                ] /* plan_prefix */,
+                "table": "`t1`",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "ref",
+                      "index": "b_idx",
+                      "rows": 2,
+                      "cost": 2.4,
+                      "chosen": true
+                    },
+                    {
+                      "access_type": "range",
+                      "rows": 2,
+                      "cost": 2.81,
+                      "chosen": false
+                    }
+                  ] /* considered_access_paths */
+                } /* best_access_path */,
+                "cost_for_plan": 2.4,
+                "rows_for_plan": 2,
+                "chosen": true
+              }
+            ] /* considered_execution_plans */
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "((`t1`.`b` = 2) and (`t1`.`a` in ('a','b')))",
+              "attached_conditions_computation": [
+                {
+                  "rerunning_range_optimizer_for_single_index": [
+                    {
+                      "table_scan": {
+                        "rows": 11,
+                        "cost": 5.3
+                      } /* table_scan */,
+                      "potential_range_indices": [
+                        {
+                          "index": "PRIMARY",
+                          "usable": false,
+                          "cause": "not_applicable"
+                        },
+                        {
+                          "index": "b_idx",
+                          "usable": true,
+                          "key_parts": [
+                            "b",
+                            "a"
+                          ] /* key_parts */
+                        }
+                      ] /* potential_range_indices */,
+                      "setup_range_conditions": [
+                      ] /* setup_range_conditions */,
+                      "group_index_range": {
+                        "chosen": false,
+                        "cause": "not_group_by_or_distinct"
+                      } /* group_index_range */,
+                      "analyzing_range_alternatives": {
+                        "range_scan_alternatives": [
+                          {
+                            "index": "b_idx",
+                            "ranges": [
+                              "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value",
+                              "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value"
+                            ] /* ranges */,
+                            "index_dives_for_eq_ranges": true,
+                            "rowid_ordered": false,
+                            "using_mrr": false,
+                            "index_only": false,
+                            "rows": 2,
+                            "cost": 4.41,
+                            "chosen": true
+                          }
+                        ] /* range_scan_alternatives */,
+                        "analyzing_roworder_intersect": {
+                          "usable": false,
+                          "cause": "too_few_roworder_scans"
+                        } /* analyzing_roworder_intersect */
+                      } /* analyzing_range_alternatives */,
+                      "chosen_range_access_summary": {
+                        "range_access_plan": {
+                          "type": "range_scan",
+                          "index": "b_idx",
+                          "rows": 2,
+                          "ranges": [
+                            "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value",
+                            "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value"
+                          ] /* ranges */
+                        } /* range_access_plan */,
+                        "rows_for_plan": 2,
+                        "cost_for_plan": 4.41,
+                        "chosen": true
+                      } /* chosen_range_access_summary */
+                    } /* range_analysis */
+                  ] /* rerunning_range_optimizer_for_single_index */
+                },
+                {
+                  "access_type_changed": {
+                    "table": "`t1`",
+                    "index": "b_idx",
+                    "old_type": "ref",
+                    "new_type": "range",
+                    "cause": "uses_more_keyparts"
+                  } /* access_type_changed */
+                }
+              ] /* attached_conditions_computation */,
+              "attached_conditions_summary": [
+                {
+                  "table": "`t1`",
+                  "attached": "((`t1`.`b` = 2) and (`t1`.`a` in ('a','b')))"
+                }
+              ] /* attached_conditions_summary */
+            } /* attaching_conditions_to_tables */
+          },
+          {
+            "refine_plan": [
+              {
+                "table": "`t1`",
+                "pushed_index_condition": "(`t1`.`b` = 2)",
+                "table_condition_attached": "(`t1`.`a` in ('a','b'))",
+                "access_type": "range"
+              }
+            ] /* refine_plan */
+          }
+        ] /* steps */
+      } /* join_optimization */
+    },
+    {
+      "join_explain": {
+        "select#": 1,
+        "steps": [
+        ] /* steps */
+      } /* join_explain */
+    }
+  ] /* steps */
+}      0       0
+SET optimizer_trace="enabled=off";
+SET @@session.optimizer_switch=@optimizer_switch_saved;
+DROP TABLE t1;
index ef8b165d0b5bb3248766396ef9e9b7422896eb90..e0f1e562ae3cdc66ea596c3a965f60eb26146672 100644 (file)
@@ -1859,3 +1859,311 @@ AND alias1.col_int_key = alias2.pk
 HAVING  alias1.col_int_nokey  IN ( SELECT 2 FROM DUAL ) ;
 field1 field2  field3  field4
 DROP TABLE t1,t2,t3,t4;
+#
+# Bug #23259872: OPTIMIZER CHOOSES TO USE NON PRIMARY
+#                INDEX, EVEN THOUGH COST IS HIGHER
+#
+CREATE TABLE t1 (
+a TINYTEXT NOT NULL,
+b TINYINT(3) UNSIGNED NOT NULL,
+PRIMARY KEY (a(32),b),
+KEY b_idx(b)
+) ENGINE=INNODB;
+INSERT INTO t1 VALUES ('a',1),('a',2),('a',3),('b',1),('b',4),('c',1),('d',1),
+('c',4),('d',3),('e',2),('f',2);
+SET @optimizer_switch_saved=@@session.optimizer_switch;
+SET @@session.optimizer_switch=default;
+SET optimizer_trace="enabled=on";
+EXPLAIN SELECT * FROM t1 WHERE a IN ('a', 'b') AND b = 2;
+id     select_type     table   type    possible_keys   key     key_len ref     rows    Extra
+1      SIMPLE  t1      range   PRIMARY,b_idx   b_idx   35      NULL    2       Using index condition; Using where
+SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE;
+QUERY  TRACE   MISSING_BYTES_BEYOND_MAX_MEM_SIZE       INSUFFICIENT_PRIVILEGES
+EXPLAIN SELECT * FROM t1 WHERE a IN ('a', 'b') AND b = 2       {
+  "steps": [
+    {
+      "join_preparation": {
+        "select#": 1,
+        "steps": [
+          {
+            "expanded_query": "/* select#1 */ select `t1`.`a` AS `a`,`t1`.`b` AS `b` from `t1` where ((`t1`.`a` in ('a','b')) and (`t1`.`b` = 2))"
+          }
+        ] /* steps */
+      } /* join_preparation */
+    },
+    {
+      "join_optimization": {
+        "select#": 1,
+        "steps": [
+          {
+            "condition_processing": {
+              "condition": "WHERE",
+              "original_condition": "((`t1`.`a` in ('a','b')) and (`t1`.`b` = 2))",
+              "steps": [
+                {
+                  "transformation": "equality_propagation",
+                  "resulting_condition": "((`t1`.`a` in ('a','b')) and multiple equal(2, `t1`.`b`))"
+                },
+                {
+                  "transformation": "constant_propagation",
+                  "resulting_condition": "((`t1`.`a` in ('a','b')) and multiple equal(2, `t1`.`b`))"
+                },
+                {
+                  "transformation": "trivial_condition_removal",
+                  "resulting_condition": "((`t1`.`a` in ('a','b')) and multiple equal(2, `t1`.`b`))"
+                }
+              ] /* steps */
+            } /* condition_processing */
+          },
+          {
+            "table_dependencies": [
+              {
+                "table": "`t1`",
+                "row_may_be_null": false,
+                "map_bit": 0,
+                "depends_on_map_bits": [
+                ] /* depends_on_map_bits */
+              }
+            ] /* table_dependencies */
+          },
+          {
+            "ref_optimizer_key_uses": [
+              {
+                "table": "`t1`",
+                "field": "b",
+                "equals": "2",
+                "null_rejecting": false
+              }
+            ] /* ref_optimizer_key_uses */
+          },
+          {
+            "rows_estimation": [
+              {
+                "table": "`t1`",
+                "range_analysis": {
+                  "table_scan": {
+                    "rows": 11,
+                    "cost": 5.3
+                  } /* table_scan */,
+                  "potential_range_indices": [
+                    {
+                      "index": "PRIMARY",
+                      "usable": true,
+                      "key_parts": [
+                        "a",
+                        "b"
+                      ] /* key_parts */
+                    },
+                    {
+                      "index": "b_idx",
+                      "usable": true,
+                      "key_parts": [
+                        "b",
+                        "a"
+                      ] /* key_parts */
+                    }
+                  ] /* potential_range_indices */,
+                  "setup_range_conditions": [
+                  ] /* setup_range_conditions */,
+                  "group_index_range": {
+                    "chosen": false,
+                    "cause": "not_group_by_or_distinct"
+                  } /* group_index_range */,
+                  "analyzing_range_alternatives": {
+                    "range_scan_alternatives": [
+                      {
+                        "index": "PRIMARY",
+                        "ranges": [
+                          "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2",
+                          "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2"
+                        ] /* ranges */,
+                        "index_dives_for_eq_ranges": true,
+                        "rowid_ordered": true,
+                        "using_mrr": false,
+                        "index_only": false,
+                        "rows": 2,
+                        "cost": 2.41,
+                        "chosen": true
+                      },
+                      {
+                        "index": "b_idx",
+                        "ranges": [
+                          "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value",
+                          "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value"
+                        ] /* ranges */,
+                        "index_dives_for_eq_ranges": true,
+                        "rowid_ordered": false,
+                        "using_mrr": false,
+                        "index_only": false,
+                        "rows": 2,
+                        "cost": 4.41,
+                        "chosen": false,
+                        "cause": "cost"
+                      }
+                    ] /* range_scan_alternatives */,
+                    "analyzing_roworder_intersect": {
+                      "usable": false,
+                      "cause": "too_few_roworder_scans"
+                    } /* analyzing_roworder_intersect */
+                  } /* analyzing_range_alternatives */,
+                  "chosen_range_access_summary": {
+                    "range_access_plan": {
+                      "type": "range_scan",
+                      "index": "PRIMARY",
+                      "rows": 2,
+                      "ranges": [
+                        "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2",
+                        "unprintable_blob_value <= a <= unprintable_blob_value AND 2 <= b <= 2"
+                      ] /* ranges */
+                    } /* range_access_plan */,
+                    "rows_for_plan": 2,
+                    "cost_for_plan": 2.41,
+                    "chosen": true
+                  } /* chosen_range_access_summary */
+                } /* range_analysis */
+              }
+            ] /* rows_estimation */
+          },
+          {
+            "considered_execution_plans": [
+              {
+                "plan_prefix": [
+                ] /* plan_prefix */,
+                "table": "`t1`",
+                "best_access_path": {
+                  "considered_access_paths": [
+                    {
+                      "access_type": "ref",
+                      "index": "b_idx",
+                      "rows": 2,
+                      "cost": 2.4,
+                      "chosen": true
+                    },
+                    {
+                      "access_type": "range",
+                      "rows": 2,
+                      "cost": 2.81,
+                      "chosen": false
+                    }
+                  ] /* considered_access_paths */
+                } /* best_access_path */,
+                "cost_for_plan": 2.4,
+                "rows_for_plan": 2,
+                "chosen": true
+              }
+            ] /* considered_execution_plans */
+          },
+          {
+            "attaching_conditions_to_tables": {
+              "original_condition": "((`t1`.`b` = 2) and (`t1`.`a` in ('a','b')))",
+              "attached_conditions_computation": [
+                {
+                  "rerunning_range_optimizer_for_single_index": [
+                    {
+                      "table_scan": {
+                        "rows": 11,
+                        "cost": 5.3
+                      } /* table_scan */,
+                      "potential_range_indices": [
+                        {
+                          "index": "PRIMARY",
+                          "usable": false,
+                          "cause": "not_applicable"
+                        },
+                        {
+                          "index": "b_idx",
+                          "usable": true,
+                          "key_parts": [
+                            "b",
+                            "a"
+                          ] /* key_parts */
+                        }
+                      ] /* potential_range_indices */,
+                      "setup_range_conditions": [
+                      ] /* setup_range_conditions */,
+                      "group_index_range": {
+                        "chosen": false,
+                        "cause": "not_group_by_or_distinct"
+                      } /* group_index_range */,
+                      "analyzing_range_alternatives": {
+                        "range_scan_alternatives": [
+                          {
+                            "index": "b_idx",
+                            "ranges": [
+                              "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value",
+                              "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value"
+                            ] /* ranges */,
+                            "index_dives_for_eq_ranges": true,
+                            "rowid_ordered": false,
+                            "using_mrr": false,
+                            "index_only": false,
+                            "rows": 2,
+                            "cost": 4.41,
+                            "chosen": true
+                          }
+                        ] /* range_scan_alternatives */,
+                        "analyzing_roworder_intersect": {
+                          "usable": false,
+                          "cause": "too_few_roworder_scans"
+                        } /* analyzing_roworder_intersect */
+                      } /* analyzing_range_alternatives */,
+                      "chosen_range_access_summary": {
+                        "range_access_plan": {
+                          "type": "range_scan",
+                          "index": "b_idx",
+                          "rows": 2,
+                          "ranges": [
+                            "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value",
+                            "2 <= b <= 2 AND unprintable_blob_value <= a <= unprintable_blob_value"
+                          ] /* ranges */
+                        } /* range_access_plan */,
+                        "rows_for_plan": 2,
+                        "cost_for_plan": 4.41,
+                        "chosen": true
+                      } /* chosen_range_access_summary */
+                    } /* range_analysis */
+                  ] /* rerunning_range_optimizer_for_single_index */
+                },
+                {
+                  "access_type_changed": {
+                    "table": "`t1`",
+                    "index": "b_idx",
+                    "old_type": "ref",
+                    "new_type": "range",
+                    "cause": "uses_more_keyparts"
+                  } /* access_type_changed */
+                }
+              ] /* attached_conditions_computation */,
+              "attached_conditions_summary": [
+                {
+                  "table": "`t1`",
+                  "attached": "((`t1`.`b` = 2) and (`t1`.`a` in ('a','b')))"
+                }
+              ] /* attached_conditions_summary */
+            } /* attaching_conditions_to_tables */
+          },
+          {
+            "refine_plan": [
+              {
+                "table": "`t1`",
+                "pushed_index_condition": "(`t1`.`b` = 2)",
+                "table_condition_attached": "(`t1`.`a` in ('a','b'))",
+                "access_type": "range"
+              }
+            ] /* refine_plan */
+          }
+        ] /* steps */
+      } /* join_optimization */
+    },
+    {
+      "join_explain": {
+        "select#": 1,
+        "steps": [
+        ] /* steps */
+      } /* join_explain */
+    }
+  ] /* steps */
+}      0       0
+SET optimizer_trace="enabled=off";
+SET @@session.optimizer_switch=@optimizer_switch_saved;
+DROP TABLE t1;
index db3ab6b7f82306dfb1aca6a8e8ddc97113bdcb77..0f52fa474f234afb7a600ceba936463aea069543 100644 (file)
@@ -27,6 +27,9 @@ let $TABLENAME= t1;
 GRANT ALL PRIVILEGES ON test.* TO test_user_1 IDENTIFIED BY 'testpw';
 GRANT ALL PRIVILEGES ON test.* TO test_user_2 IDENTIFIED BY 'testpw';
 
+--echo # FILE is needed to use the DATA DIRECTORY or INDEX DIRECTORY option
+GRANT FILE ON *.* TO test_user_2 IDENTIFIED BY 'testpw';
+
 connect (session1, localhost, test_user_1,'testpw',test);
 --sorted_result
 SELECT * FROM t1 PARTITION (`p0-29`);
index ca29757c519fe0c5364df9b401168a8cf33d70c8..1574017c58ca45279d5db959f1912e1df369759e 100644 (file)
@@ -33,6 +33,8 @@ INSERT INTO t1 PARTITION (`p3000-299999`, subp14) VALUES (299998, '(p3000-299999
 INSERT INTO t1 PARTITION (`p3000-299999`, subp14) VALUES (299999, '(p3000-299999-)subp14');
 GRANT ALL PRIVILEGES ON test.* TO test_user_1 IDENTIFIED BY 'testpw';
 GRANT ALL PRIVILEGES ON test.* TO test_user_2 IDENTIFIED BY 'testpw';
+# FILE is needed to use the DATA DIRECTORY or INDEX DIRECTORY option
+GRANT FILE ON *.* TO test_user_2 IDENTIFIED BY 'testpw';
 connect  session1, localhost, test_user_1,'testpw',test;
 SELECT * FROM t1 PARTITION (`p0-29`);
 a      b
index ca29757c519fe0c5364df9b401168a8cf33d70c8..1574017c58ca45279d5db959f1912e1df369759e 100644 (file)
@@ -33,6 +33,8 @@ INSERT INTO t1 PARTITION (`p3000-299999`, subp14) VALUES (299998, '(p3000-299999
 INSERT INTO t1 PARTITION (`p3000-299999`, subp14) VALUES (299999, '(p3000-299999-)subp14');
 GRANT ALL PRIVILEGES ON test.* TO test_user_1 IDENTIFIED BY 'testpw';
 GRANT ALL PRIVILEGES ON test.* TO test_user_2 IDENTIFIED BY 'testpw';
+# FILE is needed to use the DATA DIRECTORY or INDEX DIRECTORY option
+GRANT FILE ON *.* TO test_user_2 IDENTIFIED BY 'testpw';
 connect  session1, localhost, test_user_1,'testpw',test;
 SELECT * FROM t1 PARTITION (`p0-29`);
 a      b
index de8db96e9576acfd362f9f27557b4ba6dbd2fa80..cd40054abaee6f1549ff0cec395b87446964cdb7 100644 (file)
@@ -208,9 +208,10 @@ set @b1 = concat(@b1,@b1);
 INSERT INTO t9 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
 select * from t9;
 a      b       c       d       e       f       g       h       i
-1      b1b1b1b1b1b1b1b1        Kyle    0000-00-00 00:00:00     0               NULL            NULL
-2      b1b1b1b1b1b1b1b1        JOE     0000-00-00 00:00:00     0               NULL            NULL
-3      b1b1b1b1b1b1b1b1        QA      0000-00-00 00:00:00     0               NULL            NULL
+1      b1b1b1b1b1b1b1b1        Kyle    CURRENT_TIMESTAMP       0               NULL            NULL
+2      b1b1b1b1b1b1b1b1        JOE     CURRENT_TIMESTAMP       0               NULL            NULL
+3      b1b1b1b1b1b1b1b1        QA      CURRENT_TIMESTAMP       0               NULL            NULL
+include/assert.inc [The values of column 'd' should have non-zero timetsamp.]
 DROP TABLE t9;
 *** Create t10 on slave  ***
 STOP SLAVE;
index b7ac0f9c0f6fd7e7beede8471c60f8ca06e2f918..2fb257e2916aec746cb6f7f9e04b3291e0035a1d 100644 (file)
@@ -208,9 +208,10 @@ set @b1 = concat(@b1,@b1);
 INSERT INTO t9 () VALUES(1,@b1,'Kyle'),(2,@b1,'JOE'),(3,@b1,'QA');
 select * from t9;
 a      b       c       d       e       f       g       h       i
-1      b1b1b1b1b1b1b1b1        Kyle    0000-00-00 00:00:00     0               NULL            NULL
-2      b1b1b1b1b1b1b1b1        JOE     0000-00-00 00:00:00     0               NULL            NULL
-3      b1b1b1b1b1b1b1b1        QA      0000-00-00 00:00:00     0               NULL            NULL
+1      b1b1b1b1b1b1b1b1        Kyle    CURRENT_TIMESTAMP       0               NULL            NULL
+2      b1b1b1b1b1b1b1b1        JOE     CURRENT_TIMESTAMP       0               NULL            NULL
+3      b1b1b1b1b1b1b1b1        QA      CURRENT_TIMESTAMP       0               NULL            NULL
+include/assert.inc [The values of column 'd' should have non-zero timetsamp.]
 DROP TABLE t9;
 *** Create t10 on slave  ***
 STOP SLAVE;
diff --git a/mysql-wsrep-5.6/mysql-test/suite/sys_vars/r/innodb_stats_include_delete_marked_basic.result b/mysql-wsrep-5.6/mysql-test/suite/sys_vars/r/innodb_stats_include_delete_marked_basic.result
new file mode 100644 (file)
index 0000000..ffd208e
--- /dev/null
@@ -0,0 +1,25 @@
+SELECT @@innodb_stats_include_delete_marked;
+@@innodb_stats_include_delete_marked
+0
+SET GLOBAL innodb_stats_include_delete_marked=1;
+SELECT @@innodb_stats_include_delete_marked;
+@@innodb_stats_include_delete_marked
+1
+SET SESSION innodb_stats_include_delete_marked=1;
+ERROR HY000: Variable 'innodb_stats_include_delete_marked' is a GLOBAL variable and should be set with SET GLOBAL
+SET GLOBAL innodb_stats_include_delete_marked=100;
+ERROR 42000: Variable 'innodb_stats_include_delete_marked' can't be set to the value of '100'
+SET GLOBAL innodb_stats_include_delete_marked=foo;
+ERROR 42000: Variable 'innodb_stats_include_delete_marked' can't be set to the value of 'foo'
+SET GLOBAL innodb_stats_include_delete_marked=OFF ;
+SELECT @@innodb_stats_include_delete_marked;
+@@innodb_stats_include_delete_marked
+0
+SET GLOBAL innodb_stats_include_delete_marked=ON ;
+SELECT @@innodb_stats_include_delete_marked;
+@@innodb_stats_include_delete_marked
+1
+SET GLOBAL innodb_stats_include_delete_marked=Default ;
+SELECT @@innodb_stats_include_delete_marked;
+@@innodb_stats_include_delete_marked
+0
diff --git a/mysql-wsrep-5.6/mysql-test/suite/sys_vars/t/innodb_stats_include_delete_marked_basic.test b/mysql-wsrep-5.6/mysql-test/suite/sys_vars/t/innodb_stats_include_delete_marked_basic.test
new file mode 100644 (file)
index 0000000..919c426
--- /dev/null
@@ -0,0 +1,53 @@
+ ###############################################################################
+#                                                                             #
+# Variable Name: innodb_stats_include_delete_marked                           #
+# Scope: Global                                                               #
+# Access Type: Dynamic                                                        #
+# Data Type: numeric                                                          #
+#                                                                             #
+#                                                                             #
+# Creation Date: 2016-08-29                                                   #
+# Author : Aditya                                                             #
+#                                                                             #
+#                                                                             #
+# Description:                                                                #
+#              * Value check                                                  #
+#              * Scope check                                                  #
+#                                                                             #
+###############################################################################
+
+--source include/have_innodb.inc
+
+####################################################################
+#   Display default value                                          #
+####################################################################
+SELECT @@innodb_stats_include_delete_marked;
+
+SET GLOBAL innodb_stats_include_delete_marked=1;
+
+SELECT @@innodb_stats_include_delete_marked;
+
+# check error
+--error ER_GLOBAL_VARIABLE
+SET SESSION innodb_stats_include_delete_marked=1;
+
+# check error
+--error ER_WRONG_VALUE_FOR_VAR
+SET GLOBAL innodb_stats_include_delete_marked=100;
+
+# check error
+--error ER_WRONG_VALUE_FOR_VAR
+SET GLOBAL innodb_stats_include_delete_marked=foo;
+
+SET GLOBAL innodb_stats_include_delete_marked=OFF ;
+
+SELECT @@innodb_stats_include_delete_marked;
+
+SET GLOBAL innodb_stats_include_delete_marked=ON ;
+
+SELECT @@innodb_stats_include_delete_marked;
+
+# Check with default setting
+SET GLOBAL innodb_stats_include_delete_marked=Default ;
+
+SELECT @@innodb_stats_include_delete_marked;
index 2ebf990a58a9de2f07bcad0e60a203cab937783f..4b4a11e490f82accc3edfde93db8750ce746d055 100644 (file)
@@ -2118,4 +2118,43 @@ let $test_dir =
 
 --list_files $test_dir `#sql-*.frm`
 
+DROP TABLE t1; 
+
+
+--echo #
+--echo # Bug#19635706
+--echo # Verify that it is possible to add a unique key to a not-NULL POINT 
+--echo # column and that this key is promoted to primary key
+--echo # 
+
+CREATE TABLE t1(a INT NOT NULL, b POINT NOT NULL) ENGINE=INNODB;
+SHOW CREATE TABLE t1;
+ALTER TABLE t1 ADD UNIQUE INDEX (b);
+
+--echo # Note that SHOW CREATE TABLE does not list b as a primary key, 
+--echo # even though it was promoted. This appears to be the case also 
+--echo # for other column types.
+SHOW CREATE TABLE t1;
+
+ALTER TABLE t1 ADD UNIQUE INDEX (a);
+SHOW CREATE TABLE t1;
+
+--echo # Verify that the expected indices have been created by Innodb
+SELECT T.NAME AS TABLE_NAME, I.NAME AS INDEX_NAME, 
+       CASE I.TYPE 
+            WHEN 0 THEN 'Secondary' 
+            WHEN 1 THEN 'Clustered' 
+            WHEN 2 THEN 'Unique' 
+            WHEN 3 THEN 'Primary' 
+            WHEN 32 THEN 'Full text' 
+            WHEN 64 THEN 'Spatial' 
+            ELSE 'Unknown' 
+       END AS INDEX_TYPE, 
+       F.NAME AS FIELD_NAME, F.POS AS FIELD_POS FROM 
+              INFORMATION_SCHEMA.INNODB_SYS_TABLES AS T JOIN 
+              INFORMATION_SCHEMA.INNODB_SYS_INDEXES AS I JOIN 
+              INFORMATION_SCHEMA.INNODB_SYS_FIELDS AS F 
+              ON I.INDEX_ID = F.INDEX_ID AND I.TABLE_ID = T.TABLE_ID 
+       WHERE T.NAME = 'test/t1';
+
 DROP TABLE t1;
index e12201dd870c8385750db310867077cfc61ea23d..4e64670258926e18df45bd1eb04c0697c471e32c 100644 (file)
@@ -13,7 +13,7 @@ use events_test;
 # mysql.event intact checking end
 #
 
-create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
+create event e_26 on schedule at '2038-01-19 03:14:07' disable do set @a = 5;
 select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
 drop event e_26;
 --error ER_WRONG_VALUE
index 9a664b848433cc3a0befc33f2f34095f4310f429..aa7be52484e43f21288e2aa63d8c103de12ba10a 100644 (file)
@@ -610,7 +610,7 @@ disconnect con1;
 --echo #
 
 CREATE TABLE t1(f1 INT);
-EVAL SELECT 0xE1C330 INTO OUTFILE 't1.dat';
+EVAL SELECT 0xE1BB30 INTO OUTFILE 't1.dat';
 --disable_warnings
 LOAD DATA INFILE 't1.dat' IGNORE INTO TABLE t1 CHARACTER SET utf8;
 --enable_warnings
@@ -656,26 +656,3 @@ SET @@sql_mode= @old_mode;
 --remove_file $MYSQLTEST_VARDIR/mysql
 DROP TABLE t1;
 
---echo
---echo #
---echo #  Bug#23080148 - Backport of Bug#20683959.
---echo #  Bug#20683959 LOAD DATA INFILE IGNORES A SPECIFIC ROW SILENTLY
---echo #               UNDER DB CHARSET IS UTF8.
---echo #
-
-CREATE DATABASE d1 CHARSET latin1;
-USE d1;
-CREATE TABLE t1 (val TEXT);
-LOAD DATA INFILE '../../std_data/bug20683959loaddata.txt' INTO TABLE t1;
-SELECT COUNT(*) FROM t1;
-SELECT HEX(val) FROM t1;
-
-CREATE DATABASE d2 CHARSET utf8;
-USE d2;
-CREATE TABLE t1 (val TEXT);
---error ER_INVALID_CHARACTER_STRING
-LOAD DATA INFILE '../../std_data/bug20683959loaddata.txt' INTO TABLE t1;
-
-DROP TABLE d1.t1, d2.t1;
-DROP DATABASE d1;
-DROP DATABASE d2;
index e11ddfbb7a2288ddbb3d274b9029407ca583ce4e..4fe1458fc17921a50c0a068382ebdacbc3567464 100644 (file)
@@ -203,3 +203,19 @@ DROP USER test_user1, test_user2;
 
 --echo #### End of test ####
 
+
+--echo #
+--echo # Bug #24557925: MYSQL_CONFIG_EDITOR CAN MAKE SERVER UNBOOTABLE
+--echo #
+
+
+--exec $MYSQL_CONFIG_EDITOR set --login-path=mysqld --host=test_user5
+
+--echo # Restarting the server. Should work
+--source include/restart_mysqld.inc
+
+--echo # Cleanup
+--exec $MYSQL_CONFIG_EDITOR remove --login-path=mysqld
+--remove_file $MYSQL_TEST_LOGIN_FILE
+
+--echo # End of 5.6 tests
index 0c836a7b06aac9505e3d395d57541e15204bcf65..d5c55dacd61b3665acaa460a3a9a128f81c563eb 100644 (file)
@@ -74,6 +74,8 @@ DROP TABLE t1, t2;
 -- echo # test.t1 have partitions in mysqltest2-directory!
 -- echo # user root:
   CREATE USER mysqltest_1@localhost;
+-- echo # Need FILE permission to use external datadir or indexdir.
+  GRANT FILE ON *.* TO mysqltest_1@localhost;
   CREATE DATABASE mysqltest2;
   USE mysqltest2;
   CREATE TABLE t1 (a INT) ENGINE = MyISAM;
index 40d83cfc61419664f3ab1d403aad85c714403ed9..a03643a9bb5ac1f7b0f5b9a0fdada24a83a5e9a0 100644 (file)
    fun:my_b_flush_io_cache
    fun:_my_b_write
    fun:_Z*10write_keysP10Sort_paramP13Filesort_infojP11st_io_cacheS4_
-   fun:_Z*13find_all_keysP10Sort_paramP10SQL_SELECTP13Filesort_infoP11st_io_cacheS6_P13Bounded_queueIhhEPy
+   ...
    fun:_Z8filesortP3THDP5TABLEP8FilesortbPyS5_
 }
 
index b880111d737e5243a328123e042f83218f932fc2..0969842e741013e02c657f936eb071a7aa02db5b 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
 # 
 # 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
@@ -60,7 +60,7 @@ ENDIF()
 
 ADD_CONVENIENCE_LIBRARY(mysys ${MYSYS_SOURCES})
 TARGET_LINK_LIBRARIES(mysys dbug strings ${ZLIB_LIBRARY} 
- ${LIBNSL} ${LIBM} ${LIBRT})
+ ${LIBNSL} ${LIBM} ${LIBRT} ${LIBEXECINFO})
 DTRACE_INSTRUMENT(mysys)
 
 # Need explicit pthread for gcc -fsanitize=address
index 65db784c4ef6e5704dd06368382140490dd08253..0bf2f36c97a29651a08b2a2a261f6473f35a7e63 100644 (file)
@@ -1,5 +1,5 @@
 /* QQ: TODO multi-pinbox */
-/* Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
 
    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
   as necessary, old are pushed in the stack for reuse. ABA is solved by
   versioning a pointer - because we use an array, a pointer to pins is 16 bit,
   upper 16 bits are used for a version.
-
-  It is assumed that pins belong to a THD and are not transferable
-  between THD's (LF_PINS::stack_ends_here being a primary reason
-  for this limitation).
 */
-#include <my_global.h>
-#include <my_sys.h>
-#include <lf.h>
+
+#include "lf.h"
+#include "mysys_priv.h" /* key_memory_lf_node */
 
 #define LF_PINBOX_MAX_PINS 65536
 
@@ -139,14 +135,9 @@ void lf_pinbox_destroy(LF_PINBOX *pinbox)
   DESCRIPTION
     get a new LF_PINS structure from a stack of unused pins,
     or allocate a new one out of dynarray.
-
-  NOTE
-    It is assumed that pins belong to a thread and are not transferable
-    between threads.
 */
 LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox)
 {
-  struct st_my_thread_var *var;
   uint32 pins, next, top_ver;
   LF_PINS *el;
   /*
@@ -156,7 +147,7 @@ LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox)
     pinstack_top_ver is 32 bits; 16 low bits are the index in the
     array, to the first element of the list. 16 high bits are a version
     (every time the 16 low bits are updated, the 16 high bits are
-    incremented). Versioniong prevents the ABA problem.
+    incremented). Versioning prevents the ABA problem.
   */
   top_ver= pinbox->pinstack_top_ver;
   do
@@ -189,12 +180,6 @@ LF_PINS *_lf_pinbox_get_pins(LF_PINBOX *pinbox)
   el->link= pins;
   el->purgatory_count= 0;
   el->pinbox= pinbox;
-  var= my_thread_var;
-  /*
-    Threads that do not call my_thread_init() should still be
-    able to use the LF_HASH.
-  */
-  el->stack_ends_here= (var ? & var->stack_ends_here : NULL);
   return el;
 }
 
@@ -244,22 +229,21 @@ void _lf_pinbox_put_pins(LF_PINS *pins)
   } while (!my_atomic_cas32((int32 volatile*) &pinbox->pinstack_top_ver,
                             (int32*) &top_ver,
                             top_ver-pins->link+nr+LF_PINBOX_MAX_PINS));
-  return;
 }
 
-static int ptr_cmp(void **a, void **b)
+/*
+  Get the next pointer in the purgatory list.
+  Note that next_node is not used to avoid the extra volatile.
+*/
+#define pnext_node(P, X) (*((void **)(((char *)(X)) + (P)->free_ptr_offset)))
+
+static inline void add_to_purgatory(LF_PINS *pins, void *addr)
 {
-  return *a < *b ? -1 : *a == *b ? 0 : 1;
+  pnext_node(pins->pinbox, addr)= pins->purgatory;
+  pins->purgatory= addr;
+  pins->purgatory_count++;
 }
 
-#define add_to_purgatory(PINS, ADDR)                                    \
-  do                                                                    \
-  {                                                                     \
-    *(void **)((char *)(ADDR)+(PINS)->pinbox->free_ptr_offset)=         \
-      (PINS)->purgatory;                                                \
-    (PINS)->purgatory= (ADDR);                                          \
-    (PINS)->purgatory_count++;                                          \
-  } while (0)
 
 /*
   Free an object allocated via pinbox allocator
@@ -271,145 +255,88 @@ static int ptr_cmp(void **a, void **b)
 void _lf_pinbox_free(LF_PINS *pins, void *addr)
 {
   add_to_purgatory(pins, addr);
-  if (pins->purgatory_count % LF_PURGATORY_SIZE)
+  if (pins->purgatory_count % LF_PURGATORY_SIZE == 0)
     _lf_pinbox_real_free(pins);
 }
 
-struct st_harvester {
-  void **granary;
-  int npins;
+struct st_match_and_save_arg {
+  LF_PINS *pins;
+  LF_PINBOX *pinbox;
+  void *old_purgatory;
 };
 
 /*
-  callback for _lf_dynarray_iterate:
-  scan all pins of all threads and accumulate all pins
+  Callback for lf_dynarray_iterate:
+  Scan all pins of all threads, for each active (non-null) pin,
+  scan the current thread's purgatory. If present there, move it
+  to a new purgatory. At the end, the old purgatory will contain
+  pointers not pinned by any thread.
 */
-static int harvest_pins(LF_PINS *el, struct st_harvester *hv)
+static int match_and_save(LF_PINS *el, struct st_match_and_save_arg *arg)
 {
   int i;
-  LF_PINS *el_end= el + MY_MIN(hv->npins, LF_DYNARRAY_LEVEL_LENGTH);
+  LF_PINS *el_end= el + LF_DYNARRAY_LEVEL_LENGTH;
   for (; el < el_end; el++)
   {
     for (i= 0; i < LF_PINBOX_PINS; i++)
     {
       void *p= el->pin[i];
       if (p)
-        *hv->granary++= p;
+      {
+        void *cur= arg->old_purgatory;
+        void **list_prev= &arg->old_purgatory;
+        while (cur)
+        {
+          void *next= pnext_node(arg->pinbox, cur);
+
+          if (p == cur)
+          {
+            /* pinned - keeping */
+            add_to_purgatory(arg->pins, cur);
+            /* unlink from old purgatory */
+            *list_prev= next;
+          }
+          else
+            list_prev= (void **)((char *)cur+arg->pinbox->free_ptr_offset);
+          cur= next;
+        }
+        if (!arg->old_purgatory)
+          return 1;
+      }
     }
   }
-  /*
-    hv->npins may become negative below, but it means that
-    we're on the last dynarray page and harvest_pins() won't be
-    called again. We don't bother to make hv->npins() correct
-    (that is 0) in this case.
-  */
-  hv->npins-= LF_DYNARRAY_LEVEL_LENGTH;
   return 0;
 }
 
-/*
-  callback for _lf_dynarray_iterate:
-  scan all pins of all threads and see if addr is present there
-*/
-static int match_pins(LF_PINS *el, void *addr)
-{
-  int i;
-  LF_PINS *el_end= el+LF_DYNARRAY_LEVEL_LENGTH;
-  for (; el < el_end; el++)
-    for (i= 0; i < LF_PINBOX_PINS; i++)
-      if (el->pin[i] == addr)
-        return 1;
-  return 0;
-}
-
-#if STACK_DIRECTION < 0
-#define available_stack_size(CUR,END) (long) ((char*)(CUR) - (char*)(END))
-#else
-#define available_stack_size(CUR,END) (long) ((char*)(END) - (char*)(CUR))
-#endif
-
-#define next_node(P, X) (*((uchar * volatile *)(((uchar *)(X)) + (P)->free_ptr_offset)))
-#define anext_node(X) next_node(&allocator->pinbox, (X))
-
 /*
   Scan the purgatory and free everything that can be freed
 */
 static void _lf_pinbox_real_free(LF_PINS *pins)
 {
-  int npins;
-  void *list;
-  void **addr= NULL;
-  void *first= NULL, *last= NULL;
   LF_PINBOX *pinbox= pins->pinbox;
 
-  npins= pinbox->pins_in_array+1;
+  /* Store info about current purgatory. */
+  struct st_match_and_save_arg arg = {pins, pinbox, pins->purgatory};
+  /* Reset purgatory. */
+  pins->purgatory= NULL;
+  pins->purgatory_count= 0;
 
-#ifdef HAVE_ALLOCA
-  if (pins->stack_ends_here != NULL)
-  {
-    int alloca_size= sizeof(void *)*LF_PINBOX_PINS*npins;
-    /* create a sorted list of pinned addresses, to speed up searches */
-    if (available_stack_size(&pinbox, *pins->stack_ends_here) > alloca_size)
-    {
-      struct st_harvester hv;
-      addr= (void **) alloca(alloca_size);
-      hv.granary= addr;
-      hv.npins= npins;
-      /* scan the dynarray and accumulate all pinned addresses */
-      _lf_dynarray_iterate(&pinbox->pinarray,
-                           (lf_dynarray_func)harvest_pins, &hv);
-
-      npins= hv.granary-addr;
-      /* and sort them */
-      if (npins)
-        qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp);
-    }
-  }
-#endif
+  lf_dynarray_iterate(&pinbox->pinarray,
+                      (lf_dynarray_func)match_and_save, &arg);
 
-  list= pins->purgatory;
-  pins->purgatory= 0;
-  pins->purgatory_count= 0;
-  while (list)
+  if (arg.old_purgatory)
   {
-    void *cur= list;
-    list= *(void **)((char *)cur+pinbox->free_ptr_offset);
-    if (npins)
-    {
-      if (addr) /* use binary search */
-      {
-        void **a, **b, **c;
-        for (a= addr, b= addr+npins-1, c= a+(b-a)/2; (b-a) > 1; c= a+(b-a)/2)
-          if (cur == *c)
-            a= b= c;
-          else if (cur > *c)
-            a= c;
-          else
-            b= c;
-        if (cur == *a || cur == *b)
-          goto found;
-      }
-      else /* no alloca - no cookie. linear search here */
-      {
-        if (_lf_dynarray_iterate(&pinbox->pinarray,
-                                 (lf_dynarray_func)match_pins, cur))
-          goto found;
-      }
-    }
-    /* not pinned - freeing */
-    if (last)
-      last= next_node(pinbox, last)= (uchar *)cur;
-    else
-      first= last= (uchar *)cur;
-    continue;
-found:
-    /* pinned - keeping */
-    add_to_purgatory(pins, cur);
+    /* Some objects in the old purgatory were not pinned, free them. */
+    void *last= arg.old_purgatory;
+    while (pnext_node(pinbox, last))
+      last= pnext_node(pinbox, last);
+    pinbox->free_func(arg.old_purgatory, last, pinbox->free_func_arg);
   }
-  if (last)
-    pinbox->free_func(first, last, pinbox->free_func_arg);
 }
 
+#define next_node(P, X) (*((uchar * volatile *)(((uchar *)(X)) + (P)->free_ptr_offset)))
+#define anext_node(X) next_node(&allocator->pinbox, (X))
+
 /* lock-free memory allocator for fixed-size objects */
 
 LF_REQUIRE_PINS(1)
index 204c79e8ee02c287f6a39d83ca9d89effe7a1a95..f4d0ebed8f8ca9eb93864227410f9d28c1cde1dd 100644 (file)
 #include       <m_string.h>
 #include       <my_dir.h>      /* Structs used by my_dir,includes sys/types */
 #include       "mysys_err.h"
-#if defined(HAVE_DIRENT_H)
+#if !defined(_WIN32)
 # include <dirent.h>
-# define NAMLEN(dirent) strlen((dirent)->d_name)
-#else
-# define dirent direct
-# define NAMLEN(dirent) (dirent)->d_namlen
-# if defined(HAVE_SYS_NDIR_H)
-#  include <sys/ndir.h>
-# endif
-# if defined(HAVE_SYS_DIR_H)
-#  include <sys/dir.h>
-# endif
-# if defined(HAVE_NDIR_H)
-#  include <ndir.h>
 # endif
-# if defined(_WIN32)
-# ifdef __BORLANDC__
-# include <dir.h>
-# endif
-# endif
-#endif
 
-#if defined(HAVE_READDIR_R)
-#define READDIR(A,B,C) ((errno=readdir_r(A,B,&C)) != 0 || !C)
-#else
-#define READDIR(A,B,C) (!(C=readdir(A)))
-#endif
 
 /*
   We are assuming that directory we are reading is either has less than 
@@ -88,6 +65,8 @@ static int comp_names(struct fileinfo *a, struct fileinfo *b)
 
 #if !defined(_WIN32)
 
+static char* directory_file_name(char *dst, const char *src);
+
 MY_DIR *my_dir(const char *path, myf MyFlags)
 {
   char          *buffer;
@@ -96,17 +75,12 @@ MY_DIR      *my_dir(const char *path, myf MyFlags)
   DYNAMIC_ARRAY *dir_entries_storage;
   MEM_ROOT      *names_storage;
   DIR          *dirp;
-  struct dirent *dp;
   char         tmp_path[FN_REFLEN + 2], *tmp_file;
-  char dirent_tmp[sizeof(struct dirent)+_POSIX_PATH_MAX+1];
+  const struct dirent *dp;
 
   DBUG_ENTER("my_dir");
   DBUG_PRINT("my",("path: '%s' MyFlags: %d",path,MyFlags));
 
-#if !defined(HAVE_READDIR_R)
-  mysql_mutex_lock(&THR_LOCK_open);
-#endif
-
   dirp = opendir(directory_file_name(tmp_path,(char *) path));
 #if defined(__amiga__)
   if ((dirp->dd_fd) < 0)                       /* Directory doesn't exists */
@@ -135,9 +109,7 @@ MY_DIR      *my_dir(const char *path, myf MyFlags)
 
   tmp_file=strend(tmp_path);
 
-  dp= (struct dirent*) dirent_tmp;
-  
-  while (!(READDIR(dirp,(struct dirent*) dirent_tmp,dp)))
+  for (dp= readdir(dirp) ; dp; dp= readdir(dirp))
   {
     if (!(finfo.name= strdup_root(names_storage, dp->d_name)))
       goto error;
@@ -162,9 +134,7 @@ MY_DIR      *my_dir(const char *path, myf MyFlags)
   }
 
   (void) closedir(dirp);
-#if !defined(HAVE_READDIR_R)
-  mysql_mutex_unlock(&THR_LOCK_open);
-#endif
+
   result->dir_entry= (FILEINFO *)dir_entries_storage->buffer;
   result->number_off_files= dir_entries_storage->elements;
   
@@ -174,9 +144,6 @@ MY_DIR      *my_dir(const char *path, myf MyFlags)
   DBUG_RETURN(result);
 
  error:
-#if !defined(HAVE_READDIR_R)
-  mysql_mutex_unlock(&THR_LOCK_open);
-#endif
   my_errno=errno;
   if (dirp)
     (void) closedir(dirp);
@@ -198,7 +165,7 @@ MY_DIR      *my_dir(const char *path, myf MyFlags)
  * Returns pointer to dst;
  */
 
-char * directory_file_name (char * dst, const char *src)
+static char* directory_file_name(char *dst, const char *src)
 {
   /* Process as Unix format: just remove test the final slash. */
   char *end;
index 6d5615035c2a2b436b8ed32ebb6f551c517dd0de..6eda795ddba22bab2109271a426b47d335ed3892 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
 
    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
@@ -297,9 +297,6 @@ my_bool my_thread_init(void)
   mysql_mutex_init(key_my_thread_var_mutex, &tmp->mutex, MY_MUTEX_INIT_FAST);
   mysql_cond_init(key_my_thread_var_suspend, &tmp->suspend, NULL);
 
-  tmp->stack_ends_here= (char*)&tmp +
-                         STACK_DIRECTION * (long)my_thread_stack_size;
-
   mysql_mutex_lock(&THR_LOCK_threads);
   tmp->id= ++thread_id;
   ++THR_thread_count;
index 9e7a991f0f88363ac75de1c2988775d4e447e72e..16014e5e543f85f76d0656e56817be88c6bd248d 100644 (file)
 #include <execinfo.h>
 #endif
 
+#ifdef __linux__
+/* __bss_start doesn't seem to work on FreeBSD and doesn't exist on OSX/Solaris. */
 #define PTR_SANE(p) ((p) && (char*)(p) >= heap_start && (char*)(p) <= heap_end)
-
 static char *heap_start;
-
-#ifdef HAVE_BSS_START
 extern char *__bss_start;
-#endif
+#else
+#define PTR_SANE(p) (p)
+#endif /* __linux */
 
 void my_init_stacktrace()
 {
-#ifdef HAVE_BSS_START
+#ifdef __linux__
   heap_start = (char*) &__bss_start;
-#endif
+#endif /* __linux__ */
 }
 
 #ifdef __linux__
@@ -134,14 +135,15 @@ static int safe_print_str(const char *addr, int max_len)
 
 void my_safe_print_str(const char* val, int max_len)
 {
+#ifdef __linux__
+/* Only needed by the linux version of PTR_SANE */
   char *heap_end;
 
-#ifdef __linux__
   if (!safe_print_str(val, max_len))
     return;
-#endif
 
   heap_end= (char*) sbrk(0);
+#endif
 
   if (!PTR_SANE(val))
   {
index 4e51ce23e1f2e6335e2f0e052f36dff3f96b8537..262c6620976e87696202119c3de880057efcfa98 100644 (file)
@@ -591,6 +591,8 @@ int load_defaults(const char *conf_file, const char **groups,
   return my_load_defaults(conf_file, groups, argc, argv, &default_directories);
 }
 
+/** A global to turn off or on reading the mylogin file. On by default */
+my_bool my_defaults_read_login_file= TRUE;
 /*
   Read options from configurations files
 
@@ -678,16 +680,18 @@ int my_load_defaults(const char *conf_file, const char **groups,
     DBUG_RETURN(error);
   }
 
-  /* Read options from login group. */
-  if (my_default_get_login_file(my_login_file, sizeof(my_login_file)) &&
-      (error= my_search_option_files(my_login_file,argc, argv, &args_used,
+  if (my_defaults_read_login_file)
+  {
+    /* Read options from login group. */
+    if (my_default_get_login_file(my_login_file, sizeof(my_login_file)) &&
+      (error= my_search_option_files(my_login_file, argc, argv, &args_used,
                                      handle_default_option, (void *) &ctx,
                                      dirs, true, found_no_defaults)))
-  {
-    free_root(&alloc,MYF(0));
-    DBUG_RETURN(error);
+    {
+      free_root(&alloc, MYF(0));
+      DBUG_RETURN(error);
+    }
   }
-
   /*
     Here error contains <> 0 only if we have a fully specified conf_file
     or a forced default file
index 9dcb8c6bb5482d84a80d434a8bd9056235336e07..adb5f54bb2d29c25dd31fb952c4177d5f895d29b 100644 (file)
@@ -32,3 +32,4 @@ debian/extra/semisync_master-plugin
 debian/extra/semisync_slave-plugin
 debian/extra/test_udf_services-plugin
 debian/extra/validate_password-plugin
+debian/extra/connection_control-plugin
index 9dcb8c6bb5482d84a80d434a8bd9056235336e07..adb5f54bb2d29c25dd31fb952c4177d5f895d29b 100644 (file)
@@ -32,3 +32,4 @@ debian/extra/semisync_master-plugin
 debian/extra/semisync_slave-plugin
 debian/extra/test_udf_services-plugin
 debian/extra/validate_password-plugin
+debian/extra/connection_control-plugin
index 9dcb8c6bb5482d84a80d434a8bd9056235336e07..adb5f54bb2d29c25dd31fb952c4177d5f895d29b 100644 (file)
@@ -32,3 +32,4 @@ debian/extra/semisync_master-plugin
 debian/extra/semisync_slave-plugin
 debian/extra/test_udf_services-plugin
 debian/extra/validate_password-plugin
+debian/extra/connection_control-plugin
index 9dcb8c6bb5482d84a80d434a8bd9056235336e07..adb5f54bb2d29c25dd31fb952c4177d5f895d29b 100644 (file)
@@ -32,3 +32,4 @@ debian/extra/semisync_master-plugin
 debian/extra/semisync_slave-plugin
 debian/extra/test_udf_services-plugin
 debian/extra/validate_password-plugin
+debian/extra/connection_control-plugin
index 47ad2c2c0d0461df7a25a14ff9566abc7b7fe2c8..e51fdbcbeb2e37bfa274fe0f27c51a3996b079a9 100644 (file)
@@ -239,6 +239,7 @@ rm -r $(readlink var) var
 %dir %{_libdir}/mysql/plugin
 %attr(755, root, root) %{_libdir}/mysql/plugin/adt_null.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/auth_socket.so
+%attr(755, root, root) %{_libdir}/mysql/plugin/connection_control.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/innodb_engine.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/libmemcached.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/mypluglib.so
@@ -287,6 +288,9 @@ rm -r $(readlink var) var
 %dir %attr(750, mysql, mysql) /var/lib/mysql-files
 
 %changelog
+* Tue Sep 13 2016 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com> - 5.6.34-1
+- Add connection_control.so to server subpackage
+
 * Mon Mar 14 2016 Georgi Kodinov <georgi.kodinov@oracle.com> - 5.6.31-1
 - Add test_udf_services.so plugin
 
index 231a76087ac3e2df699154ac7ba00a1248f0c46a..c744bdceeb4d9aafedb9760c67e42c619c76188b 100644 (file)
@@ -22,7 +22,9 @@ install_db () {
     datadir=$(get_option mysqld datadir "/var/lib/mysql")
 
     # Restore log, dir, perms and SELinux contexts
-    [ -d "$datadir" ] || install -d -m 0755 -omysql -gmysql "$datadir" || exit 1
+    if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
+       install -d -m 0755 -omysql -gmysql "$datadir" || exit 1
+    fi
     log=/var/log/mysqld.log
     [ -e $log ] || touch $log
     chmod 0640 $log
index 1e8852e7410fd1c549cfd02f6c813ed899e2015e..55fb390113b10ca6b0a1e7b25eb037b2d6fdf810 100644 (file)
@@ -547,6 +547,7 @@ datadir=$(/usr/bin/my_print_defaults server mysqld | grep '^--datadir=' | sed -n
 %dir %{_libdir}/mysql/plugin
 %attr(755, root, root) %{_libdir}/mysql/plugin/adt_null.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/auth_socket.so
+%attr(755, root, root) %{_libdir}/mysql/plugin/connection_control.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/innodb_engine.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/libmemcached.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/mypluglib.so
@@ -557,6 +558,7 @@ datadir=$(/usr/bin/my_print_defaults server mysqld | grep '^--datadir=' | sed -n
 %dir %{_libdir}/mysql/plugin/debug
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/adt_null.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/auth_socket.so
+%attr(755, root, root) %{_libdir}/mysql/plugin/debug/connection_control.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/innodb_engine.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/libmemcached.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/mypluglib.so
@@ -722,6 +724,9 @@ datadir=$(/usr/bin/my_print_defaults server mysqld | grep '^--datadir=' | sed -n
 %attr(755, root, root) %{_libdir}/mysql/libmysqld.so
 
 %changelog
+* Mon Oct 31 2016 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com> - 5.6.35-1
+- Add connection_control.so to server subpackage
+
 * Mon Sep 26 2016 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com> - 5.6.34-1
 - Include mysql-files directory
 
index abe46e0ed74dee4fc05e1c2de5ccbd5b9b2ff38c..8044ed441641a4536363b823d9d009092a66f2d2 100644 (file)
@@ -2,22 +2,30 @@
 #
 # Wrapper script for mysql_config to support multilib
 #
-# Only works on OEL6/RHEL6 and similar
 #
-# This command respects setarch
 
+# This command respects setarch, works on OL6/RHEL6 and later
 bits=$(rpm --eval %__isa_bits)
 
 case $bits in
-    32|64) status=known ;;
-        *) status=unknown ;;
+    32|64) ;;
+        *) bits=unknown ;;
 esac
 
-if [ "$status" = "unknown" ] ; then
-    echo "$0: error: command 'rpm --eval %__isa_bits' returned unknown value: $bits"
-    exit 1
+# Try mapping by uname if rpm command failed
+if [ "$bits" = "unknown" ] ; then
+    arch=$(uname -m)
+    case $arch in
+       x86_64|ppc64|ppc64le|aarch64|s390x|sparc64) bits=64 ;;
+       i386|i486|i586|i686|pentium3|pentium4|athlon|ppc|s390|sparc) bits=32 ;;
+       *) bits=unknown ;;
+    esac
 fi
 
+if [ "$bits" == "unknown" ] ; then
+    echo "$0: error: failed to determine isa bits on your arch."
+    exit 1
+fi
 
 if [ -x /usr/bin/mysql_config-$bits ] ; then
     /usr/bin/mysql_config-$bits "$@"
@@ -25,4 +33,3 @@ else
     echo "$0: error: needed binary: /usr/bin/mysql_config-$bits is missing. Please check your MySQL installation."
     exit 1
 fi
-
index 8831cc6642f625b6b503320696baa2b1601c9852..0f75a1302569eae68acbb7605bf18dea5a6b7467 100644 (file)
@@ -34,7 +34,7 @@ PermissionsStartOnly=true
 ExecStartPre=/usr/bin/mysql-systemd-start pre
 
 # Start main service
-ExecStart=/usr/bin/mysqld_safe
+ExecStart=/usr/bin/mysqld_safe --basedir=/usr
 
 # Don't signal startup success before a ping works
 ExecStartPost=/usr/bin/mysql-systemd-start post
index 231a76087ac3e2df699154ac7ba00a1248f0c46a..c744bdceeb4d9aafedb9760c67e42c619c76188b 100644 (file)
@@ -22,7 +22,9 @@ install_db () {
     datadir=$(get_option mysqld datadir "/var/lib/mysql")
 
     # Restore log, dir, perms and SELinux contexts
-    [ -d "$datadir" ] || install -d -m 0755 -omysql -gmysql "$datadir" || exit 1
+    if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
+       install -d -m 0755 -omysql -gmysql "$datadir" || exit 1
+    fi
     log=/var/log/mysqld.log
     [ -e $log ] || touch $log
     chmod 0640 $log
index ca1ed295121b34ab97b20a935d8765bd021a2742..a316e29e115d8876bf9c8a24b79d4ff678cbf4c9 100644 (file)
@@ -70,18 +70,19 @@ start(){
        ret=0
     else
        # prepare for start
-       touch "$errlogfile"
-       chown mysql:mysql "$errlogfile" 
-       chmod 0640 "$errlogfile"
+       if [ ! -e "$errlogfile" -a ! -h "$errlogfile" -a "x$(dirname "$errlogfile")" = "x/var/log" ]; then
+           install /dev/null -m0640 -omysql -gmysql "$errlogfile"
+       fi
        [ -x /sbin/restorecon ] && /sbin/restorecon "$errlogfile"
        if [ ! -d "$datadir/mysql" ] ; then
            # First, make sure $datadir is there with correct permissions
-           if [ ! -e "$datadir" -a ! -h "$datadir" ]
-           then
-               mkdir -p "$datadir" || exit 1
+           if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
+               install -d -m0755 -omysql -gmysql "$datadir" || exit 1
+           fi
+           if [ ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
+               chown mysql:mysql "$datadir"
+               chmod 0755 "$datadir"
            fi
-           chown mysql:mysql "$datadir"
-           chmod 0755 "$datadir"
            if [ -x /sbin/restorecon ]; then
                /sbin/restorecon "$datadir"
                for dir in /var/lib/mysql-files ; do
@@ -94,13 +95,14 @@ start(){
            # Now create the database
            action $"Initializing MySQL database: " /usr/bin/mysql_install_db --rpm --datadir="$datadir" --user=mysql
            ret=$?
-           chown -R mysql:mysql "$datadir"
            if [ $ret -ne 0 ] ; then
                return $ret
            fi
        fi
-       chown mysql:mysql "$datadir"
-       chmod 0755 "$datadir"
+       if [ ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
+           chown mysql:mysql "$datadir"
+           chmod 0755 "$datadir"
+       fi
        # Pass all the options determined above, to ensure consistent behavior.
        # In many cases mysqld_safe would arrive at the same conclusions anyway
        # but we need to be sure.  (An exception is that we don't force the
index 73ed29e5f64087d787e5493cf3a918c730a978ab..c5da35b2c0306a1e4fcd20bbb51f2c95ffa401e2 100644 (file)
@@ -747,6 +747,7 @@ fi
 %dir %{_libdir}/mysql/plugin
 %attr(755, root, root) %{_libdir}/mysql/plugin/adt_null.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/auth_socket.so
+%attr(755, root, root) %{_libdir}/mysql/plugin/connection_control.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/innodb_engine.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/libmemcached.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/mypluglib.so
@@ -757,6 +758,7 @@ fi
 %dir %{_libdir}/mysql/plugin/debug
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/adt_null.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/auth_socket.so
+%attr(755, root, root) %{_libdir}/mysql/plugin/debug/connection_control.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/innodb_engine.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/libmemcached.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/mypluglib.so
@@ -954,6 +956,9 @@ fi
 %endif
 
 %changelog
+* Mon Oct 31 2016 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com> - 5.6.35-1
+- Add connection_control.so to server subpackage
+
 * Mon Sep 26 2016 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com> - 5.6.34-1
 - Include mysql-files directory
 
index 05007f7344e020d3f0683b5a04aa9a677b727a0e..8044ed441641a4536363b823d9d009092a66f2d2 100644 (file)
@@ -5,10 +5,10 @@
 #
 
 # This command respects setarch, works on OL6/RHEL6 and later
-isa_bits=$(rpm --eval %__isa_bits)
+bits=$(rpm --eval %__isa_bits)
 
 case $bits in
-    32|64) bits=$isa_bits ;;
+    32|64) ;;
         *) bits=unknown ;;
 esac
 
@@ -16,8 +16,8 @@ esac
 if [ "$bits" = "unknown" ] ; then
     arch=$(uname -m)
     case $arch in
-       x86_64|ppc64) bits=64 ;;
-       i386|i486|i586|i686|pentium3|pentium4|athlon|ppc) bits=32 ;;
+       x86_64|ppc64|ppc64le|aarch64|s390x|sparc64) bits=64 ;;
+       i386|i486|i586|i686|pentium3|pentium4|athlon|ppc|s390|sparc) bits=32 ;;
        *) bits=unknown ;;
     esac
 fi
@@ -33,4 +33,3 @@ else
     echo "$0: error: needed binary: /usr/bin/mysql_config-$bits is missing. Please check your MySQL installation."
     exit 1
 fi
-
index 78ef3bffe601ce37299afde6deddaf3e8e048b25..871f191c0171aeb8d15e4524ccf9395de69fc4ac 100644 (file)
@@ -34,7 +34,7 @@ PermissionsStartOnly=true
 ExecStartPre=/usr/bin/mysql-systemd-start pre
 
 # Start main service
-ExecStart=/usr/bin/mysqld_safe
+ExecStart=/usr/bin/mysqld_safe --basedir=/usr
 
 # Don't signal startup success before a ping works
 ExecStartPost=/usr/bin/mysql-systemd-start post
index d3a79202e749d7cbb212ee5b279837c0754345c2..29b6de5c7c448d46f4e2a5e2a4f640d2676ef18a 100644 (file)
@@ -13,7 +13,9 @@ install_db () {
     datadir=$(/usr/bin/my_print_defaults server mysqld | grep '^--datadir=' | sed -n 's/--datadir=//p' | tail -n 1)
     
     # Restore log, dir, perms and SELinux contexts
-    [ -d "$datadir" ] || install -d -m 0755 -omysql -gmysql "$datadir" || exit 1
+    if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
+       install -d -m 0755 -omysql -gmysql "$datadir" || exit 1
+    fi
     log=/var/log/mysql/mysqld.log
     [ -e $log ] || touch $log
     chmod 0640 $log
index 298625681234e652e982595af4264b806fc4fcc6..8b7c94475f7543c1b9e1f8df7d11aa4185a12507 100644 (file)
@@ -65,7 +65,6 @@ get_option () {
 datadir=$(get_option mysqld datadir "/var/lib/mysql")
 socket=$(get_option  mysqld socket "$datadir/mysql.sock")
 pidfile=$(get_option mysqld_safe pid-file "/var/run/mysql/mysqld.pid")
-logfile=$(get_option mysqld_safe log-error "/var/log/mysql/mysqld.log")
 
 install_db () {
     # Note: something different than datadir=/var/lib/mysql requires 
@@ -74,14 +73,16 @@ install_db () {
     logfile=$(get_option mysqld_safe log-error "/var/log/mysql/mysqld.log")
 
     # Restore log, dir, perms and SELinux contexts
-    [ -d "$datadir" ] || install -d -m 0755 -omysql -gmysql "$datadir" || return 1
+    if [ ! -d "$datadir" -a ! -h "$datadir" -a "x$(dirname "$datadir")" = "x/var/lib" ]; then
+       install -d -m 0755 -omysql -gmysql "$datadir" || return 1
+    fi
 
-    [ -e $logfile ] || touch $logfile || return 1
-    chmod 0640 $logfile
-    chown mysql:mysql $logfile || return 1
+    if [ ! -e "$logfile" -a ! -h "$logfile" -a "x$(dirname "$logfile")" = "x/var/log/mysql" ]; then
+       install /dev/null -omysql -gmysql "$logfile" || return 1
+    fi
     if [ -x /usr/sbin/restorecon ]; then
         /usr/sbin/restorecon "$datadir"
-        /usr/sbin/restorecon $logfile
+        /usr/sbin/restorecon "$logfile"
     fi
 
     # If special mysql dir is in place, skip db install 
index 153c4b61d7e0dbce276486bfbe3647989452eceb..ca3494936b659caee5ff90d4d0739a52ddec1488 100644 (file)
@@ -623,6 +623,7 @@ fi
 %dir %{_libdir}/mysql/plugin
 %attr(755, root, root) %{_libdir}/mysql/plugin/adt_null.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/auth_socket.so
+%attr(755, root, root) %{_libdir}/mysql/plugin/connection_control.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/innodb_engine.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/libmemcached.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/mypluglib.so
@@ -633,6 +634,7 @@ fi
 %dir %{_libdir}/mysql/plugin/debug
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/adt_null.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/auth_socket.so
+%attr(755, root, root) %{_libdir}/mysql/plugin/debug/connection_control.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/innodb_engine.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/libmemcached.so
 %attr(755, root, root) %{_libdir}/mysql/plugin/debug/mypluglib.so
@@ -824,6 +826,9 @@ fi
 %attr(755, root, root) %{_libdir}/mysql/libmysqld.so
 
 %changelog
+* Mon Oct 31 2016 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com> - 5.6.35-1
+- Add connection_control.so to server subpackage
+
 * Mon Sep 26 2016 Balasubramanian Kandasamy <balasubramanian.kandasamy@oracle.com> - 5.6.34-1
 - Include mysql-files directory
 
index 78ef3bffe601ce37299afde6deddaf3e8e048b25..871f191c0171aeb8d15e4524ccf9395de69fc4ac 100644 (file)
@@ -34,7 +34,7 @@ PermissionsStartOnly=true
 ExecStartPre=/usr/bin/mysql-systemd-start pre
 
 # Start main service
-ExecStart=/usr/bin/mysqld_safe
+ExecStart=/usr/bin/mysqld_safe --basedir=/usr
 
 # Don't signal startup success before a ping works
 ExecStartPost=/usr/bin/mysql-systemd-start post
diff --git a/mysql-wsrep-5.6/plugin/connection_control/CMakeLists.txt b/mysql-wsrep-5.6/plugin/connection_control/CMakeLists.txt
new file mode 100644 (file)
index 0000000..700a805
--- /dev/null
@@ -0,0 +1,22 @@
+# Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
+#
+# 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 St, Fifth Floor, Boston, MA  02110-1301 USA
+
+MYSQL_ADD_PLUGIN(connection_control
+                connection_control_coordinator.cc
+                connection_control.cc
+                security_context_wrapper.cc
+                connection_delay.cc
+                 MODULE_ONLY)
+
diff --git a/mysql-wsrep-5.6/plugin/connection_control/connection_control.cc b/mysql-wsrep-5.6/plugin/connection_control/connection_control.cc
new file mode 100644 (file)
index 0000000..c19845b
--- /dev/null
@@ -0,0 +1,480 @@
+/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+
+   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 St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#include <mysql/plugin_audit.h>         /* mysql_event_connection */
+#include "mysql_version.h"
+#include <my_global.h>
+#include <my_pthread.h>
+#include <my_atomic.h>
+
+#include "connection_control.h"
+#include "connection_delay_api.h"       /* connection_delay apis */
+#include "connection_control_coordinator.h" /* g_connection_event_coordinator */
+
+namespace connection_control
+{
+  class Connection_control_error_handler : public Error_handler
+  {
+  public:
+    Connection_control_error_handler(MYSQL_PLUGIN plugin_info)
+      : m_plugin_info(plugin_info)
+    {}
+
+    void handle_error(const char * error_message)
+    {
+      my_plugin_log_message(&m_plugin_info,
+                            MY_ERROR_LEVEL,
+                            error_message);
+    }
+  private:
+    MYSQL_PLUGIN m_plugin_info;
+  };
+}
+
+using connection_control::Connection_event_coordinator;
+using connection_control::Connection_event_coordinator_services;
+using connection_control::Connection_control_statistics;
+using connection_control::Connection_control_variables;
+using connection_control::Error_handler;
+using connection_control::Connection_control_error_handler;
+
+typedef unsigned int mysql_event_class_t;
+
+Connection_control_statistics g_statistics;
+Connection_control_variables g_variables;
+
+Connection_event_coordinator *g_connection_event_coordinator= 0;
+MYSQL_PLUGIN connection_control_plugin_info= 0;
+
+
+/**
+  event_notify() implementation for connection_control
+
+  For connection event, notify Connection_event_coordinator
+  which in turn will notify subscribers.
+
+  @param thd [in]            Handle to THD
+  @param event_class [in]    Event class.
+                             We are interested in MYSQL_AUDIT_CONNECTION_CLASS.
+  @param event [in]          mysql_event_connection handle
+*/
+
+static void
+connection_control_notify(MYSQL_THD thd,
+                          mysql_event_class_t event_class,
+                          const void *event)
+{
+  DBUG_ENTER("connection_control_notify");
+  try
+  {
+    if (event_class == MYSQL_AUDIT_CONNECTION_CLASS)
+    {
+      const struct mysql_event_connection *connection_event=
+        (const struct mysql_event_connection *) event;
+      Connection_control_error_handler error_handler(connection_control_plugin_info);
+      /** Notify event coordinator */
+      g_connection_event_coordinator->notify_event(thd, &error_handler,
+                                                   connection_event);
+    }
+  }
+  catch (...)
+  {
+    /* Happily ignore any bad behavior */
+  }
+
+  DBUG_VOID_RETURN;
+}
+
+
+/**
+  Plugin initialization function
+
+  @param plugin_info [in]  MYSQL_PLUGIN information
+
+  @returns initialization status
+    @retval 0 Success
+    @retval 1 Failure
+*/
+
+static int
+connection_control_init(MYSQL_PLUGIN plugin_info)
+{
+  connection_control_plugin_info= plugin_info;
+  Connection_control_error_handler error_handler(connection_control_plugin_info);
+  g_connection_event_coordinator= new Connection_event_coordinator();
+  if (!g_connection_event_coordinator)
+  {
+    error_handler.handle_error("Failed to initialize Connection_event_coordinator");
+    return 1;
+  }
+
+  if (init_connection_delay_event((Connection_event_coordinator_services *)
+                                  g_connection_event_coordinator,
+                                  &error_handler))
+  {
+    delete g_connection_event_coordinator;
+    return 1;
+  }
+  return 0;
+}
+
+
+/**
+  Plugin deinitialization
+
+  @param arg  Unused
+
+  @returns success
+*/
+
+static int
+connection_control_deinit(void *arg MY_ATTRIBUTE((unused)))
+{
+  delete g_connection_event_coordinator;
+  g_connection_event_coordinator= 0;
+  connection_control::deinit_connection_delay_event();
+  connection_control_plugin_info= 0;
+  return 0;
+}
+
+
+/** Connection_control plugin descriptor */
+static struct st_mysql_audit connection_control_descriptor=
+{
+  MYSQL_AUDIT_INTERFACE_VERSION,                    /* interface version */\r
+  NULL,                                             /* release_thd() */\r
+  connection_control_notify,                        /* event_notify() */\r
+  {(ulong)MYSQL_AUDIT_CONNECTION_CLASSMASK}         /* class mask */
+};
+
+
+/**
+  check() function for connection_control_failed_connections_threshold
+
+  Check whether new value is within valid bounds or not.
+
+  @param thd        Not used.
+  @param var        Not used.
+  @param save       Not used.
+  @param value      New value for the option.
+
+  @returns whether new value is within valid bounds or not.
+    @retval 0 Value is ok
+    @retval 1 Value is not within valid bounds
+*/
+
+static int
+check_failed_connections_threshold(MYSQL_THD thd MY_ATTRIBUTE((unused)),
+                                   struct st_mysql_sys_var *var MY_ATTRIBUTE((unused)),
+                                   void *save MY_ATTRIBUTE((unused)),
+                                   struct st_mysql_value *value)
+{
+  longlong new_value;
+  if (value->val_int(value, &new_value))
+    return 1;                           /* NULL value */
+
+  if (new_value >= connection_control::MIN_THRESHOLD &&
+      new_value <= connection_control::MAX_THRESHOLD)
+  {
+    *(reinterpret_cast<longlong *>(save))= new_value;
+    return 0;
+  }
+
+  return 1;
+}
+
+
+/**
+  update() function for connection_control_failed_connections_threshold
+
+  Updates g_connection_event_coordinator with new value.
+  Also notifies observers about the update.
+
+  @param thd        Not used.
+  @param var        Not used.
+  @param var_ptr    Variable information
+  @param save       New value for connection_control_failed_connections_threshold
+*/
+
+static void
+update_failed_connections_threshold(MYSQL_THD thd MY_ATTRIBUTE((unused)),
+                                    struct st_mysql_sys_var *var MY_ATTRIBUTE((unused)),
+                                    void *var_ptr, const void *save)
+{
+  /*
+    This won't result in overflow because we have already checked that this is
+    within valid bounds.
+  */
+  longlong new_value= *(reinterpret_cast<const longlong *>(save));
+  g_variables.failed_connections_threshold= (int64)new_value;
+  Connection_control_error_handler error_handler(connection_control_plugin_info);
+  g_connection_event_coordinator->notify_sys_var(&error_handler,
+                                                 OPT_FAILED_CONNECTIONS_THRESHOLD,
+                                                 &new_value);
+  return;
+}
+
+
+/** Declaration of connection_control_failed_connections_threshold */
+static MYSQL_SYSVAR_LONGLONG(
+  failed_connections_threshold,
+  g_variables.failed_connections_threshold,
+  PLUGIN_VAR_RQCMDARG,
+  "Failed connection threshold to trigger delay. Default is 3.",
+  check_failed_connections_threshold,
+  update_failed_connections_threshold,
+  connection_control::DEFAULT_THRESHOLD,
+  connection_control::MIN_THRESHOLD,
+  connection_control::MAX_THRESHOLD,
+  1
+);
+
+
+/**
+  check() function for connection_control_min_connection_delay
+
+  Check whether new value is within valid bounds or not.
+
+  @param thd        Not used.
+  @param var        Not used.
+  @param save       Not used.
+  @param value      New value for the option.
+
+  @returns whether new value is within valid bounds or not.
+    @retval 0 Value is ok
+    @retval 1 Value is not within valid bounds
+*/
+
+static int
+check_min_connection_delay(MYSQL_THD thd MY_ATTRIBUTE((unused)),
+                           struct st_mysql_sys_var *var MY_ATTRIBUTE((unused)),
+                           void *save MY_ATTRIBUTE((unused)),
+                           struct st_mysql_value *value)
+{
+  long long new_value;
+  int64 existing_value= g_variables.max_connection_delay;
+  if (value->val_int(value, &new_value))
+    return 1;                           /* NULL value */
+
+  if (new_value >= connection_control::MIN_DELAY &&
+      new_value <= connection_control::MAX_DELAY &&
+      new_value <= existing_value)
+  {
+    *(reinterpret_cast<longlong *>(save))= new_value;
+    return 0;
+  }
+  return 1;
+}
+
+
+/**
+  update() function for connection_control_min_connection_delay
+
+  Updates g_connection_event_coordinator with new value.
+  Also notifies observers about the update.
+
+  @param thd        Not used.
+  @param var        Not used.
+  @param var_ptr    Variable information
+  @param save       New value for connection_control_min_connection_delay
+*/
+
+static void
+update_min_connection_delay(MYSQL_THD thd MY_ATTRIBUTE((unused)),
+                            struct st_mysql_sys_var *var MY_ATTRIBUTE((unused)),
+                            void *var_ptr, const void *save)
+{
+  longlong new_value= *(reinterpret_cast<const longlong *>(save));
+  g_variables.min_connection_delay= (int64)new_value;
+  Connection_control_error_handler error_handler(connection_control_plugin_info);
+  g_connection_event_coordinator->notify_sys_var(&error_handler,
+                                                 OPT_MIN_CONNECTION_DELAY,
+                                                 &new_value);
+  return;
+}
+
+
+/** Declaration of connection_control_max_connection_delay */
+static MYSQL_SYSVAR_LONGLONG(
+  min_connection_delay,
+  g_variables.min_connection_delay,
+  PLUGIN_VAR_RQCMDARG,
+  "Maximum delay to be introduced. Default is 1000.",
+  check_min_connection_delay,
+  update_min_connection_delay,
+  connection_control::DEFAULT_MIN_DELAY,
+  connection_control::MIN_DELAY,
+  connection_control::MAX_DELAY,
+  1
+);
+
+
+/**
+  check() function for connection_control_max_connection_delay
+
+  Check whether new value is within valid bounds or not.
+
+  @param thd        Not used.
+  @param var        Not used.
+  @param save       Not used.
+  @param value      New value for the option.
+
+  @returns whether new value is within valid bounds or not.
+    @retval 0 Value is ok
+    @retval 1 Value is not within valid bounds
+*/
+
+static int
+check_max_connection_delay(MYSQL_THD thd MY_ATTRIBUTE((unused)),
+                           struct st_mysql_sys_var *var MY_ATTRIBUTE((unused)),
+                           void *save MY_ATTRIBUTE((unused)),
+                           struct st_mysql_value *value)
+{
+  long long new_value;
+  int64 existing_value= my_atomic_load64(&g_variables.min_connection_delay);
+  if (value->val_int(value, &new_value))
+    return 1;                           /* NULL value */
+
+  if (new_value >= connection_control::MIN_DELAY &&
+      new_value <= connection_control::MAX_DELAY &&
+      new_value >= existing_value)
+  {
+    *(reinterpret_cast<longlong *>(save))= new_value;
+    return 0;
+  }
+  return 1;
+}
+
+
+/**
+  update() function for connection_control_max_connection_delay
+
+  Updates g_connection_event_coordinator with new value.
+  Also notifies observers about the update.
+
+  @param thd        Not used.
+  @param var        Not used.
+  @param var_ptr    Variable information
+  @param save       New value for connection_control_max_connection_delay
+*/
+
+static void
+update_max_connection_delay(MYSQL_THD thd MY_ATTRIBUTE((unused)),
+                            struct st_mysql_sys_var *var MY_ATTRIBUTE((unused)),
+                            void *var_ptr, const void *save)
+{
+  longlong new_value= *(reinterpret_cast<const longlong *>(save));
+  my_atomic_store64(&g_variables.max_connection_delay, (int64)new_value);
+  Connection_control_error_handler error_handler(connection_control_plugin_info);
+  g_connection_event_coordinator->notify_sys_var(&error_handler,
+                                                 OPT_MAX_CONNECTION_DELAY,
+                                                 &new_value);
+  return;
+}
+
+
+/** Declaration of connection_control_max_connection_delay */
+static MYSQL_SYSVAR_LONGLONG(
+  max_connection_delay,
+  g_variables.max_connection_delay,
+  PLUGIN_VAR_RQCMDARG,
+  "Maximum delay to be introduced. Default is 2147483647.",
+  check_max_connection_delay,
+  update_max_connection_delay,
+  connection_control::DEFAULT_MAX_DELAY,
+  connection_control::MIN_DELAY,
+  connection_control::MAX_DELAY,
+  1
+);
+
+
+/** Array of system variables. Used in plugin declaration. */
+struct st_mysql_sys_var *
+connection_control_system_variables[OPT_LAST + 1]=
+{
+  MYSQL_SYSVAR(failed_connections_threshold),
+  MYSQL_SYSVAR(min_connection_delay),
+  MYSQL_SYSVAR(max_connection_delay),
+  NULL
+};
+
+
+/**
+  Function to display value for status variable : Connection_control_delay_generated
+
+  @param thd  MYSQL_THD handle. Unused.
+  @param var  Status variable structure
+  @param buff Value buffer.
+
+  @returns Always returns success.
+*/
+
+static int show_delay_generated(MYSQL_THD,
+                                struct st_mysql_show_var *var,
+                                char *buff)
+{
+  var->type= SHOW_LONGLONG;
+  var->value= buff;
+  longlong *value= reinterpret_cast<longlong *>(buff);
+  int64 current_val= my_atomic_load64(&g_statistics.stats_array[STAT_CONNECTION_DELAY_TRIGGERED]);
+  *value= static_cast<longlong>(current_val);
+  return 0;
+}
+
+
+/** Array of status variables. Used in plugin declaration. */
+struct st_mysql_show_var
+connection_control_status_variables[STAT_LAST + 1]={
+  {
+    "Connection_control_delay_generated",
+    (char *)&show_delay_generated,
+    SHOW_FUNC
+  },
+  {0, 0, enum_mysql_show_type(0)}
+};
+
+
+mysql_declare_plugin(audit_log)
+{
+  MYSQL_AUDIT_PLUGIN,                   /* plugin type                   */
+  &connection_control_descriptor,       /* type specific descriptor      */
+  "CONNECTION_CONTROL",                 /* plugin name                   */
+  "Oracle Inc",                         /* author                        */
+  "Connection event processing",        /* description                   */
+  PLUGIN_LICENSE_GPL        ,           /* license                       */
+  connection_control_init,              /* plugin initializer            */
+  connection_control_deinit,            /* plugin deinitializer          */
+  0x0100,                               /* version                       */
+  connection_control_status_variables,  /* status variables              */
+  connection_control_system_variables,  /* system variables              */
+  NULL,                                 /* reserverd                     */
+  0                                     /* flags                         */
+},
+{
+  MYSQL_INFORMATION_SCHEMA_PLUGIN,
+   &connection_control_failed_attempts_view,
+   "CONNECTION_CONTROL_FAILED_LOGIN_ATTEMPTS",
+   "Oracle Inc",
+   "I_S table providing a view into failed attempts statistics",
+   PLUGIN_LICENSE_GPL,
+   connection_control_failed_attempts_view_init,
+   NULL,
+   0x0100,
+   NULL,
+   NULL,
+   NULL,
+   0
+}
+mysql_declare_plugin_end;
diff --git a/mysql-wsrep-5.6/plugin/connection_control/connection_control.h b/mysql-wsrep-5.6/plugin/connection_control/connection_control.h
new file mode 100644 (file)
index 0000000..638143f
--- /dev/null
@@ -0,0 +1,87 @@
+/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+
+   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 St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#ifndef CONNECTION_CONTROL_H
+#define CONNECTION_CONTROL_H
+
+#include <mysql/psi/mysql_thread.h>     /* mysql_rwlock_t */
+
+#include "connection_control_data.h"
+
+namespace connection_control
+{
+
+  /** Helper class : Wrapper on READ lock */
+
+  class RD_lock
+  {
+  public:
+    explicit RD_lock(mysql_rwlock_t *lock) : m_lock(lock)
+    {
+      if (m_lock)
+        mysql_rwlock_rdlock(m_lock);
+    }
+    ~RD_lock()
+    {
+      if (m_lock)
+        mysql_rwlock_unlock(m_lock);
+    }
+    void lock()
+    {
+      mysql_rwlock_rdlock(m_lock);
+    }
+    void unlock()
+    {
+      mysql_rwlock_unlock(m_lock);
+    }
+  private:
+    mysql_rwlock_t *m_lock;
+
+    RD_lock(const RD_lock&);             /* Not copyable. */
+    void operator=(const RD_lock&);      /* Not assignable. */
+  };
+
+
+  /** Helper class : Wrapper on write lock */
+
+  class WR_lock
+  {
+  public:
+    explicit WR_lock(mysql_rwlock_t *lock) : m_lock(lock)
+    {
+      if (m_lock)
+        mysql_rwlock_wrlock(m_lock);
+    }
+    ~WR_lock()
+    {
+      if (m_lock)
+        mysql_rwlock_unlock(m_lock);
+    }
+    void lock()
+    {
+      mysql_rwlock_wrlock(m_lock);
+    }
+    void unlock()
+    {
+      mysql_rwlock_unlock(m_lock);
+    }
+  private:
+    mysql_rwlock_t *m_lock;
+
+    WR_lock(const WR_lock&);             /* Not copyable. */
+    void operator=(const WR_lock&);      /* Not assignable. */
+  };
+}
+#endif /* !CONNECTION_CONTROL_H */
diff --git a/mysql-wsrep-5.6/plugin/connection_control/connection_control_coordinator.cc b/mysql-wsrep-5.6/plugin/connection_control/connection_control_coordinator.cc
new file mode 100644 (file)
index 0000000..ab2ea83
--- /dev/null
@@ -0,0 +1,280 @@
+/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+
+   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 St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#include <my_global.h>
+#include <my_pthread.h>
+#include <my_atomic.h>
+
+#include "connection_control_coordinator.h"
+#include "connection_control.h"
+
+namespace connection_control
+{
+  /**
+    Reset Connection_event_coordinator information
+  */
+
+  void
+    Connection_event_coordinator::reset()
+  {
+    m_subscribers.clear();
+    for (uint i= (uint)STAT_CONNECTION_DELAY_TRIGGERED;
+         i < (uint)STAT_LAST; ++i)
+      m_status_vars_subscription[i]= 0;
+  }
+
+
+  /**
+    Register an event subscriber.
+
+    A subscriber can provide following preferences:
+      1. Set of events for which subscriber is interested
+      2. Set of variables for which subscriber would like to receive update
+      3. Set of stats for which subscriber would like to send update
+
+    @param subscriber [in]    Handle to Connection_event_observers
+    @param events [in]        Event mask supplied by subscriber
+    @param sys_vars [in]      opt_connection_control vector
+    @param status_vars [in]   stats_connection_control vector
+
+    @returns subscription status
+      @retval false Subscription successful
+      @retval true Failure in subscription for given combination of prefernece.
+                   Most probably, other subscriber has already subscribed for
+                   status var update.
+  */
+
+  bool
+  Connection_event_coordinator::register_event_subscriber(
+    Connection_event_observer **subscriber,
+    std::vector<opt_connection_control> *sys_vars,
+    std::vector<stats_connection_control> *status_vars)
+  {
+    DBUG_ENTER("Connection_event_coordinator::register_event_subscriber");
+    bool error= false;
+    std::vector<opt_connection_control>::iterator sys_vars_it;
+    std::vector<stats_connection_control>::iterator status_vars_it;
+
+    DBUG_ASSERT(subscriber != 0);
+
+    if (status_vars)
+    {
+      for (status_vars_it= status_vars->begin();
+           status_vars_it != status_vars->end();
+           ++status_vars_it)
+      {
+        if (*status_vars_it >= STAT_LAST ||
+            m_status_vars_subscription[*status_vars_it] != 0)
+        {
+          /*
+            Either an invalid status variable is specified or
+            someone has already subscribed for status variable
+          */
+          error= true;
+          break;
+        }
+      }
+    }
+
+    if (!error && sys_vars)
+    {
+      for (sys_vars_it= sys_vars->begin();
+           sys_vars_it != sys_vars->end();
+           ++sys_vars_it)
+      {
+        if (*sys_vars_it >= OPT_LAST)
+          error= true;
+        break;
+      }
+    }
+
+    if (!error)
+    {
+      /*
+        Create Connection_event_subscriber object and
+        initialize it with required details.
+      */
+      Connection_event_subscriber subscriber_info;
+      subscriber_info.m_subscriber= *subscriber;
+
+      /* Reset the list first */
+      for (uint i= (uint)OPT_FAILED_CONNECTIONS_THRESHOLD;
+           i < (uint)OPT_LAST;
+           ++i)
+        subscriber_info.m_sys_vars[i]= false;
+
+      /* Now set the bits which are requested by subscriber */
+      for (sys_vars_it= sys_vars->begin();
+           sys_vars_it != sys_vars->end();
+           ++sys_vars_it)
+        subscriber_info.m_sys_vars[*sys_vars_it]= true;
+
+      /* Insert new entry in m_subscribers */
+      try
+      {
+        m_subscribers.push_back(subscriber_info);
+      }
+      catch (...)
+      {
+        /* Something went wrong. Mostly likely OOM. */
+        error= true;
+      }
+
+      /*
+        Update m_status_vars_subscription only if subscriber information
+        has been inserted in m_subscribers successfully.
+      */
+      if (!error)
+      {
+        for (status_vars_it= status_vars->begin();
+             status_vars_it != status_vars->end();
+             ++status_vars_it)
+          m_status_vars_subscription[*status_vars_it]= *subscriber;
+      }
+    }
+    DBUG_RETURN(error);
+  }
+
+
+  /**
+      Handle connection event.
+      When a notification from server is received, perform following:
+      1. Iterate through list of subscribers
+      - If a subscriber has shown interest in received event,
+        call notify() for the subscriber
+      2. Interate through list of status variables
+      - If subscriber has show interest in any status variable,
+        call notify_status_var() for the subscriber
+      - If subscriber suggests an action on status variable,
+        perform the action
+
+      Note : If we receive error from a subscriber, we log it and move on.
+
+      @param thd [in]               THD handle
+      @param error_handler [in]     Error handler class
+      @param connection_event [in]  Event information
+  */
+
+  void
+  Connection_event_coordinator::notify_event(
+    MYSQL_THD thd,
+    Error_handler *error_handler,
+    const mysql_event_connection *connection_event)
+  {
+    DBUG_ENTER("Connection_event_coordinator::notify_event");
+    std::vector<Connection_event_subscriber>::iterator it= m_subscribers.begin();
+
+    while (it != m_subscribers.end())
+    {
+      Connection_event_subscriber event_subscriber= *it;
+      (void)event_subscriber.m_subscriber->notify_event(thd, this,
+                                                        connection_event,
+                                                        error_handler);
+
+      ++it;
+    }
+
+    DBUG_VOID_RETURN;
+  }
+
+
+  /**
+    Process change in sys_var value
+
+    Iterate through all subscribers
+    - If a subscriber has shown interest in getting notification for given
+      system variable, call notify_sys_var.
+
+    Note : If we receive error from a subscriber, we log it and move on.
+
+    @param error_hanlder [in]     Error handler class
+    @param opt_connection_control Variable information
+    @param new_value [in]         New value for variable
+  */
+
+  void
+  Connection_event_coordinator::notify_sys_var(Error_handler *error_handler,
+                                               opt_connection_control variable,
+                                               void *new_value)
+  {
+    DBUG_ENTER("Connection_event_coordinator::notify_sys_var");
+    std::vector<Connection_event_subscriber>::iterator it= m_subscribers.begin();
+
+    while (it != m_subscribers.end())
+    {
+      Connection_event_subscriber event_subscriber= *it;
+      if (event_subscriber.m_sys_vars[variable])
+      {
+        (void) event_subscriber.m_subscriber->notify_sys_var(this,
+                                                             variable,
+                                                             new_value,
+                                                             error_handler);
+      }
+      ++it;
+    }
+
+    DBUG_VOID_RETURN;
+  }
+
+
+  /**
+    Update a status variable
+
+    @param observer [in]   Requestor
+    @param status_var [in] Status variable to be updated
+    @param action [in]     Operation to be performed on status variable
+
+    @returns status of the operation
+      @retval false Success
+      @retval true Error in processing
+  */
+
+  bool
+  Connection_event_coordinator::notify_status_var(Connection_event_observer **observer,
+                                                  stats_connection_control status_var,
+                                                  status_var_action action)
+  {
+    DBUG_ENTER("Connection_event_coordinator::notify_status_var");
+    bool error= false;
+
+    if (m_status_vars_subscription[status_var] == *observer)
+    {
+      if (status_var < STAT_LAST)
+      {
+        switch (action)
+        {
+          case ACTION_INC:
+          {
+            my_atomic_add64(&g_statistics.stats_array[status_var], 1);
+            break;
+          }
+          case ACTION_RESET:
+          {
+            my_atomic_store64(&g_statistics.stats_array[status_var], 0);
+            break;
+          }
+          default:
+          {
+            error= true;
+            DBUG_ASSERT(FALSE);
+            break;
+          }
+        }
+      }
+    }
+
+    DBUG_RETURN(error);
+  }
+}
diff --git a/mysql-wsrep-5.6/plugin/connection_control/connection_control_coordinator.h b/mysql-wsrep-5.6/plugin/connection_control/connection_control_coordinator.h
new file mode 100644 (file)
index 0000000..4509c5a
--- /dev/null
@@ -0,0 +1,73 @@
+/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+
+   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 St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#ifndef CONNECTION_CONTROL_COORDINATOR_H
+#define CONNECTION_CONTROL_COORDINATOR_H
+
+#include "connection_control_interfaces.h" /* Connection_event_coordinator_services */
+#include "connection_control_memory.h"  /* Connection_control_alloc */
+
+namespace connection_control
+{
+  /**
+    Connection event coordinator.
+    This class will keep list of subscribers for different  subevents
+    and notify them based on their preference.
+  */
+
+  class Connection_event_coordinator : public Connection_event_coordinator_services,
+                                       public Connection_control_alloc
+  {
+  public:
+    Connection_event_coordinator()
+    {
+      reset();
+    }
+    ~Connection_event_coordinator()
+    {
+      reset();
+    }
+
+    /* Functions to receive notification from server */
+    void notify_event(MYSQL_THD thd,
+                      Error_handler * error_handler,
+                      const mysql_event_connection *connection_event);
+    void notify_sys_var(Error_handler * error_handler,
+                        opt_connection_control variable,
+                        void *new_value);
+
+    /* Services provided to observers */
+    bool register_event_subscriber(Connection_event_observer **subscriber,
+                                   std::vector<opt_connection_control> *sys_vars,
+                                   std::vector<stats_connection_control> *status_vars);
+
+    bool notify_status_var(Connection_event_observer **observer,
+                           stats_connection_control status_var,
+                           status_var_action action);
+
+  private:
+    void reset();
+    class Connection_event_subscriber
+    {
+    public:
+      Connection_event_observer * m_subscriber;
+      bool m_sys_vars[OPT_LAST];
+    };
+
+    std::vector<Connection_event_subscriber> m_subscribers;
+    Connection_event_observer *m_status_vars_subscription[STAT_LAST];
+  };
+}
+#endif // !CONNECTION_CONTROL_COORDINATOR_H
diff --git a/mysql-wsrep-5.6/plugin/connection_control/connection_control_data.h b/mysql-wsrep-5.6/plugin/connection_control/connection_control_data.h
new file mode 100644 (file)
index 0000000..1372447
--- /dev/null
@@ -0,0 +1,68 @@
+/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+
+   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 St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#ifndef CONNECTION_CONTROL_DATA_H
+#define CONNECTION_CONTROL_DATA_H
+
+#include <my_global.h>
+
+/**
+  Enum for system variables : Must be in sync with
+  members of Connection_control_variables.
+*/
+typedef enum opt_connection_control
+{
+  OPT_FAILED_CONNECTIONS_THRESHOLD= 0,
+  OPT_MIN_CONNECTION_DELAY,
+  OPT_MAX_CONNECTION_DELAY,
+  OPT_LAST /* Must be last */
+}opt_connection_control;
+
+/**
+  Enum for status variables : Must be in sync with
+  memebers of Connection_control_statistics.
+*/
+typedef enum stats_connection_control
+{
+  STAT_CONNECTION_DELAY_TRIGGERED= 0,
+  STAT_LAST /* Must be last */
+}stats_connection_control;
+
+namespace connection_control
+{
+  /** Structure to maintain system variables */
+  class Connection_control_variables
+  {
+  public:
+    /* Various global variables */
+    int64 failed_connections_threshold;
+    int64 min_connection_delay;
+    int64 max_connection_delay;
+  };
+
+  /** Structure to maintain statistics */
+  class Connection_control_statistics
+  {
+  public:
+    Connection_control_statistics()
+    {}
+    /* Various statistics to be collected */
+    volatile int64 stats_array[STAT_LAST];
+  };
+}
+
+extern connection_control::Connection_control_statistics g_statistics;
+extern connection_control::Connection_control_variables g_variables;
+#endif // !CONNECTION_CONTROL_DATA_H
diff --git a/mysql-wsrep-5.6/plugin/connection_control/connection_control_interfaces.h b/mysql-wsrep-5.6/plugin/connection_control/connection_control_interfaces.h
new file mode 100644 (file)
index 0000000..1faff23
--- /dev/null
@@ -0,0 +1,103 @@
+/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+
+   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 St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#ifndef CONNECTION_CONTROL_INTERFACES_H
+#define CONNECTION_CONTROL_INTERFACES_H
+
+#include <mysql/plugin_audit.h>         /* mysql_event_connection */
+
+#include "connection_control_data.h"    /* Variables and Status */
+
+#include <vector>                       /* std::vector */
+#include <string>                       /* std::string */
+
+namespace connection_control
+{
+  /* Typedefs for convenience */
+  typedef std::string Sql_string;
+
+  /* Forward declarations */
+  class Connection_event_coordinator_services;
+
+  class Error_handler
+  {
+  public:
+    virtual void handle_error(const char * error_message)= 0;
+    virtual ~Error_handler() {}
+  };
+
+  /**
+    Interface for recording connection events
+  */
+
+  class Connection_event_records
+  {
+  public:
+    virtual bool create_or_update_entry(const Sql_string &s)= 0;
+    virtual bool remove_entry(const Sql_string &s)= 0;
+    virtual bool match_entry(const Sql_string &s, void *value)= 0;
+    virtual void reset_all()= 0;
+    virtual ~Connection_event_records()
+    { /* Emptiness! */ }
+  };
+
+
+  /**
+    Interface for defining action on connection events
+  */
+  class Connection_event_observer
+  {
+  public:
+    virtual bool notify_event(MYSQL_THD thd,
+                              Connection_event_coordinator_services *coordinator,
+                              const mysql_event_connection *connection_event,
+                              Error_handler *error_handler)= 0;
+    virtual bool notify_sys_var(Connection_event_coordinator_services *coordinator,
+                                opt_connection_control variable,
+                                void *new_value,
+                                Error_handler *error_handler)= 0;
+    virtual ~Connection_event_observer()
+    { /* Nothing to see here! */ }
+  };
+
+
+  /* Status variable action enum */
+  typedef enum status_var_action
+  {
+    ACTION_NONE=0,
+    ACTION_INC,
+    ACTION_RESET,
+    ACTION_LAST /* Must be at the end */
+  }status_var_action;
+
+
+  /**
+    Interface to provide service to observers
+  */
+
+  class Connection_event_coordinator_services
+  {
+  public:
+    virtual bool notify_status_var(Connection_event_observer **observer,
+                                   stats_connection_control status_var,
+                                   status_var_action action)= 0;
+    virtual bool register_event_subscriber(Connection_event_observer **subscriber,
+                                           std::vector<opt_connection_control> *sys_vars,
+                                           std::vector<stats_connection_control> *status_vars)= 0;
+    virtual ~Connection_event_coordinator_services()
+    { /* go away */ }
+  };
+}
+#endif // !CONNECTION_CONTROL_INTERFACES_H
diff --git a/mysql-wsrep-5.6/plugin/connection_control/connection_control_memory.h b/mysql-wsrep-5.6/plugin/connection_control/connection_control_memory.h
new file mode 100644 (file)
index 0000000..710cc1a
--- /dev/null
@@ -0,0 +1,55 @@
+/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+
+   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 St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#ifndef CONNECTION_CONTROL_MEMORY_H
+#define CONNECTION_CONTROL_MEMORY_H
+
+#include <my_global.h>
+#include <my_sys.h>
+#include <limits>
+#include <memory>
+
+namespace connection_control
+{
+  template <class T>
+  T Connection_control_malloc(size_t size)
+  {
+    void *allocated_memory= my_malloc(size, MYF(MY_WME));
+    return allocated_memory ? reinterpret_cast<T>(allocated_memory) : NULL;
+  }
+
+  class Connection_control_alloc
+  {
+    public:
+      static void *operator new(size_t size) throw ()
+      {
+        return Connection_control_malloc<void*>(size);
+      }
+      static void *operator new[](size_t size) throw ()
+      {
+        return Connection_control_malloc<void*>(size);
+      }
+      static void operator delete(void* ptr, std::size_t sz)
+      {
+          my_free(ptr);
+      }
+      static void operator delete[](void* ptr, std::size_t sz)
+      {
+          my_free(ptr);
+      }
+  };
+}
+
+#endif //CONNECTION_CONTROL_MEMORY_H
diff --git a/mysql-wsrep-5.6/plugin/connection_control/connection_delay.cc b/mysql-wsrep-5.6/plugin/connection_control/connection_delay.cc
new file mode 100644 (file)
index 0000000..e7172ba
--- /dev/null
@@ -0,0 +1,998 @@
+/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+
+   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 St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#define MYSQL_SERVER  "We need security context"
+#include <m_ctype.h>                    /* my_charset_bin */
+#include <sql_class.h>                  /* THD, Security context */
+#include <item_cmpfunc.h>
+#include <mysql/psi/mysql_thread.h>
+
+#include "connection_delay.h"
+#include "connection_control.h"
+#include "security_context_wrapper.h"
+
+
+
+/* Forward declaration */
+bool schema_table_store_record(THD *thd, TABLE *table);
+
+struct st_mysql_information_schema
+  connection_control_failed_attempts_view={MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION};
+
+/** Fields of information_schema.connection_control_failed_attempts */
+static ST_FIELD_INFO failed_attempts_view_fields[]=
+{
+  {"USERHOST", USERNAME_LENGTH + MAX_HOSTNAME + 5, MYSQL_TYPE_STRING, 0, MY_I_S_UNSIGNED, 0, 0},
+  {"FAILED_ATTEMPTS", 16, MYSQL_TYPE_LONG, 0, MY_I_S_UNSIGNED, 0, 0},
+  {0, 0, MYSQL_TYPE_NULL, 0, 0, 0, 0}
+};
+
+
+namespace connection_control
+{
+
+  /** constants/variables declared in connection_delay_interfaces.h */
+
+  int64 DEFAULT_THRESHOLD= 3;
+  int64 MIN_THRESHOLD= 0;
+  int64 DISABLE_THRESHOLD= 0;
+  int64 MAX_THRESHOLD= INT_MAX32;
+
+  int64 DEFAULT_MAX_DELAY= INT_MAX32;
+  int64 DEFAULT_MIN_DELAY= 1000;
+  int64 MIN_DELAY= 1000;
+  int64 MAX_DELAY= INT_MAX32;
+
+  /** variables used by connection_delay.cc */
+  static mysql_rwlock_t connection_event_delay_lock;
+  static PSI_rwlock_key key_connection_event_delay_lock;
+  static PSI_rwlock_info all_rwlocks[]=
+  {
+    {&key_connection_event_delay_lock, "connection_event_delay_lock", 0}
+  };
+
+  static opt_connection_control opt_enums[]=
+  {
+    OPT_FAILED_CONNECTIONS_THRESHOLD,
+    OPT_MIN_CONNECTION_DELAY,
+    OPT_MAX_CONNECTION_DELAY
+  };
+  size_t opt_enums_size= 3;
+
+  static stats_connection_control status_vars_enums[]=
+  {
+    STAT_CONNECTION_DELAY_TRIGGERED
+  };
+  size_t status_vars_enums_size= 1;
+
+  static Connection_delay_action *g_max_failed_connection_handler= 0;
+
+  Sql_string I_S_CONNECTION_CONTROL_FAILED_ATTEMPTS_USERHOST
+    ("information_schema.connection_control_failed_login_attempts.userhost");
+
+  /**
+    Helper function for Connection_delay_event::reset_all
+
+    @param ptr [in]        Pointer to an entry in hash
+
+    @returns 1 to indicate that entry is a match
+  */
+  int match_all_entries(const uchar *ptr)
+  {
+    return 1;
+  }
+
+
+  /**
+    Callback function for LF hash to get key information
+
+    Returns a pointer to a buffer which represent a key in the hash.
+    The function does NOT calculate a hash.
+    The function is called during lf_hash_insert(). The buffer is
+    fed to an internal calc_hash() which use the defined charset to
+    calculate a hash from the key buffer (in most cases a murmur)
+
+    @param el [in]        Pointer to an element in the hash
+    @param length [out]   The length of the key belonging to the element
+
+    @returns Pointer to key buffer
+  */
+
+  uchar *connection_delay_event_hash_key(const uchar *el, size_t *length, my_bool huh)
+  {
+    const Connection_event_record * const *entry;
+    const Connection_event_record *entry_info;
+    entry= reinterpret_cast<const Connection_event_record* const *>(el);
+    DBUG_ASSERT(entry != NULL);
+    entry_info= *entry;
+    *length= entry_info->get_length();
+    return (const_cast<uchar *>(entry_info->get_userhost()));
+  }
+
+
+  /**
+    Constructor for Connection_delay_event
+
+    Initialize LF hash.
+  */
+
+  Connection_delay_event::Connection_delay_event()
+  {
+    lf_hash_init(&m_entries, sizeof(Connection_event_record**), LF_HASH_UNIQUE,
+                 0, /* key offset */
+                 0, /* key length not used */
+                 connection_delay_event_hash_key,
+                 &my_charset_bin);
+  }
+
+
+  /**
+    Creates or updates an entry in hash
+
+    @param s [in]    User information in '<user'@'<host>' format
+
+    @returns status of insertion/update
+      @retval false  Insertion/Update successful
+      @retval true   Failed to insert/update an entry
+  */
+
+  bool
+  Connection_delay_event::create_or_update_entry(const Sql_string &s)
+  {
+    Connection_event_record **searched_entry= NULL;
+    Connection_event_record *searched_entry_info= NULL;
+    Connection_event_record *new_entry= NULL;
+    int insert_status;
+    DBUG_ENTER("Connection_delay_event::create_or_update_entry");
+
+    LF_PINS *pins= lf_hash_get_pins(&m_entries);
+    if (unlikely(pins == NULL))
+      DBUG_RETURN(true);
+
+    searched_entry= reinterpret_cast<Connection_event_record **>
+      (lf_hash_search(&m_entries, pins, s.c_str(), s.length()));
+
+    if (searched_entry && (searched_entry != MY_ERRPTR))
+    {
+      /* We found an entry, so increment the count */
+      searched_entry_info= *searched_entry;
+      DBUG_ASSERT(searched_entry_info != NULL);
+      searched_entry_info->inc_count();
+      lf_hash_search_unpin(pins);
+      lf_hash_put_pins(pins);
+      DBUG_RETURN(false);
+    }
+    else
+    {
+      /* No entry found, so try to add new entry */
+      lf_hash_search_unpin(pins);
+      new_entry= new Connection_event_record(s);
+
+      insert_status= lf_hash_insert(&m_entries, pins, &new_entry);
+
+      if (likely(insert_status == 0))
+      {
+        lf_hash_put_pins(pins);
+        DBUG_RETURN(false);
+      }
+      else
+      {
+        /*
+          OOM. We are likely in bigger trouble than just
+          failing to insert an entry in hash.
+        */
+        lf_hash_put_pins(pins);
+        delete new_entry;
+        new_entry= NULL;
+        DBUG_RETURN(true);
+      }
+    }
+  }
+
+
+  /**
+    Resets count stored against given user entry
+
+    @param s [in]    User information in '<user'@'<host>' format
+
+    @returns status of reset operation
+      @retval false Reset successful
+      @retval true Failed to find given entry
+  */
+
+  bool
+  Connection_delay_event::remove_entry(const Sql_string &s)
+  {
+    Connection_event_record **searched_entry= NULL;
+    Connection_event_record *searched_entry_info= NULL;
+    DBUG_ENTER("Connection_delay_event::reset_entry");
+
+    LF_PINS *pins= lf_hash_get_pins(&m_entries);
+
+    searched_entry= reinterpret_cast<Connection_event_record **>
+      (lf_hash_search(&m_entries, pins, s.c_str(), s.length()));
+
+    if (searched_entry && searched_entry != MY_ERRPTR)
+    {
+      searched_entry_info= *searched_entry;
+      DBUG_ASSERT(searched_entry_info != NULL);
+      int rc= lf_hash_delete(&m_entries, pins, s.c_str(), s.length());
+      lf_hash_search_unpin(pins);
+      lf_hash_put_pins(pins);
+      if (rc == 0)
+      {
+        /* free memory upon successful deletion */
+        delete searched_entry_info;
+      }
+      DBUG_RETURN(rc != 0);
+    }
+    else
+    {
+      /* No entry found. */
+      lf_hash_search_unpin(pins);
+      lf_hash_put_pins(pins);
+      DBUG_RETURN(true);
+    }
+  }
+
+
+  /**
+    Retrieve stored value for given user entry
+
+    @param s [in]        User information in '<user'@'<host>' format
+    @param value [out]   Buffer to hold value stored against given user
+
+    @returns whether given entry is present in hash or not
+      @retval false  Entry found. Corresponding value is copied in value buffer.
+      @retval true   No matching entry found. value buffer should not be used.
+  */
+
+  bool
+  Connection_delay_event::match_entry(const Sql_string &s, void *value)
+  {
+    Connection_event_record **searched_entry= NULL;
+    Connection_event_record *searched_entry_info= NULL;
+    int64 count= DISABLE_THRESHOLD;
+    bool error= true;
+    DBUG_ENTER("Connection_delay_event::match_entry");
+
+    LF_PINS *pins= lf_hash_get_pins(&m_entries);
+
+    searched_entry= reinterpret_cast<Connection_event_record **>
+      (lf_hash_search(&m_entries, pins, s.c_str(), s.length()));
+
+    if (searched_entry && searched_entry != MY_ERRPTR)
+    {
+      searched_entry_info= *searched_entry;
+      count= searched_entry_info->get_count();
+      error= false;
+    }
+
+    lf_hash_search_unpin(pins);
+    lf_hash_put_pins(pins);
+    *(reinterpret_cast<int64 *>(value))= count;
+
+    DBUG_RETURN(error);
+  }
+
+
+  /**
+    Delete all entries from hash and free memory
+
+    @returns Reset was successful or not
+      @retval true All entries removed.
+      @retval false Failed to remove some entries
+  */
+
+  void
+  Connection_delay_event::reset_all()
+  {
+    Connection_event_record **searched_entry= NULL;
+    DBUG_ENTER("Connection_delay_event::reset_all");
+    LF_PINS *pins= lf_hash_get_pins(&m_entries);
+
+    do
+    {
+      /* match anything */
+      searched_entry= reinterpret_cast<Connection_event_record**>
+        (lf_hash_random_match(&m_entries, pins, match_all_entries, 0));
+
+      if (searched_entry != NULL && searched_entry != MY_ERRPTR
+          && (*searched_entry)
+          && !lf_hash_delete(&m_entries, pins,
+          (*searched_entry)->get_userhost(),
+                             (*searched_entry)->get_length()))
+      {
+        delete (*searched_entry);
+        *searched_entry= NULL;
+      }
+      else
+      {
+        /* Failed to delete didn't remove any pins */
+        lf_hash_search_unpin(pins);
+      }
+    } while (searched_entry != 0);
+
+    lf_hash_put_pins(pins);
+    DBUG_VOID_RETURN;
+  }
+
+
+  /** This works because connction_delay_IS_table is protected by wrlock */
+  static TABLE * connection_delay_IS_table;
+  void set_connection_delay_IS_table(TABLE *t)
+  {
+    connection_delay_IS_table= t;
+  }
+
+
+  /**
+    Function to populate information_schema view.
+
+    @param ptr [in]  Entry from LF hash
+
+    @returns status of row insertion
+      @retval 0 Success
+      @retval 1 Error
+  */
+
+  int connection_delay_IS_table_writer(const uchar *ptr)
+  {
+    /* Always return "no match" so that we go through all entries */
+    THD *thd= current_thd;
+    const Connection_event_record * const * entry;
+    const Connection_event_record *entry_info;
+    entry= reinterpret_cast<const Connection_event_record * const *>(ptr);
+    entry_info= *entry;
+    connection_delay_IS_table->field[0]->store((char *)entry_info->get_userhost(),
+                                               entry_info->get_length(),
+                                               system_charset_info);
+    connection_delay_IS_table->field[1]->store(entry_info->get_count(), true);
+    if (schema_table_store_record(thd, connection_delay_IS_table))
+      return 1;
+    /* Always return "no match" so that we go over all entries in the hash */
+    return 0;
+  }
+
+
+  /**
+    Function to dump LF hash data to IS table.
+
+    @param thd [in]    THD handle
+    @param tables [in] Handle to
+                       information_schema.connection_control_failed_attempts
+  */
+
+  void
+  Connection_delay_event::fill_IS_table(THD *thd,
+                                        TABLE_LIST *tables)
+  {
+    DBUG_ENTER("Connection_delay_event::fill_IS_table");
+    TABLE *table= tables->table;
+    set_connection_delay_IS_table(table);
+    LF_PINS *pins= lf_hash_get_pins(&m_entries);
+    void *key= 0;
+
+    do
+    {
+      key= lf_hash_random_match(&m_entries,
+                                pins,
+                                /* Functor: match anything and store the fields */
+                                connection_delay_IS_table_writer,
+                                0);
+      /* Always unpin after lf_hash_random_match() */
+      lf_hash_search_unpin(pins);
+    } while (key != 0);
+
+    lf_hash_put_pins(pins);
+    DBUG_VOID_RETURN;
+  }
+
+
+  /**
+    Connection_delay_action Constructor.
+
+    @param [in] threshold         Defines a threshold after which wait is triggered
+    @param [in] min_delay         Lower cap on wait
+    @param [in] max_delay         Upper cap on wait
+    @param [in] sys_vars          System variables
+    @param [in] sys_vars_size     Size of sys_vars array
+    @param [in] status_vars       Status variables
+    @param [in] status_vars_size  Size of status_vars array
+    @param [in] lock              RW lock handle
+  */
+
+  Connection_delay_action::Connection_delay_action(int64 threshold,
+                                                   int64 min_delay,
+                                                   int64 max_delay,
+                                                   opt_connection_control *sys_vars,
+                                                   size_t sys_vars_size,
+                                                   stats_connection_control *status_vars,
+                                                   size_t status_vars_size,
+                                                   mysql_rwlock_t *lock)
+    : m_threshold(threshold),
+      m_min_delay(min_delay),
+      m_max_delay(max_delay),
+      m_lock(lock)
+  {
+    if (sys_vars_size)
+    {
+      for (uint i=0; i < sys_vars_size; ++i)
+        m_sys_vars.push_back(sys_vars[i]);
+    }
+
+    if (status_vars_size)
+    {
+      for (uint i=0; i < status_vars_size; ++i)
+        m_stats_vars.push_back(status_vars[i]);
+    }
+  }
+
+
+  /**
+    Create hash key of the format '<user>'@'<host>'.
+    Policy:
+    1. Use proxy_user information if available. Else if,
+    2. Use priv_user/priv_host if either of them is not empty. Else,
+    3. Use user/host
+
+    @param thd [in]        THD pointer for getting security context
+    @param s [out]         Hash key is stored here
+  */
+
+  void
+  Connection_delay_action::make_hash_key(MYSQL_THD thd, Sql_string &s)
+  {
+    /* Our key for hash will be of format : '<user>'@'<host>' */
+
+    /* If proxy_user is set then use it directly for lookup */
+    Security_context_wrapper sctx_wrapper(thd);
+    const char * proxy_user= sctx_wrapper.get_proxy_user();
+    if (proxy_user && *proxy_user)
+    {
+      s.append(proxy_user);
+    } /* else if priv_user and/or priv_host is set, then use them */
+    else
+    {
+      const char * priv_user= sctx_wrapper.get_priv_user();
+      const char * priv_host= sctx_wrapper.get_priv_host();
+      if ((priv_user && *priv_user) || (priv_host && *priv_host))
+      {
+        s.append("'");
+
+        if (*priv_user)
+          s.append(priv_user);
+
+        s.append("'@'");
+
+        if (*priv_host)
+          s.append(priv_host);
+
+        s.append("'");
+      }
+      else
+      {
+        const char *user= sctx_wrapper.get_user();
+        const char *host= sctx_wrapper.get_host();
+        const char *ip= sctx_wrapper.get_ip();
+
+        s.append("'");
+
+        if (user && *user)
+          s.append(user);
+
+        s.append("'@'");
+
+        if (host && *host)
+          s.append(host);
+        else if (ip && *ip)
+          s.append(ip);
+
+        s.append("'");
+      }
+    }
+  }
+
+
+  /**
+    Wait till the wait_time expires or thread is killed
+
+    @param thd [in]        Handle to MYSQL_THD object
+    @param wait_time [in]  Maximum time to wait
+  */
+
+  void
+  Connection_delay_action::conditional_wait(MYSQL_THD thd,
+                                            ulonglong wait_time)
+  {
+    DBUG_ENTER("Connection_delay_action::conditional_wait");
+    const char * category= "connection_delay";
+
+    /** mysql_cond_timedwait requires wait time in timespec format */
+    struct timespec abstime;
+    /** Since we get wait_time in milliseconds, convert it to nanoseconds */
+    set_timespec_nsec(abstime, wait_time * 1000000ULL);
+
+    /** PSI_stage_info for thd_enter_cond/thd_exit_cond */
+    PSI_stage_info old_stage;
+    PSI_stage_info stage_waiting_in_connection_control_plugin=
+    {0, "Waiting in connection_control plugin", 0};
+
+    /** Initialize mutex required for mysql_cond_timedwait */
+    mysql_mutex_t connection_delay_mutex;
+    PSI_mutex_key key_connection_delay_mutex;
+    PSI_mutex_info connection_delay_mutex_info[]=
+    {
+      {&key_connection_delay_mutex, "connection_delay_mutex", PSI_FLAG_GLOBAL}
+    };
+    int count_mutex= array_elements(connection_delay_mutex_info);
+    PSI_server->register_mutex(category, connection_delay_mutex_info, count_mutex);
+    mysql_mutex_init(key_connection_delay_mutex, &connection_delay_mutex,
+                     MY_MUTEX_INIT_FAST);
+
+    /* Initialize condition to wait for */
+    mysql_cond_t connection_delay_wait_condition;
+    PSI_cond_key key_connection_delay_wait;
+    PSI_cond_info connection_delay_wait_info[]=
+    {
+      {&key_connection_delay_wait, "connection_delay_wait_condition", 0}
+    };
+    int count_cond= array_elements(connection_delay_wait_info);
+    PSI_server->register_cond(category, connection_delay_wait_info, count_cond);
+    mysql_cond_init(key_connection_delay_wait, &connection_delay_wait_condition, NULL);
+
+    /** Register wait condition with THD */
+    mysql_mutex_lock(&connection_delay_mutex);
+    thd_enter_cond(thd, &connection_delay_wait_condition, &connection_delay_mutex,
+                   &stage_waiting_in_connection_control_plugin, &old_stage,
+                   __func__, __FILE__, __LINE__);
+
+    /*
+      At this point, thread is essentially going to sleep till
+      timeout. If admin issues KILL statement for this THD,
+      there is no point keeping this thread in sleep mode only
+      to wake up to be terminated. Hence, in case of KILL,
+      we will return control to server without worring about
+      wait_time.
+    */
+    mysql_cond_timedwait(&connection_delay_wait_condition, &connection_delay_mutex, &abstime);
+
+    /* Finish waiting and deregister wait condition */
+    thd_exit_cond(thd, &stage_waiting_in_connection_control_plugin,
+                  __func__, __FILE__, __LINE__);
+
+    /* Cleanup */
+    mysql_mutex_destroy(&connection_delay_mutex);
+    mysql_cond_destroy(&connection_delay_wait_condition);
+    DBUG_VOID_RETURN;
+  }
+
+
+  /**
+    @brief  Handle a connection event and if requried,
+    wait for random amount of time before returning.
+
+    We only care about CONNECT and CHANGE_USER sub events.
+
+    @param thd [in]                THD pointer
+    @param coordinator [in]        Connection_event_coordinator
+    @param connection_event [in]   Connection event to be handled
+    @param error_handler [in]      Error handler object
+
+    @returns status of connection event handling
+      @retval false  Successfully handled an event.
+      @retval true   Something went wrong.
+                     error_buffer may contain details.
+  */
+
+  bool
+  Connection_delay_action::notify_event(MYSQL_THD thd,
+                                        Connection_event_coordinator_services *coordinator,
+                                        const mysql_event_connection *connection_event,
+                                        Error_handler *error_handler)
+  {
+    DBUG_ENTER("Connection_delay_action::notify");
+    bool error= false;
+    unsigned int subclass= connection_event->event_subclass;
+    Connection_event_observer *self= this;
+
+    if (subclass != MYSQL_AUDIT_CONNECTION_CONNECT &&
+        subclass != MYSQL_AUDIT_CONNECTION_CHANGE_USER)
+      DBUG_RETURN(error);
+
+    RD_lock rd_lock(m_lock);
+
+    int64 threshold= this->get_threshold();
+
+    /* If feature was disabled, return */
+    if (threshold <= DISABLE_THRESHOLD)
+      DBUG_RETURN(error);
+
+    int64 current_count= 0;
+    bool user_present= false;
+    Sql_string userhost;
+
+    make_hash_key(thd, userhost);
+
+    DBUG_PRINT("info", ("Connection control : Connection event lookup for: %s",
+                        userhost.c_str()));
+
+    /* Cache current failure count */
+    user_present=
+      m_userhost_hash.match_entry(userhost, (void *)&current_count) ? false : true;
+
+    if (current_count >= threshold || current_count < 0)
+    {
+      /*
+        If threshold is crosed, regardless of connection success
+        or failure, wait for (current_count + 1) - threshold seconds
+        Note that current_count is not yet updated in hash. So we
+        have to consider current connection as well - Hence the usage
+        of current_count + 1.
+      */
+      ulonglong wait_time= get_wait_time((current_count + 1) - threshold);
+
+      if ((error= coordinator->notify_status_var(
+                    &self, STAT_CONNECTION_DELAY_TRIGGERED, ACTION_INC)))
+      {
+        error_handler->handle_error("Failed to update connection delay triggered stats");
+      }
+      /*
+        Invoking sleep while holding read lock on Connection_delay_action
+        would block access to cache data through IS table.
+      */
+      rd_lock.unlock();
+      conditional_wait(thd, wait_time);
+      rd_lock.lock();
+    }
+
+    if (connection_event->status)
+    {
+      /*
+        Connection failure.
+        Add new entry to hash or increment failed connection count
+        for an existing entry
+      */
+      if (m_userhost_hash.create_or_update_entry(userhost))
+      {
+        char error_buffer[512];
+        memset(error_buffer, 0, sizeof(error_buffer));
+        my_snprintf(error_buffer, sizeof(error_buffer)-1,
+                    "Failed to update connection delay hash for account : %s",
+                    userhost.c_str());
+        error_handler->handle_error(error_buffer);
+        error= true;
+      }
+    }
+    else
+    {
+      /*
+        Successful connection.
+        delete entry for given account from the hash
+      */
+      if (user_present && m_userhost_hash.remove_entry(userhost))
+      {
+        char error_buffer[512];
+        memset(error_buffer, 0, sizeof(error_buffer));
+        my_snprintf(error_buffer, sizeof(error_buffer) - 1,
+                    "Failed to delete connection delay hash entry for acount : %s."
+                    " It might have been deleted already.",
+                    userhost.c_str());
+        error_handler->handle_error(error_buffer);
+        error= true;
+      }
+    }
+
+    DBUG_RETURN(error);
+  }
+
+
+  /**
+    Notification of a change in system variable value
+
+    @param coordinator [in]        Handle to coordinator
+    @param variable [in]           Enum of variable
+    @param new_value [in]          New value for variable
+    @param error_buffer [out]      Buffer to log error message if any
+    @param error_buffer_size [in]  Size of error buffer
+
+    @returns processing status
+      @retval false  Change in variable value processed successfully
+      @retval true Error processing new value.
+                    error_buffer may contain more details.
+  */
+
+  bool
+  Connection_delay_action::notify_sys_var(Connection_event_coordinator_services *coordinator,
+                                          opt_connection_control variable,
+                                          void *new_value,
+                                          Error_handler * error_handler)
+  {
+    DBUG_ENTER("Connection_delay_action::notify_sys_var");
+    bool error= true;
+    Connection_event_observer *self= this;
+
+    WR_lock wr_lock(m_lock);
+
+    switch (variable)
+    {
+      case OPT_FAILED_CONNECTIONS_THRESHOLD:
+      {
+        int64 new_threshold= *(static_cast<int64 *>(new_value));
+        DBUG_ASSERT(new_threshold >= DISABLE_THRESHOLD);
+        set_threshold(new_threshold);
+
+        if ((error= coordinator->notify_status_var(&self,
+                                                   STAT_CONNECTION_DELAY_TRIGGERED,
+                                                   ACTION_RESET)))
+        {
+          error_handler->handle_error("Failed to reset connection delay triggered stats");
+        }
+        break;
+      }
+      case OPT_MIN_CONNECTION_DELAY:
+      case OPT_MAX_CONNECTION_DELAY:
+      {
+        int64 new_delay= *(static_cast<int64 *>(new_value));
+        if ((error= set_delay(new_delay,
+                      (variable == OPT_MIN_CONNECTION_DELAY))))
+        {
+          char error_buffer[512];
+          memset(error_buffer, 0, sizeof(error_buffer));
+          my_snprintf(error_buffer, sizeof(error_buffer) - 1,
+                      "Could not set %s delay for connection delay.",
+                      (variable == OPT_MIN_CONNECTION_DELAY) ? "min" : "max");
+          error_handler->handle_error(error_buffer);
+        }
+        break;
+      }
+      default:
+        /* Should never reach here. */
+        DBUG_ASSERT(FALSE);
+        error_handler->handle_error("Unexpected option type for connection delay.");
+    };
+    DBUG_RETURN(error);
+  }
+
+
+  /**
+    Subscribe with coordinator for connection events
+
+    @param coordinator [in]  Handle to Connection_event_coordinator_services
+                             for registration
+  */
+  void
+  Connection_delay_action::init(Connection_event_coordinator_services *coordinator)
+  {
+    DBUG_ENTER("Connection_delay_action::init");
+    DBUG_ASSERT(coordinator);
+    bool retval;
+    Connection_event_observer *subscriber= this;
+    WR_lock wr_lock(m_lock);
+    retval= coordinator->register_event_subscriber(&subscriber,
+                                                   &m_sys_vars,
+                                                   &m_stats_vars);
+    DBUG_ASSERT(!retval);
+    if (retval)
+      retval= false;                    /* Make compiler happy */
+    DBUG_VOID_RETURN;
+  }
+
+
+  /**
+    Clear data from Connection_delay_action
+  */
+
+  void
+    Connection_delay_action::deinit()
+  {
+    mysql_rwlock_wrlock(m_lock);
+    m_userhost_hash.reset_all();
+    m_sys_vars.clear();
+    m_stats_vars.clear();
+    m_threshold= DISABLE_THRESHOLD;
+    mysql_rwlock_unlock(m_lock);
+    m_lock= 0;
+  }
+
+
+
+  /**
+    Get user information from "where userhost = <value>"
+
+    @param cond [in]        Equality condition structure
+    @param eq_arg [out]     Sql_string handle to store user information
+    @param field_name [in]  userhost field
+
+    @returns whether a value was found or not
+      @retval false Found a value. Check eq_arg
+      @retval true Error.
+  */
+
+  static
+  bool get_equal_condition_argument(Item *cond, Sql_string *eq_arg,
+                                    const Sql_string &field_name)
+  {
+    if (cond != 0 && cond->type() == Item::FUNC_ITEM)
+    {
+      Item_func *func= static_cast<Item_func *>(cond);
+      if (func != NULL && func->functype() == Item_func::EQ_FUNC)
+      {
+        Item_func_eq* eq_func= static_cast<Item_func_eq*>(func);
+        if (eq_func->arguments()[0]->type() == Item::FIELD_ITEM &&
+            my_strcasecmp(system_charset_info,
+                          eq_func->arguments()[0]->full_name(),
+                          field_name.c_str()) == 0)
+        {
+          char buff[1024];
+          String *res;
+          String filter(buff, sizeof(buff), system_charset_info);
+          if (eq_func->arguments()[1] != NULL &&
+            (res= eq_func->arguments()[1]->val_str(&filter)))
+          {
+            eq_arg->append(res->c_ptr_safe(), res->length());
+            return false;
+          }
+        }
+      }
+    }
+    return true;
+  }
+
+
+  /**
+    Function to fill information_schema.connection_control_failed_attempts.
+
+    Handles query with equality condition.
+    For full scan, calls Connection_delay_event::fill_IS_table()
+
+    Permission : SUPER_ACL is required.
+
+    @param thd [in]     THD handle.
+    @param tables [in]  Handle to
+                        information_schema.connection_control_failed_attempts.
+    @param cond [in]    Condition if any.
+  */
+
+  void
+  Connection_delay_action::fill_IS_table(THD *thd,
+                                         TABLE_LIST *tables,
+                                         Item *cond)
+  {
+    DBUG_ENTER("Connection_delay_action::fill_IS_table");
+    Security_context_wrapper sctx_wrapper(thd);
+    if (!sctx_wrapper.is_super_user())
+      DBUG_VOID_RETURN;
+    WR_lock wr_lock(m_lock);
+    Sql_string eq_arg;
+    if (cond != 0 &&
+        !get_equal_condition_argument(cond,
+                                      &eq_arg,
+                                      I_S_CONNECTION_CONTROL_FAILED_ATTEMPTS_USERHOST))
+    {
+      int64 current_count= 0;
+      if (m_userhost_hash.match_entry(eq_arg, (void *)&current_count))
+      {
+        /* There are no matches given the condition */
+        DBUG_VOID_RETURN;
+      }
+      else
+      {
+        /* There is exactly one matching userhost entry */
+        TABLE *table= tables->table;
+        table->field[0]->store(eq_arg.c_str(), eq_arg.length(),
+                               system_charset_info);
+        table->field[1]->store(current_count, true);
+        schema_table_store_record(thd, table);
+      }
+    }
+    else
+      m_userhost_hash.fill_IS_table(thd, tables);
+
+    DBUG_VOID_RETURN;
+  }
+
+
+  /**
+    Initializes required objects for handling connection events.
+
+    @param coordinator [in]    Connection_event_coordinator_services handle.
+  */
+
+  bool init_connection_delay_event(Connection_event_coordinator_services *coordinator,
+                                   Error_handler *error_handler)
+  {
+    /*
+      1. Initialize lock(s)
+    */
+    const char *category= "conn_control";
+    int count= array_elements(all_rwlocks);
+    mysql_rwlock_register(category, all_rwlocks, count);
+    mysql_rwlock_init(key_connection_event_delay_lock,
+                      &connection_event_delay_lock);
+    g_max_failed_connection_handler= new Connection_delay_action(g_variables.failed_connections_threshold,
+                                                                 g_variables.min_connection_delay,
+                                                                 g_variables.max_connection_delay,
+                                                                 opt_enums, opt_enums_size,
+                                                                 status_vars_enums, status_vars_enums_size,
+                                                                 &connection_event_delay_lock);
+    if (!g_max_failed_connection_handler)
+    {
+      error_handler->handle_error("Failed to initialization Connection_delay_action");
+      return true;
+    }
+    g_max_failed_connection_handler->init(coordinator);
+
+    return false;
+  }
+
+
+  /**
+    Deinitializes objects and frees associated memory.
+  */
+
+  void deinit_connection_delay_event()
+  {
+    if (g_max_failed_connection_handler)
+      delete g_max_failed_connection_handler;
+    g_max_failed_connection_handler= 0;
+    mysql_rwlock_destroy(&connection_event_delay_lock);
+    return;
+  }
+}
+
+
+/**
+  Function to fill information_schema.connection_control_failed_attempts.
+
+  @param thd [in]     THD handle.
+  @param tables [in]  Handle to
+                      information_schema.connection_control_failed_attempts.
+  @param cond [in]    Condition if any.
+
+  @returns Always returns FALSE.
+*/
+
+int fill_failed_attempts_view(THD *thd,
+                              TABLE_LIST *tables,
+                              Item *cond)
+{
+  if (connection_control::g_max_failed_connection_handler)
+    connection_control::g_max_failed_connection_handler->fill_IS_table(thd, tables, cond);
+  return FALSE;
+}
+
+
+/**
+  View init function
+
+  @param ptr [in]    Handle to
+                     information_schema.connection_control_failed_attempts.
+
+  @returns Always returns 0.
+*/
+
+int connection_control_failed_attempts_view_init(void *ptr)
+{
+  ST_SCHEMA_TABLE *schema_table= (ST_SCHEMA_TABLE *)ptr;
+
+  schema_table->fields_info= failed_attempts_view_fields;
+  schema_table->fill_table= fill_failed_attempts_view;
+  schema_table->idx_field1= 0;
+  schema_table->idx_field2= 1;
+  return 0;
+}
+
+
diff --git a/mysql-wsrep-5.6/plugin/connection_control/connection_delay.h b/mysql-wsrep-5.6/plugin/connection_control/connection_delay.h
new file mode 100644 (file)
index 0000000..48fc5a0
--- /dev/null
@@ -0,0 +1,292 @@
+/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+
+   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 St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#ifndef CONNECTION_DELAY_H
+#define CONNECTION_DELAY_H
+
+#include <lf.h>                         /* LF Hash */
+#include <my_global.h>
+#include <my_atomic.h>                  /* my_atomic_* */
+#include <mysql_com.h>                  /* USERNAME_LENGTH */
+#include "table.h"                      /* TABLE_LIST */
+
+#include "connection_control_interfaces.h" /* Observer interface */
+#include "connection_delay_api.h"       /* Constants */
+#include "connection_control_data.h"    /* variables and status */
+#include "connection_control_memory.h"  /* Connection_control_alloc */
+
+namespace connection_control
+{
+  /**
+    Class to store failed attempts information for a given user.
+  */
+
+  class Connection_event_record : public Connection_control_alloc
+  {
+  public:
+
+    /**
+      Constructor for Connection_event_record. Always initializes failed login count to 1.
+    */
+    Connection_event_record(const Sql_string &s)
+      : m_count(1)
+    {
+      memset((void *)m_userhost, 0, sizeof(m_userhost));
+      memcpy((void *)m_userhost, s.c_str(), s.length());
+      m_length= s.length();
+      m_count= 1;
+    }
+
+    /**
+      Retrives failed login count for given user entry
+
+      @returns Failed login count
+    */
+    int64 get_count() const
+    {
+      int64 result= my_atomic_load64((volatile int64*)&m_count);
+      return result;
+    }
+
+    /** Increment failed login count for given user entry by 1 */
+    void inc_count()
+    {
+      my_atomic_add64((volatile int64*)&m_count, 1);
+    }
+
+    /** Reset failed login count for given user entry */
+    void reset_count()
+    {
+      my_atomic_store64(&m_count, 0);
+    }
+
+    /** Get user information */
+    uchar * get_userhost() const
+    {
+      return const_cast<uchar *> (m_userhost);
+    }
+
+    /**  Get length information  */
+    size_t get_length() const
+    {
+      return m_length;
+    }
+
+    /** Destructor */
+    ~Connection_event_record()
+    {
+      m_count= DISABLE_THRESHOLD;
+    }
+
+  private:
+    /* '<user>'@'<host>' */
+    uchar m_userhost[1 + USERNAME_LENGTH + 3 + HOSTNAME_LENGTH + 1 + 1];
+    /* Length of m_userhost */
+    size_t m_length;
+    /* connection event count */
+    volatile int64 m_count;
+  };
+
+
+  /**
+    Hash for a connection event.
+    Stores information in Connection_event_record object for each user.
+  */
+
+  class Connection_delay_event : public Connection_event_records
+  {
+  public:
+
+    /** Constructor. Also initializes the hash */
+    Connection_delay_event();
+
+    /** Destructor. Removes all entries from hash before destroying hash */
+    ~Connection_delay_event()
+    {
+      reset_all();
+      lf_hash_destroy(&m_entries);
+    }
+
+    void fill_IS_table(THD *thd, TABLE_LIST *tables);
+
+    /* Overridden function */
+    bool create_or_update_entry(const Sql_string &s);
+    bool remove_entry(const Sql_string &s);
+    bool match_entry(const Sql_string &s, void * value);
+    void reset_all();
+
+  private:
+    /** Hash for storing Connection_event_record per user */
+    LF_HASH m_entries;
+  };
+
+
+  /**
+    Connection event action to enforce max failed login constraint
+  */
+
+  class Connection_delay_action : public Connection_event_observer,
+                                  public Connection_control_alloc
+  {
+  public:
+
+    Connection_delay_action(int64 threshold,
+                            int64 min_delay,
+                            int64 max_delay,
+                            opt_connection_control *sys_vars,
+                            size_t sys_vars_size,
+                            stats_connection_control *status_vars,
+                            size_t status_vars_size,
+                            mysql_rwlock_t *lock);
+
+    /** Destructor */
+    ~Connection_delay_action()
+    {
+      deinit();
+      m_lock= 0;
+    }
+
+    void init(Connection_event_coordinator_services *coordinator);
+
+    /**
+      Set threshold value.
+
+      @param threshold [in]        New threshold value
+
+      @returns whether threshold value was changed successfully or not
+        @retval true  Success
+        @retval false Failure. Invalid threshold value specified.
+    */
+
+    void set_threshold(int64 threshold)
+    {
+      my_atomic_store64(&m_threshold, threshold);
+      /* Clear the hash */
+      m_userhost_hash.reset_all();
+    }
+
+    /** Get threshold value */
+    int64 get_threshold()
+    {
+      int64 result= my_atomic_load64(&m_threshold);
+      return result;
+    }
+
+    /**
+      Set min/max delay
+
+      @param new_value [in]        New m_min_delay/m_max_delay value
+      @param min [in]              true for m_min_delay. false otherwise.
+
+      @returns whether m_min_delay/m_max_delay value was changed successfully or not
+        @retval false  Success
+        @retval true Failure. Invalid value specified.
+    */
+
+    bool set_delay(int64 new_value, bool min)
+    {
+      int64 current_max= get_max_delay();
+      int64 current_min= get_min_delay();
+
+      if (new_value < MIN_DELAY)
+        return true;
+
+      if ((min && new_value > current_max) ||
+        (!min && new_value < current_min))
+        return true;
+
+      else
+        min ? my_atomic_store64(&m_min_delay, new_value) :
+        my_atomic_store64(&m_max_delay, new_value);
+      return false;
+    }
+
+    /** Get max value */
+    int64 get_max_delay()
+    {
+      int64 result= my_atomic_load64(&m_max_delay);
+      return result;
+    }
+
+    /** Get min value */
+    int64 get_min_delay()
+    {
+      int64 result= my_atomic_load64(&m_min_delay);
+      return result;
+    }
+
+    void fill_IS_table(THD *thd,
+                       TABLE_LIST *tables,
+                       Item *cond);
+
+    /** Overridden functions */
+    bool notify_event(MYSQL_THD thd,
+                      Connection_event_coordinator_services *coordinator,
+                      const mysql_event_connection *connection_event,
+                      Error_handler *error_handler);
+    bool notify_sys_var(Connection_event_coordinator_services *coordinator,
+                        opt_connection_control variable,
+                        void *new_value,
+                        Error_handler *error_handler);
+
+  private:
+    void deinit();
+    void make_hash_key(MYSQL_THD thd, Sql_string &s);
+    /**
+      Generates wait time
+
+      @param count [in] Proposed delay
+
+      @returns wait time
+    */
+
+    inline ulonglong get_wait_time(int64 count)
+    {
+      int64 max_delay= get_max_delay();
+      int64 min_delay= get_min_delay();
+      int64 count_mili= count*1000;
+
+      /*
+        if count < 0 (can happen in edge cases
+        we return max_delay.
+        Otherwise, following equation will be used:
+        wait_time = MIN(MIN(count, min_delay),
+                        max_delay)
+      */
+      return (static_cast<ulonglong>((count_mili >= MIN_DELAY && count_mili < max_delay) ?
+        (count_mili < min_delay ? min_delay : count_mili) :
+                                  max_delay));
+    }
+    void conditional_wait(THD *thd,
+                          ulonglong wait_time);
+
+  private:
+    /** Threshold value which triggers wait */
+    volatile int64 m_threshold;
+    /** Lower cap on delay to be generated */
+    volatile int64 m_min_delay;
+    /** Upper cap on delay to be generated */
+    volatile int64 m_max_delay;
+    /** System variables */
+    std::vector<opt_connection_control> m_sys_vars;
+    /** Status variables */
+    std::vector<stats_connection_control> m_stats_vars;
+    /** Hash to store failed attempts for each user entry */
+    Connection_delay_event m_userhost_hash;
+    /** RW lock */
+    mysql_rwlock_t *m_lock;
+  };
+}
+#endif /* !CONNECTION_DELAY_H */
diff --git a/mysql-wsrep-5.6/plugin/connection_control/connection_delay_api.h b/mysql-wsrep-5.6/plugin/connection_control/connection_delay_api.h
new file mode 100644 (file)
index 0000000..81a4b89
--- /dev/null
@@ -0,0 +1,49 @@
+/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+
+   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 St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#ifndef CONNECTION_DELAY_API_H
+#define CONNECTION_DELAY_API_H
+
+/* Structures/Functions requried for information schema table */
+
+extern struct st_mysql_information_schema connection_control_failed_attempts_view;
+int connection_control_failed_attempts_view_init(void *ptr);
+
+namespace connection_control
+{
+
+  /* constants/variables defined in connection_delay.cc */
+
+  extern int64 DEFAULT_THRESHOLD;
+  extern int64 MIN_THRESHOLD;
+  extern int64 DISABLE_THRESHOLD;
+  extern int64 MAX_THRESHOLD;
+
+  extern int64 DEFAULT_MAX_DELAY;
+  extern int64 DEFAULT_MIN_DELAY;
+  extern int64 MIN_DELAY;
+  extern int64 MAX_DELAY;
+
+  /** Functions being used by connection_control.cc */
+
+  class Connection_event_coordinator_services;
+  class Error_handler;
+
+  bool init_connection_delay_event(Connection_event_coordinator_services *coordinator,
+                                   Error_handler *error_handler);
+  void deinit_connection_delay_event();
+
+}
+#endif // !CONNECTION_DELAY_API_H
diff --git a/mysql-wsrep-5.6/plugin/connection_control/security_context_wrapper.cc b/mysql-wsrep-5.6/plugin/connection_control/security_context_wrapper.cc
new file mode 100644 (file)
index 0000000..44f1ade
--- /dev/null
@@ -0,0 +1,219 @@
+/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+
+   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 St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#define MYSQL_SERVER  "We need security context"
+
+#include <sql_class.h>                      /* THD, Security context */
+#include <sql_acl.h>                        /* SUPER_ACL */
+
+#include "security_context_wrapper.h"
+
+namespace connection_control
+{
+  /**
+    Security_context_wrapper constructor.
+
+    @param thd [in]    Handle to THD
+
+    Get security context from thd.
+  */
+  Security_context_wrapper::Security_context_wrapper(MYSQL_THD thd)
+  {
+    m_valid= thd->security_ctx ? true : false;
+    m_thd= thd;
+  }
+
+
+  /**
+    Get value for given property from security context
+
+    @param property [in]    Property to be checked
+    @param value    [out]   Value of the property
+
+    @returns status of property check
+      @retval true Error fetching property value
+      @retval false value contains valid value for given property
+  */
+
+  bool
+  Security_context_wrapper::get_property(const char *property, LEX_CSTRING *value)
+  {
+    value->length=0;
+    value->str= 0;
+
+    if (!m_valid || !property)
+      return true;
+    else
+    {
+      if (!strcmp(property, "priv_user"))\r
+      {\r
+        if (m_thd->security_ctx->priv_user)\r
+        {\r
+          value->str= m_thd->security_ctx->priv_user;\r
+          value->length= strlen(value->str);\r
+        }\r
+      }
+      else if (!strcmp(property, "priv_host"))
+      {
+        if (m_thd->security_ctx->priv_host)
+        {
+          value->str= m_thd->security_ctx->priv_host;
+          value->length= strlen(value->str);
+        }
+      }
+      else if (!strcmp(property, "user"))
+      {
+        if (m_thd->security_ctx->user)
+        {
+          value->str= m_thd->security_ctx->user;
+          value->length= strlen(value->str);
+        }
+      }
+      else if (!strcmp(property, "proxy_user"))\r
+      {\r
+        if (m_thd->security_ctx->proxy_user)\r
+        {\r
+          value->str= m_thd->security_ctx->proxy_user;\r
+          value->length= strlen(value->str);\r
+        }\r
+      }
+      else if (!strcmp(property, "host"))
+      {
+        if (m_thd->security_ctx->get_host()->length())
+        {
+          value->str= m_thd->security_ctx->get_host()->c_ptr();
+          value->length= strlen(value->str);
+        }
+      }
+      else if (!strcmp(property, "ip"))
+      {
+        if (m_thd->security_ctx->get_ip()->length())
+        {
+          value->str= m_thd->security_ctx->get_ip()->c_ptr();
+          value->length= strlen(value->str);
+        }
+      }
+      else
+      {
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+  /**  Get proxy user information from security context */
+
+  const char *
+    Security_context_wrapper::get_proxy_user()
+  {
+    LEX_CSTRING proxy_user;
+    if (get_property("proxy_user", &proxy_user))
+      return 0;
+    return proxy_user.str;
+  }
+
+
+  /** Get priv user information from security context */
+
+  const char *
+    Security_context_wrapper::get_priv_user()
+  {
+    LEX_CSTRING priv_user;
+    if (get_property("priv_user", &priv_user))
+      return 0;
+    return priv_user.str;
+  }
+
+
+  /** Get priv host information from security context */
+
+  const char *
+    Security_context_wrapper::get_priv_host()
+  {
+    LEX_CSTRING priv_host;
+    if (get_property("priv_host", &priv_host))
+      return 0;
+    return priv_host.str;
+  }
+
+
+  /** Get connected user information from security context */
+
+  const char *
+    Security_context_wrapper::get_user()
+  {
+    LEX_CSTRING user;
+    if (get_property("user", &user))
+      return 0;
+    return user.str;
+  }
+
+
+  /** Get connected host information from security context */
+
+  const char *
+    Security_context_wrapper::get_host()
+  {
+    /*
+      We can't use thd->security_ctx->priv_host_name()
+      because it returns "%" if hostname is empty.
+      However, thd->security_ctx->proxy_user won't have
+      "%" if hostname was empty.
+
+      To be consistent, we will always use
+      'user'@'host'/''@'host'/''@'' type of representation.
+    */
+    LEX_CSTRING host;
+    if (get_property("host", &host))
+      return 0;
+    return host.str;
+  }
+
+
+  /** Get connected ip information from security context */
+
+  const char *
+    Security_context_wrapper::get_ip()
+  {
+    LEX_CSTRING ip;
+    if (get_property("ip", &ip))
+      return 0;
+    return ip.str;
+  }
+
+
+  /** Check if valid security context exists for give THD or not */
+
+  bool
+    Security_context_wrapper::security_context_exists()
+  {
+    return m_valid;
+  }
+
+
+  /** Check whether user has requried privilege or not */
+
+  bool
+    Security_context_wrapper::is_super_user()
+  {
+    if (!m_valid)
+      return false;
+
+    bool has_super= ((m_thd->security_ctx->master_access & SUPER_ACL) == SUPER_ACL);
+
+    return has_super;
+  }
+}
diff --git a/mysql-wsrep-5.6/plugin/connection_control/security_context_wrapper.h b/mysql-wsrep-5.6/plugin/connection_control/security_context_wrapper.h
new file mode 100644 (file)
index 0000000..41a2f1f
--- /dev/null
@@ -0,0 +1,44 @@
+/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+
+   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 St, Fifth Floor, Boston, MA 02110-1301  USA */
+
+#ifndef HAVE_SECURITY_CONTEXT_WRAPPER_H
+#define HAVE_SECURITY_CONTEXT_WRAPPER_H
+
+#include <mysql/plugin.h>
+
+namespace connection_control
+{
+  class Security_context_wrapper
+  {
+  public:
+    Security_context_wrapper(MYSQL_THD thd);
+    ~Security_context_wrapper()
+    {}
+    const char * get_proxy_user();
+    const char * get_priv_user();
+    const char * get_priv_host();
+    const char * get_user();
+    const char * get_host();
+    const char * get_ip();
+    bool security_context_exists();
+    bool is_super_user();
+
+  private:
+    bool get_property(const char *property, LEX_CSTRING *value);
+    MYSQL_THD m_thd;
+    bool m_valid;
+  };
+}
+#endif // !HAVE_SECURITY_CONTEXT_WRAPPER_H
index af459cc7d2200a50cc8b968ae9f0e46a66c455d8..a2d03bc2a1d17d5dc970339e18be4d3f4ad20765 100644 (file)
@@ -670,6 +670,7 @@ int ReplSemiSyncMaster::commitTrx(const char* trx_wait_binlog_name,
 
   TranxNode* entry= NULL;
   mysql_cond_t* thd_cond= NULL;
+  bool is_semi_sync_trans= true;
   if (active_tranxs_ != NULL && trx_wait_binlog_name)
   {
     entry=
@@ -733,6 +734,25 @@ int ReplSemiSyncMaster::commitTrx(const char* trx_wait_binlog_name,
           break;
         }
       }
+      /*
+        When code reaches here an Entry object may not be present in the
+        following scenario.
+
+        Semi sync was not enabled when transaction entered into ordered_commit
+        process. During flush stage, semi sync was not enabled and there was no
+        'Entry' object created for the transaction being committed and at a
+        later stage it was enabled. In this case trx_wait_binlog_name and
+        trx_wait_binlog_pos are set but the 'Entry' object is not present. Hence
+        dump thread will not wait for reply from slave and it will not update
+        reply_file_name. In such case the committing transaction should not wait
+        for an ack from slave and it should be considered as an async
+        transaction.
+      */
+      if (!entry)
+      {
+        is_semi_sync_trans= false;
+        goto l_end;
+      }
 
       /* Let us update the info about the minimum binlog position of waiting
        * threads.
@@ -833,7 +853,7 @@ int ReplSemiSyncMaster::commitTrx(const char* trx_wait_binlog_name,
 
 l_end:
     /* Update the status counter. */
-    if (is_on())
+    if (is_on() && is_semi_sync_trans)
       rpl_semi_sync_master_yes_transactions++;
     else
       rpl_semi_sync_master_no_transactions++;
index 265f81f2755aca7d4dd1ce00f818a2ca136d7a70..37c34e60813c5cbb40ec80b77888675a2f8c254d 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
 # 
 # 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
@@ -125,7 +125,13 @@ STRING(REPLACE       "-grecord-gcc-switches"         "" CXXFLAGS "${CXXFLAGS}")
 STRING(REPLACE       "-pipe"                         "" CXXFLAGS "${CXXFLAGS}")
 
 IF(UNIX)
-  # FIND_PROC and CHECK_PID are used by mysqld_safe
+  # SHELL_PATH, FIND_PROC, CHECK_PID are used by mysqld_safe
+IF(CMAKE_SYSTEM_NAME MATCHES "SunOS")
+  SET (SHELL_PATH "/bin/bash")
+ELSE()
+  SET (SHELL_PATH "/bin/sh")
+ENDIF()
+
 IF(CMAKE_SYSTEM_NAME MATCHES "Linux")
   SET (FIND_PROC 
     "ps wwwp $PID | grep -v mysqld_safe | grep -- $MYSQLD > /dev/null")
index d39c0e9d2992365d4cf92673279997a14d5a2766..eb408b34d9d3861d276d754fa1ab033a82cbf2bf 100644 (file)
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!@SHELL_PATH@
 # Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
 # This file is public domain and comes with NO WARRANTY of any kind
 #
@@ -126,7 +126,13 @@ log_generic () {
   echo "$msg"
   case $logging in
     init) ;;  # Just echo the message, don't save it anywhere
-    file) echo "$msg" >> "$err_log" ;;
+    file)
+      if [ -w / -o "$USER" = "root" ]; then
+        true
+      else
+        echo "$msg" >> "$err_log"
+      fi
+      ;;
     syslog) logger -t "$syslog_tag_mysqld_safe" -p "$priority" "$*" ;;
     *)
       echo "Internal program error (non-fatal):" \
@@ -146,7 +152,13 @@ log_notice () {
 eval_log_error () {
   local cmd="$1"
   case $logging in
-    file) cmd="$cmd >> "`shell_quote_string "$err_log"`" 2>&1" ;;
+    file)
+      if [ -w / -o "$USER" = "root" ]; then
+        cmd="$cmd > /dev/null 2>&1"
+      else
+        cmd="$cmd >> "`shell_quote_string "$err_log"`" 2>&1"
+      fi
+      ;;
     syslog)
       # mysqld often prefixes its messages with a timestamp, which is
       # redundant when logging to syslog (which adds its own timestamp)
@@ -279,7 +291,13 @@ parse_arguments() {
 
       # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])!
       --core-file-size=*) core_file_size="$val" ;;
-      --ledir=*) ledir="$val" ;;
+      --ledir=*)
+        if [ -z "$pick_args" ]; then
+          log_error "--ledir option can only be used as command line option, found in config file"
+          exit 1
+        fi
+        ledir="$val"
+        ;;
       --malloc-lib=*) set_malloc_lib "$val" ;;
       --mysqld=*)
         if [ -z "$pick_args" ]; then
@@ -461,7 +479,15 @@ else
   relpkgdata='@pkgdatadir@'
 fi
 
-MY_PWD=`pwd`
+case "$0" in
+  /*)
+  MY_PWD='@prefix@'
+  ;;
+  *)
+  MY_PWD=`dirname $0`
+  MY_PWD=`dirname $MY_PWD`
+  ;;
+esac
 # Check for the directories we would expect from a binary release install
 if test -n "$MY_BASEDIR_VERSION" -a -d "$MY_BASEDIR_VERSION"
 then
@@ -649,14 +675,7 @@ then
   fi
 
   # Log to err_log file
-  log_notice "Logging to '$err_log'."
   logging=file
-
-  if [ ! -f "$err_log" -a ! -h "$err_log" ]; then # if error log already exists,
-    touch "$err_log"                            # we just append. otherwise,
-    chmod "$fmode" "$err_log"                   # fix the permissions here!
-  fi
-
 else
   if [ -n "$syslog_tag" ]
   then
@@ -669,6 +688,48 @@ else
   logging=syslog
 fi
 
+logdir=`dirname "$err_log"`
+# Change the err log to the right user, if possible and it is in use
+if [ $logging = "file" -o $logging = "both" ]; then
+  if [ ! -f "$err_log" -a ! -h "$err_log" ]; then
+    if test -w / -o "$USER" = "root"; then
+      case $logdir in
+        /var/log)
+          (
+            umask 0137
+            set -o noclobber
+            > "$err_log" && chown $user "$err_log"
+          ) ;;
+        *) ;;
+      esac
+    else
+      (
+        umask 0137
+        set -o noclobber
+        > "$err_log"
+      )
+    fi
+  fi
+
+  if [ -f "$err_log" ]; then        # Log to err_log file
+    log_notice "Logging to '$err_log'."
+  elif [ "x$user" = "xroot" ]; then # running as root, mysqld can create log file; continue
+    echo "Logging to '$err_log'." >&2
+  else
+    case $logdir in
+      # We can't create $err_log, however mysqld can; continue
+      /tmp|/var/tmp|/var/log/mysql|$DATADIR)
+        echo "Logging to '$err_log'." >&2
+        ;;
+      # We can't create $err_log and don't know if mysqld can; error out
+      *)
+        log_error "error: log-error set to '$err_log', however file don't exists. Create writable for user '$user'."
+        exit 1
+        ;;
+    esac
+  fi
+fi
+
 USER_OPTION=""
 if test -w / -o "$USER" = "root"
 then
@@ -676,11 +737,6 @@ then
   then
     USER_OPTION="--user=$user"
   fi
-  # Change the err log to the right user, if it is in use
-  if [ $want_syslog -eq 0 -a ! -h "$err_log" ]; then
-    touch "$err_log"
-    chown $user "$err_log"
-  fi
   if test -n "$open_files"
   then
     ulimit -n $open_files
@@ -693,15 +749,12 @@ then
 fi
 
 safe_mysql_unix_port=${mysql_unix_port:-${MYSQL_UNIX_PORT:-@MYSQL_UNIX_ADDR@}}
-# Make sure that directory for $safe_mysql_unix_port exists
+# Check that directory for $safe_mysql_unix_port exists
 mysql_unix_port_dir=`dirname $safe_mysql_unix_port`
 if [ ! -d $mysql_unix_port_dir ]
 then
-  if [ ! -h $mysql_unix_port_dir ]; then
-    mkdir $mysql_unix_port_dir
-    chown $user $mysql_unix_port_dir
-    chmod 755 $mysql_unix_port_dir
-  fi
+  log_error "Directory '$mysql_unix_port_dir' for UNIX socket file don't exists."
+  exit 1
 fi
 
 # If the user doesn't specify a binary, we assume name "mysqld"
@@ -894,11 +947,31 @@ do
     eval_log_error "$cmd $wsrep_start_position_opt --wsrep_cluster_address=$url $nohup_redir"
   fi
 
+  # hypothetical: log was renamed but not
+  # flushed yet. we'd recreate it with
+  # wrong owner next time we log, so set
+  # it up correctly while we can!
+
   if [ $want_syslog -eq 0 -a ! -f "$err_log" -a ! -h "$err_log" ]; then
-    touch "$err_log"                    # hypothetical: log was renamed but not
-    chown $user "$err_log"              # flushed yet. we'd recreate it with
-    chmod "$fmode" "$err_log"           # wrong owner next time we log, so set
-  fi                                    # it up correctly while we can!
+    if test -w / -o "$USER" = "root"; then
+      logdir=`dirname "$err_log"`
+      case $logdir in
+        /var/log)
+          (
+            umask 0137
+            set -o noclobber
+            > "$err_log" && chown $user "$err_log"
+          ) ;;
+        *) ;;
+      esac
+    else
+      (
+        umask 0137
+        set -o noclobber
+        > "$err_log"
+      )
+    fi
+  fi
 
   end_time=`date +%M%S`
 
index ddc24bbec3dd9df12664f094cb74dd65a9bf6a8a..bf04d0d4bd7caa1fa4f736fffd62c61a583e6311 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
 
  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
@@ -64,8 +64,8 @@ uint calc_days_in_year(uint year)
    @param tm[OUT]    The value to set.
    @param time_type  Timestasmp type
 */
-inline void set_zero_time(MYSQL_TIME *tm,
-                          enum enum_mysql_timestamp_type time_type)
+void set_zero_time(MYSQL_TIME *tm,
+                   enum enum_mysql_timestamp_type time_type)
 {
   memset(tm, 0, sizeof(*tm));
   tm->time_type= time_type;
@@ -76,7 +76,7 @@ inline void set_zero_time(MYSQL_TIME *tm,
   Set hour, minute and second of a MYSQL_TIME variable to maximum time value.
   Unlike set_max_time(), does not touch the other structure members.
 */
-inline void set_max_hhmmss(MYSQL_TIME *tm)
+void set_max_hhmmss(MYSQL_TIME *tm)
 {
   tm->hour= TIME_MAX_HOUR;
   tm->minute= TIME_MAX_MINUTE;
@@ -152,7 +152,7 @@ my_bool check_date(const MYSQL_TIME *ltime, my_bool not_zero_date,
   @retval  TRUE   if the value is fatally bad.
   @retval  FALSE  if the value is Ok.
 */
-inline my_bool check_time_mmssff_range(const MYSQL_TIME *ltime)
+my_bool check_time_mmssff_range(const MYSQL_TIME *ltime)
 {
   return ltime->minute >= 60 || ltime->second >= 60 ||
          ltime->second_part > 999999;
@@ -171,7 +171,7 @@ inline my_bool check_time_mmssff_range(const MYSQL_TIME *ltime)
   @retval        FALSE if value is Ok.
   @retval        TRUE if value is out of range. 
 */
-inline my_bool check_time_range_quick(const MYSQL_TIME *ltime)
+my_bool check_time_range_quick(const MYSQL_TIME *ltime)
 {
   longlong hour= (longlong) ltime->hour + 24LL * ltime->day;
   /* The input value should not be fatally bad */
index 78f642348935c4300100d0fd6abec0b265bac0aa..9be49498ab64034dd4f468f81af29abb7ce803dc 100644 (file)
@@ -1182,6 +1182,9 @@ int gtid_empty_group_log_and_cleanup(THD *thd)
       gtid_before_write_cache(thd, cache_data))
     goto err;
 
+#ifdef WITH_WSREP
+  if (WSREP_ON && thd->slave_thread) thd->wsrep_replicate_GTID= true;
+#endif /* WITH_WSREP */
   ret= mysql_bin_log.commit(thd, true);
 
 err:
@@ -1410,7 +1413,12 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
 {
   DBUG_ENTER("binlog_rollback");
   int error= 0;
+#ifdef WITH_WSREP
+  if (thd->lex->sql_command == SQLCOM_ROLLBACK_TO_SAVEPOINT &&
+      thd->wsrep_conflict_state != ABORTING)
+#else
   if (thd->lex->sql_command == SQLCOM_ROLLBACK_TO_SAVEPOINT)
+#endif
     error= mysql_bin_log.rollback(thd, all);
   DBUG_RETURN(error);
 }
@@ -1602,7 +1610,12 @@ int MYSQL_BIN_LOG::rollback(THD *thd, bool all)
     the caches since this function is called as part of the engine
     rollback.
    */
+#ifdef WITH_WSREP
+  if (thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT ||
+      thd->wsrep_conflict_state == ABORTING)
+#else
   if (thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT)
+#endif /* WITH_WSREP */
     if ((error= ha_rollback_low(thd, all)))
       goto end;
 
@@ -6625,6 +6638,14 @@ TC_LOG::enum_result MYSQL_BIN_LOG::commit(THD *thd, bool all)
   */
   if (stuff_logged)
   {
+#ifdef WITH_WSREP
+    if (WSREP_ON && thd->wsrep_replicate_GTID &&
+        wsrep_replicate_GTID(thd))
+    {
+      /* GTID replication failed */
+      DBUG_RETURN(RESULT_ABORTED);
+    }
+#endif /* WITH_WSREP */
     if (ordered_commit(thd, all))
       DBUG_RETURN(RESULT_INCONSISTENT);
   }
@@ -7777,7 +7798,7 @@ int THD::binlog_write_table_map(TABLE *table, bool is_transactional,
   /* Pre-conditions */
 #ifdef WITH_WSREP
   DBUG_ASSERT(is_current_stmt_binlog_format_row() && 
-             (WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()));
+              (WSREP_EMULATE_BINLOG_NNULL(this) || mysql_bin_log.is_open()));
 #else
   DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
 #endif /* WITH_WSREP */
@@ -8177,10 +8198,10 @@ int THD::decide_logging_format(TABLE_LIST *tables)
     binlog by filtering rules.
   */
 #ifdef WITH_WSREP
-  if ((WSREP_EMULATE_BINLOG(this) || 
+  if ((WSREP_EMULATE_BINLOG_NNULL(this) ||
        (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG))) &&
       !(WSREP_BINLOG_FORMAT(variables.binlog_format) == BINLOG_FORMAT_STMT    &&
-       !binlog_filter->db_ok(db)))
+        !binlog_filter->db_ok(db)))
 #else
   if (mysql_bin_log.is_open() && (variables.option_bits & OPTION_BIN_LOG) &&
       !(variables.binlog_format == BINLOG_FORMAT_STMT &&
@@ -8257,13 +8278,8 @@ int THD::decide_logging_format(TABLE_LIST *tables)
     uint non_replicated_tables_count= 0;
 #ifndef DBUG_OFF
     {
-      static const char *prelocked_mode_name[] = {
-        "NON_PRELOCKED",
-        "PRELOCKED",
-        "PRELOCKED_UNDER_LOCK_TABLES",
-      };
       DBUG_PRINT("debug", ("prelocked_mode: %s",
-                           prelocked_mode_name[locked_tables_mode]));
+                           get_locked_tables_mode_name(locked_tables_mode)));
     }
 #endif
 
@@ -8522,7 +8538,7 @@ int THD::decide_logging_format(TABLE_LIST *tables)
                limited to row-logging when binlog_format = STATEMENT
           */
 #ifdef WITH_WSREP
-          if (!WSREP(this) || wsrep_exec_mode == LOCAL_STATE)
+          if (!WSREP_NNULL(this) || wsrep_exec_mode == LOCAL_STATE)
           {
 #endif /* WITH_WSREP */
           my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
@@ -8987,7 +9003,7 @@ int THD::binlog_write_row(TABLE* table, bool is_trans,
 { 
 #ifdef WITH_WSREP
   DBUG_ASSERT(is_current_stmt_binlog_format_row() && 
-             ((WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())));
+             ((WSREP_EMULATE_BINLOG_NNULL(this) || mysql_bin_log.is_open())));
 #else
   DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
 #endif /* WITH_WSREP */
@@ -9022,7 +9038,7 @@ int THD::binlog_update_row(TABLE* table, bool is_trans,
 { 
 #ifdef WITH_WSREP
   DBUG_ASSERT(is_current_stmt_binlog_format_row() && 
-             ((WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())));
+              ((WSREP_EMULATE_BINLOG_NNULL(this) || mysql_bin_log.is_open())));
 #else
   DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
 #endif /* WITH_WSREP */
@@ -9094,7 +9110,7 @@ int THD::binlog_delete_row(TABLE* table, bool is_trans,
 { 
 #ifdef WITH_WSREP
   DBUG_ASSERT(is_current_stmt_binlog_format_row() && 
-             ((WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open())));
+              ((WSREP_EMULATE_BINLOG_NNULL(this) || mysql_bin_log.is_open())));
 #else
   DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
 #endif /* WITH_WSREP */
@@ -9217,7 +9233,7 @@ int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional)
     flushing anything (e.g., if we have explicitly locked tables).
    */
 #ifdef WITH_WSREP
-  if (!(WSREP_EMULATE_BINLOG(this) || mysql_bin_log.is_open()))
+  if (!(WSREP_EMULATE_BINLOG_NNULL(this) || mysql_bin_log.is_open()))
 #else
  if (!mysql_bin_log.is_open())
 #endif /* WITH_WSREP */
@@ -9490,8 +9506,8 @@ int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
   DBUG_PRINT("enter", ("qtype: %s  query: '%s'",
                        show_query_type(qtype), query_arg));
 #ifdef WITH_WSREP
-  DBUG_ASSERT(query_arg && (WSREP_EMULATE_BINLOG(this)
-                           || mysql_bin_log.is_open()));
+  DBUG_ASSERT(query_arg && (WSREP_EMULATE_BINLOG_NNULL(this)
+                            || mysql_bin_log.is_open()));
 #else
   DBUG_ASSERT(query_arg && mysql_bin_log.is_open());
 #endif /* WITH_WSREP */
index 30fbb32a363911f85902b25d2198ad9bec338c54..2b06f8501662cd4c634a507a45a9302083e25f22 100644 (file)
@@ -1164,12 +1164,15 @@ void Field_num::prepend_zeros(String *value)
   int diff;
   if ((diff= (int) (field_length - value->length())) > 0)
   {
-    bmove_upp((uchar*) value->ptr()+field_length,
-              (uchar*) value->ptr()+value->length(),
-             value->length());
-    memset(const_cast<char*>(value->ptr()), '0', diff);
-    value->length(field_length);
-    (void) value->c_ptr_quick();               // Avoid warnings in purify
+   const bool error= value->realloc(field_length);
+   if (!error)
+   {
+     bmove_upp((uchar*) value->ptr()+field_length,
+               (uchar*) value->ptr()+value->length(),
+              value->length());
+     memset(const_cast<char*>(value->ptr()), '0', diff);
+     value->length(field_length);
+   }
   }
 }
 
index bbbcf1b6401905fbbdde98cddab4dcbe04f3b8ca..7c4c4eff19e59db491bd7011f47d5c7af32c02f0 100644 (file)
@@ -1,5 +1,5 @@
 /*
-   Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+   Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
 
    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
@@ -229,6 +229,21 @@ void generate_find_structs()
   insert_sql_functions();
 }
 
+struct hash_map_cleanup
+{
+  hash_map_cleanup(char **buffer, int *sz)
+    : m_buffer(buffer), m_sz(sz)
+  {}
+  ~hash_map_cleanup()
+  {
+    free(*m_buffer);
+    *m_buffer= NULL;
+    *m_sz= 0;
+  }
+  char **m_buffer;
+  int   *m_sz;
+};
+
 char *hash_map= 0;
 int size_hash_map= 0;
 
@@ -307,18 +322,21 @@ void print_hash_map(const char *name)
 
 void print_find_structs()
 {
-  add_structs_to_map(root_by_len,max_len);
-  set_links(root_by_len,max_len);
-  print_hash_map("sql_functions_map");
-
-  hash_map= 0;
-  size_hash_map= 0;
+  {
+    hash_map_cleanup cleanup(&hash_map, &size_hash_map);
+    add_structs_to_map(root_by_len,max_len);
+    set_links(root_by_len,max_len);
+    print_hash_map("sql_functions_map");
+  }
 
   printf("\n");
 
-  add_structs_to_map(root_by_len2,max_len2);
-  set_links(root_by_len2,max_len2);
-  print_hash_map("symbols_map");
+  {
+    hash_map_cleanup cleanup(&hash_map, &size_hash_map);
+    add_structs_to_map(root_by_len2,max_len2);
+    set_links(root_by_len2,max_len2);
+    print_hash_map("symbols_map");
+  }
 }
 
 int check_dup_symbols(SYMBOL *s1, SYMBOL *s2)
index 017481f845f4b25188ee58af92c35ab52dab0615..ecb2a35f8f4cc72a12bd0035df0ed460fa336d29 100644 (file)
@@ -1595,6 +1595,9 @@ int ha_rollback_low(THD *thd, bool all)
       { // cannot happen
         my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
         error= 1;
+        WSREP_WARN("handlerton rollback failed, thd %lu %lld conf %d SQL %s",
+                   thd->thread_id, thd->query_id, thd->wsrep_conflict_state,
+                   thd->query());
       }
       status_var_increment(thd->status_var.ha_rollback_count);
       ha_info_next= ha_info->next();
index 7e82f940e0f53422b25e020e5b6a8bb0ccd88dc8..bfa9028664ec4c480bb11b2196097102ec13ee45 100644 (file)
@@ -5909,6 +5909,7 @@ int mysqld_main(int argc, char **argv)
   orig_argc= argc;
   orig_argv= argv;
   my_getopt_use_args_separator= TRUE;
+  my_defaults_read_login_file= FALSE;
   if (load_defaults(MYSQL_CONFIG_NAME, load_default_groups, &argc, &argv))
     return 1;
   my_getopt_use_args_separator= FALSE;
index 7859b11cf86bcd6ee73992877ee534b8d85d299d..2d660eb3619593b8e674e0934b43dd4b3fcc1b66 100644 (file)
@@ -3127,6 +3127,30 @@ void partition_info::print_debug(const char *str, uint *value)
     DBUG_PRINT("info", ("parser: %s", str));
   DBUG_VOID_RETURN;
 }
+
+bool has_external_data_or_index_dir(partition_info &pi)
+{
+  List_iterator<partition_element> part_it(pi.partitions);
+  for (partition_element *part= part_it++; part; part= part_it++)
+  {
+    if (part->data_file_name != NULL || part->index_file_name != NULL)
+    {
+      return true;
+    }
+    List_iterator<partition_element> subpart_it(part->subpartitions);
+    for (const partition_element *subpart= subpart_it++;
+         subpart;
+         subpart= subpart_it++)
+    {
+      if (subpart->data_file_name != NULL || subpart->index_file_name != NULL)
+      {
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
 #else /* WITH_PARTITION_STORAGE_ENGINE */
  /*
    For builds without partitioning we need to define these functions
index 37f00eaf1cc7d9c5cc8ebe6ad94febeebb791fe9..e98d7fe88189fdbb4a632e59429031e4f3aed0ee 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef PARTITION_INFO_INCLUDED
 #define PARTITION_INFO_INCLUDED
 
-/* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
 
    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
@@ -404,4 +404,15 @@ void init_all_partitions_iterator(partition_info *part_info,
   part_iter->get_next= get_next_partition_id_range;
 }
 
+/**
+  Predicate which returns true if any partition or subpartition uses
+  an external data directory or external index directory.
+
+  @param pi partitioning information
+  @retval true if any partition or subpartition has an external
+  data directory or external index directory.
+  @retval false otherwise
+ */
+bool has_external_data_or_index_dir(partition_info &pi);
+
 #endif /* PARTITION_INFO_INCLUDED */
index 7ed317ea173689c8beb467f861d1f5dffae840cf..93d12c8776d1a71f27bb1e3b44675d747daf8b9f 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
 
    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
@@ -487,11 +487,30 @@ int prepare_record(TABLE *const table, const MY_BITMAP *cols, const bool check)
   */
   
   DBUG_PRINT_BITSET("debug", "cols: %s", cols);
+  /**
+    Save a reference to the original write set bitmaps.
+    We will need this to restore the bitmaps at the end.
+  */
+  MY_BITMAP *old_write_set= table->write_set;
+  /**
+    Just to be sure that tmp_set is currently not in use as
+    the read_set already.
+  */
+  DBUG_ASSERT(table->write_set != &table->tmp_set);
+  /* set the temporary write_set */
+  table->column_bitmaps_set_no_signal(table->read_set,
+                                      &table->tmp_set);
+  /**
+    Set table->write_set bits for all the columns as they
+    will be checked in set_default() function.
+  */
+  bitmap_set_all(table->write_set);
+
   for (Field **field_ptr= table->field; *field_ptr; ++field_ptr)
   {
-    if ((uint) (field_ptr - table->field) >= cols->n_bits ||
-        !bitmap_is_set(cols, field_ptr - table->field))
-    {   
+    uint field_index= (uint) (field_ptr - table->field);
+    if (field_index >= cols->n_bits || !bitmap_is_set(cols, field_index))
+    {
       Field *const f= *field_ptr;
       if ((f->flags &  NO_DEFAULT_VALUE_FLAG) &&
           (f->real_type() != MYSQL_TYPE_ENUM))
@@ -503,9 +522,17 @@ int prepare_record(TABLE *const table, const MY_BITMAP *cols, const bool check)
                             ER(ER_NO_DEFAULT_FOR_FIELD),
                             f->field_name);
       }
+      else if (f->has_insert_default_function())
+      {
+        f->set_default();
+      }
     }
   }
 
+  /* set the write_set back to original*/
+  table->column_bitmaps_set_no_signal(table->read_set,
+                                      old_write_set);
+
   DBUG_RETURN(0);
 }
 
index 6fd518971104d84e75a8eaf7361d7316b25009e7..2397125e61c25ba1929438f6d4332967e522c314 100644 (file)
@@ -640,21 +640,26 @@ void THD::enter_stage(const PSI_stage_info *new_stage,
 
 extern "C"
 void thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond, mysql_mutex_t *mutex,
-                    const PSI_stage_info *stage, PSI_stage_info *old_stage)
+                    const PSI_stage_info *stage, PSI_stage_info *old_stage,
+                    const char *src_function, const char *src_file,
+                    int src_line)
 {
   if (!thd)
     thd= current_thd;
 
-  return thd->ENTER_COND(cond, mutex, stage, old_stage);
+  return thd->enter_cond(cond, mutex, stage, old_stage,
+                         src_function, src_file, src_line);
 }
 
 extern "C"
-void thd_exit_cond(MYSQL_THD thd, const PSI_stage_info *stage)
+void thd_exit_cond(MYSQL_THD thd, const PSI_stage_info *stage,
+                   const char *src_function, const char *src_file,
+                  int src_line)
 {
   if (!thd)
     thd= current_thd;
 
-  thd->EXIT_COND(stage);
+  thd->exit_cond(stage, src_function, src_file, src_line);
   return;
 }
 
@@ -911,11 +916,11 @@ extern "C" wsrep_ws_handle_t* wsrep_thd_ws_handle(THD *thd)
   return &thd->wsrep_ws_handle;
 }
 
-extern "C"void wsrep_thd_LOCK(THD *thd)
+extern "C" void wsrep_thd_LOCK(THD *thd)
 {
   mysql_mutex_lock(&thd->LOCK_wsrep_thd);
 }
-extern "C"void wsrep_thd_UNLOCK(THD *thd)
+extern "C" void wsrep_thd_UNLOCK(THD *thd)
 {
   mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
 }
@@ -1217,6 +1222,7 @@ THD::THD(bool enable_plugins)
   wsrep_TOI_pre_query_len = 0;
   wsrep_sync_wait_gtid    = WSREP_GTID_UNDEFINED;
   wsrep_affected_rows     = 0;
+  wsrep_replicate_GTID    = false;
 #endif
   /* Call to init() below requires fully initialized Open_tables_state. */
   reset_open_tables_state();
@@ -1493,8 +1499,15 @@ Sql_condition* THD::raise_condition(uint sql_errno,
       thd->lex->current_select == 0 if lex structure is not inited
       (not query command (COM_QUERY))
     */
+#ifdef WITH_WSREP
+    if (lex->current_select &&
+        lex->current_select->no_error && !is_fatal_error &&
+        (!(wsrep_conflict_state == ABORTED ||
+           wsrep_conflict_state == MUST_ABORT)))
+#else
     if (lex->current_select &&
         lex->current_select->no_error && !is_fatal_error)
+#endif
     {
       DBUG_PRINT("error",
                  ("Error converted to warning: current_select: no_error %d  "
@@ -1627,6 +1640,7 @@ void THD::init(void)
   wsrep_TOI_pre_query_len = 0;
   wsrep_sync_wait_gtid    = WSREP_GTID_UNDEFINED;
   wsrep_affected_rows     = 0;
+  wsrep_replicate_GTID    = false;
 #endif
   binlog_row_event_extra_data= 0;
 
@@ -2139,13 +2153,13 @@ bool THD::notify_shared_lock(MDL_context_owner *ctx_in_use,
       if (!thd_table->needs_reopen())
 #ifdef WITH_WSREP
       {
-       signalled|= mysql_lock_abort_for_thread(this, thd_table);
-       if (this && WSREP(this) && wsrep_thd_is_BF((void *)this, FALSE)) 
-       {
-         WSREP_DEBUG("remove_table_from_cache: %llu",
-                     (unsigned long long) this->real_id);
-         wsrep_abort_thd((void *)this, (void *)in_use, FALSE);
-       }
+        signalled|= mysql_lock_abort_for_thread(this, thd_table);
+        if (WSREP_NNULL(this) && wsrep_thd_is_BF((void *)this, FALSE))
+        {
+          WSREP_DEBUG("remove_table_from_cache: %llu",
+                      (unsigned long long) this->real_id);
+          wsrep_abort_thd((void *)this, (void *)in_use, FALSE);
+        }
       }
 #else
         signalled|= mysql_lock_abort_for_thread(this, thd_table);
index 4f85e41441dec531698b851816d91be05eecba50..33fe0a3efa5b0a1dfde2968923bc5a174ecc1c5c 100644 (file)
@@ -69,7 +69,17 @@ void set_thd_stage_info(void *thd,
                         const char *calling_func,
                         const char *calling_file,
                         const unsigned int calling_line);
-                        
+extern "C"
+void thd_enter_cond(MYSQL_THD thd, mysql_cond_t *cond, mysql_mutex_t *mutex,
+                    const PSI_stage_info *stage, PSI_stage_info *old_stage,
+                    const char *src_function, const char *src_file,
+                    int src_line);
+
+extern "C"
+void thd_exit_cond(MYSQL_THD thd, const PSI_stage_info *stage,
+                   const char *src_function, const char *src_file,
+                   int src_line);
+
 #define THD_STAGE_INFO(thd, stage) \
   (thd)->enter_stage(& stage, NULL, __func__, __FILE__, __LINE__)
 
@@ -84,6 +94,7 @@ struct wsrep_thd_shadow {
   char                 *db;
   size_t               db_length;
   struct timeval       user_time;
+  longlong             row_count_func;
 };
 #endif
 class Reprepare_observer;
@@ -1585,7 +1596,7 @@ typedef I_List<Item_change_record> Item_change_list;
   Type of locked tables mode.
   See comment for THD::locked_tables_mode for complete description.
   While adding new enum values add them to the getter method for this enum
-  declared below and defined in sql_class.cc as well.
+  declared below and defined in binlog.cc as well.
 */
 
 enum enum_locked_tables_mode
@@ -3218,6 +3229,7 @@ public:
   bool                      wsrep_apply_toi; /* applier processing in TOI */
   wsrep_gtid_t              wsrep_sync_wait_gtid;
   ulong                     wsrep_affected_rows;
+  bool                      wsrep_replicate_GTID;
 #endif /* WITH_WSREP */
   /**
     Internal parser state.
index 14702ecbe68a8dc8d440ddf48335519052a5fad1..b60f2f4f548f3b2eddaeeb34dbbfe6f6ad324601 100644 (file)
@@ -451,7 +451,7 @@ bool thd_init_client_charset(THD *thd, uint cs_number)
       my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), "character_set_client",
                global_system_variables.character_set_client->csname);
       return true;
-    }    
+    }
     thd->variables.character_set_client=
       global_system_variables.character_set_client;
     thd->variables.collation_connection=
@@ -751,6 +751,7 @@ bool login_connection(THD *thd)
   my_net_set_write_timeout(net, connect_timeout);
 
   error= check_connection(thd);
+  MYSQL_AUDIT_NOTIFY_CONNECTION_CONNECT(thd);
   thd->protocol->end_statement();
 
   if (error)
@@ -922,7 +923,6 @@ bool thd_prepare_connection(THD *thd)
   bool rc;
   lex_start(thd);
   rc= login_connection(thd);
-  MYSQL_AUDIT_NOTIFY_CONNECTION_CONNECT(thd);
   if (rc)
     return rc;
 
index 92b3c6e4fa9a281189d8498a4e10e4acee8ab4e4..c9245bf215a9a8fc2426f9032f8abafd2f494554 100644 (file)
@@ -1413,8 +1413,8 @@ READ_INFO::READ_INFO(File file_par, uint tot_length, const CHARSET_INFO *cs,
   set_if_bigger(length,line_start.length());
   stack=stack_pos=(int*) sql_alloc(sizeof(int)*length);
 
-  if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(MY_WME))))
-    error= true; /* purecov: inspected */
+  if (!(buffer=(uchar*) my_malloc(buff_length+1,MYF(0))))
+    error=1; /* purecov: inspected */
   else
   {
     end_of_buff=buffer+buff_length;
@@ -1607,50 +1607,37 @@ int READ_INFO::read_field()
        }
       }
 #ifdef USE_MB
-        uint ml= my_mbcharlen(read_charset, chr);
-        if (ml == 0)
-        {
-          *to= '\0';
-          my_error(ER_INVALID_CHARACTER_STRING, MYF(0),
-                   read_charset->csname, buffer);
-          error= true;
-          return 1;
-        }
+      if (my_mbcharlen(read_charset, chr) > 1 &&
+          to + my_mbcharlen(read_charset, chr) <= end_of_buff)
+      {
+        uchar* p= to;
+        int ml, i;
+        *to++ = chr;
 
-        if (ml > 1 &&
-            to + ml <= end_of_buff)
-        {
-          uchar* p= to;
-          *to++ = chr;
+        ml= my_mbcharlen(read_charset, chr);
 
-          for (uint i= 1; i < ml; i++)
+        for (i= 1; i < ml; i++) 
+        {
+          chr= GET;
+          if (chr == my_b_EOF)
           {
-            chr= GET;
-            if (chr == my_b_EOF)
-            {
-              /*
-                Need to back up the bytes already ready from illformed
-                multi-byte char 
-              */
-              to-= i;
-              goto found_eof;
-            }
-            *to++ = chr;
+            /*
+             Need to back up the bytes already ready from illformed
+             multi-byte char 
+            */
+            to-= i;
+            goto found_eof;
           }
-          if (my_ismbchar(read_charset,
+          *to++ = chr;
+        }
+        if (my_ismbchar(read_charset,
                         (const char *)p,
                         (const char *)to))
-            continue;
-          for (uint i= 0; i < ml; i++)
-            PUSH(*--to);
-          chr= GET;
-        }
-        else if (ml > 1)
-        {
-          // Buffer is too small, exit while loop, and reallocate.
-          PUSH(chr);
-          break;
-        }
+          continue;
+        for (i= 0; i < ml; i++)
+          PUSH(*--to);
+        chr= GET;
+      }
 #endif
       *to++ = (uchar) chr;
     }
@@ -1899,15 +1886,7 @@ int READ_INFO::read_value(int delim, String *val)
   for (chr= GET; my_tospace(chr) != delim && chr != my_b_EOF;)
   {
 #ifdef USE_MB
-    uint ml= my_mbcharlen(read_charset, chr);
-    if (ml == 0)
-    {
-      chr= my_b_EOF;
-      val->length(0);
-      return chr;
-    }
-
-    if (ml > 1)
+    if (my_mbcharlen(read_charset, chr) > 1)
     {
       DBUG_PRINT("read_xml",("multi byte"));
       int i, ml= my_mbcharlen(read_charset, chr);
index 57014aa5fe564a019a5a0af99bf671ead9c4cdb3..5e75a099f67cbeab47c3b6b6e60fe5dec3335d24 100644 (file)
@@ -100,6 +100,7 @@ only_eq_ref_tables(JOIN *join, ORDER *order, table_map tables,
                    table_map *cached_eq_ref_tables, table_map
                    *eq_ref_tables);
 
+static bool can_switch_from_ref_to_range(THD *thd, JOIN_TAB *tab);
 
 /**
   global select optimisation.
@@ -1656,6 +1657,9 @@ static Item *build_equal_items_for_cond(THD *thd, Item *cond,
   COND_EQUAL cond_equal;
   cond_equal.upper_levels= inherited;
 
+  if (check_stack_overrun(thd, STACK_MIN_SIZE, NULL))
+    return cond;
+
   if (cond->type() == Item::COND_ITEM)
   {
     List<Item> eq_list;
@@ -7669,45 +7673,8 @@ static bool make_join_select(JOIN *join, Item *cond)
       bool use_quick_range=0;
       Item *tmp;
 
-      /*
-        Heuristic: Switch from 'ref' to 'range' access if 'range'
-        access can utilize more keyparts than 'ref' access. Conditions
-        for doing switching:
-
-        1) Current decision is to use 'ref' access
-        2) 'ref' access depends on a constant, not a value read from a
-           table earlier in the join sequence.
-
-           Rationale: if 'ref' depends on a value from another table,
-           the join condition is not used to limit the rows read by
-           'range' access (that would require dynamic range - 'Range
-           checked for each record'). In other words, if 'ref' depends
-           on a value from another table, we have a query with
-           conditions of the form
-
-            this_table.idx_col1 = other_table.col AND   <<- used by 'ref'
-            this_table.idx_col1 OP <const> AND          <<- used by 'range'
-            this_table.idx_col2 OP <const> AND ...      <<- used by 'range'
-
-           and an index on (idx_col1,idx_col2,...). But the fact that
-           'range' access uses more keyparts does not mean that it is
-           more selective than 'ref' access because these access types
-           utilize different parts of the query condition. We
-           therefore trust the cost based choice made by
-           best_access_path() instead of forcing a heuristic choice
-           here.
-        3) Range access is possible, and it is less costly than
-           table/index scan
-        4) 'ref' access and 'range' access uses the same index
-        5) 'range' access uses more keyparts than 'ref' access
-
-        @todo: This decision should rather be made in best_access_path()
-       */
-      if (tab->type == JT_REF &&                                  // 1)
-          !tab->ref.depend_map &&                                 // 2)
-          tab->quick &&                                           // 3)
-          (uint) tab->ref.key == tab->quick->index &&             // 4)
-          tab->ref.key_length < tab->quick->max_used_key_length)  // 5)
+      /// See if you need to switch to range access
+      if (tab->type == JT_REF && can_switch_from_ref_to_range(thd, tab))
       {
         Opt_trace_object wrapper(trace);
         Opt_trace_object (trace, "access_type_changed").
@@ -8210,6 +8177,99 @@ only_eq_ref_tables(JOIN *join, ORDER *order, table_map tables,
   return true;
 }
 
+/**
+  Heuristic: Switch from 'ref' to 'range' access if 'range' access can utilize
+  more keyparts than 'ref' access. Conditions for doing switching:
+
+  1) 'ref' access depends on a constant, not a value read from a table earlier
+      in the join sequence.
+
+  Rationale: if 'ref' depends on a value from another table, the join condition
+  is not used to limit the rows read by 'range' access (that would require
+  dynamic range - 'Range checked for each record'). In other words, if 'ref'
+  depends on a value from another table, we have a query with conditions of
+  the form
+    this_table.idx_col1 = other_table.col AND   <<- used by 'ref'
+    this_table.idx_col1 OP <const> AND          <<- used by 'range'
+    this_table.idx_col2 OP <const> AND ...      <<- used by 'range'
+
+  and an index on (idx_col1,idx_col2,...). But the fact that 'range' access
+  uses more keyparts does not mean that it is more selective than 'ref' access
+  because these access types utilize different parts of the query condition. We
+  therefore trust the cost based choice made by best_access_path() instead of
+  forcing a heuristic choice here.
+
+  2) Range access is possible, and it is less costly than table/index scan.
+
+    3a) 'ref' access and 'range' access uses the same index.
+    3b) 'range' access uses more keyparts than 'ref' access
+
+    OR
+
+    4) Ref has borrowed the index estimate from range and created a cost
+       estimate (See Optimize_table_order::find_best_ref). This will be a
+       problem if range built it's row estimate using a larger number of key
+       parts than ref. In such a case, shift to range access over the same
+       index. So run the range optimizer with that index as the only choice.
+       (Condition 5 is not relevant here since it has been tested in
+       find_best_ref.)
+
+  @param thd THD      To re-run range optimizer.
+  @param tab JOIN_TAB To check the above conditions.
+
+  @return true   Range is better than ref
+  @return false  Ref is better or switch isn't possible
+
+  @todo: This decision should rather be made in best_access_path()
+*/
+static bool can_switch_from_ref_to_range(THD *thd, JOIN_TAB *tab)
+{
+  if (!tab->ref.depend_map &&                                          // 1)
+      tab->quick)                                                      // 2)
+  {
+    if ((uint) tab->ref.key == tab->quick->index &&                    // 3a)
+        tab->ref.key_length < tab->quick->max_used_key_length)         // 3b)
+      return true;
+    else if (tab->dodgy_ref_cost)                                      // 4)
+    {
+      int error;
+      SQL_SELECT *select;
+      JOIN *join= tab->join;
+      select= make_select(tab->table, join->found_const_table_map,
+                          join->found_const_table_map,
+                          *tab->on_expr_ref ? *tab->on_expr_ref : join->conds,
+                          1, &error);
+
+      if (select)
+      {
+        Opt_trace_context * const trace= &thd->opt_trace;
+        Opt_trace_object trace_wrapper(trace);
+        Opt_trace_array
+          trace_setup_cond(trace,
+                           "rerunning_range_optimizer_for_single_index");
+
+        key_map new_ref_key_map;
+        new_ref_key_map.set_bit(tab->position->key->key);
+        bool retcode= false;
+        if (select->test_quick_select(thd, new_ref_key_map, 0,
+                                      (join->select_options &
+                                       OPTION_FOUND_ROWS ? HA_POS_ERROR :
+                                       join->unit->select_limit_cnt),
+                                      false,  // don't force quick range
+                                      ORDER::ORDER_NOT_RELEVANT) > 0)
+        {
+          delete tab->quick;
+          tab->quick= select->quick;
+          retcode= true;
+        }
+        select->quick= 0;
+        delete select;
+        return retcode;
+      }
+    }
+  }
+  return false;
+}
 
 /**
   Check if an expression in ORDER BY or GROUP BY is a duplicate of a
index f8a8643279e708a06de00e859656388e864aee1d..3634646e8e077b087824177551eb9561adea12ee 100644 (file)
@@ -35,6 +35,9 @@
 #include "sql_insert.h"       // mysql_insert
 #include "sql_update.h"       // mysql_update, mysql_multi_update
 #include "sql_partition.h"    // struct partition_info
+#ifdef WITH_PARTITION_STORAGE_ENGINE
+#include "partition_info.h"   // has_external_data_or_index_dir
+#endif /* WITH_PARTITION_STORAGE_ENGINE */
 #include "sql_db.h"           // mysql_change_db, mysql_create_db,
                               // mysql_rm_db, mysql_upgrade_db,
                               // mysql_alter_db,
@@ -1378,17 +1381,47 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
   thd->enable_slow_log= TRUE;
   thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
   thd->set_time();
-  if (!thd->is_valid_time())
+  if (thd->is_valid_time() == false)
   {
     /*
-     If the time has got past 2038 we need to shut this server down
-     We do this by making sure every command is a shutdown and we 
-     have enough privileges to shut the server down
-
-     TODO: remove this when we have full 64 bit my_time_t support
+      If the time has gone past 2038 we need to shutdown the server. But
+      there is possibility of getting invalid time value on some platforms.
+      For example, gettimeofday() might return incorrect value on solaris
+      platform. Hence validating the current time with 5 iterations before
+      initiating the normal server shutdown process because of time getting
+      past 2038.
     */
-    thd->security_ctx->master_access|= SHUTDOWN_ACL;
-    command= COM_SHUTDOWN;
+    const int max_tries= 5;
+    sql_print_warning("Current time has got past year 2038. Validating current "
+                      "time with %d iterations before initiating the normal "
+                      "server shutdown process.", max_tries);
+
+    int tries= 0;
+    while (++tries <= max_tries)
+    {
+      thd->set_time();
+      if (thd->is_valid_time() == true)
+      {
+        sql_print_warning("Iteration %d: Obtained valid current time from "
+                           "system", tries);
+        break;
+      }
+      sql_print_warning("Iteration %d: Current time obtained from system is "
+                        "greater than 2038", tries);
+    }
+    if (tries > max_tries)
+    {
+      /*
+        If the time has got past 2038 we need to shut this server down.
+        We do this by making sure every command is a shutdown and we
+        have enough privileges to shut the server down
+
+        TODO: remove this when we have full 64 bit my_time_t support
+      */
+      sql_print_error("This MySQL server doesn't support dates later than 2038");
+      thd->security_ctx->master_access|= SHUTDOWN_ACL;
+      command= COM_SHUTDOWN;
+    }
   }
   thd->set_query_id(next_query_id());
   inc_thread_running();
@@ -2062,6 +2095,7 @@ done:
 
   thd->reset_query();
   thd->set_command(COM_SLEEP);
+  thd->proc_info= 0;
 
   /* Performance Schema Interface instrumentation, end */
   MYSQL_END_STATEMENT(thd->m_statement_psi, thd->get_stmt_da());
@@ -3216,7 +3250,6 @@ case SQLCOM_PREPARE:
       copy.
     */
     Alter_info alter_info(lex->alter_info, thd->mem_root);
-
     if (thd->is_fatal_error)
     {
       /* If out of memory when creating a copy of alter_info. */
@@ -3224,6 +3257,15 @@ case SQLCOM_PREPARE:
       goto end_with_restore_list;
     }
 
+    if (((lex->create_info.used_fields & HA_CREATE_USED_DATADIR) != 0 ||
+         (lex->create_info.used_fields & HA_CREATE_USED_INDEXDIR) != 0) &&
+        check_access(thd, FILE_ACL, NULL, NULL, NULL, FALSE, FALSE))
+    {
+      res= 1;
+      my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "FILE");
+      goto end_with_restore_list;
+    }
+
     if ((res= create_table_precheck(thd, select_tables, create_table)))
       goto end_with_restore_list;
 
@@ -3261,6 +3303,12 @@ case SQLCOM_PREPARE:
 #ifdef WITH_PARTITION_STORAGE_ENGINE
     {
       partition_info *part_info= thd->lex->part_info;
+      if (part_info != NULL && has_external_data_or_index_dir(*part_info) &&
+          check_access(thd, FILE_ACL, NULL, NULL, NULL, FALSE, FALSE))
+      {
+        res= -1;
+        goto end_with_restore_list;
+      }
       if (part_info && !(part_info= thd->lex->part_info->get_clone(true)))
       {
         res= -1;
index e6db9115ceedcce675425f4dcb1c867069244da0..7924d5f06b19cce138386aa8a7a0f7089e05c6be 100644 (file)
@@ -482,6 +482,8 @@ void Optimize_table_order::best_access_path(
       key_part_map const_part= 0;
       /* The or-null keypart in ref-or-null access: */
       key_part_map ref_or_null_part= 0;
+      /// Set dodgy_ref_cost only if that index is chosen for ref access.
+      bool is_dodgy= false;
 
       /* Calculate how many key segments of the current key we can use */
       Key_use *const start_key= keyuse;
@@ -747,7 +749,10 @@ void Optimize_table_order::best_access_path(
                 if (!found_ref && table->quick_keys.is_set(key) &&    // (1)
                     table->quick_key_parts[key] > max_key_part &&     // (2)
                     records < (double)table->quick_rows[key])         // (3)
+                {
                   records= (double)table->quick_rows[key];
+                  is_dodgy= true;
+                }
 
                 tmp= records;
               }
@@ -855,7 +860,10 @@ void Optimize_table_order::best_access_path(
         }
       }
   done_with_index:
-      trace_access_idx.add("chosen", best_key == start_key);
+      bool chosen= (best_key == start_key);
+      trace_access_idx.add("chosen", chosen);
+      if (chosen)
+        s->dodgy_ref_cost= is_dodgy;
     } /* for each key */
     records= best_records;
   }
index 01cf33ba67f9c4782396b3d59fd64de1711c6435..76d6f21158c55debc2073a7d58d72c59ae970c85 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef SQL_SELECT_INCLUDED
 #define SQL_SELECT_INCLUDED
 
-/* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
 
    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
@@ -769,6 +769,12 @@ public:
   /** TRUE <=> remove duplicates on this table. */
   bool distinct;
 
+  /**
+    Setting this flag means ref is using lesser number of key parts than range
+    and it borrows range's row estimate.
+  */
+  bool dodgy_ref_cost;
+
   /** Clean up associated table after query execution, including resources */
   void cleanup();
   inline bool is_using_loose_index_scan()
@@ -968,7 +974,8 @@ st_join_table::st_join_table()
     ref_array(NULL),
     send_records(0),
     having(NULL),
-    distinct(false)
+    distinct(false),
+    dodgy_ref_cost(false)
 {
   /**
     @todo Add constructor to READ_RECORD.
index baee91c2b3729c1cdb2975a5d81ec908c819a398..00cb417b74991688cf780e8c9a4ba2dc44f9cf4a 100644 (file)
@@ -87,7 +87,9 @@ static bool check_engine(THD *thd, const char *db_name,
                          HA_CREATE_INFO *create_info);
 
 static int
-mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
+mysql_prepare_create_table(THD *thd, const char *error_schema_name,
+                           const char *error_table_name,
+                           HA_CREATE_INFO *create_info,
                            Alter_info *alter_info,
                            bool tmp_table,
                            uint *db_options,
@@ -1863,7 +1865,9 @@ bool mysql_write_frm(ALTER_PARTITION_PARAM_TYPE *lpt, uint flags)
   strxmov(shadow_frm_name, shadow_path, reg_ext, NullS);
   if (flags & WFRM_WRITE_SHADOW)
   {
-    if (mysql_prepare_create_table(lpt->thd, lpt->create_info,
+    if (mysql_prepare_create_table(lpt->thd, lpt->db,
+                                   lpt->table_name,
+                                   lpt->create_info,
                                    lpt->alter_info,
                                    /*tmp_table*/ 1,
                                    &lpt->db_options,
@@ -3267,12 +3271,15 @@ void promote_first_timestamp_column(List<Create_field> *column_definitions)
 /**
   Check if there is a duplicate key. Report a warning for every duplicate key.
 
-  @param thd              Thread context.
-  @param key              Key to be checked.
-  @param key_info         Key meta-data info.
-  @param alter_info       List of columns and indexes to create.
+  @param thd                Thread context.
+  @param error_schema_name  Schema name of the table used for error reporting.
+  @param error_table_name   Table name used for error reporting.
+  @param key                Key to be checked.
+  @param key_info           Key meta-data info.
+  @param alter_info         List of columns and indexes to create.
 */
-static void check_duplicate_key(THD *thd,
+static void check_duplicate_key(THD *thd, const char *error_schema_name,
+                                const char *error_table_name,
                                 Key *key, KEY *key_info,
                                 Alter_info *alter_info)
 {
@@ -3352,8 +3359,8 @@ static void check_duplicate_key(THD *thd,
       push_warning_printf(thd, Sql_condition::WARN_LEVEL_NOTE,
                           ER_DUP_INDEX, ER(ER_DUP_INDEX),
                           key_info->name,
-                          thd->lex->query_tables->db,
-                          thd->lex->query_tables->table_name);
+                          error_schema_name,
+                          error_table_name);
       break;
     }
   }
@@ -3366,6 +3373,10 @@ static void check_duplicate_key(THD *thd,
   SYNOPSIS
     mysql_prepare_create_table()
       thd                       Thread object.
+      error_schema_name         Schema name of the table to create/alter,only
+                                used for error reporting.
+      error_table_name          Name of table to create/alter, only used for
+                                error reporting.
       create_info               Create information (like MAX_ROWS).
       alter_info                List of columns and indexes to create
       tmp_table                 If a temporary table is to be created.
@@ -3387,7 +3398,9 @@ static void check_duplicate_key(THD *thd,
 */
 
 static int
-mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
+mysql_prepare_create_table(THD *thd, const char *error_schema_name,
+                           const char *error_table_name,
+                           HA_CREATE_INFO *create_info,
                            Alter_info *alter_info,
                            bool tmp_table,
                            uint *db_options,
@@ -4219,9 +4232,18 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
        else
          key_info->flags|= HA_PACK_KEY;
       }
-      /* Check if the key segment is partial, set the key flag accordingly */
-      if (key_part_length != sql_field->key_length)
-        key_info->flags|= HA_KEY_HAS_PART_KEY_SEG;
+      /* 
+         Check if the key segment is partial, set the key flag
+         accordingly. The key segment for a POINT column is NOT considered
+         partial if key_length==MAX_LEN_GEOM_POINT_FIELD.
+      */
+      if (key_part_length != sql_field->key_length &&
+          !(sql_field->sql_type == MYSQL_TYPE_GEOMETRY &&
+            sql_field->geom_type == Field::GEOM_POINT &&
+            key_part_length == MAX_LEN_GEOM_POINT_FIELD))
+        {
+          key_info->flags|= HA_KEY_HAS_PART_KEY_SEG;
+        }
 
       key_length+= key_part_length;
       key_part_info++;
@@ -4279,7 +4301,8 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
     }
 
     // Check if a duplicate index is defined.
-    check_duplicate_key(thd, key, key_info, alter_info);
+    check_duplicate_key(thd, error_schema_name, error_table_name,
+                        key, key_info, alter_info);
 
     key_info++;
   }
@@ -4529,6 +4552,8 @@ static void sp_prepare_create_field(THD *thd, Create_field *sql_field)
   @param thd                 Thread object
   @param db                  Database
   @param table_name          Table name
+  @param error_table_name    The real table name in case table_name is a temporary
+                             table (ALTER). Only used for error messages.
   @param path                Path to table (i.e. to its .FRM file without
                              the extension).
   @param create_info         Create information (like MAX_ROWS)
@@ -4561,6 +4586,7 @@ static void sp_prepare_create_field(THD *thd, Create_field *sql_field)
 static
 bool create_table_impl(THD *thd,
                        const char *db, const char *table_name,
+                       const char *error_table_name,
                        const char *path,
                        HA_CREATE_INFO *create_info,
                        Alter_info *alter_info,
@@ -4807,7 +4833,8 @@ bool create_table_impl(THD *thd,
   }
 #endif
 
-  if (mysql_prepare_create_table(thd, create_info, alter_info,
+  if (mysql_prepare_create_table(thd, db, error_table_name,
+                                 create_info, alter_info,
                                  internal_tmp_table,
                                  &db_options, file,
                                  key_info, key_count,
@@ -5080,9 +5107,9 @@ bool mysql_create_table_no_lock(THD *thd,
     }
   }
 
-  return create_table_impl(thd, db, table_name, path, create_info, alter_info,
-                           false, select_field_count, false, is_trans,
-                           &not_used_1, &not_used_2);
+  return create_table_impl(thd, db, table_name, table_name, path, create_info,
+                           alter_info, false, select_field_count, false,
+                           is_trans, &not_used_1, &not_used_2);
 }
 
 
@@ -6303,8 +6330,8 @@ bool mysql_compare_tables(TABLE *table,
   KEY *key_info_buffer= NULL;
 
   /* Create the prepared information. */
-  if (mysql_prepare_create_table(thd, create_info,
-                                 &tmp_alter_info,
+  if (mysql_prepare_create_table(thd, "", "",
+                                 create_info, &tmp_alter_info,
                                  (table->s->tmp_table != NO_TMP_TABLE),
                                  &db_options,
                                  table->file, &key_info_buffer,
@@ -8437,6 +8464,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
 
   tmp_disable_binlog(thd);
   error= create_table_impl(thd, alter_ctx.new_db, alter_ctx.tmp_name,
+                           alter_ctx.table_name,
                            alter_ctx.get_tmp_path(),
                            create_info, alter_info,
                            true, 0, true, NULL,
index b2f54e25622680f0af2105e2e8dabda3fdf5a3aa..a80d6d11762c3a9bda7a7255f02538a32700bb93 100644 (file)
@@ -5562,6 +5562,12 @@ part_name:
           {
             partition_info *part_info= Lex->part_info;
             partition_element *p_elem= part_info->curr_part_elem;
+            if (check_string_char_length(&$1, "", NAME_CHAR_LEN,
+                                         system_charset_info, true))
+            {
+              my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str);
+              MYSQL_YYABORT;
+            }
             p_elem->partition_name= $1.str;
           }
         ;
@@ -5856,7 +5862,15 @@ sub_part_definition:
 
 sub_name:
           ident_or_text
-          { Lex->part_info->curr_part_elem->partition_name= $1.str; }
+          {
+            if (check_string_char_length(&$1, "", NAME_CHAR_LEN,
+                                         system_charset_info, true))
+            {
+              my_error(ER_TOO_LONG_IDENT, MYF(0), $1.str);
+              MYSQL_YYABORT;
+            }
+            Lex->part_info->curr_part_elem->partition_name= $1.str;
+          }
         ;
 
 opt_part_options:
index b53a3e9d5170bbdeeafbb459e99d2f938d53fe6d..a848dd27e3a7715534c4396638333755e1873540 100644 (file)
@@ -1788,8 +1788,10 @@ static int open_binary_frm(THD *thd, TABLE_SHARE *share, uchar *head,
   /* Fix key->name and key_part->field */
   if (key_parts)
   {
-    uint primary_key=(uint) (find_type(primary_key_name, &share->keynames,
-                                       FIND_TYPE_NO_PREFIX) - 1);
+    const int pk_off= find_type(primary_key_name, &share->keynames,
+                                  FIND_TYPE_NO_PREFIX);
+    uint primary_key= (pk_off > 0 ? pk_off-1 : MAX_KEY);
+
     longlong ha_option= handler_file->ha_table_flags();
     keyinfo= share->key_info;
     key_part= keyinfo->key_part;
index 124791786471394b88c77aa4ea4ea0e812563681..5f3b4c95343cac634b74856af83e39606def0067 100644 (file)
@@ -702,7 +702,7 @@ bool trans_rollback_to_savepoint(THD *thd, LEX_STRING name)
 #ifdef WITH_WSREP
   bool mdl_can_safely_rollback_to_savepoint=
                 (!((WSREP_EMULATE_BINLOG(thd) ||  mysql_bin_log.is_open()) 
-                  && thd->variables.sql_log_bin) ||
+                   && thd->variables.sql_log_bin) ||
                  ha_rollback_to_savepoint_can_release_mdl(thd));
 #else
   bool mdl_can_safely_rollback_to_savepoint=
index cbe8c0a01e9b9e6d13122ac4fc402f8f7d64f8d2..b2be924593099e94d27f58272e87c3f179036e3c 100644 (file)
@@ -315,7 +315,7 @@ wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all)
   int replay_round= 0;
 
   if (thd->get_stmt_da()->is_error()) {
-    WSREP_ERROR("commit issue, error: %d %s",
+    WSREP_DEBUG("commit issue, error: %d %s",
                 thd->get_stmt_da()->sql_errno(), thd->get_stmt_da()->message());
   }
 
@@ -515,7 +515,10 @@ wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all)
       set to NO_CONFLICT and commit proceeds as usual.
     */
     if (thd->wsrep_conflict_state == MUST_ABORT)
-        thd->wsrep_conflict_state= NO_CONFLICT;
+    {
+      thd->killed= THD::NOT_KILLED;
+      thd->wsrep_conflict_state= NO_CONFLICT;
+    }
 
     if (thd->wsrep_conflict_state != NO_CONFLICT)
     {
@@ -580,6 +583,38 @@ wsrep_run_wsrep_commit(THD *thd, handlerton *hton, bool all)
   DBUG_RETURN(WSREP_TRX_OK);
 }
 
+bool wsrep_replicate_GTID(THD *thd)
+{
+  if (thd->slave_thread)
+  {
+    WSREP_DEBUG("GTID replication");
+    DBUG_ASSERT (WSREP_UNDEFINED_TRX_ID == thd->wsrep_ws_handle.trx_id);
+    (void)wsrep_ws_handle_for_trx(&thd->wsrep_ws_handle, thd->query_id);
+    DBUG_ASSERT (WSREP_UNDEFINED_TRX_ID != thd->wsrep_ws_handle.trx_id);
+    WSREP_DEBUG("slave trx using query ID %lu for replication GTID",
+                thd->wsrep_ws_handle.trx_id);
+    enum wsrep_trx_status rcode= wsrep_run_wsrep_commit(thd, wsrep_hton, true);
+    if (rcode)
+    {
+      /*
+        TODO: should error here cause stopping of MySQL slave?
+        Slave applying was totally filtered out, and fauílure in replicating
+        GTID event, would cause a hole in GTID history in other cluster nodes
+
+      */
+      WSREP_INFO("GTID replication failed: %d", rcode);
+      wsrep->post_rollback(wsrep, &thd->wsrep_ws_handle);
+      thd->wsrep_replicate_GTID= false;
+      my_message(ER_ERROR_DURING_COMMIT,
+                 "WSREP GTID replication was interrupted", MYF(0));
+      return true;
+    }
+    wsrep_post_commit(thd, true);
+  }
+  thd->wsrep_replicate_GTID= false;
+
+  return false;
+}
 
 static int wsrep_hton_init(void *p)
 {
index 96004983989d12e14b9c031bb150c478b614a949..ded6d871a8ca1568521dad44edac63c836657595 100644 (file)
@@ -1226,7 +1226,7 @@ static int wsrep_TOI_begin(THD *thd, char *db_, char *table_,
     if (buf) my_free(buf);
     wsrep_keys_free(&key_arr);
     WSREP_DEBUG("TO BEGIN: %lld, %d",(long long)wsrep_thd_trx_seqno(thd),
-               thd->wsrep_exec_mode);
+                thd->wsrep_exec_mode);
   }
   else if (key_arr.keys_len > 0) {
     /* jump to error handler in mysql_execute_command() */
@@ -1234,7 +1234,7 @@ static int wsrep_TOI_begin(THD *thd, char *db_, char *table_,
                "connection state and retry the query.",
                ret, (thd->db ? thd->db : "(null)"), WSREP_QUERY(thd));
     my_error(ER_LOCK_DEADLOCK, MYF(0), "WSREP replication failed. Check "
-            "your wsrep connection state and retry the query.");
+             "your wsrep connection state and retry the query.");
     if (buf) my_free(buf);
     wsrep_keys_free(&key_arr);
     return -1;
@@ -1242,8 +1242,8 @@ static int wsrep_TOI_begin(THD *thd, char *db_, char *table_,
   else {
     /* non replicated DDL, affecting temporary tables only */
     WSREP_DEBUG("TO isolation skipped for: %d, sql: %s."
-               "Only temporary tables affected.",
-               ret, WSREP_QUERY(thd));
+                "Only temporary tables affected.",
+                ret, WSREP_QUERY(thd));
     return 1;
   }
   return 0;
index bfc94af94f13c7e192713d0f19ff5f1e2db8739c..098ae79a86882f646a5183370c19fa5c90a050c6 100644 (file)
@@ -206,11 +206,19 @@ extern wsrep_seqno_t wsrep_locked_seqno;
    wsrep_provider                     && \
    strcmp(wsrep_provider, WSREP_NONE))
 
+/* use xxxxxx_NNULL macros when thd pointer is guaranteed to be non-null to
+ * avoid compiler warnings (GCC 6 and later) */
+#define WSREP_NNULL(thd) \
+  (WSREP_ON && wsrep && thd->variables.wsrep_on)
+
 #define WSREP(thd) \
-  (WSREP_ON && wsrep && (thd && thd->variables.wsrep_on))
+  (thd && WSREP_NNULL(thd))
 
 #define WSREP_CLIENT(thd) \
-    (WSREP(thd) && thd->wsrep_client_thread)
+  (WSREP(thd) && thd->wsrep_client_thread)
+
+#define WSREP_EMULATE_BINLOG_NNULL(thd) \
+  (WSREP_NNULL(thd) && wsrep_emulate_bin_log)
 
 #define WSREP_EMULATE_BINLOG(thd) \
   (WSREP(thd) && wsrep_emulate_bin_log)
@@ -332,4 +340,6 @@ bool wsrep_stmt_rollback_is_safe(THD* thd);
 void wsrep_init_sidno(const wsrep_uuid_t&);
 bool wsrep_node_is_donor();
 bool wsrep_node_is_synced();
+bool wsrep_replicate_GTID(THD* thd);
+
 #endif /* WSREP_MYSQLD_H */
index 54d165c377e7d144d9125d4a9e841abd427057ff..8042339ae150f692c40d6bd66388a5931fda87ac 100644 (file)
@@ -811,7 +811,7 @@ static int sst_donate_mysqldump (const char*         addr,
                      "%s",
                      host, port, mysqld_port, mysqld_unix_port,
                      wsrep_defaults_file, uuid_str,
-                     (long long)seqno, bypass ? " "WSREP_SST_OPT_BYPASS : "");
+                     (long long)seqno, bypass ? " " WSREP_SST_OPT_BYPASS : "");
 
   if (ret < 0 || ret >= cmd_len)
   {
@@ -1074,7 +1074,7 @@ static int sst_donate_other (const char*   method,
                  wsrep_defaults_file, wsrep_defaults_group_suffix,
                  binlog_opt, binlog_opt_val,
                  uuid, (long long) seqno,
-                 bypass ? " "WSREP_SST_OPT_BYPASS : "");
+                 bypass ? " " WSREP_SST_OPT_BYPASS : "");
   my_free(binlog_opt_val);
 
   if (ret < 0 || ret >= cmd_len)
index 0778389347241182cc4a62842c4657d5f2a1c32b..8de761031f69fd5c8fc989b0747ec712d5144f79 100644 (file)
@@ -36,14 +36,18 @@ int wsrep_show_bf_aborts (THD *thd, SHOW_VAR *var, char *buff)
 /* must have (&thd->LOCK_wsrep_thd) */
 void wsrep_client_rollback(THD *thd)
 {
-  WSREP_DEBUG("client rollback due to BF abort for (%ld), query: %s",
-              thd->thread_id, WSREP_QUERY(thd));
+  WSREP_DEBUG("client rollback due to BF abort for (%ld %lld), query: %s",
+              thd->thread_id, thd->query_id, WSREP_QUERY(thd));
 
   my_atomic_add64(&wsrep_bf_aborts_counter, 1);
 
   thd->wsrep_conflict_state= ABORTING;
   mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
-  trans_rollback(thd);
+  if (trans_rollback(thd))
+  {
+    WSREP_WARN("client rollback failed for: %lu %lld, conf: %d",
+               thd->thread_id, thd->query_id, thd->wsrep_conflict_state);
+  }
 
   if (thd->locked_tables_mode && thd->lock)
   {
@@ -86,61 +90,6 @@ static Relay_log_info* wsrep_relay_log_init(const char* log_fname)
       new Format_description_log_event(BINLOG_VERSION));
 
   return (rli);
-
-#ifdef REMOVED
-  Rpl_info_handler* handler_src= NULL;
-  Rpl_info_handler* handler_dest= NULL;
-  ulong *key_info_idx= NULL;
-  const char *msg= "Failed to allocate memory for the relay log info "
-                   "structure";
-
-  DBUG_ENTER("Rpl_info_factory::create_rli");
-
-  if (!(rli= new Relay_log_info(false
-#ifdef HAVE_PSI_INTERFACE
-                                ,&key_relay_log_info_run_lock,
-                                &key_relay_log_info_data_lock,
-                                &key_relay_log_info_sleep_lock,
-                                &key_relay_log_info_data_cond,
-                                &key_relay_log_info_start_cond,
-                                &key_relay_log_info_stop_cond,
-                                &key_relay_log_info_sleep_cond
-#endif /* HAVE_PSI_INTERFACE */
-                               )))
-    goto err;
-
-  if (!(key_info_idx= new ulong[NUMBER_OF_FIELDS_TO_IDENTIFY_COORDINATOR]))
-     goto err;
-  key_info_idx[0]= server_id;
-  rli->set_idx_info(key_info_idx, NUMBER_OF_FIELDS_TO_IDENTIFY_COORDINATOR);
-
-  if(Rpl_info_factory::init_rli_repositories(rli, rli_option, &handler_src,
-                                             &handler_dest, &msg))
-    goto err;
-
-  if (Rpl_info_factory::decide_repository(rli, rli_option, &handler_src,
-                                          &handler_dest, &msg))
-    goto err;
-
-  DBUG_RETURN(rli);
-err:
-  delete handler_src;
-  delete handler_dest;
-  delete []key_info_idx;
-  if (rli)
-  {
-    /*
-      The handler was previously deleted so we need to remove
-      any reference to it.
-    */
-    rli->set_idx_info(NULL, 0);
-    rli->set_rpl_info_handler(NULL);
-    rli->set_rpl_info_type(INVALID_INFO_REPOSITORY);
-    delete rli;
-  }
-  WSREP_ERROR("Error creating relay log info: %s.", msg);
-  DBUG_RETURN(NULL);
-#endif /* REMOVED */
 }
 
 static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow)
@@ -174,6 +123,7 @@ static void wsrep_prepare_bf_thd(THD *thd, struct wsrep_thd_shadow* shadow)
   thd->reset_db(NULL, 0);
 
   shadow->user_time = thd->user_time;
+  shadow->row_count_func= thd->get_row_count_func();
 }
 
 static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow)
@@ -185,6 +135,7 @@ static void wsrep_return_from_bf_mode(THD *thd, struct wsrep_thd_shadow* shadow)
   thd->variables.tx_isolation = shadow->tx_isolation;
   thd->reset_db(shadow->db, shadow->db_length);
   thd->user_time              = shadow->user_time;
+  thd->set_row_count_func(shadow->row_count_func);
 }
 
 void wsrep_replay_transaction(THD *thd)
@@ -207,6 +158,25 @@ void wsrep_replay_transaction(THD *thd)
         WSREP_WARN("dangling observer in replay transaction: (thr %lu %lld %s)",
                    thd->thread_id, thd->query_id, thd->query());
       }
+
+      struct da_shadow
+      {
+          enum Diagnostics_area::enum_diagnostics_status status;
+          ulonglong affected_rows;
+          ulonglong last_insert_id;
+          char message[MYSQL_ERRMSG_SIZE];
+      };
+      struct da_shadow da_status;
+      da_status.status= thd->get_stmt_da()->status();
+      if (da_status.status == Diagnostics_area::DA_OK)
+      {
+        da_status.affected_rows= thd->get_stmt_da()->affected_rows();
+        da_status.last_insert_id= thd->get_stmt_da()->last_insert_id();
+        strmake(da_status.message,
+                thd->get_stmt_da()->message(),
+                sizeof(da_status.message)-1);
+      }
+
       thd->get_stmt_da()->reset_diagnostics_area();
 
       thd->wsrep_conflict_state= REPLAYING;
@@ -273,7 +243,17 @@ void wsrep_replay_transaction(THD *thd)
         }
         else
         {
-          my_ok(thd);
+          if (da_status.status == Diagnostics_area::DA_OK)
+          {
+            my_ok(thd,
+                  da_status.affected_rows,
+                  da_status.last_insert_id,
+                  da_status.message);
+          }
+          else
+          {
+            my_ok(thd);
+          }
         }
         break;
       case WSREP_TRX_FAIL:
@@ -464,6 +444,11 @@ static void wsrep_rollback_process(THD *thd)
       aborting->store_globals();
 
       mysql_mutex_lock(&aborting->LOCK_wsrep_thd);
+
+      /* prepare THD for rollback processing */
+      mysql_reset_thd_for_next_command(aborting);
+      aborting->lex->sql_command= SQLCOM_ROLLBACK;
+
       wsrep_client_rollback(aborting);
       WSREP_DEBUG("WSREP rollbacker aborted thd: (%lu %llu)",
                   aborting->thread_id, (long long)aborting->real_id);
@@ -522,9 +507,9 @@ my_bool wsrep_thd_is_BF(void *thd_ptr, my_bool sync)
   {
     THD* thd = (THD*)thd_ptr;
     if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd);
-    
+
     status = ((thd->wsrep_exec_mode == REPL_RECV)    ||
-             (thd->wsrep_exec_mode == TOTAL_ORDER));
+              (thd->wsrep_exec_mode == TOTAL_ORDER));
     if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
   }
   return status;
@@ -538,10 +523,10 @@ my_bool wsrep_thd_is_BF_or_commit(void *thd_ptr, my_bool sync)
   {
     THD* thd = (THD*)thd_ptr;
     if (sync) mysql_mutex_lock(&thd->LOCK_wsrep_thd);
-    
+
     status = ((thd->wsrep_exec_mode == REPL_RECV)    ||
-             (thd->wsrep_exec_mode == TOTAL_ORDER)  ||
-             (thd->wsrep_exec_mode == LOCAL_COMMIT));
+              (thd->wsrep_exec_mode == TOTAL_ORDER)  ||
+              (thd->wsrep_exec_mode == LOCAL_COMMIT));
     if (sync) mysql_mutex_unlock(&thd->LOCK_wsrep_thd);
   }
   return status;
index 9aa63caa579a81aa43659009e93f224ed87b2b97..b0ba98308be71e406be10fdf915067c4de1d5f24 100644 (file)
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 2009, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2009, 2016, Oracle and/or its affiliates. All Rights Reserved.
 
 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
@@ -1095,7 +1095,8 @@ dict_stats_analyze_index_level(
                them away) which brings non-determinism. We skip only
                leaf-level delete marks because delete marks on
                non-leaf level do not make sense. */
-               if (level == 0 &&
+
+               if (level == 0 && srv_stats_include_delete_marked? 0:
                    rec_get_deleted_flag(
                            rec,
                            page_is_comp(btr_pcur_get_page(&pcur)))) {
@@ -1281,8 +1282,12 @@ enum page_scan_method_t {
                                the given page and count the number of
                                distinct ones, also ignore delete marked
                                records */
-       QUIT_ON_FIRST_NON_BORING/* quit when the first record that differs
+       QUIT_ON_FIRST_NON_BORING,/* quit when the first record that differs
                                from its right neighbor is found */
+       COUNT_ALL_NON_BORING_INCLUDE_DEL_MARKED/* scan all records on
+                               the given page and count the number of
+                               distinct ones, include delete marked
+                               records */
 };
 /* @} */
 
@@ -1558,6 +1563,8 @@ dict_stats_analyze_index_below_cur(
 
        offsets_rec = dict_stats_scan_page(
                &rec, offsets1, offsets2, index, page, n_prefix,
+               srv_stats_include_delete_marked ?
+               COUNT_ALL_NON_BORING_INCLUDE_DEL_MARKED:
                COUNT_ALL_NON_BORING_AND_SKIP_DEL_MARKED, n_diff,
                n_external_pages);
 
index 6c13603bba5bee2f01f8c66603c95e9aa25891c8..6ea529971d2c8b42346b78666d156dbcf648ec8a 100644 (file)
@@ -578,9 +578,6 @@ fts_zip_read_word(
        fts_zip_t*      zip,            /*!< in: Zip state + data */
        fts_string_t*   word)           /*!< out: uncompressed word */
 {
-#ifdef UNIV_DEBUG
-       ulint           i;
-#endif
        short           len = 0;
        void*           null = NULL;
        byte*           ptr = word->f_str;
@@ -655,10 +652,9 @@ fts_zip_read_word(
                }
        }
 
-#ifdef UNIV_DEBUG
        /* All blocks must be freed at end of inflate. */
        if (zip->status != Z_OK) {
-               for (i = 0; i < ib_vector_size(zip->blocks); ++i) {
+               for (ulint i = 0; i < ib_vector_size(zip->blocks); ++i) {
                        if (ib_vector_getp(zip->blocks, i)) {
                                ut_free(ib_vector_getp(zip->blocks, i));
                                ib_vector_set(zip->blocks, i, &null);
@@ -669,7 +665,6 @@ fts_zip_read_word(
        if (ptr != NULL) {
                ut_ad(word->f_len == strlen((char*) ptr));
        }
-#endif /* UNIV_DEBUG */
 
        return(zip->status == Z_OK || zip->status == Z_STREAM_END ? ptr : NULL);
 }
index c2b3e10de24b47a653249c7e9293546abd92849b..5580517afc496dac8848e4af9acc80d78a62356a 100644 (file)
@@ -14509,6 +14509,37 @@ ha_innobase::get_auto_increment(
        ulonglong       col_max_value = innobase_get_int_col_max_value(
                table->next_number_field);
 
+       /** The following logic is needed to avoid duplicate key error
+       for autoincrement column.
+
+       (1) InnoDB gives the current autoincrement value with respect
+       to increment and offset value.
+
+       (2) Basically it does compute_next_insert_id() logic inside InnoDB
+       to avoid the current auto increment value changed by handler layer.
+
+       (3) It is restricted only for insert operations. */
+
+       if (increment > 1 && thd_sql_command(user_thd) != SQLCOM_ALTER_TABLE
+           && autoinc < col_max_value) {
+
+               ulonglong       prev_auto_inc = autoinc;
+
+               autoinc = ((autoinc - 1) + increment - offset)/ increment;
+
+               autoinc = autoinc * increment + offset;
+
+               /* If autoinc exceeds the col_max_value then reset
+               to old autoinc value. Because in case of non-strict
+               sql mode, boundary value is not considered as error. */
+
+               if (autoinc >= col_max_value) {
+                       autoinc = prev_auto_inc;
+               }
+
+               ut_ad(autoinc > 0);
+       }
+
        /* Called for the first time ? */
        if (trx->n_autoinc_rows == 0) {
 
@@ -17340,6 +17371,12 @@ static MYSQL_SYSVAR_BOOL(doublewrite, innobase_use_doublewrite,
   "Disable with --skip-innodb-doublewrite.",
   NULL, NULL, TRUE);
 
+static MYSQL_SYSVAR_BOOL(stats_include_delete_marked,
+  srv_stats_include_delete_marked,
+  PLUGIN_VAR_OPCMDARG,
+  "Scan delete marked records for persistent stat",
+  NULL, NULL, FALSE);
+
 static MYSQL_SYSVAR_ULONG(io_capacity, srv_io_capacity,
   PLUGIN_VAR_RQCMDARG,
   "Number of IOPs the server can do. Tunes the background IO rate",
@@ -18175,6 +18212,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
   MYSQL_SYSVAR(data_file_path),
   MYSQL_SYSVAR(data_home_dir),
   MYSQL_SYSVAR(doublewrite),
+  MYSQL_SYSVAR(stats_include_delete_marked),
   MYSQL_SYSVAR(api_enable_binlog),
   MYSQL_SYSVAR(api_enable_mdl),
   MYSQL_SYSVAR(api_disable_rowlock),
index 5990443ddbc05946772e8fe8535c134ba787f32d..898d47a533074f70af65cbfd30e7bab581dd7f49 100644 (file)
@@ -464,8 +464,8 @@ extern "C" void wsrep_thd_set_conflict_state(
 
 extern "C" void wsrep_thd_set_trx_to_replay(THD *thd, uint64 trx_id);
 
-extern "C"void wsrep_thd_LOCK(THD *thd);
-extern "C"void wsrep_thd_UNLOCK(THD *thd);
+extern "C" void wsrep_thd_LOCK(THD *thd);
+extern "C" void wsrep_thd_UNLOCK(THD *thd);
 extern "C" uint32 wsrep_thd_wsrep_rand(THD *thd);
 extern "C" time_t wsrep_thd_query_start(THD *thd);
 extern "C" my_thread_id wsrep_thd_thread_id(THD *thd);
index 540a819925e57e0aa82eff25c697ffe93cc32bbb..836c30d4365c3392744581384d77fb552f5d6a59 100644 (file)
@@ -1713,6 +1713,7 @@ innobase_fts_check_doc_id_index_in_def(
 
        return(FTS_NOT_EXIST_DOC_ID_INDEX);
 }
+
 /*******************************************************************//**
 Create an index table where indexes are ordered as follows:
 
@@ -1779,26 +1780,11 @@ innobase_create_key_defs(
        (only prefix/part of the column is indexed), MySQL will treat the
        index as a PRIMARY KEY unless the table already has one. */
 
-       if (n_add > 0 && !new_primary && got_default_clust
-           && (key_info[*add].flags & HA_NOSAME)
-           && !(key_info[*add].flags & HA_KEY_HAS_PART_KEY_SEG)) {
-               uint    key_part = key_info[*add].user_defined_key_parts;
-
-               new_primary = true;
+       ut_ad(altered_table->s->primary_key == 0
+             || altered_table->s->primary_key == MAX_KEY);
 
-               while (key_part--) {
-                       const uint      maybe_null
-                               = key_info[*add].key_part[key_part].key_type
-                               & FIELDFLAG_MAYBE_NULL;
-                       DBUG_ASSERT(!maybe_null
-                                   == !key_info[*add].key_part[key_part].
-                                   field->real_maybe_null());
-
-                       if (maybe_null) {
-                               new_primary = false;
-                               break;
-                       }
-               }
+       if (got_default_clust && !new_primary) {
+               new_primary = (altered_table->s->primary_key != MAX_KEY);
        }
 
        const bool rebuild = new_primary || add_fts_doc_id
@@ -1816,8 +1802,14 @@ innobase_create_key_defs(
                ulint   primary_key_number;
 
                if (new_primary) {
-                       DBUG_ASSERT(n_add > 0);
-                       primary_key_number = *add;
+                       if (n_add == 0) {
+                               DBUG_ASSERT(got_default_clust);
+                               DBUG_ASSERT(altered_table->s->primary_key
+                                           == 0);
+                               primary_key_number = 0;
+                       } else {
+                               primary_key_number = *add;
+                       }
                } else if (got_default_clust) {
                        /* Create the GEN_CLUST_INDEX */
                        index_def_t*    index = indexdef++;
@@ -2904,6 +2896,8 @@ prepare_inplace_alter_table_dict(
                ctx->add_cols = add_cols;
        } else {
                DBUG_ASSERT(!innobase_need_rebuild(ha_alter_info));
+               DBUG_ASSERT(old_table->s->primary_key
+                           == altered_table->s->primary_key);
 
                if (!ctx->new_table->fts
                    && innobase_fulltext_exist(altered_table)) {
@@ -3896,6 +3890,27 @@ found_col:
                            add_fts_doc_id_idx));
 }
 
+/** Get the name of an erroneous key.
+@param[in]     error_key_num   InnoDB number of the erroneus key
+@param[in]     ha_alter_info   changes that were being performed
+@param[in]     table           InnoDB table
+@return        the name of the erroneous key */
+static
+const char*
+get_error_key_name(
+       ulint                           error_key_num,
+       const Alter_inplace_info*       ha_alter_info,
+       const dict_table_t*             table)
+{
+       if (error_key_num == ULINT_UNDEFINED) {
+               return(FTS_DOC_ID_INDEX_NAME);
+       } else if (ha_alter_info->key_count == 0) {
+               return(dict_table_get_first_index(table)->name);
+       } else {
+               return(ha_alter_info->key_info_buffer[error_key_num].name);
+       }
+}
+
 /** Alter the table structure in-place with operations
 specified using Alter_inplace_info.
 The level of concurrency allowed during this operation depends
@@ -4013,17 +4028,13 @@ oom:
        case DB_ONLINE_LOG_TOO_BIG:
                DBUG_ASSERT(ctx->online);
                my_error(ER_INNODB_ONLINE_LOG_TOO_BIG, MYF(0),
-                        (prebuilt->trx->error_key_num == ULINT_UNDEFINED)
-                        ? FTS_DOC_ID_INDEX_NAME
-                        : ha_alter_info->key_info_buffer[
-                                prebuilt->trx->error_key_num].name);
+                        get_error_key_name(prebuilt->trx->error_key_num,
+                                           ha_alter_info, prebuilt->table));
                break;
        case DB_INDEX_CORRUPT:
                my_error(ER_INDEX_CORRUPT, MYF(0),
-                        (prebuilt->trx->error_key_num == ULINT_UNDEFINED)
-                        ? FTS_DOC_ID_INDEX_NAME
-                        : ha_alter_info->key_info_buffer[
-                                prebuilt->trx->error_key_num].name);
+                        get_error_key_name(prebuilt->trx->error_key_num,
+                                           ha_alter_info, prebuilt->table));
                break;
        default:
                my_error_innodb(error,
@@ -4833,7 +4844,6 @@ innobase_update_foreign_cache(
                                "Foreign key constraints for table '%s'"
                                " are loaded with charset check off",
                                user_table->name);
-                               
                }
        }
 
@@ -4933,14 +4943,13 @@ commit_try_rebuild(
                        DBUG_RETURN(true);
                case DB_ONLINE_LOG_TOO_BIG:
                        my_error(ER_INNODB_ONLINE_LOG_TOO_BIG, MYF(0),
-                                ha_alter_info->key_info_buffer[0].name);
+                                get_error_key_name(err_key, ha_alter_info,
+                                                   rebuilt_table));
                        DBUG_RETURN(true);
                case DB_INDEX_CORRUPT:
                        my_error(ER_INDEX_CORRUPT, MYF(0),
-                                (err_key == ULINT_UNDEFINED)
-                                ? FTS_DOC_ID_INDEX_NAME
-                                : ha_alter_info->key_info_buffer[err_key]
-                                .name);
+                                get_error_key_name(err_key, ha_alter_info,
+                                                   rebuilt_table));
                        DBUG_RETURN(true);
                default:
                        my_error_innodb(error, table_name, user_table->flags);
index 9a1ada8fa0dff9df4432f484e7991bce94b25da8..54f3d7554bf9568e22ea73b00c516fd39b0e1112 100644 (file)
@@ -117,14 +117,25 @@ os_thread_create_func(
        os_thread_id_t*         thread_id);     /*!< out: id of the created
                                                thread, or NULL */
 
+/** Waits until the specified thread completes and joins it.
+Its return value is ignored.
+@param[in,out] thread  thread to join */
+UNIV_INTERN
+void
+os_thread_join(
+       os_thread_t     thread);
+
 /*****************************************************************//**
 Exits the current thread. */
 UNIV_INTERN
 void
 os_thread_exit(
 /*===========*/
-       void*   exit_value)     /*!< in: exit value; in Windows this void*
+       void*   exit_value,     /*!< in: exit value; in Windows this void*
                                is cast as a DWORD */
+       bool    detach = true)  /*!< in: if true, the thread will be detached
+                               right before exiting. If false, another thread
+                               is responsible for joining this thread. */
        UNIV_COLD MY_ATTRIBUTE((noreturn));
 /*****************************************************************//**
 Returns the thread identifier of current thread.
index 7f2aeb12cd0fe7e1e5a6b3c3c27123caa4004d90..29557a1b8916abfe1de2a9355b3f4c5881adcdb0 100644 (file)
@@ -351,6 +351,7 @@ extern unsigned long long   srv_stats_transient_sample_pages;
 extern my_bool                 srv_stats_persistent;
 extern unsigned long long      srv_stats_persistent_sample_pages;
 extern my_bool                 srv_stats_auto_recalc;
+extern my_bool                 srv_stats_include_delete_marked;
 
 extern ibool   srv_use_doublewrite_buf;
 extern ulong   srv_doublewrite_batch_size;
index 4ea505264899b55a8eb8e88910bf254fec702a7b..fa1fa415f6a5ecdca6179e14b923bd5120bdbe74 100644 (file)
@@ -333,6 +333,23 @@ trx_print_latched(
                                        or 0 to use the default max length */
        MY_ATTRIBUTE((nonnull));
 
+#ifdef WITH_WSREP
+/**********************************************************************//**
+Prints info about a transaction.
+Transaction information may be retrieved without having trx_sys->mutex acquired
+so it may not be completely accurate. The caller must own lock_sys->mutex
+and the trx must have some locks to make sure that it does not escape
+without locking lock_sys->mutex. */
+UNIV_INTERN
+void
+wsrep_trx_print_locking(
+/*==============*/
+       FILE*           f,              /*!< in: output stream */
+       const trx_t*    trx,            /*!< in: transaction */
+       ulint           max_query_len)  /*!< in: max query length to print,
+                                       or 0 to use the default max length */
+       MY_ATTRIBUTE((nonnull));
+#endif /* WITH_WSREP */
 /**********************************************************************//**
 Prints info about a transaction.
 Acquires and releases lock_sys->mutex and trx_sys->mutex. */
index 133e513038a04f4100aea3852e88c030fb7e11fe..c7d05090e8d78deb8231f70b073a9186e33c1630 100644 (file)
@@ -1653,14 +1653,13 @@ wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) {
                        is in the queue*/
                } else if (lock->trx != trx) {
                        if (wsrep_log_conflicts) {
-                               mutex_enter(&trx_sys->mutex);
                                if (bf_this)
                                        fputs("\n*** Priority TRANSACTION:\n", 
                                              stderr);
                                else
                                        fputs("\n*** Victim TRANSACTION:\n", 
                                              stderr);
-                               trx_print_latched(stderr, trx, 3000);
+                               wsrep_trx_print_locking(stderr, trx, 3000);
 
                                if (bf_other)
                                        fputs("\n*** Priority TRANSACTION:\n", 
@@ -1668,9 +1667,8 @@ wsrep_kill_victim(const trx_t * const trx, const lock_t *lock) {
                                else
                                        fputs("\n*** Victim TRANSACTION:\n", 
                                              stderr);
-                               trx_print_latched(stderr, lock->trx, 3000);
+                               wsrep_trx_print_locking(stderr, lock->trx, 3000);
 
-                               mutex_exit(&trx_sys->mutex);
                                fputs("*** WAITING FOR THIS LOCK TO BE GRANTED:\n",
                                      stderr);
 
index df68aab8a187410208e80dfb46486a663c8b42c6..feeedb01609480df367944474cc503565c09b811 100644 (file)
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2009, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
 
 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
@@ -55,8 +55,22 @@ mach_parse_compressed(
        if (flag < 0x80UL) {
                *val = flag;
                return(ptr + 1);
+       }
+
+       /* Workaround GCC bug
+       https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77673:
+       the compiler moves mach_read_from_4 right to the beginning of the
+       function, causing and out-of-bounds read if we are reading a short
+       integer close to the end of buffer. */
+#if defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__clang__)
+#define DEPLOY_FENCE
+#endif
+
+#ifdef DEPLOY_FENCE
+       __atomic_thread_fence(__ATOMIC_ACQUIRE);
+#endif
 
-       } else if (flag < 0xC0UL) {
+       if (flag < 0xC0UL) {
                if (end_ptr < ptr + 2) {
                        return(NULL);
                }
@@ -64,8 +78,13 @@ mach_parse_compressed(
                *val = mach_read_from_2(ptr) & 0x7FFFUL;
 
                return(ptr + 2);
+       }
+
+#ifdef DEPLOY_FENCE
+       __atomic_thread_fence(__ATOMIC_ACQUIRE);
+#endif
 
-       } else if (flag < 0xE0UL) {
+       if (flag < 0xE0UL) {
                if (end_ptr < ptr + 3) {
                        return(NULL);
                }
@@ -73,7 +92,13 @@ mach_parse_compressed(
                *val = mach_read_from_3(ptr) & 0x3FFFFFUL;
 
                return(ptr + 3);
-       } else if (flag < 0xF0UL) {
+       }
+
+#ifdef DEPLOY_FENCE
+       __atomic_thread_fence(__ATOMIC_ACQUIRE);
+#endif
+
+       if (flag < 0xF0UL) {
                if (end_ptr < ptr + 4) {
                        return(NULL);
                }
@@ -81,14 +106,20 @@ mach_parse_compressed(
                *val = mach_read_from_4(ptr) & 0x1FFFFFFFUL;
 
                return(ptr + 4);
-       } else {
-               ut_ad(flag == 0xF0UL);
+       }
 
-               if (end_ptr < ptr + 5) {
-                       return(NULL);
-               }
+#ifdef DEPLOY_FENCE
+       __atomic_thread_fence(__ATOMIC_ACQUIRE);
+#endif
+
+#undef DEPLOY_FENCE
+
+       ut_ad(flag == 0xF0UL);
 
-               *val = mach_read_from_4(ptr + 1);
-               return(ptr + 5);
+       if (end_ptr < ptr + 5) {
+               return(NULL);
        }
+
+       *val = mach_read_from_4(ptr + 1);
+       return(ptr + 5);
 }
index 772336215c9ed86e65b418f1b37c064f57127646..d6f897ca46addd1c13e302b79d51cc033d8f189d 100644 (file)
@@ -1,6 +1,6 @@
 /*****************************************************************************
 
-Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
 
 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
@@ -191,14 +191,38 @@ os_thread_create_func(
 #endif
 }
 
+/** Waits until the specified thread completes and joins it.
+Its return value is ignored.
+@param[in,out] thread  thread to join */
+UNIV_INTERN
+void
+os_thread_join(
+       os_thread_t     thread)
+{
+#ifdef __WIN__
+       /* Do nothing. */
+#else
+#ifdef UNIV_DEBUG
+       const int       ret =
+#endif /* UNIV_DEBUG */
+       pthread_join(thread, NULL);
+
+       /* Waiting on already-quit threads is allowed. */
+       ut_ad(ret == 0 || ret == ESRCH);
+#endif /* __WIN__ */
+}
+
 /*****************************************************************//**
 Exits the current thread. */
 UNIV_INTERN
 void
 os_thread_exit(
 /*===========*/
-       void*   exit_value)     /*!< in: exit value; in Windows this void*
+       void*   exit_value,     /*!< in: exit value; in Windows this void*
                                is cast as a DWORD */
+       bool    detach)         /*!< in: if true, the thread will be detached
+                               right before exiting. If false, another thread
+                               is responsible for joining this thread. */
 {
 #ifdef UNIV_DEBUG_THREAD_CREATION
        fprintf(stderr, "Thread exits, id %lu\n",
@@ -216,7 +240,9 @@ os_thread_exit(
 #ifdef __WIN__
        ExitThread((DWORD) exit_value);
 #else
-       pthread_detach(pthread_self());
+       if (detach) {
+               pthread_detach(pthread_self());
+       }
        pthread_exit(exit_value);
 #endif
 }
index 4fd3a51040a0b788a9ae22b376ab9ec81ce80203..7d3fcf675ece2861487d73cd74f0760acca64551 100644 (file)
@@ -957,7 +957,7 @@ fts_parallel_merge(
        CloseHandle(psort_info->thread_hdl);
 #endif /*__WIN__ */
 
-       os_thread_exit(NULL);
+       os_thread_exit(NULL, false);
 
        OS_THREAD_DUMMY_RETURN;
 }
index c094be8a23b2fd0ae8c3d354d7ea52df543f02b9..f8bea67906c3f35797c63810007a50b5f83efab3 100644 (file)
@@ -3774,6 +3774,13 @@ wait_again:
                                                " exited when creating FTS"
                                                " index '%s'",
                                                indexes[i]->name);
+                               } else {
+                                       for (j = 0; j < FTS_NUM_AUX_INDEX;
+                                            j++) {
+
+                                               os_thread_join(merge_info[j]
+                                                              .thread_hdl);
+                                       }
                                }
                        } else {
                                /* This cannot report duplicates; an
index 11bef1064d6f5a3af87a70b5056957e61f97da9e..09c20911ec9e377690189f059385cdb446842062 100644 (file)
@@ -1362,6 +1362,8 @@ run_again:
 
        row_ins_step(thr);
 
+       DEBUG_SYNC_C("ib_after_row_insert_step");
+
        err = trx->error_state;
 
        if (err != DB_SUCCESS) {
index c37d5e1fbf9a9739faba652d92f5118586f357d0..7a7588d12af08aa7b09ef6813c5385e4c3e27d2c 100644 (file)
@@ -348,6 +348,7 @@ this many index pages, there are 2 ways to calculate statistics:
   table/index are not found in the innodb database */
 UNIV_INTERN unsigned long long srv_stats_transient_sample_pages = 8;
 UNIV_INTERN my_bool            srv_stats_persistent = TRUE;
+UNIV_INTERN my_bool            srv_stats_include_delete_marked = FALSE;
 UNIV_INTERN unsigned long long srv_stats_persistent_sample_pages = 20;
 UNIV_INTERN my_bool            srv_stats_auto_recalc = TRUE;
 
index dc09e2884f1e8d0fff56f44c75c31d5068f1ba41..e3a131b5f0f29cc7d27fa5af395d80f187f4d5d0 100644 (file)
@@ -1874,6 +1874,118 @@ trx_print_latched(
                      mem_heap_get_size(trx->lock.lock_heap));
 }
 
+#ifdef WITH_WSREP
+/**********************************************************************//**
+Prints info about a transaction.
+Transaction information may be retrieved without having trx_sys->mutex acquired
+so it may not be completely accurate. The caller must own lock_sys->mutex
+and the trx must have some locks to make sure that it does not escape
+without locking lock_sys->mutex. */
+UNIV_INTERN
+void
+wsrep_trx_print_locking(
+/*==========*/
+       FILE*           f,
+                       /*!< in: output stream */
+       const trx_t*    trx,
+                       /*!< in: transaction */
+       ulint           max_query_len)
+                       /*!< in: max query length to print,
+                       or 0 to use the default max length */
+{
+       ibool           newline;
+       const char*     op_info;
+
+       ut_ad(lock_mutex_own());
+       ut_ad(trx->lock.trx_locks.count > 0);
+
+       fprintf(f, "TRANSACTION " TRX_ID_FMT, trx->id);
+
+       /* trx->state may change since trx_sys->mutex is not required */
+       switch (trx->state) {
+       case TRX_STATE_NOT_STARTED:
+               fputs(", not started", f);
+               goto state_ok;
+       case TRX_STATE_ACTIVE:
+               fprintf(f, ", ACTIVE %lu sec",
+                       (ulong) difftime(time(NULL), trx->start_time));
+               goto state_ok;
+       case TRX_STATE_PREPARED:
+               fprintf(f, ", ACTIVE (PREPARED) %lu sec",
+                       (ulong) difftime(time(NULL), trx->start_time));
+               goto state_ok;
+       case TRX_STATE_COMMITTED_IN_MEMORY:
+               fputs(", COMMITTED IN MEMORY", f);
+               goto state_ok;
+       }
+       fprintf(f, ", state %lu", (ulong) trx->state);
+       ut_ad(0);
+state_ok:
+
+       /* prevent a race condition */
+       op_info = trx->op_info;
+
+       if (*op_info) {
+               putc(' ', f);
+               fputs(op_info, f);
+       }
+
+       if (trx->is_recovered) {
+               fputs(" recovered trx", f);
+       }
+
+       if (trx->declared_to_be_inside_innodb) {
+               fprintf(f, ", thread declared inside InnoDB %lu",
+                       (ulong) trx->n_tickets_to_enter_innodb);
+       }
+
+       putc('\n', f);
+
+       if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) {
+               fprintf(f, "mysql tables in use %lu, locked %lu\n",
+                       (ulong) trx->n_mysql_tables_in_use,
+                       (ulong) trx->mysql_n_tables_locked);
+       }
+
+       newline = TRUE;
+
+       /* trx->lock.que_state of an ACTIVE transaction may change
+       while we are not holding trx->mutex. We perform a dirty read
+       for performance reasons. */
+
+       switch (trx->lock.que_state) {
+       case TRX_QUE_RUNNING:
+               newline = FALSE; break;
+       case TRX_QUE_LOCK_WAIT:
+               fputs("LOCK WAIT ", f); break;
+       case TRX_QUE_ROLLING_BACK:
+               fputs("ROLLING BACK ", f); break;
+       case TRX_QUE_COMMITTING:
+               fputs("COMMITTING ", f); break;
+       default:
+               fprintf(f, "que state %lu ", (ulong) trx->lock.que_state);
+       }
+
+       if (trx->has_search_latch) {
+               newline = TRUE;
+               fputs(", holds adaptive hash latch", f);
+       }
+
+       if (trx->undo_no != 0) {
+               newline = TRUE;
+               fprintf(f, ", undo log entries " TRX_ID_FMT, trx->undo_no);
+       }
+
+       if (newline) {
+               putc('\n', f);
+       }
+
+       if (trx->mysql_thd != NULL) {
+               innobase_mysql_print_thd(
+                       f, trx->mysql_thd, static_cast<uint>(max_query_len));
+       }
+}
+#endif /* WITH_WSREP */
 /**********************************************************************//**
 Prints info about a transaction.
 Acquires and releases lock_sys->mutex and trx_sys->mutex. */
index cf0fa82ba3f86b87d31d63f531ca009a2cf37f7f..3bbc0a4602e8545535a66bf6428b44cd6f18facd 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
 
   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
@@ -2560,10 +2560,7 @@ start_table_io_wait_v1(PSI_table_locker_state *state,
   if (! pfs_table->m_io_enabled)
     return NULL;
 
-  PFS_thread *pfs_thread= pfs_table->m_thread_owner;
-
-  DBUG_ASSERT(pfs_thread ==
-              my_pthread_getspecific_ptr(PFS_thread*, THR_PFS));
+  PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
 
   register uint flags;
   ulonglong timer_start= 0;
@@ -2666,7 +2663,7 @@ start_table_lock_wait_v1(PSI_table_locker_state *state,
   if (! pfs_table->m_lock_enabled)
     return NULL;
 
-  PFS_thread *pfs_thread= pfs_table->m_thread_owner;
+  PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
 
   PFS_TL_LOCK_TYPE lock_type;
 
@@ -3068,7 +3065,12 @@ start_socket_wait_v1(PSI_socket_locker_state *state,
 
   if (flag_thread_instrumentation)
   {
-    PFS_thread *pfs_thread= pfs_socket->m_thread_owner;
+    /*
+       Do not use pfs_socket->m_thread_owner here,
+       as different threads may use concurrently the same socket,
+       for example during a KILL.
+    */
+    PFS_thread *pfs_thread= my_pthread_getspecific_ptr(PFS_thread*, THR_PFS);
 
     if (unlikely(pfs_thread == NULL))
       return NULL;
@@ -3436,6 +3438,8 @@ static void end_idle_wait_v1(PSI_idle_locker* locker)
       if (flag_events_waits_history_long)
         insert_events_waits_history_long(wait);
       thread->m_events_waits_current--;
+
+      DBUG_ASSERT(wait == thread->m_events_waits_current);
     }
   }
 
@@ -3517,6 +3521,8 @@ static void end_mutex_wait_v1(PSI_mutex_locker* locker, int rc)
       if (flag_events_waits_history_long)
         insert_events_waits_history_long(wait);
       thread->m_events_waits_current--;
+
+      DBUG_ASSERT(wait == thread->m_events_waits_current);
     }
   }
 }
@@ -3596,6 +3602,8 @@ static void end_rwlock_rdwait_v1(PSI_rwlock_locker* locker, int rc)
       if (flag_events_waits_history_long)
         insert_events_waits_history_long(wait);
       thread->m_events_waits_current--;
+
+      DBUG_ASSERT(wait == thread->m_events_waits_current);
     }
   }
 }
@@ -3668,6 +3676,8 @@ static void end_rwlock_wrwait_v1(PSI_rwlock_locker* locker, int rc)
       if (flag_events_waits_history_long)
         insert_events_waits_history_long(wait);
       thread->m_events_waits_current--;
+
+      DBUG_ASSERT(wait == thread->m_events_waits_current);
     }
   }
 }
@@ -3732,6 +3742,8 @@ static void end_cond_wait_v1(PSI_cond_locker* locker, int rc)
       if (flag_events_waits_history_long)
         insert_events_waits_history_long(wait);
       thread->m_events_waits_current--;
+
+      DBUG_ASSERT(wait == thread->m_events_waits_current);
     }
   }
 }
@@ -3826,6 +3838,8 @@ static void end_table_io_wait_v1(PSI_table_locker* locker)
       if (flag_events_waits_history_long)
         insert_events_waits_history_long(wait);
       thread->m_events_waits_current--;
+
+      DBUG_ASSERT(wait == thread->m_events_waits_current);
     }
   }
 
@@ -3895,6 +3909,8 @@ static void end_table_lock_wait_v1(PSI_table_locker* locker)
       if (flag_events_waits_history_long)
         insert_events_waits_history_long(wait);
       thread->m_events_waits_current--;
+
+      DBUG_ASSERT(wait == thread->m_events_waits_current);
     }
   }
 
@@ -4143,6 +4159,8 @@ static void end_file_wait_v1(PSI_file_locker *locker,
       if (flag_events_waits_history_long)
         insert_events_waits_history_long(wait);
       thread->m_events_waits_current--;
+
+      DBUG_ASSERT(wait == thread->m_events_waits_current);
     }
   }
 }
@@ -5070,6 +5088,8 @@ static void end_socket_wait_v1(PSI_socket_locker *locker, size_t byte_count)
     if (flag_events_waits_history_long)
       insert_events_waits_history_long(wait);
     thread->m_events_waits_current--;
+
+    DBUG_ASSERT(wait == thread->m_events_waits_current);
   }
 }
 
index 1053bd59571c2053e06b2f6d8cc62c84a9c07517..5886c379b2f491cfba5fa14d75745e645d96cc78 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
 
   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
@@ -45,7 +45,7 @@ bool flag_statements_digest= true;
   Current index in Stat array where new record is to be inserted.
   index 0 is reserved for "all else" case when entire array is full.
 */
-volatile uint32 digest_index;
+volatile uint32 PFS_ALIGNED digest_monotonic_index;
 bool digest_full= false;
 
 LF_HASH digest_hash;
@@ -63,7 +63,7 @@ int init_digest(const PFS_global_param *param)
   */
   digest_max= param->m_digest_sizing;
   digest_lost= 0;
-  digest_index= 1;
+  PFS_atomic::store_u32(& digest_monotonic_index, 1);
   digest_full= false;
 
   if (digest_max == 0)
@@ -105,6 +105,9 @@ int init_digest(const PFS_global_param *param)
                                                    + index * pfs_max_digest_length, pfs_max_digest_length);
   }
 
+  /* Set record[0] as allocated. */
+  statements_digest_stat_array[0].m_lock.set_allocated();
+
   return 0;
 }
 
@@ -207,9 +210,10 @@ find_or_create_digest(PFS_thread *thread,
     memcpy(hash_key.m_schema_name, schema_name, schema_name_length);
 
   int res;
-  ulong safe_index;
   uint retry_count= 0;
   const uint retry_max= 3;
+  size_t safe_index;
+  size_t attempts= 0;
   PFS_statements_digest_stat **entry;
   PFS_statements_digest_stat *pfs= NULL;
 
@@ -245,55 +249,70 @@ search:
     return & pfs->m_stat;
   }
 
-  safe_index= PFS_atomic::add_u32(& digest_index, 1);
-  if (safe_index >= digest_max)
+  while (++attempts <= digest_max)
   {
-    /* The digest array is now full. */
-    digest_full= true;
-    pfs= &statements_digest_stat_array[0];
-
-    if (pfs->m_first_seen == 0)
-      pfs->m_first_seen= now;
-    pfs->m_last_seen= now;
-    return & pfs->m_stat;
-  }
-
-  /* Add a new record in digest stat array. */
-  pfs= &statements_digest_stat_array[safe_index];
-
-  /* Copy digest hash/LF Hash search key. */
-  memcpy(& pfs->m_digest_key, &hash_key, sizeof(PFS_digest_key));
-
-  /*
-    Copy digest storage to statement_digest_stat_array so that it could be
-    used later to generate digest text.
-  */
-  pfs->m_digest_storage.copy(digest_storage);
-
-  pfs->m_first_seen= now;
-  pfs->m_last_seen= now;
+    safe_index= PFS_atomic::add_u32(& digest_monotonic_index, 1) % digest_max;
+    if (safe_index == 0)
+    {
+      /* Record [0] is reserved. */
+      safe_index= 1;
+    }
 
-  res= lf_hash_insert(&digest_hash, pins, &pfs);
-  if (likely(res == 0))
-  {
-    return & pfs->m_stat;
-  }
+    /* Add a new record in digest stat array. */
+    pfs= &statements_digest_stat_array[safe_index];
 
-  if (res > 0)
-  {
-    /* Duplicate insert by another thread */
-    if (++retry_count > retry_max)
+    if (pfs->m_lock.is_free())
     {
-      /* Avoid infinite loops */
-      digest_lost++;
-      return NULL;
+      if (pfs->m_lock.free_to_dirty())
+      {
+        /* Copy digest hash/LF Hash search key. */
+        memcpy(& pfs->m_digest_key, &hash_key, sizeof(PFS_digest_key));
+
+        /*
+          Copy digest storage to statement_digest_stat_array so that it could be
+          used later to generate digest text.
+        */
+        pfs->m_digest_storage.copy(digest_storage);
+
+        pfs->m_first_seen= now;
+        pfs->m_last_seen= now;
+
+        res= lf_hash_insert(&digest_hash, pins, &pfs);
+        if (likely(res == 0))
+        {
+          pfs->m_lock.dirty_to_allocated();
+          return & pfs->m_stat;
+        }
+
+        pfs->m_lock.dirty_to_free();
+
+        if (res > 0)
+        {
+          /* Duplicate insert by another thread */
+          if (++retry_count > retry_max)
+          {
+            /* Avoid infinite loops */
+            digest_lost++;
+            return NULL;
+          }
+          goto search;
+        }
+
+        /* OOM in lf_hash_insert */
+        digest_lost++;
+        return NULL;
+      }
     }
-    goto search;
   }
 
-  /* OOM in lf_hash_insert */
-  digest_lost++;
-  return NULL;
+  /* The digest array is now full. */
+  digest_full= true;
+  pfs= &statements_digest_stat_array[0];
+
+  if (pfs->m_first_seen == 0)
+    pfs->m_first_seen= now;
+  pfs->m_last_seen= now;
+  return & pfs->m_stat;
 }
 
 void purge_digest(PFS_thread* thread, PFS_digest_key *hash_key)
@@ -320,10 +339,12 @@ void purge_digest(PFS_thread* thread, PFS_digest_key *hash_key)
 
 void PFS_statements_digest_stat::reset_data(unsigned char *token_array, uint length)
 {
+  m_lock.set_dirty();
   m_digest_storage.reset(token_array, length);
   m_stat.reset();
   m_first_seen= 0;
   m_last_seen= 0;
+  m_lock.dirty_to_free();
 }
 
 void PFS_statements_digest_stat::reset_index(PFS_thread *thread)
@@ -351,11 +372,14 @@ void reset_esms_by_digest()
     statements_digest_stat_array[index].reset_data(statements_digest_token_array + index * pfs_max_digest_length, pfs_max_digest_length);
   }
 
+  /* Mark record[0] as allocated again. */
+  statements_digest_stat_array[0].m_lock.set_allocated();
+
   /*
     Reset index which indicates where the next calculated digest information
     to be inserted in statements_digest_stat_array.
   */
-  digest_index= 1;
+  PFS_atomic::store_u32(& digest_monotonic_index, 1);
   digest_full= false;
 }
 
index 76d6c33d984fbbbbba816f518198835389ceffa0..429a9f4250a5b3075bc76934a9686832f79d29af 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 
   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
@@ -44,6 +44,9 @@ struct PFS_digest_key
 /** A statement digest stat record. */
 struct PFS_ALIGNED PFS_statements_digest_stat
 {
+  /** Internal lock. */
+  pfs_lock m_lock;
+
   /** Digest Schema + MD5 Hash. */
   PFS_digest_key m_digest_key;
 
index c429d9347029cdbb2042b95629747231da7e9cc8..339a893c83370706dff39effd1223282ef771bdf 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
 
   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
@@ -155,6 +155,18 @@ struct pfs_lock
     PFS_atomic::store_u32(&m_version_state, new_val);
   }
 
+  /**
+    Initialize a lock to dirty.
+  */
+  void set_dirty(void)
+  {
+    /* Do not set the version to 0, read the previous value. */
+    uint32 copy= PFS_atomic::load_u32(&m_version_state);
+    /* Increment the version, set the DIRTY state */
+    uint32 new_val= (copy & VERSION_MASK) + VERSION_INC + PFS_LOCK_DIRTY;
+    PFS_atomic::store_u32(&m_version_state, new_val);
+  }
+
   /**
     Execute a dirty to free transition.
     This transition should be executed by the writer that owns the record.
index 99e24316cbb9d794bba3ebeb85ddd842e2a8ac23..002a7f0104b2d16297a8d2de401ed1c42d2f170d 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
 
   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
@@ -238,11 +238,14 @@ int table_esms_by_digest::rnd_next(void)
        m_pos.next())
   {
     digest_stat= &statements_digest_stat_array[m_pos.m_index];
-    if (digest_stat->m_first_seen != 0)
+    if (digest_stat->m_lock.is_populated())
     {
-      make_row(digest_stat);
-      m_next_pos.set_after(&m_pos);
-      return 0;
+      if (digest_stat->m_first_seen != 0)
+      {
+        make_row(digest_stat);
+        m_next_pos.set_after(&m_pos);
+        return 0;
+      }
     }
   }
 
@@ -260,10 +263,13 @@ table_esms_by_digest::rnd_pos(const void *pos)
   set_position(pos);
   digest_stat= &statements_digest_stat_array[m_pos.m_index];
 
-  if (digest_stat->m_first_seen != 0)
+  if (digest_stat->m_lock.is_populated())
   {
-    make_row(digest_stat);
-    return 0;
+    if (digest_stat->m_first_seen != 0)
+    {
+      make_row(digest_stat);
+      return 0;
+    }
   }
 
   return HA_ERR_RECORD_DELETED;
index db53c655022fa9f68285e708d7dce4316ae869e2..a77080cac74418a00aed22760079489e13ccc797 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
 # 
 # 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
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-# We want gmock-1.6.0.zip in order to build these unit tests.
+# We want release-1.8.0.zip in order to build these unit tests.
 # If you have already downloaded it,
-# invoke cmake with -DWITH_GMOCK=/path/to/gmock-1.6.0.zip
+# invoke cmake with -DWITH_GMOCK=/path/to/release-1.8.0.zip
 #                or -DWITH_GMOCK=/path/to
 #
 # Alternatively, set an environment variable
-# export WITH_GMOCK=/path/to/gmock-1.6.0.zip
+# export WITH_GMOCK=/path/to/release-1.8.0.zip
 #
 # You can also do cmake -DENABLE_DOWNLOADS=1 
-# and we will download it from http://googlemock.googlecode.com
+# and we will download it from https://github.com/google/googletest/archive/
 #
 # Either way: we will unpack the zip, compile gmock-all.cc and gtest-all.cc
 # and link them into the executables.
 
-# Where to download and build gmock/gtest.
+# Disable googletest for Solaris Studio < 12.4 since it doesn't compile.
+IF(CMAKE_C_COMPILER_ID MATCHES "SunPro")
+  IF(${CC_MINOR_VERSION} LESS 13)
+    MESSAGE(WARNING "Googletest requires Solaris Studio 12.4 or newer.")
+    UNSET(GMOCK_FOUND)
+    UNSET(GMOCK_FOUND CACHE)
+    RETURN()
+  ENDIF()
+ENDIF()
+
+# Default location for where to download and build gmock/gtest.
 IF(NOT DOWNLOAD_ROOT)
   SET(DOWNLOAD_ROOT ${CMAKE_SOURCE_DIR}/source_downloads)
 ENDIF()
-IF(NOT EXISTS DOWNLOAD_ROOT)
-  MAKE_DIRECTORY(${DOWNLOAD_ROOT})
-ENDIF()
 
-# We want googlemock version 1.6, which also contains googletest.
-SET(GMOCK_PACKAGE_NAME "gmock-1.6.0")
-SET(GMOCK_SOURCE_DIR ${DOWNLOAD_ROOT}/${GMOCK_PACKAGE_NAME})
-SET(GTEST_SOURCE_DIR ${DOWNLOAD_ROOT}/${GMOCK_PACKAGE_NAME}/gtest)
+# We want googletest version 1.8, which also contains googlemock.
+SET(GMOCK_PACKAGE_NAME "release-1.8.0")
 
 IF (DEFINED ENV{WITH_GMOCK} AND NOT DEFINED WITH_GMOCK)
-  SET(WITH_GMOCK "$ENV{WITH_GMOCK}")
+  FILE(TO_CMAKE_PATH "$ENV{WITH_GMOCK}" WITH_GMOCK)
+ENDIF()
+
+IF(LOCAL_GMOCK_ZIP
+   AND NOT ${LOCAL_GMOCK_ZIP} MATCHES ".*${GMOCK_PACKAGE_NAME}\\.zip")
+ SET(LOCAL_GMOCK_ZIP 0)
 ENDIF()
 
 IF (WITH_GMOCK)
@@ -54,21 +64,37 @@ IF (WITH_GMOCK)
               PATHS ${GMOCK_DIR}
               NO_DEFAULT_PATH
              )
+  ELSE()
+    ## Did we get a path name to the directory of the .zip file?
+    ## Check for both release-x.y.z.zip and googletest-release-x.y.z.zip
+    FIND_FILE(LOCAL_GMOCK_ZIP
+              NAMES "${GMOCK_PACKAGE_NAME}.zip" "googletest-${GMOCK_PACKAGE_NAME}.zip"
+              PATHS ${WITH_GMOCK}
+              NO_DEFAULT_PATH
+              )
+    ## If WITH_GMOCK is a directory, use it for download.
+    SET(DOWNLOAD_ROOT ${WITH_GMOCK})
   ENDIF()
-  ## Did we get a path name to the directory of the .zip file?
-  FIND_FILE(LOCAL_GMOCK_ZIP
-            NAMES "${GMOCK_PACKAGE_NAME}.zip"
-            PATHS ${WITH_GMOCK}
-            NO_DEFAULT_PATH
-           )
   MESSAGE(STATUS "Local gmock zip ${LOCAL_GMOCK_ZIP}")
 ENDIF()
 
+IF(NOT EXISTS DOWNLOAD_ROOT)
+  MAKE_DIRECTORY(${DOWNLOAD_ROOT})
+ENDIF()
+SET(GMOCK_SOURCE_DIR ${DOWNLOAD_ROOT}/googletest-${GMOCK_PACKAGE_NAME}/googlemock)
+SET(GTEST_SOURCE_DIR ${DOWNLOAD_ROOT}/googletest-${GMOCK_PACKAGE_NAME}/googletest)
+
 # We may have downloaded gmock/gtest already, building in a different directory.
-IF(EXISTS ${GMOCK_SOURCE_DIR})
+IF(EXISTS ${GMOCK_SOURCE_DIR} OR EXISTS ${LOCAL_GMOCK_ZIP})
   MESSAGE(STATUS "GMOCK_SOURCE_DIR:${GMOCK_SOURCE_DIR}")
   SET(GMOCK_DOWNLOADED 1 CACHE INTERNAL "")
   SET(GMOCK_FOUND 1 CACHE INTERNAL "")
+# If source dir does not exist, reset dependent variables (might be set from before).
+ELSE()
+  SET(LOCAL_GMOCK_ZIP 0 CACHE INTERNAL "")
+  SET(GMOCK_DOWNLOADED 0 CACHE INTERNAL "")
+  SET(GMOCK_FOUND 0 CACHE INTERNAL "")
+  SET(GMOCK_INCLUDE_DIRS 0 CACHE INTERNAL "")
 ENDIF()
 
 
@@ -86,37 +112,34 @@ ENDIF()
 
 
 OPTION(ENABLE_DOWNLOADS
-  "Download and build 3rd party source code components, e.g. google mock"
+  "Download and build 3rd party source code components, e.g. googletest"
   OFF)
 
 # While experimenting, use local URL rather than google.
-SET(GMOCK_TARBALL "${GMOCK_PACKAGE_NAME}.zip")
+SET(GMOCK_TARBALL "googletest-${GMOCK_PACKAGE_NAME}.zip")
 SET(GMOCK_DOWNLOAD_URL 
-  "http://googlemock.googlecode.com/files/${GMOCK_TARBALL}"
+  "https://github.com/google/googletest/archive/${GMOCK_PACKAGE_NAME}.zip"
   )
   
 MACRO(HTTP_PROXY_HINT)
   MESSAGE(STATUS
-    "If you are inside a firewall, you may need to use an http proxy: "
-    "export http_proxy=http://example.com:80")
+    "If you are inside a firewall, you may need to use an https proxy: "
+    "export https_proxy=http://example.com:80")
 ENDMACRO()
 
 
 IF(NOT GMOCK_FOUND)
   IF(NOT ENABLE_DOWNLOADS)
-    # Give one-time warning
-    IF(NOT ONETIME_GTEST_WARNING)
-      MESSAGE(STATUS 
-        "Googlemock was not found. gtest-based unit tests will be disabled. "
-        "You can run cmake . -DENABLE_DOWNLOADS=1 to automatically download "
-        "and build required components from source.")
-      HTTP_PROXY_HINT()
-      SET(ONETIME_GTEST_WARNING 1 CACHE INTERNAL "")
-    ENDIF()
+    # Give warning
+    MESSAGE(STATUS
+      "Googletest was not found. gtest-based unit tests will be disabled. "
+      "You can run cmake . -DENABLE_DOWNLOADS=1 to automatically download "
+      "and build required components from source.")
+    HTTP_PROXY_HINT()
     RETURN()
   ENDIF()
   
-  # Download gmock source
+  # Download googletest source
   IF(NOT EXISTS ${GMOCK_SOURCE_DIR})
     IF(NOT EXISTS ${DOWNLOAD_ROOT}/${GMOCK_TARBALL})
       # Download the tarball
@@ -136,7 +159,7 @@ IF(NOT GMOCK_FOUND)
           "Successfully downloaded ${GMOCK_DOWNLOAD_URL} to ${DOWNLOAD_ROOT}")
       ELSE()
         MESSAGE(STATUS 
-          "To enable google test, please download ${GMOCK_DOWNLOAD_URL} "
+          "To enable googletest, please download ${GMOCK_DOWNLOAD_URL} "
           "to the directory ${DOWNLOAD_ROOT}")
         HTTP_PROXY_HINT()
         RETURN()