Import mariadb_10.11.8-1.debian.tar.xz
authorOtto Kekäläinen <otto@debian.org>
Fri, 17 May 2024 05:02:04 +0000 (22:02 -0700)
committerOtto Kekäläinen <otto@debian.org>
Fri, 17 May 2024 05:02:04 +0000 (22:02 -0700)
[dgit import tarball mariadb 1:10.11.8-1 mariadb_10.11.8-1.debian.tar.xz]

175 files changed:
README.Contributor [new file with mode: 0644]
README.Maintainer [new file with mode: 0644]
additions/debian-start [new file with mode: 0755]
additions/debian-start.inc.sh [new file with mode: 0755]
additions/echo_stderr [new file with mode: 0755]
additions/innotop/changelog.innotop [new file with mode: 0644]
additions/innotop/innotop [new file with mode: 0755]
additions/innotop/innotop.1 [new file with mode: 0644]
additions/mariadb-report [new file with mode: 0755]
additions/mariadb-report.1 [new file with mode: 0644]
additions/mariadb.cnf [new file with mode: 0644]
additions/mariadb.conf.d/50-client.cnf [new file with mode: 0644]
additions/mariadb.conf.d/50-mysql-clients.cnf [new file with mode: 0644]
additions/mariadb.conf.d/50-mysqld_safe.cnf [new file with mode: 0644]
additions/mariadb.conf.d/50-server.cnf [new file with mode: 0644]
additions/mariadb.conf.d/60-galera.cnf [new file with mode: 0644]
additions/source_mariadb.py [new file with mode: 0644]
apparmor-profile [new file with mode: 0644]
autobake-deb.sh [new file with mode: 0755]
changelog [new file with mode: 0644]
control [new file with mode: 0644]
copyright [new file with mode: 0644]
gbp.conf [new file with mode: 0644]
libmariadb-dev-compat.install [new file with mode: 0644]
libmariadb-dev-compat.links [new file with mode: 0755]
libmariadb-dev.README.Maintainer [new file with mode: 0644]
libmariadb-dev.examples [new file with mode: 0644]
libmariadb-dev.install [new file with mode: 0644]
libmariadb-dev.links [new file with mode: 0644]
libmariadb-dev.lintian-overrides [new file with mode: 0644]
libmariadb3.install [new file with mode: 0644]
libmariadb3.lintian-overrides [new file with mode: 0644]
libmariadb3.symbols [new file with mode: 0644]
libmariadb3.symbols.README [new file with mode: 0644]
libmariadbd-dev.install [new file with mode: 0644]
libmariadbd19t64.install [new file with mode: 0644]
libmariadbd19t64.lintian-overrides [new file with mode: 0644]
mariadb-backup.install [new file with mode: 0644]
mariadb-backup.lintian-overrides [new file with mode: 0644]
mariadb-client-core.install [new file with mode: 0644]
mariadb-client-core.links [new file with mode: 0644]
mariadb-client-core.lintian-overrides [new file with mode: 0644]
mariadb-client.README.Debian [new file with mode: 0644]
mariadb-client.docs [new file with mode: 0644]
mariadb-client.install [new file with mode: 0644]
mariadb-client.links [new file with mode: 0644]
mariadb-client.lintian-overrides [new file with mode: 0644]
mariadb-client.manpages [new file with mode: 0644]
mariadb-client.menu [new file with mode: 0644]
mariadb-common.dirs [new file with mode: 0644]
mariadb-common.install [new file with mode: 0644]
mariadb-common.postinst [new file with mode: 0644]
mariadb-common.postrm [new file with mode: 0644]
mariadb-common.preinst [new file with mode: 0644]
mariadb-plugin-connect.install [new file with mode: 0644]
mariadb-plugin-cracklib-password-check.install [new file with mode: 0644]
mariadb-plugin-gssapi-client.install [new file with mode: 0644]
mariadb-plugin-gssapi-server.install [new file with mode: 0644]
mariadb-plugin-hashicorp-key-management.install [new file with mode: 0644]
mariadb-plugin-mroonga.install [new file with mode: 0644]
mariadb-plugin-mroonga.lintian-overrides [new file with mode: 0644]
mariadb-plugin-mroonga.postinst [new file with mode: 0644]
mariadb-plugin-mroonga.prerm [new file with mode: 0644]
mariadb-plugin-oqgraph.install [new file with mode: 0644]
mariadb-plugin-provider-bzip2.install [new file with mode: 0644]
mariadb-plugin-provider-bzip2.lintian-overrides [new file with mode: 0644]
mariadb-plugin-provider-lz4.install [new file with mode: 0644]
mariadb-plugin-provider-lz4.lintian-overrides [new file with mode: 0644]
mariadb-plugin-provider-lzma.install [new file with mode: 0644]
mariadb-plugin-provider-lzma.lintian-overrides [new file with mode: 0644]
mariadb-plugin-provider-lzo.install [new file with mode: 0644]
mariadb-plugin-provider-lzo.lintian-overrides [new file with mode: 0644]
mariadb-plugin-provider-snappy.install [new file with mode: 0644]
mariadb-plugin-provider-snappy.lintian-overrides [new file with mode: 0644]
mariadb-plugin-rocksdb.install [new file with mode: 0644]
mariadb-plugin-rocksdb.lintian-overrides [new file with mode: 0644]
mariadb-plugin-s3.install [new file with mode: 0644]
mariadb-plugin-spider.install [new file with mode: 0644]
mariadb-server-core.install [new file with mode: 0644]
mariadb-server-core.links [new file with mode: 0644]
mariadb-server-core.lintian-overrides [new file with mode: 0644]
mariadb-server.NEWS [new file with mode: 0644]
mariadb-server.README.Debian [new file with mode: 0644]
mariadb-server.config [new file with mode: 0644]
mariadb-server.insserv.conf [new file with mode: 0644]
mariadb-server.install [new file with mode: 0755]
mariadb-server.links [new file with mode: 0644]
mariadb-server.lintian-overrides [new file with mode: 0644]
mariadb-server.logcheck.ignore.paranoid [new file with mode: 0644]
mariadb-server.logcheck.ignore.server [new file with mode: 0644]
mariadb-server.logcheck.ignore.workstation [new file with mode: 0644]
mariadb-server.mariadb.init [new file with mode: 0644]
mariadb-server.mysql.default [new file with mode: 0644]
mariadb-server.postinst [new file with mode: 0644]
mariadb-server.postrm [new file with mode: 0644]
mariadb-server.preinst [new file with mode: 0644]
mariadb-server.templates [new file with mode: 0644]
mariadb-server.triggers [new file with mode: 0644]
mariadb-test-data.install [new file with mode: 0644]
mariadb-test-data.lintian-overrides [new file with mode: 0644]
mariadb-test.install [new file with mode: 0644]
mariadb-test.lintian-overrides [new file with mode: 0644]
not-installed [new file with mode: 0644]
patches/0025-Change-the-default-optimization-from-O3-to-O2-in-mys.patch [new file with mode: 0644]
patches/1006531-hurd-no-auth-socket.patch [new file with mode: 0644]
patches/2541-fix-stack-overflow-in-pinbox-allocator.patch [new file with mode: 0644]
patches/env-perl-usr-bin-perl.patch [new file with mode: 0644]
patches/fix-reproducible-builds-rocksdb.patch [new file with mode: 0644]
patches/fix-spelling-libmariadb.patch [new file with mode: 0644]
patches/fix-spelling-mariadb.patch [new file with mode: 0644]
patches/fix-spelling-rocksdb.patch [new file with mode: 0644]
patches/hurd-i386-plugin_disks_information_schema_disks.cc.patch [new file with mode: 0644]
patches/hurd-i386-storage_connect_ioapi.h.patch [new file with mode: 0644]
patches/install-files-into-usr.patch [new file with mode: 0644]
patches/mroonga-mrn-lib-dirs-path-reproducible-build.patch [new file with mode: 0644]
patches/rocksdb-kfreebsd.patch [new file with mode: 0644]
patches/series [new file with mode: 0644]
patches/startup-message.patch [new file with mode: 0644]
po/POTFILES.in [new file with mode: 0644]
po/ar.po [new file with mode: 0644]
po/ca.po [new file with mode: 0644]
po/cs.po [new file with mode: 0644]
po/da.po [new file with mode: 0644]
po/de.po [new file with mode: 0644]
po/es.po [new file with mode: 0644]
po/eu.po [new file with mode: 0644]
po/fi.po [new file with mode: 0644]
po/fr.po [new file with mode: 0644]
po/gl.po [new file with mode: 0644]
po/it.po [new file with mode: 0644]
po/ja.po [new file with mode: 0644]
po/ka.po [new file with mode: 0644]
po/nb.po [new file with mode: 0644]
po/nl.po [new file with mode: 0644]
po/pt.po [new file with mode: 0644]
po/pt_BR.po [new file with mode: 0644]
po/ro.po [new file with mode: 0644]
po/ru.po [new file with mode: 0644]
po/sv.po [new file with mode: 0644]
po/sw.po [new file with mode: 0644]
po/templates.pot [new file with mode: 0644]
po/tr.po [new file with mode: 0644]
po/vi.po [new file with mode: 0644]
po/zh_CN.po [new file with mode: 0644]
rules [new file with mode: 0755]
salsa-ci.yml [new file with mode: 0644]
source/format [new file with mode: 0644]
source/lintian-overrides [new file with mode: 0644]
tests/configuration-tracing [new file with mode: 0755]
tests/control [new file with mode: 0644]
tests/smoke [new file with mode: 0644]
tests/traces/mariadb-print-defaults.expected [new file with mode: 0644]
tests/traces/mariadb-verbose-help.expected [new file with mode: 0644]
tests/traces/mariadbd-print-defaults.expected [new file with mode: 0644]
tests/traces/mariadbd-verbose-help.expected [new file with mode: 0644]
tests/upstream [new file with mode: 0644]
unstable-tests.alpha [new file with mode: 0644]
unstable-tests.amd64 [new file with mode: 0644]
unstable-tests.arm64 [new file with mode: 0644]
unstable-tests.armel [new file with mode: 0644]
unstable-tests.armhf [new file with mode: 0644]
unstable-tests.hppa [new file with mode: 0644]
unstable-tests.hurd [new file with mode: 0644]
unstable-tests.hurd-i386 [new symlink]
unstable-tests.m68k [new file with mode: 0644]
unstable-tests.powerpc [new file with mode: 0644]
unstable-tests.ppc64 [new file with mode: 0644]
unstable-tests.ppc64el [new file with mode: 0644]
unstable-tests.riscv64 [new file with mode: 0644]
unstable-tests.s390x [new file with mode: 0644]
unstable-tests.sh4 [new file with mode: 0644]
unstable-tests.sparc64 [new file with mode: 0644]
upstream/metadata [new file with mode: 0644]
upstream/signing-key.asc [new file with mode: 0644]
watch [new file with mode: 0644]

diff --git a/README.Contributor b/README.Contributor
new file mode 100644 (file)
index 0000000..bf8505b
--- /dev/null
@@ -0,0 +1,420 @@
+# README for Debian packaging contributors
+
+This documentation describes how to contribute to the official Debian packages
+of MariaDB. The packaging in Debian repositories is not identical to the packaging
+in mariadb.org repositories, but whatever is in Debian repositories will eventually
+be upstreamed.
+
+
+## Development environment and tools
+
+Use a recent version of Debian or Ubuntu as the environment for Debian packaging
+testing and development. Preferred environment is Debian Sid (unstable).
+
+Install the tool used to manage and build the source:
+
+    sudo apt-get install git-buildpackage
+
+
+## Getting the source
+
+The official Debian package source is hosted on the Debian Gitlab server under
+the MariaDB/MySQL packaging team at https://salsa.debian.org/mariadb-team/. You
+are welcome to fork it and make merge requests.
+
+To get the latest official Debian packaging source of `mariadb`, clone the
+source repository with all relevant branches (main branch `debian/latest`) to
+your local environment using _git-buildpackage_:
+
+    gbp clone https://salsa.debian.org/mariadb-team/mariadb-server.git
+
+If you have your own fork and SSH keys set up on Salsa, you can run:
+
+    gbp clone git@salsa.debian.org:<username>/mariadb-server.git
+
+
+The clone needs to be run only once. On later runs you can refresh your clone with
+relevant branches using:
+
+    gbp pull --force
+
+
+## Building the packages
+
+Build binaries, run testsuite and build Debian packages with:
+
+    gbp buildpackage
+
+On the first run git-buildpackage will complain if some of the build dependencies
+defined in debian/control are missing. Simply install those packages and run the
+build again.
+
+A quick command to install all dependencies:
+
+    sudo mk-build-deps -r -i debian/control -t "apt-get -y -o Debug::pkgProblemResolver=yes --no-install-recommends"
+
+If the build fails, the easiest way to clean up before a new run is
+
+    git clean -fdx && git reset --hard
+
+
+### Build options
+
+If you want to skip the mysql-test-run step (which takes a lot of time) set
+the following environment variable:
+
+    export DEB_BUILD_OPTIONS="nocheck"
+
+If you want to run the build in parallel on 2 CPUs and have verbose output:
+
+    export DEB_BUILD_OPTIONS="parallel=2 verbose"
+
+The options above can also be combined freely to get desired behavior.
+
+
+### Using special build environments
+
+If you want to ensure all build dependencies are clean, you can build inside a
+Docker or sbuild (Debian tool) environment.
+
+#### Build in Docker
+
+First make a working directory for the build artifacts. Inside that directory
+clone the repository. Then start a Docker session using whatever Debian/Ubuntu
+image you want with the command:
+
+    docker run -it -v ${PWD}:/build -w /build debian:sid bash
+
+This will start a session, where you are as the root user in the path /build
+inside the Docker container. Here you can `cd` into the source directory,
+install dependencies and start the build. Note that when you exit the session,
+everything will be lost apart from the files you had inside the mounted volume
+in `/build`.
+
+#### Build using sbuild
+
+If you prefer sbuild, you can build with something like:
+
+    gbp buildpackage --git-builder=sbuild -A -v -d unstable
+
+## Creating a feature or bugfix branch
+
+The repository layout follows the DEP-14 standard:
+https://dep-team.pages.debian.net/deps/dep14/
+
+All new features and also bug fixes are done only in the `debian/latest` branch.
+The release branches for Debian and Ubuntu are only used for security updates.
+
+To prepare the Salsa pull request, create a bugfix branch from master with:
+
+    git checkout -b bugfix/NNNNNN-example-name
+
+After this you can develop with all the usual git commit and push commands
+until you have in your fork at Salsa the desired change and you are ready
+to open the merge request.
+
+
+### Notes about how to make changes in the proper way
+
+First consider submitting your patch upstream. Upstream MariaDB makes frequent
+maintenance releases and any fix done upstream will therefore be included in
+Debian relatively quickly. You can send email to the developers mailing list
+or open a pull request at https://github.com/MariaDB/server.
+
+Follow these instructions if your fix is about packaging in Debian specifically.
+Start by using `gitk --all` or similar tool to browse the previous changes. Try
+to follow similar pattern in your new changes.
+
+Keep in mind that all changes must done only for files residing in the `debian/`
+sub-directory. If you need to create changes outside the `debian/` directory,
+then you need to create a patch file using the same pattern as the patches
+found in `debian/patches` and activated by a line in `debian/patches/series`.
+
+Do not bundle in your commit any changes to `debian/changelog`. The correct
+changelog entries will be created later by the maintainer using `git-dch` in an
+automated fashion.
+
+For an example of a patch adding commit see
+https://salsa.debian.org/mariadb-team/mariadb-server/-/commit/7972a38e
+
+
+# Quality assurance tips
+
+Ensure most packaging files are formatted correctly:
+
+    wrap-and-sort -vast
+
+Check man pages for syntax errors:
+
+    LC_ALL=en_US.UTF-8 MANROFFSEQ='' MANWIDTH=80 man --warnings -E UTF-8 -l -Tutf8 -Z mariadb.1 >/dev/null
+
+Find spelling errors:
+
+    find * -type f | xargs spellintian
+
+
+# Debugging tips
+
+## Debug mariadb-test-run failures
+
+If the test suite is failing on Launchpad or some other CI system where you
+don't have access to the build artifacts, you can extend the debian/rules file
+to print out valuable information with the commands:
+
+    cd $(BUILDDIR)/mysql-test && find var/log/ -ls || true
+    cd $(BUILDDIR)/mysql-test && cat var/log/*.err || true
+    cd $(BUILDDIR)/mysql-test && tail -n 1000 var/log/*.log || true
+
+The `cd` is required on every line since it is a Makefile and the actual command
+needs to run in the correct directory. Also, the `|| true` at the end ensures
+the build will complete and not abort if any of those debug steps fail.
+
+## Debugging with gdb
+
+If the `mariadb-test-run` fails on a `mariadbd` crash it should produce a core
+dump file, from which a full stack trace can be produced with:
+
+    cd $(BUILDDIR)/mysql-test && gdb --batch --ex 'thr a a bt' var/log/*/mysqld.1/core || true
+
+To attach `gdb` on a running process and get a stack trace run:
+
+    gdb -p $(pgrep -x mariadbd) /usr/sbin/mariadbd
+    set height 0
+    set logging file /tmp/mysqld.log
+    set logging on
+    thread apply all backtrace full
+
+The readability of the stack traces depends on if symbols are available on the
+system. In Debian and Ubuntu all (C/C++) software is automatically built with
+debug symbols, but to save disk space they are distributed in separate packages
+(usually with `-dbg` or `-dbgsym` suffix) which users need to install in the
+rare case stack traces are needed. See the Debian and Ubuntu documentation on
+how to enable the repository that has the debug symbol packages.
+
+* https://wiki.ubuntu.com/Debug%20Symbol%20Packages
+* https://wiki.debian.org/HowToGetABacktrace
+
+## Debug build
+
+A debug build can be created using the following build flags:
+
+    -DCMAKE_BUILD_TYPE=Debug \
+    -DMYSQL_MAINTAINER_MODE=OFF \
+
+The latter flag ensures a build does not stop on warnings but continues to the
+end.
+
+A 'mariadbd' binary from a debug build can be started with argument '--debug' to
+be verbose about what is going on in the server. Debug binaries should not be
+used in production as they are slower than normal binaries.
+
+Core dumps and stack traces can be produced on any build running with
+`--core-file --stack-trace` and *debug builds are not needed to run `gdb`*.
+
+## Debugging a running server
+
+Linux distros come standard with tools like `strace` and `lsof` which can also
+be used to inspect what processes are doing (no need for debug build). For
+example to see what `mariadbd` is writing to the database files can be viewed
+with:
+
+    strace -ffp $(pgrep -x mariadbd) -e pwrite,write,fsync,fdatasync,sync,send,sendto,sendmsg
+    lsof -a -p $(pgrep -x mariadbd) | grep "/var/lib/mysql"
+
+## Compare changes between builds
+
+Diffoscope can be used to investigate small changes between recent builds:
+
+    docker run --rm -t -w $(pwd) -v $(pwd):$(pwd) registry.salsa.debian.org/reproducible-builds/diffoscope --html-dir report mariadb-server-1.deb mariadb-server-2.deb
+    firefox report/index.html
+
+## Test autopkgtest locally
+
+If Debian CI fails (or Ubuntu CI) one might need to debug the autopkgtests
+manually. The easiest way to do it is to start a Docker container that has
+access to the packaging source directory via a local mount:
+
+    laptop$ docker run -it -v ${PWD}:/build -w /build debian:sid bash
+    container$ apt update && apt install -y autopkgtest
+    container$ autopkgtest --no-built-binaries --shell-fail -- null
+
+Edit the files in `debian/tests` in your favorite code editor and re-run the
+`autopkgtest -- null` until the tests are passing. When the autopkgtests work
+the container can be shut down and the valid `debian/tests` committed in git.
+
+If you want to iterate on a single test, use `--test-name`, e.g.
+`autopkgtest --no-built-binaries --test-name=configuration-tracing -- null`.
+
+If you don't want to use the MariaDB binaries from Debian Sid but instead build
+them from the source tree to be used in autopkgtest directly, simply omit
+`--no-built-binaries` from the `autopkgtest` command.
+
+For more information please read:
+* https://manpages.debian.org/unstable/autopkgtest/autopkgtest.1.en.html
+* https://salsa.debian.org/ci-team/autopkgtest/-/tree/master/doc
+
+## Debug installation/upgrade
+
+To see what exactly the Debian maintainer scripts run, they can be made verbose with:
+
+    export DEBIAN_SCRIPT_DEBUG=1
+    apt install ...
+
+The source files of the Debian maintainer scripts are not the final ones, as the
+package building stage may make changes and additions to them. To view a
+maintainer script in the final form on an installed system run:
+
+    cat /var/lib/dpkg/info/mariadb-server.postinst
+
+To review the my.cnf status run:
+
+    find /etc/mysql/ -ls
+    update-alternatives --display my.cnf
+
+## Debug apt Depends/Conflicts/Breaks
+
+It can be quite frustrating to debug situations where `apt` (or `apt-get`) fails
+on an install or upgrade with an error message like:
+
+    The following packages have unmet dependencies:
+     mariadb-client : Depends: mariadb-client-10.5 but 1:10.5.12 is to be installed
+     mariadb-server : Depends: mariadb-server-10.5 but 1:10.5.12 is to be installed
+     mariadb-test : Depends: mariadb-client-10.5 but 1:10.5.12 is to be installed
+                    Depends: mariadb-server-10.5 but 1:10.5.12 is to be installed
+    E: Unable to correct problems, you have held broken packages.
+
+To make apt show debug information on what it tried to resolve and how it failed
+enable debug features by addin a file in `/etc/apt/apt.conf.d/` with:
+
+   Debug::pkgProblemResolver 1;
+   Debug::pkgDepCache::AutoInstall 1;
+   Debug::pkgDepCache::Marker 1;
+
+>lternatively append options directly to `apt` commands:
+
+    apt dist-upgrade -o Debug::pkgProblemResolver=1
+
+It can be also quite annoying to rebuild the entire package to debug small
+changes in the `debian/control` file. To have a much faster change->test->change
+cycle one can simply instruct `apt` to use a custom `Packages` file to read the
+`control` data.
+
+First ensure `apt` forgets all repositories:
+
+    rm /etc/apt/sources.list
+    apt clean
+    apt update
+
+Download a Packages file for so it can be edited:
+
+    curl -O http://ftp.debian.org/debian/dists/sid/main/binary-amd64/Packages.xz
+    unxz Packages.xz
+    cp Packages Packages.orig
+
+Open the file in an editor, scroll down to the MariadB packages and make any
+changes you want and then test them:
+
+    nano Packages
+    apt install --with-source ./Packages -s mariadb-server -o Debug::pkgDepCache::Marker=1 -o Debug::pkgDepCache::AutoInstall=1 -o Debug::pkgProblemResolver=1
+
+The example uses maximum verbosity but it is naturally not mandatory. When the
+solution has been found, compare to the original and transfer the changes into
+the actual debian/control in the MariaDB packaging:
+
+    diff -u Packages.orig Packages
+
+## Test install/upgrade with local package repository
+
+Normally the fastest way to test that the built *.deb files install and upgrade
+properly is simply to run `apt` directly on them inside a container that has
+access to the .deb files via a local mount:
+
+    laptop$ docker run -it -v ${PWD}:/build -w /build debian:sid bash
+    container$ apt update && apt install ./*.deb
+
+Some bugs however occur only when apt does various dependency resolving and can
+only be tested with an installation from an actual apt repository. The fastest
+way to get a directory with deb files served via a local repository is to run:
+
+    apt install apt-utils
+    apt-ftparchive packages . > Packages
+    apt-ftparchive release . > Release
+    echo 'deb [trusted=yes] file:/build/mariadb-bionic ./' >> /etc/apt/sources.list
+    apt update
+    apt install mariadb-server
+
+The example above assumes that the .deb files are in path `/build`.
+
+## Check Breaks/Replaces
+
+MariaDB is not only a massive package by itself, it also has several parallel
+major releases at any given time and also other variants (MySQL, Percona Server)
+the packaging might interact with.
+
+The standard Salsa-CI pipeline checks Breaks/Replaces for what is currently in
+the Debian repositories, but to check Breaks/Replaces across all known
+repositories one needs to run:
+
+    docker run -it -v ${PWD}:/build -w /build debian:sid bash
+    apt update
+    apt install --yes python3-junit.xml python3-debian apt-file
+    curl -O https://salsa.debian.org/salsa-ci-team/pipeline/-/raw/master/images/scripts/check_for_missing_breaks_replaces.py
+    chmod +x check_for_missing_breaks_replaces.py
+    apt install --no-install-recommends --yes gpg gpg-agent dirmngr ca-certificates curl debian-archive-keyring
+    curl -sS https://mariadb.org/mariadb_release_signing_key.asc -o /etc/apt/trusted.gpg.d/mariadb.asc
+    gpg --list-keys # Initialize default keyring
+    gpg --no-default-keyring --keyring gnupg-ring:/etc/apt/trusted.gpg.d/mariadb.gpg --keyserver hkps://keyserver.ubuntu.com:443 --recv-keys 871920D1991BC93C 3B4FE6ACC0B21F32 CBF8D6FD518E17E1 7638D0442B90D010 8C718D3B5072E1F5 9334A25F8507EFA5 CBCB082A1BB943DB 467B942D3A79BD29
+    chmod 644 /etc/apt/trusted.gpg.d/mariadb.gpg
+    cat > /etc/apt/sources.list.d/mariadb.list <<EOF
+    deb http://deb.debian.org/debian bullseye main
+    deb http://deb.debian.org/debian buster main
+    deb http://deb.debian.org/debian stretch main
+    deb [trusted=yes] http://deb.debian.org/debian jessie main
+    deb http://archive.ubuntu.com/ubuntu/ jammy main restricted universe multiverse
+    deb http://archive.ubuntu.com/ubuntu/ focal main restricted universe multiverse
+    deb http://archive.ubuntu.com/ubuntu/ bionic main restricted universe multiverse
+    deb http://archive.ubuntu.com/ubuntu/ xenial main restricted universe multiverse
+    deb http://archive.ubuntu.com/ubuntu/ trusty main restricted universe multiverse
+    deb https://archive.mariadb.org/mariadb-10.11/repo/debian bullseye main
+    deb https://archive.mariadb.org/mariadb-10.10/repo/debian bullseye main
+    deb https://archive.mariadb.org/mariadb-10.9/repo/debian bullseye main
+    deb https://archive.mariadb.org/mariadb-10.8/repo/debian bullseye main
+    deb https://archive.mariadb.org/mariadb-10.7/repo/debian bullseye main
+    deb https://archive.mariadb.org/mariadb-10.6/repo/debian buster main
+    deb https://archive.mariadb.org/mariadb-10.5/repo/debian buster main
+    deb https://archive.mariadb.org/mariadb-10.4/repo/debian buster main
+    deb https://archive.mariadb.org/mariadb-10.3/repo/debian buster main
+    deb https://archive.mariadb.org/mariadb-10.2/repo/debian buster main
+    deb https://archive.mariadb.org/mariadb-10.1/repo/debian stretch main
+    deb [trusted=yes] https://archive.mariadb.org/mariadb-10.0/repo/debian jessie main
+    deb [trusted=yes] https://archive.mariadb.org/mariadb-5.5/repo/debian wheezy main
+    deb https://repo.mysql.com/apt/ubuntu/ jammy mysql-8.0
+    deb https://repo.mysql.com/apt/ubuntu/ focal mysql-8.0
+    deb https://repo.mysql.com/apt/debian/ buster mysql-8.0
+    deb https://repo.mysql.com/apt/debian/ buster mysql-5.7
+    deb https://repo.mysql.com/apt/debian/ buster mysql-5.6
+    deb https://repo.mysql.com/apt/debian/ buster mysql-cluster-8.0
+    deb https://repo.mysql.com/apt/debian/ buster mysql-cluster-7.6
+    deb https://repo.mysql.com/apt/debian/ buster mysql-cluster-7.5
+    deb https://repo.mysql.com/apt/debian/ buster mysql-tools
+    deb https://repo.percona.com/apt/ bullseye main
+    deb https://repo.percona.com/apt/ buster main
+    deb https://repo.percona.com/apt/ stretch main
+    deb https://repo.percona.com/apt/ jessie main
+    deb https://repo.percona.com/apt/ wheezy main
+    EOF
+    apt-file update
+    ./check_for_missing_breaks_replaces.py --changes-file mariadb-*.changes --debug
+
+## Check reverse dependencies
+
+When making changes to the MariaDB packaging in Debian and Ubuntu, keep in mind
+that there are hundreds of packages that depend on MariaDB. Most of them can be
+found by running:
+
+    apt rdepends 'default-mysql*' 'default-libmysql*' 'mariadb*' 'libmariadb*'
+
+The separate command/package 'apt-rdepends' can also check for reverse
+build-dependencies.
+
+Please be diligent in all changes to not wreak havoc in Debian.
diff --git a/README.Maintainer b/README.Maintainer
new file mode 100644 (file)
index 0000000..419826d
--- /dev/null
@@ -0,0 +1,212 @@
+# README for Debian package maintainers
+
+This file mostly applies to how the packaging work-flow works for the official
+Debian packages, but it may contain useful information also for anybody doing
+their own private .deb builds.
+
+## Version control
+
+This package is maintained by the MariaDB/MySQL team in Debian using the
+git-buildpackage tool and storing the git repositories on the Debian Gitlab
+instance Salsa. For details see https://salsa.debian.org/mariadb-team/.
+
+The official Ubuntu packages are also maintained by the same team using the same
+source repository.
+
+### Ensuring git contents match what has been uploaded to Debian/Ubuntu
+
+It is possible (but extremely rare) that somebody uploads a MariaDB package to
+Debian/Ubuntu and either does not use git at all, or simply forgets to push the
+same changes on git, or makes an error in tagging the release or something.
+Therefore, maintainers should check that the git contents match what has been
+uploaded to Debian/Ubuntu before making new changes on git.
+
+This can be done by using dgit. The example command below will fetch the latest
+mariadb-10.1 package available in Ubuntu 18.04 (Bionic) base archive, security
+archive or updates archive (whichever has a newer version):
+
+    dgit -d ubuntu clone mariadb-10.6 jammy,-security,-updates
+    cp -ra mariadb-10.6/* .
+    rm -rf mariadb-10.6
+
+You can then compare these two directories with a recursive diff or `git diff`.
+
+
+Another option is to manually check on packages.debian.org or packages.ubuntu.com
+what is the latest version, and download and extract it on top of the existing
+debian/ directory with:
+
+    curl -SL https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/mariadb-10.6/\
+    1:10.6.7-2ubuntu1.1/mariadb-10.6_10.6.7-2ubuntu1.1.debian.tar.xz -o - | tar xv --xz
+
+You can simply run `git diff` to see the report on differences.
+
+
+## Building from sources with git-buildpackage
+
+See README.Contributor for details.
+
+
+## Upgrading sources from upstream
+
+Upstream will publish maintenance releases at least 5 years after the major
+version release, and security updates are likely to come even after that as
+long as major distributions ship the version.
+
+See table at
+https://mariadb.com/kb/en/mariadb/development/mariadb-maintenance-policy/
+
+Release notes are available at
+https://mariadb.com/kb/en/mariadb/development/release-notes/
+
+
+### Steps to import new upstream version
+
+Download new source package:
+
+    git checkout 10.11
+    git pull --tags upstream 10.11
+    git tag -v mariadb-10.11.3
+    git checkout debian/latest
+    git merge -v mariadb-10.11.3
+
+Refresh patches:
+
+    while quilt push; do quilt refresh; done; quilt pop -a
+
+Simple offsets will be updated automatically. If there are any rejects, inspect
+the files and update the patches or discard the patch completely if you are
+_sure_ that it has been applied upstream.
+
+Generate new debian/changelog entry automatically with git-dch:
+
+    gbp dch -vR
+
+Edit the details to match correct release:
+
+    gedit debian/changelog &
+
+Commit to git:
+
+    git citool
+
+Build and test locally to verify it works:
+
+    gbp buildpackage
+
+Alternatively you can use Docker with something like this:
+
+    mkdir ccache buildout
+    docker run -it -v "${PWD}/buildout":/tmp/build -v "${PWD}/ccache":/.ccache \
+       -v "${PWD}/$PKG":/tmp/build/source -w /tmp/build/source \
+       -e DEB_BUILD_OPTIONS="$DEB_BUILD_OPTIONS" -e CCACHE_DIR=/var/cache/ccache \
+       --user=1001 registry.gitlab.com/mariadb/mariadb.org-build-containers:$PKG-debian-sid-build-env \
+       gbp buildpackage | tee latest.build
+
+If needed, add commits or amend the ones you made until the package is in
+perfect shape.
+
+Let Lintian automatically check as much as possible:
+
+    lintian -EvIL +pedantic --color=always *.changes
+
+Then proceed to make a source only build:
+
+    gbp buildpackage -S
+
+Test more with upload to Launchpad:
+
+    COMMIT_ID=`git log -n 1 --oneline | cut -d ' ' -f 1`
+    PKG=mariadb-10.6
+    backportpackage --yes -u ppa:mysql-ubuntu/$PKG -d groovy -S ~`date '+%s'`.$COMMIT_ID $PKG*.dsc
+
+When done, push to Salsa:
+
+    gbp push # gbp branches and tags
+    git push # master branch
+
+Wait until the Salsa CI pipeline finishes. If it did not either spot any
+regressions, proceed to tagging the commit:
+
+    gbp tag
+    gbp push
+
+Once you are sure there are no regressions, finally upload to Debian:
+
+    dput ftp-master *.changes
+
+After the upload, check that everything is OK at
+* https://tracker.debian.org/mariadb (Debian)
+* https://launchpad.net/ubuntu/+source/mariadb-10.6 (Ubuntu)
+
+## Maintaining translations
+
+Running `debconf-updatepo --verbose` will refresh the translation files.
+
+A call for translations can be initiated with e.g. `podebconf-report-po --call -v --smtp=smtp.kolumbus.fi`.
+
+### Launchpad testing matrix
+
+Since Launchpad only has Ubuntu releases, packages for specific Debian releases
+needs to be tested on the Ubuntu release which most closely matches the Debian
+release in question. The following matrix maps what package should be tested
+where:
+
+- 10.6 for sid on Launchpad lunar
+- 10.6 for kinetic on Launchpad kinetic
+- 10.6 for jammy on Launchpad jammy
+- 10.5 for bullseye on Launchpad hirsute (not available anymore)
+- 10.3 for focal on Launchpad focal
+- 10.3 for buster on Launchpad disco (not available anymore)
+- 10.1 for bionic on Launchpad bionic
+- 10.1 for stretch on Launchpad xenial (not available anymore)
+
+## Uploading security releases to Debian
+
+After you've got permission from the security team, upload with `dput security-master *.changes`.
+
+For details see https://www.debian.org/doc/manuals/developers-reference/pkgs.html#bug-security
+
+## Uploading security releases to Ubuntu
+
+See example with documented procedure:
+ * https://bugs.launchpad.net/ubuntu/+source/mariadb-10.3/+bug/1861260
+
+### Upload priority
+
+Do the security uploads in this order for having the best chance of catching
+regressions before they spread out to too many users.
+
+Upload priority for 10.6
+- debian sid
+- ubuntu-22.10 kinetic
+- ubuntu-22.04 jammy
+
+Upload priority for 10.5
+- debian-11 bullseye
+
+Upload priority for 10.3
+- ubuntu-20.04 focal
+- debian-10 buster
+
+for 10.1 (only in case there are extra releases after official EOL)
+- ubuntu-18.04 bionic
+- debian-9 stretch
+
+## Comparison to other distributions
+
+For tracking security release information, finding solutions for build errors
+on many architectures and for general quality control it can be useful to keep
+an eye on what packagers in other distributions do:
+
+Fedora:
+  * https://apps.fedoraproject.org/packages/mariadb/
+  * http://pkgs.fedoraproject.org/cgit/mariadb.git/
+OpenSUSE:
+  * https://build.opensuse.org/package/show/server:database/mariadb
+Arch Linux:
+  * https://projects.archlinux.org/svntogit/packages.git/?h=packages/mariadb
+Mageia:
+  * http://svnweb.mageia.org/packages/cauldron/mariadb/current/
+
+See also: https://repology.org/project/mariadb/badges
diff --git a/additions/debian-start b/additions/debian-start
new file mode 100755 (executable)
index 0000000..d85e4a1
--- /dev/null
@@ -0,0 +1,50 @@
+#!/bin/bash
+#
+# This script is executed by both SysV init /etc/init.d/mariadb and
+# systemd mariadb.service on every (re)start.
+#
+# Changes to this file will be preserved when updating the Debian package.
+#
+
+# shellcheck source=debian/additions/debian-start.inc.sh
+source /usr/share/mysql/debian-start.inc.sh
+
+# Read default/mysql first and then default/mariadb just like the init.d file does
+if [ -f /etc/default/mysql ]
+then
+  # shellcheck source=/dev/null
+  . /etc/default/mysql
+fi
+
+if [ -f /etc/default/mariadb ]
+then
+  # shellcheck source=/dev/null
+  . /etc/default/mariadb
+fi
+
+MARIADB="/usr/bin/mariadb --defaults-file=/etc/mysql/debian.cnf"
+MYADMIN="/usr/bin/mariadb-admin --defaults-file=/etc/mysql/debian.cnf"
+# Don't run full mariadb-upgrade on every server restart, use --version-check to do it only once
+MYUPGRADE="/usr/bin/mariadb-upgrade --defaults-extra-file=/etc/mysql/debian.cnf --version-check --silent"
+MYCHECK_SUBJECT="WARNING: mariadb-check has found corrupt tables"
+MYCHECK_RCPT="${MYCHECK_RCPT:-root}"
+
+## Checking for corrupt, not cleanly closed (only for MyISAM and Aria engines) and upgrade needing tables.
+
+# 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!)
+
+# Need to ignore SIGHUP, as otherwise a SIGHUP can sometimes abort the upgrade
+# process in the middle.
+trap "" SIGHUP
+(
+  upgrade_system_tables_if_necessary;
+  check_root_accounts;
+  check_for_crashed_tables;
+) >&2 &
+
+exit 0
diff --git a/additions/debian-start.inc.sh b/additions/debian-start.inc.sh
new file mode 100755 (executable)
index 0000000..f6929f7
--- /dev/null
@@ -0,0 +1,92 @@
+#!/bin/bash
+#
+# This file is included by /etc/mysql/debian-start
+#
+
+## Check MyISAM and Aria 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 and aria-recover for all Aria tables"
+
+  # Checking for $? is unreliable so the size of the output is checked.
+  # Some table handlers like HEAP do not support CHECK TABLE.
+  tempfile=$(mktemp)
+
+  # We have to use xargs in this case, because a for loop barfs on the
+  # spaces in the thing to be looped over.
+
+  # If a crashed table is encountered, the "mariadb" command will return with a status different from 0
+  #
+  # The first query will generate lines like.
+  #   select count(*) into @discard from 'mysql'.'db'
+  # The second line will load all tables without printing any actual results,
+  # but may show warnings and definitely is expected to have some error and
+  # exit code if crashed tables are encountered.
+  #
+  # Note that inside single quotes must be quoted with '\'' (to be outside of single quotes).
+  set +e
+  # The $MARIADB is intentionally used to expand into a command and arguments
+  # shellcheck disable=SC2086
+  LC_ALL=C echo '
+    SELECT CONCAT("select count(*) into @discard from '\''", TABLE_SCHEMA, "'\''.'\''", TABLE_NAME, "'\''")
+    FROM information_schema.TABLES WHERE TABLE_SCHEMA<>"INFORMATION_SCHEMA" AND TABLE_SCHEMA<>"PERFORMANCE_SCHEMA"
+    AND (ENGINE="MyISAM" OR ENGINE="Aria")
+    ' |
+    $MARIADB --skip-column-names --batch |
+    xargs -i $MARIADB --skip-column-names --silent --batch --force -e "{}" &> "${tempfile}"
+  set -e
+
+  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 MariaDB 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 \
+    | grep -E -v '^(1|@had|ERROR (1051|1054|1060|1061|1146|1347|1348))' \
+    | 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='' and plugin in ('', 'mysql_native_password', 'mysql_old_password');" | $MARIADB --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/additions/echo_stderr b/additions/echo_stderr
new file mode 100755 (executable)
index 0000000..67b3ed7
--- /dev/null
@@ -0,0 +1,2 @@
+#!/bin/bash
+echo "$*" 1>&2
diff --git a/additions/innotop/changelog.innotop b/additions/innotop/changelog.innotop
new file mode 100644 (file)
index 0000000..1816595
--- /dev/null
@@ -0,0 +1,441 @@
+Changelog for innotop:
+
+2017-01-20: version 1.11.4
+       * add SUM function for ONLY_FULL_GROUP_BY
+
+2017-01-20: version 1.11.3
+
+       * Undisplay handlersocket's threads in hide_inactive
+       * fix runtime error regarding redundant sprintf argument #122
+       * added sort on connection-name in display M, after sql/io running, seconds behind master and channel_name
+       * fixed bug that removed value for cxn and channel_name columns in display M
+       * added sort on replication delay, so that the replication-display will sort on slave_sql_running, timelag (in minutes) and channel_name. 
+       * support for MariaDB 10.0 in InnoDB row (issue 93)
+
+2013-07-12: version 1.9.1
+
+   Bugs fixed:
+       * Support of MySQL 5.6 was broken on some pages (issue 82, 83)
+       * Deadlock clearing transactions is now not included in binary log
+       (issue 84)
+       * New spec file with requirements and build requirements for
+       CentOS/RHEL and Fedora
+
+2012-09-07: version 1.9.0
+
+   Changes:
+       * A new Health Dashboard (A) mode is the default mode.
+       * Added a new InnoDB Locked (K) mode.
+       * Added a new 'spark' config variable for sparklines.
+       * Added a new fuzzy_time formatting function.
+       * Added "query distill" summarizing.
+       * Handled more types of errors connecting to the server.
+       * Displayed some data more compactly.
+
+   Bugs fixed:
+       * Double-quotes were used to terminate strings in SQL (issue 57).
+       * T mode didn't show InnoDB transaction times (issue 67).
+       * Killing a query didn't suggest the longest-running one automatically.
+       * Connections weren't closed on exit (issue 64).
+       * Q mode didn't have connections in its header (issue 63).
+       * Connections and server groups were poorly handled (issue 68).
+       * The RPM spec file was buggy (issue 59).
+       * Event filters were defined wrong (issue 54).
+
+2012-02-25: version 1.8.1
+
+   Bugs fixed:
+   * Various parsing errors with MySQL 5.5 (issue 23, 45, 47, 51, 52, 53).
+   * RPM spec file prevented building on CentOS 5.5 using mock (issue 44).
+   * Tests worked only from the test subdirectory (issue 43).
+
+2010-11-06: version 1.8.0
+
+   Changes:
+   * Don't re-fetch SHOW VARIABLES every iteration; it's too slow on many hosts.
+   * Add a filter to remove EVENT threads in SHOW PROCESSLIST (issue 32).
+   * Add a timestamp to output in -n mode, when -t is specified (issue 37).
+   * Add a new U mode, for Percona/MariaDB USER_STATISTICS (issue 39).
+   * Add support for millisecond query time in Percona Server (issue 39).
+   * Display a summary of queries executed in Query List mode (issue 26).
+
+   Bugs fixed:
+   * Made config-file reading more robust (issue 41).
+   * Hostname parsing wasn't standards compliant (issue 30).
+   * MKDEBUG didn't work on some Perl versions (issue 22).
+   * Don't try to get InnoDB status if have_innodb != YES (issue 33).
+   * Status text from the InnoDB plugin wasn't parsed correctly (issue 36).
+   * Transaction ID from InnoDB plugin wasn't subtracted correctly (issue 38).
+   * Switching modes and pressing ? for help caused a crash (issue 40).
+
+2009-09-06: version 1.7.2
+
+   Changes:
+   * add support for --socket
+
+   Bugs fixed:
+   * remove cxn from $meta->{group_by} if there's only one connection displayed
+   * fix for issue 19 - cxn column won't become visible when viewing two 
+     connections after having viewed one connection
+   * suppress errors resulting from the addition of a 'BACKGROUND THREAD' 
+     section in the output of 'show innodb status' 
+   * possible fix for issue 22 - Useless use of a constant in void context
+   * small change to set_to_tbl() around hiding the cxn column if there 
+     aren't two or more connections
+
+2009-03-09: version 1.7.1
+
+   Changes:
+   * Don't display the CXN column if only one connection is active in 
+     the current view
+   * the 'state' column is now visible by default in Query List mode
+
+   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/additions/innotop/innotop b/additions/innotop/innotop
new file mode 100755 (executable)
index 0000000..e0de8cc
--- /dev/null
@@ -0,0 +1,12263 @@
+#!/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.
+# Maintainers since 2013 : Kenny Gryp - Frédéric Descamps
+# 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., 51 Franklin
+# Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+use strict;
+use warnings;
+use utf8;
+use feature ':5.16';
+use warnings FATAL => 'all';
+
+our $VERSION = '1.11.4';
+
+# 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} || 0;
+
+# 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  => 'mariadb_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  => 'mariadb_socket',
+            copy => 1,
+         },
+         u => {
+            desc => 'User for login if not current user',
+            dsn  => 'user',
+            copy => 1,
+         },
+      },
+   };
+   foreach my $opt ( @opts ) {
+      if (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:MariaDB:' . ( $info->{D} || '' ) . ';'
+         . join(';', map  { "$opts{$_}->{dsn}=$info->{$_}" }
+                     grep { defined $info->{$_} }
+                     qw(F h P S A))
+         . ';mariadb_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,
+   };
+   @{$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, ':encoding(UTF-8)')
+                  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 ( !$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->{mariadb_hostinfo} || 'undef'),
+      ' Character set info: ',
+      Dumper($dbh->selectall_arrayref(
+         'SHOW VARIABLES LIKE "character_set%"', { Slice => {}})),
+      ' $DBD::MariaDB::VERSION: ', $DBD::MariaDB::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->{mariadb_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);
+use POSIX qw(strftime);
+
+# Some common patterns
+my $d  = qr/(\d+)/;                    # Digit
+my $f  = qr/(\d+\.\d+)/;               # Float
+my $t  = qr/((?:\d+ \d+)|(?:[A-Fa-f0-9]+))/;                # 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",
+   "BACKGROUND THREAD"                     => "bt",
+);
+
+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, $mysqlversion ) = @_;
+
+   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;
+   if ( ($mysqlversion =~ /^5\.[67]\./) || ($mysqlversion =~ /^10|11\.[0-9]\./) ) {
+      ( $time_text ) = $fulltext =~ m/^([0-9-]* [0-9:]*) [0-9a-fx]* INNODB MONITOR OUTPUT/m;
+      $innodb_data{'ts'} = [ parse_innodb_timestamp_56( $time_text ) ];
+   } else {
+      ( $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 ];
+   }
+
+   # 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};
+         if ( !$header && $debug ) {
+            warn "Unknown section $section in $fulltext\n";
+         }
+
+         # The last section in the file 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.  In different versions of InnoDB, various sections are
+         # last.
+         if ( $innodb_sections{$section}->[0] =~ s/\n---+\nEND OF INNODB.+\n=+$// ) {
+            $innodb_sections{$section}->[1] ||= $innodb_data{'got_all'};
+         }
+
+         if ( $header && $section ) {
+            $innodb_data{'sections'}->{ $header }
+               ->{'fulltext'} = $innodb_sections{$section}->[0];
+            $innodb_data{'sections'}->{ $header }
+               ->{'complete'} = $innodb_sections{$section}->[1];
+         }
+         else {
+            _debug( $debug, "header = " . ($header || 'undef') . ", section = " . ($section || 'undef')) if $debug;
+         }
+      }
+   };
+   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,
+                  $mysqlversion)
+               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, $mysqlversion ) = @_;
+
+   # Parse the status text...
+   my $innodb_status
+      = $self->parse_status_text($fulltext, $debug, $sections, $full, $mysqlversion );
+
+   # 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;
+   if ( ! defined $text ) {
+        return (0, 0, 0, 0, 0, 0);
+   }
+   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_innodb_timestamp_56 {
+   my $text = shift;
+   my ( $y, $m, $d, $h, $i, $s )
+      = $text =~ m/^(\d\d\d\d)-(\d\d)-(\d\d) +(\d+):(\d+):(\d+)$/;
+   die("Can't get timestamp from $text\n") unless $y;
+   return ( $y, $m, $d, $h, $i, $s );
+}
+
+sub parse_fk_section {
+   my ( $section, $complete, $debug, $full, $mysqlversion ) = @_;
+   my $fulltext = $section->{'fulltext'};
+
+   return 0 unless $fulltext;
+
+   my ( $ts, $type );
+   if ( ($mysqlversion =~ /^5.[67]\./) || ($mysqlversion =~ /^10|11.[0-9]\./) ) {
+      ( $ts, $type ) = $fulltext =~ m/^([0-9-]* [0-9:]*)\s[0-9a-fx]*\s+(\w+)/m;
+      $section->{'ts'} = [ parse_innodb_timestamp_56( $ts ) ];
+   } else {
+      ( $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;
+   if ( !defined $section->{reason} ) {
+      ( $section->{'reason'} ) = $fulltext =~ m/(Trying to add .*)/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 ) = @_;
+   # Use bare return as recommend in page 199 of PBP
+   return 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, $mysqlversion ) = @_;
+   return unless $dl;
+   my $fulltext = $dl->{'fulltext'};
+   return 0 unless $fulltext;
+
+   my ( $ts ) = $fulltext =~ m/^$s$/m;
+   return 0 unless $ts;
+
+   if ( ($mysqlversion =~ /^5\.[67]\./) || ($mysqlversion =~ /^10|11\.[0-9]\./) ) {
+      $dl->{'ts'} = [ parse_innodb_timestamp_56( $ts ) ];
+   }
+   else {
+      $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 )
+      = $txn
+      =~ m/^(?:---)?TRANSACTION $t, ([^\n0-9,]*[^\s\d])/m;
+   $txn_status =~ s/,$// if $txn_status;
+   my ( $active_secs)
+      = $txn
+      =~ m/^[^\n]*\b$d sec\b/m;
+   my ( $proc_no )
+      = $txn
+      =~ m/process no $d/m;
+   my ( $os_thread_id )
+      = $txn
+      =~ m/OS thread id $d/m;
+   my ( $thread_status, $thread_decl_inside )
+      = $txn
+      =~ m/(?:OS thread id \d+|\d sec)(?: ([^,]+?))?(?:, 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/^((?:MariaDB|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/^(?:MariaDB|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;
+               if ( ($hostname || '') eq 'Slave' ) {
+                  $hostname     = '';
+                  $user         = 'system user';
+                  $query_status = "Slave has $query_status";
+               }
+            }
+            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 [0-9A-Fa-f].*?)(?=\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|flushes), $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;
+   if ( ! defined $section->{inserts} ) {
+      @{$section}{ 'inserts' }
+         = $fulltext =~ m/merged operations:\n  insert $d,/s;
+      # This isn't really true, but it's not really important either. We already
+      # aren't supporting the 'delete' operations.
+      @{$section}{ 'merged_recs', 'merges' } = (0, 0);
+   }
+
+   @{$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;
+   if ( ! defined $section->{rw_shared_spins} ) {
+      @{$section}{ 'rw_shared_spins', 'rw_shared_os_waits'}
+         = $fulltext =~ m/^RW-shared spins $d, rounds \d+, OS waits $d$/m;
+      @{$section}{ 'rw_excl_spins', 'rw_excl_os_waits' }
+         = $fulltext =~ m/^RW-excl spins $d, rounds \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., 51 Franklin
+Street, Fifth Floor, Boston, MA 02110-1335 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
+   agghide => 0,        # Whether NOT to show 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 => 'spark=i',    d => 'Length of status sparkline (default 10)', c=> 'spark' },
+   { 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 => 'askpass',    d => 'Prompt for a password when connecting to MySQL'},
+   { s => 'host|h=s',   d => 'Connect to host' },
+   { s => 'port|P=i',   d => 'Port number to use for connection' },
+   { s => 'socket|S=s', d => 'MySQL socket to use for connection' },
+   { s => 'timestamp|t+', d => 'Print timestamp in -n mode (1: per iter; 2: per line)' },
+);
+
+# 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{'askpass'} ) {
+    $opts{'p'} = noecho_password("Enter password ");
+}
+
+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);
+}
+
+if ( defined($opts{p}) && length($opts{p}) == 0 ) {
+   print "Enter password: ";
+   ReadMode('noecho');
+   $opts{p} = <STDIN>;
+   chomp($opts{p});
+   ReadMode('normal');
+}
+
+# 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-z0-9-]+))/i; 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 },
+   Connection        => q{ max_connections || $cur->{Threads_connected} },
+   chcxn_2_cxn       => q{ if ( defined($cur->{cxn}) ) { return $cur->{cxn}; } else { my ($cha, $conn) = split ("=",$cur->{chcxn}) ;  return $conn; } },
+   chcxn_2_ch        => q{ if ( defined($cur->{channel_name}) ) { return $cur->{channel_name}; } else { my ($cha, $conn) = split ("=",$cur->{chcxn}) ; $cha = '' if ($cha = /no_channels/); return $cha || 'failed'; } },
+   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)},
+   QueryDetail       => q{sprintf("%2d/%2d/%2d/%2d",
+                           ((Com_select||0)+(Qcache_hits||0))/(Questions||1)*100,
+                            ((Com_insert||0)+(Com_replace||0))/(Questions||1)*100,
+                            (Com_update||0)/(Questions||1)*100,
+                            (Com_delete||0)/(Questions||1)*100,
+)},
+);
+
+# ###########################################################################
+# 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 => 'Additional 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' },
+   blocking_thread             => { hdr => 'BThread',             num => 1, label => 'Blocking thread' },
+   blocking_query              => { hdr => 'Blocking Query',      num => 0, label => 'Blocking query' },
+   blocking_rows_modified      => { hdr => 'BRowsMod',            num => 1, label => 'Blocking number rows modified' },
+   blocking_age                => { hdr => 'BAge',                num => 1, label => 'Blocking age' },
+   blocking_wait_secs          => { hdr => 'BWait',               num => 1, label => 'Blocking wait time' },
+   blocking_user               => { hdr => 'BUser',               num => 0, label => 'Blocking user' },
+   blocking_host               => { hdr => 'BHost',               num => 0, label => 'Blocking host' },
+   blocking_db                 => { hdr => 'BDB',                 num => 0, label => 'Blocking database' },
+   blocking_status             => { hdr => 'BStatus',             num => 0, label => 'Blocking thread status' },
+   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' },
+   channel_name                => { hdr => 'Channel',             num => 0, label => 'The name of the replication channel' },
+   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 },
+   connections                 => { hdr => 'Cxns',                num => 1, label => 'Connections' },
+   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' },
+   executed_gtid_set           => { hdr => 'Executed GTID Set',   num => 0, label => 'Executed GTID Set', },
+   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', agghide => 1 },
+   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' },
+   locked_count                => { hdr => 'Lock',                num => 1, label => 'Number of locked threads' },
+   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_info                   => { hdr => 'Lock Info',           num => 0, label => 'Lock information' },
+   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' },
+   longest_sql                 => { hdr => 'SQL',                 num => 0, label => 'Longest-running SQL statement' },
+   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' },
+   master_uuid                 => { hdr => 'Master UUID',         num => 0, label => 'Master UUID', },
+   max_txn                     => { hdr => 'MaxTxnTime',          num => 1, label => 'MaxTxn' },
+   max_query_time              => { hdr => 'MaxSQL',              num => 1, label => 'Longest running SQL' },
+   merged_recs                 => { hdr => 'Merged Recs',         num => 1, label => 'Merged records' },
+   merges                      => { hdr => 'Merges',              num => 1, label => 'Merges' },
+   miss_rate                   => { hdr => 'Miss',                num => 1, label => 'InnoDB buffer pool miss rate' },
+   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' },
+   'open'                      => { hdr => 'Tbls',                num => 1, label => 'Number of open tables' },
+   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_detail                    => { hdr => 'Se/In/Up/De%',        num => 0, label => 'Detailed Query', },
+   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' },
+   retrieved_gtid_set          => { hdr => 'Retrieved GTID Set',  num => 0, label => 'Retrieved GTID Set', },
+   row_locks                   => { hdr => 'RLocks',              num => 1, label => 'Number of row locks' },
+   rows_changed                => { hdr => 'Changed',             num => 1, label => 'Number of rows changed' },
+   rows_changed_x_indexes      => { hdr => 'Chg X Idx',           num => 1, label => 'Number of rows changed X indexes' },
+   rows_read                   => { hdr => 'Reads',               num => 1, label => 'Number of rows read' },
+   rows_read_from_indexes      => { hdr => 'Reads Via Idx',       num => 1, label => 'Number of rows read from indexes' },
+   run                         => { hdr => 'Run',                 num => 1, label => 'Threads_running' },
+   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' },
+   spark_qps                   => { hdr => 'QPS',                 num => 0, label => 'QPS Sparkline' },
+   spark_run                   => { hdr => 'Run',                 num => 0, label => 'Threads_running Sparkline' },
+   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' },
+   server_uuid                 => { hdr => 'Server UUID',         num => 0, label => 'Server UUID', },
+   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_running               => { hdr => 'Repl',                num => 0, label => 'Slave running' },
+   slave_sql_running           => { hdr => 'Slave-SQL',           num => 0, label => 'Whether the slave SQL thread is running' },
+   sort_time                   => { hdr => 'SortTimeLag',         num => 1, label => 'Time slave lags master sort' },
+   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' },
+   uptime                      => { hdr => 'Uptime',              num => 1, label => 'Uptime' },
+   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' },
+   waiting_thread              => { hdr => 'WThread',             num => 1, label => 'Waiting thread' },
+   waiting_query               => { hdr => 'Waiting Query',       num => 0, label => 'Waiting query' },
+   waiting_rows_modified       => { hdr => 'WRowsMod',            num => 1, label => 'Waiting number rows modified' },
+   waiting_age                 => { hdr => 'WAge',                num => 1, label => 'Waiting age' },
+   waiting_wait_secs           => { hdr => 'WWait',               num => 1, label => 'Waiting wait time' },
+   waiting_user                => { hdr => 'WUser',               num => 0, label => 'Waiting user' },
+   waiting_host                => { hdr => 'WHost',               num => 0, label => 'Waiting host' },
+   waiting_db                  => { hdr => 'WDB',                 num => 0, label => 'Waiting database' },
+   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}       || '') !~ m#/\*innotop\*/# );
+      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->{state})      || $set->{state} !~ m/^handlersocket/  )
+             && ( !defined($set->{info})       || $set->{info} =~ m/\S/               );
+      END
+      note => 'Removes processes which are not doing anything',
+      tbls => [qw(innodb_transactions processlist)],
+   },
+   hide_connect => {
+      text => <<'      END',
+         return ( !defined($set->{cmd})        || $set->{cmd} !~ m/Connect/ );
+      END
+      note => 'Removes the slave processes from the list',
+      tbls => [qw(processlist)],
+   },
+   hide_slave_io => {
+      text => <<'      END',
+         return !$set->{state} || $set->{state} !~ m/^(?:Waiting for master|read all relay)/;
+      END
+      note => 'Removes slave I/O threads from the list',
+      tbls => [qw(processlist slave_io_status)],
+   },
+   hide_event => {
+      text => <<'      END',
+         return (($set->{state} || '') !~ m/^Daemon/) || (($set->{info} || '') !~ m/\S/);
+      END
+      note => 'Removes idle event threads from the list',
+      tbls => [qw(processlist)],
+   },
+   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,
+   distill      => \&distill,
+   no_ctrl_char => \&no_ctrl_char,
+   percent      => \&percent,
+   commify      => \&commify,
+   dulint_to_int => \&dulint_to_int,
+   set_precision => \&set_precision,
+   fuzzy_time    => \&fuzzy_time,
+);
+
+# 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 => {
+         cxn        => { src => 'cxn' },
+         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(cxn 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,
+   },
+   index_statistics => {
+      capt => 'Data from INDEX_STATISTICS',
+      cust => {},
+      cols => {
+         cxn                    => { src => 'cxn', minw => 6, maxw => 10 },
+         db                     => { src => 'table_schema' },
+         tbl                    => { src => 'table_name' },
+         index                  => { src => 'index_name' },
+         rows_read              => { src => 'rows_read', agg => 'sum' },
+      },
+      visible => [ qw(cxn db tbl index rows_read) ],
+      filters => [ ],
+      sort_cols => 'rows_read',
+      sort_dir => '-1',
+      innodb   => '',
+      colors   => [],
+      hide_caption => 1,
+      group_by => [qw(cxn db tbl)],
+      aggregate => 0,
+   },
+   index_table_statistics => {
+      capt => 'Data from {TABLE,INDEX}_STATISTICS',
+      cust => {},
+      cols => {
+         cxn                    => { src => 'cxn', minw => 6, maxw => 10 },
+         db                     => { src => 'table_schema' },
+         tbl                    => { src => 'table_name' },
+         index                  => { src => 'index_name' },
+         rows_read              => { src => 'rows_read' },
+         rows_read_from_indexes => { src => 'rows_read_from_indexes' },
+         rows_changed           => { src => 'rows_changed' },
+         rows_changed_x_indexes => { src => 'rows_changed_x_indexes' },
+      },
+      visible => [ qw(cxn db tbl rows_read rows_read_from_indexes rows_changed rows_changed_x_indexes) ],
+      filters => [ ],
+      sort_cols => 'rows_read',
+      sort_dir => '-1',
+      innodb   => '',
+      colors   => [],
+      hide_caption => 1,
+      group_by => [qw(cxn db tbl)],
+      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_blocked_blocker  => {
+      capt => 'InnoDB Blocked/Blocking',
+      cust => {},
+      cols => {
+        cxn                    => { src => 'cxn' },
+        waiting_thread         => { src => 'waiting_thread' },
+        waiting_query          => { src => 'waiting_query', trans => [qw(distill)] },
+        waiting_rows_modified  => { src => 'waiting_rows_modified' },
+        waiting_age            => { src => 'waiting_age', trans => [qw(fuzzy_time)] },
+        waiting_wait_secs      => { src => 'waiting_wait_secs', trans => [qw(fuzzy_time)] },
+        waiting_user           => { src => 'waiting_user' },
+        waiting_host           => { src => 'waiting_host' },
+        waiting_db             => { src => 'waiting_db' },
+        blocking_thread        => { src => 'blocking_thread' },
+        blocking_query         => { src => 'blocking_query', trans => [qw(distill)] },
+        blocking_rows_modified => { src => 'blocking_rows_modified' },
+        blocking_age           => { src => 'blocking_age', trans => [qw(fuzzy_time)] },
+        blocking_wait_secs     => { src => 'blocking_wait_secs', trans => [qw(fuzzy_time)] },
+        blocking_user          => { src => 'blocking_user' },
+        blocking_host          => { src => 'blocking_host' },
+        blocking_db            => { src => 'blocking_db' },
+        blocking_status        => { src => 'blocking_status' },
+        lock_info              => { src => 'lock_info' },
+      },
+      visible => [ qw(cxn waiting_thread waiting_query waiting_wait_secs
+                      blocking_thread blocking_rows_modified blocking_age blocking_wait_secs
+                      blocking_status blocking_query)],
+      filters => [],
+      sort_cols => 'cxn -waiting_wait_secs',
+      sort_dir => '1',
+      innodb   => 'tx',
+      colors   => [
+      ],
+      group_by => [],
+      aggregate => 0,
+      hide_caption => 1,
+   },
+   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 => $exprs{chcxn_2_cxn}, hdr => '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) ] },
+         executed_gtid_set           => { src => '(executed_gtid_set||"N/A")' },
+         server_uuid                 => { src => '(server_uuid||"N/A")' },
+         channel_name                => { src => $exprs{chcxn_2_ch}, hdr => 'Channel'},
+      },
+      visible => [ qw(cxn channel_name master_file master_pos binlog_cache_overflow executed_gtid_set server_uuid)],
+      filters => [ qw(cxn_is_master) ],
+      sort_cols => 'cxn',
+      sort_dir => '1',
+      innodb   => '',
+      group_by => [qw(channel_name)],
+      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 => 7,  maxw => 15, },
+         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 hide_event hide_connect) ],
+      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)] },
+         connections    => { src => $exprs{Connection},                     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' },
+         q_detail       => { src => $exprs{QueryDetail} },
+      },
+      visible => [ qw(cxn when load connections qps slow q_detail 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 => $exprs{chcxn_2_cxn}, hdr => 'CXN' },
+         connect_retry               => { src => 'connect_retry' },
+         master_host                 => { src => 'master_host', hdr => 'Master'},
+         master_uuid                 => { src => '(master_uuid||"N/A")' },
+         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' },
+         channel_name                => { src => $exprs{chcxn_2_ch}, hdr => 'Channel'},
+      },
+      visible => [ qw(cxn channel_name master_host master_uuid 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 channel_name cxn',
+      colors   => [
+         { col => 'slave_io_running',  op => 'ne', arg => 'Yes', color => 'black on_red' },
+      ],
+      sort_dir => '1',
+      innodb   => '',
+      group_by => [qw(channel_name)],
+      aggregate => 0,
+   },
+   slave_sql_status => {
+      capt => 'Slave SQL Status',
+      cust => {},
+      cols => {
+         cxn                         => { src => $exprs{chcxn_2_cxn}, hdr => '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' },
+         master_uuid                 => { src => '(master_uuid||"N/A")' },
+         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?' },
+         sort_time                   => { src => 'int(seconds_behind_master/60)' },
+         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' },
+         retrieved_gtid_set          => { src => '(retrieved_gtid_set||"N/A")' },
+         executed_gtid_set           => { src => '(executed_gtid_set||"N/A")' },
+         channel_name                => { src => $exprs{chcxn_2_ch}, hdr => 'Channel'},
+      },
+      visible => [ qw(cxn channel_name master_host master_uuid slave_sql_running time_behind_master slave_catchup_rate slave_open_temp_tables relay_log_pos last_error retrieved_gtid_set executed_gtid_set)],
+      filters => [ qw( cxn_is_slave ) ],
+      sort_cols => 'slave_sql_running -sort_time channel_name 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 => [qw(channel_name)],
+      aggregate => 0,
+   },
+   table_statistics => {
+      capt => 'Data from TABLE_STATISTICS',
+      cust => {},
+      cols => {
+         cxn                    => { src => 'cxn', minw => 6, maxw => 10 },
+         db                     => { src => 'table_schema' },
+         tbl                    => { src => 'table_name' },
+         rows_read              => { src => 'rows_read' },
+         rows_changed           => { src => 'rows_changed' },
+         rows_changed_x_indexes => { src => 'rows_changed_x_indexes' },
+      },
+      visible => [ qw(cxn db tbl rows_read rows_changed rows_changed_x_indexes) ],
+      filters => [ ],
+      sort_cols => 'rows_read',
+      sort_dir => '-1',
+      innodb   => '',
+      colors   => [],
+      hide_caption => 1,
+      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,
+   },
+   health_dashboard => {
+      capt         => 'Health Dashboard',
+      hide_caption => 1,
+      cust => {},
+      cols => {
+         cxn                => { src => 'cxn' },
+         uptime             => { src => 'Uptime', trans => [qw(fuzzy_time)] },
+         qps                => { src => 'Questions/Uptime_hires', dec => 1, trans => [qw(shorten)] },
+         spark_qps          => { src => 'SPARK_qps' },
+         run                => { src => 'User_threads_running' },
+         spark_run          => { src => 'SPARK_run' },
+         max_query_time     => { src => 'Max_query_time', trans => [qw(fuzzy_time)] },
+         connections        => { src => 'Threads_connected' },
+         miss_rate          => { src => 'Innodb_buffer_pool_reads/Uptime_hires', trans => [qw(set_precision)] },
+         locked_count       => { src => 'Locked_count' },
+         'open'             => { src => 'Open_tables' },
+         slave_running      => { src => 'Slave_ok . " " . (Slaves || "")' },
+         time_behind_master => { src => 'seconds_behind_master', hdr => 'ReplLag' , trans => [qw(fuzzy_time)] },
+         longest_sql        => { src => 'Longest_sql', trans => [qw(distill)] },
+      },
+      visible   => [qw(
+                        cxn uptime max_query_time time_behind_master qps connections run
+                        miss_rate locked_count open slave_running longest_sql
+                       )],
+      filters   => [],
+      sort_cols => 'cxn',
+      sort_dir  => '1',
+      innodb    => '',
+      colors   => [
+         { col => 'slave_running',      op => '=~', arg => 'No',   color => 'black on_red' },
+         { col => 'max_query_time',     op => '>',  arg => 30 * 60, color => 'red' },
+         { col => 'max_query_time',     op => '>',  arg => 600,     color => 'yellow' },
+         { col => 'time_behind_master', op => '>',  arg => 3600,    color => 'cyan' },
+      ],
+      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 = (
+   A => {
+      hdr               => 'Dashboard',
+      cust              => {},
+      note              => 'Shows health/status dashboard',
+      action_for        => {
+         k => {
+            action => sub { kill_query('CONNECTION') },
+            label => "Kill a query's connection",
+         },
+         x => {
+            action => sub { kill_query('QUERY') },
+            label => "Kill a query",
+         },
+         r => {
+            action => sub { reverse_sort('health_dashboard'); },
+            label  => 'Reverse sort order',
+         },
+         s => {
+            action => sub { choose_sort_cols('health_dashboard'); },
+            label => "Choose sort column",
+         },
+      },
+      display_sub       => \&display_A,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 0,
+      tables            => [qw(health_dashboard)],
+      visible_tables    => [qw(health_dashboard)],
+   },
+   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)],
+   },
+   K => {
+      hdr             => 'InnoDB Lock Waits',
+      cust            => {},
+      note            => 'Shows blocked and blocking transactions',
+      action_for      => {
+         k => {
+            action => sub { kill_query('CONNECTION') },
+            label => "Kill a query's connection",
+         },
+      },
+      display_sub     => \&display_K,
+      connections     => [],
+      server_group    => '',
+      one_connection  => 0,
+      tables            => [qw(innodb_blocked_blocker)],
+      visible_tables    => [qw(innodb_blocked_blocker)],
+   },
+   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)],
+   },
+   U => {
+      hdr        => 'User Statistics',
+      cust       => {},
+      note       => 'Displays Percona/MariaDB enhancements such as table statistics',
+      action_for => {
+         i => {
+            action => sub { set_visible_table('index_statistics') },
+            label  => 'Switch to INDEX_STATISTICS',
+         },
+         s => {
+            action => sub { $clear_screen_sub->(); send_cmd_to_servers('SET @@global.userstat_running := 1 - @@global.userstat_running', 1, undef, []); },
+            label => "Change the display's sort column",
+         },
+         t => {
+            action => sub { set_visible_table('table_statistics') },
+            label  => 'Switch to TABLE_STATISTICS',
+         },
+         x => {
+            action => sub { set_visible_table('index_table_statistics') },
+            label  => 'Switch to {INDEX,TABLE}_STATISTICS',
+         },
+      },
+      display_sub       => \&display_P,
+      connections       => [],
+      server_group      => '',
+      one_connection    => 0,
+      tables            => [qw(table_statistics index_statistics index_table_statistics)],
+      visible_tables    => [qw(index_table_statistics)],
+   },
+   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",
+         },
+         t => {
+            action => sub { toggle_filter('processlist', 'hide_connect') },
+            label  => 'Toggle slave processes',
+         },
+         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?
+   A => {
+      action => sub { switch_mode('A') },
+      label  => '',
+   },
+   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  => '',
+   },
+   K => {
+      action => sub { switch_mode('K') },
+      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  => '',
+   },
+   U => {
+      action => sub { switch_mode('U') },
+      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,
+            agghide => 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 MariaDB server host',
+   'Unknown database',
+   'Can\'t connect to local MariaDB server through socket',
+   'Can\'t connect to MariaDB server on',
+   'MySQL server has gone away',
+   'Cannot call SHOW INNODB STATUS',
+   'Access denied',
+   'AutoCommit',
+   'Lost connection to MariaDB server',
+   'Lost connection to server',
+   'Too many connections',
+);
+
+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.
+my %show_variables;   # Stores SHOW VARIABLES for each cxn so we don't re-fetch.
+
+# Stores info on currently displayed queries: cxn, connection ID, query text,
+# user, and host.
+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  => "A",
+      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) ],
+   },
+   timeformat => {
+      val  => '%Y-%m-%dT%H:%M:%S',
+      pat  => qr//,
+      note => 'The strftime() timestamp format to write in -n mode',
+   },
+   spark => {
+      val  => 10,
+      note => 'How long to make status variable sparklines',
+      conf => 'ALL',
+      pat  => $int_regex,
+   },
+);
+
+# ###########################################################################
+# 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 = (
+   INDEX_STATISTICS => sub {
+      my ( $dbh ) = @_;
+      # Detect whether there's a Percona Server with INFORMATION_SCHEMA.INDEX_STATISTICS
+      # and if not, just select nothing.
+      my $sth;
+      eval { # This can fail if the table doesn't exist, INFORMATION_SCHEMA doesn't exist, etc.
+         my $cols = $dbh->selectall_arrayref(q{SHOW /*innotop*/ COLUMNS FROM INFORMATION_SCHEMA.INDEX_STATISTICS});
+         if ( @$cols ) {
+            $sth = $dbh->prepare(q{SELECT /*innotop*/ * FROM INFORMATION_SCHEMA.INDEX_STATISTICS});
+         }
+      };
+      $sth ||= $dbh->prepare(q{SELECT /*innotop*/ '' FROM DUAL WHERE 1 = 0});
+      return $sth;
+   },
+   INDEX_TABLE_STATISTICS => sub {
+      my ( $dbh ) = @_;
+      # Detect whether there's a Percona Server with INFORMATION_SCHEMA.INDEX_STATISTICS
+      # and if not, just select nothing.
+      my $sth;
+      eval { # This can fail if the table doesn't exist, INFORMATION_SCHEMA doesn't exist, etc.
+         my $cols = $dbh->selectall_arrayref(q{SHOW /*innotop*/ COLUMNS FROM INFORMATION_SCHEMA.INDEX_STATISTICS});
+         if ( @$cols ) {
+            $sth = $dbh->prepare(q{SELECT /*innotop*/ L.TABLE_SCHEMA, L.TABLE_NAME, }
+               . q{SUM(L.ROWS_READ) AS ROWS_READ, SUM(R.ROWS_READ) AS ROWS_READ_FROM_INDEXES, }
+               . q{SUM(L.ROWS_CHANGED) AS ROWS_CHANGED, }
+               . q{SUM(L.ROWS_CHANGED_X_INDEXES) AS ROWS_CHANGED_X_INDEXES }
+               . q{FROM INFORMATION_SCHEMA.TABLE_STATISTICS AS L LEFT JOIN INFORMATION_SCHEMA.INDEX_STATISTICS AS R }
+               . q{USING(TABLE_SCHEMA, TABLE_NAME) GROUP BY L.TABLE_SCHEMA, L.TABLE_NAME});
+         }
+      };
+      $sth ||= $dbh->prepare(q{SELECT /*innotop*/ '' FROM DUAL WHERE 1 = 0});
+      return $sth;
+   },
+   INNODB_BLOCKED_BLOCKER => sub {
+      my ( $dbh ) = @_;
+      # Detect whether the server supports the I_S tables and if not, just select nothing.
+      my $sth;
+      eval { # This can fail if the table doesn't exist, INFORMATION_SCHEMA doesn't exist, etc.
+         my $cols = $dbh->selectall_arrayref(q{SHOW /*innotop*/ COLUMNS FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS});
+         if ( @$cols ) {
+          if ($dbh->{mariadb_serverinfo} =~ /^5.1/) {
+            $sth = $dbh->prepare(q{
+               SELECT /*innotop*/
+                  r.trx_mysql_thread_id                            AS waiting_thread,
+                  r.trx_query                                      AS waiting_query,
+                  "n/a"                                            AS waiting_rows_modified,
+                  TIMESTAMPDIFF(SECOND, r.trx_started, NOW())      AS waiting_age,
+                  TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS waiting_wait_secs,
+                  rp.user                                          AS waiting_user,
+                  rp.host                                          AS waiting_host,
+                  rp.db                                            AS waiting_db,
+                  b.trx_mysql_thread_id                            AS blocking_thread,
+                  b.trx_query                                      AS blocking_query,
+                  "n/a"                                            AS blocking_rows_modified,
+                  TIMESTAMPDIFF(SECOND, b.trx_started, NOW())      AS blocking_age,
+                  TIMESTAMPDIFF(SECOND, b.trx_wait_started, NOW()) AS blocking_wait_secs,
+                  bp.user                                          AS blocking_user,
+                  bp.host                                          AS blocking_host,
+                  bp.db                                            AS blocking_db,
+                  CONCAT(bp.command, IF(bp.command = 'Sleep', CONCAT(' ', bp.time),   '')) AS blocking_status,
+                  CONCAT(lock_mode, ' ', lock_type, ' ', lock_table, '(', lock_index, ')') AS lock_info
+               FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS w
+                  JOIN INFORMATION_SCHEMA.INNODB_TRX b   ON  b.trx_id  = w.blocking_trx_id
+                  JOIN INFORMATION_SCHEMA.INNODB_TRX r   ON  r.trx_id  = w.requesting_trx_id
+                  JOIN INFORMATION_SCHEMA.INNODB_LOCKS l ON  l.lock_id = w.requested_lock_id
+                  LEFT JOIN INFORMATION_SCHEMA.PROCESSLIST bp ON bp.id = b.trx_mysql_thread_id
+                  LEFT JOIN INFORMATION_SCHEMA.PROCESSLIST rp ON rp.id = r.trx_mysql_thread_id
+            });
+          } else {
+            $sth = $dbh->prepare(q{
+               SELECT /*innotop*/
+                  r.trx_mysql_thread_id                            AS waiting_thread,
+                  r.trx_query                                      AS waiting_query,
+                  r.trx_rows_modified                              AS waiting_rows_modified,
+                  TIMESTAMPDIFF(SECOND, r.trx_started, NOW())      AS waiting_age,
+                  TIMESTAMPDIFF(SECOND, r.trx_wait_started, NOW()) AS waiting_wait_secs,
+                  rp.user                                          AS waiting_user,
+                  rp.host                                          AS waiting_host,
+                  rp.db                                            AS waiting_db,
+                  b.trx_mysql_thread_id                            AS blocking_thread,
+                  b.trx_query                                      AS blocking_query,
+                  b.trx_rows_modified                              AS blocking_rows_modified,
+                  TIMESTAMPDIFF(SECOND, b.trx_started, NOW())      AS blocking_age,
+                  TIMESTAMPDIFF(SECOND, b.trx_wait_started, NOW()) AS blocking_wait_secs,
+                  bp.user                                          AS blocking_user,
+                  bp.host                                          AS blocking_host,
+                  bp.db                                            AS blocking_db,
+                  CONCAT(bp.command, IF(bp.command = 'Sleep', CONCAT(' ', bp.time),   '')) AS blocking_status,
+                  CONCAT(lock_mode, ' ', lock_type, ' ', lock_table, '(', lock_index, ')') AS lock_info
+               FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS w
+                  JOIN INFORMATION_SCHEMA.INNODB_TRX b   ON  b.trx_id  = w.blocking_trx_id
+                  JOIN INFORMATION_SCHEMA.INNODB_TRX r   ON  r.trx_id  = w.requesting_trx_id
+                  JOIN INFORMATION_SCHEMA.INNODB_LOCKS l ON  l.lock_id = w.requested_lock_id
+                  LEFT JOIN INFORMATION_SCHEMA.PROCESSLIST bp ON bp.id = b.trx_mysql_thread_id
+                  LEFT JOIN INFORMATION_SCHEMA.PROCESSLIST rp ON rp.id = r.trx_mysql_thread_id
+            });
+          }
+         }
+      };
+      $sth ||= $dbh->prepare(q{SELECT /*innotop*/ '' FROM DUAL WHERE 1 = 0});
+      return $sth;
+   },
+   INNODB_STATUS => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare(version_ge( $dbh, '5.0.0' )
+             ? 'SHOW /*innotop*/ ENGINE INNODB STATUS'
+             : 'SHOW /*innotop*/ INNODB STATUS');
+   },
+   SHOW_VARIABLES => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare($config{global}->{val} && version_ge( $dbh, '4.0.3' )
+             ? 'SHOW /*innotop*/ GLOBAL VARIABLES'
+             : 'SHOW /*innotop*/ VARIABLES');
+   },
+   SHOW_STATUS => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare($config{global}->{val} && version_ge( $dbh, '5.0.2' )
+             ? 'SHOW /*innotop*/ GLOBAL STATUS'
+             : 'SHOW /*innotop*/ STATUS');
+   },
+   KILL_QUERY => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare(version_ge( $dbh, '5.0.0' )
+             ? 'KILL /*innotop*/ QUERY ?'
+             : 'KILL /*innotop*/ ?');
+   },
+   SHOW_MASTER_LOGS => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare('SHOW /*innotop*/ MASTER LOGS');
+   },
+   SHOW_MASTER_STATUS => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare('SHOW /*innotop*/ MASTER STATUS');
+   },
+   SHOW_SLAVE_STATUS => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare('SHOW /*innotop*/ SLAVE STATUS');
+   },
+   GET_CHANNELS => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare(version_ge( $dbh, '5.7.0' )
+             ? 'select CHANNEL_NAME from performance_schema.replication_applier_status where CHANNEL_NAME regexp "^[a-zA-Z].*";'
+             : 'select "no_channels"');
+   },
+   KILL_CONNECTION => sub {
+      my ( $dbh ) = @_;
+      return $dbh->prepare(version_ge( $dbh, '5.0.0' )
+             ? 'KILL /*innotop*/ CONNECTION ?'
+             : 'KILL /*innotop*/ ?');
+   },
+   OPEN_TABLES => sub {
+      my ( $dbh ) = @_;
+      return version_ge($dbh, '4.0.0')
+         ? $dbh->prepare('SHOW /*innotop*/ OPEN TABLES')
+         : undef;
+   },
+   PROCESSLIST => sub {
+      my ( $dbh ) = @_;
+      # In newer versions of the server, use INFORMATION_SCHEMA table if it exists,
+      # and use the TIME_MS column (in Percona Server) if that exists.
+      my $sth;
+      eval { # This can fail if the table doesn't exist, INFORMATION_SCHEMA doesn't exist, etc.
+         my $cols = $dbh->selectall_arrayref(q{SHOW /*innotop*/ COLUMNS FROM INFORMATION_SCHEMA.PROCESSLIST LIKE 'TIME_MS'});
+         if ( @$cols ) { # The TIME_MS column exists
+            $sth = $dbh->prepare(q{SELECT /*innotop*/ ID, USER, HOST, DB, COMMAND, CASE WHEN TIME_MS/1000 > 365*86400 THEN TIME ELSE TIME_MS/1000 END AS TIME, STATE, INFO FROM INFORMATION_SCHEMA.PROCESSLIST});
+         }
+      };
+      $sth ||= $dbh->prepare('SHOW /*innotop*/ FULL PROCESSLIST');
+      return $sth;
+   },
+   PROCESSLIST_NO_IS => sub {
+      my ( $dbh ) = @_;
+      # We do not use INFORMATION_SCHEMA table because it doesn't show slave
+      # SQL statements. http://bugs.mysql.com/66401
+      my $sth = $dbh->prepare('SHOW /*innotop*/ FULL PROCESSLIST');
+      return $sth;
+   },
+   TABLE_STATISTICS => sub {
+      my ( $dbh ) = @_;
+      # Detect whether there's a Percona Server with INFORMATION_SCHEMA.TABLE_STATISTICS
+      # and if not, just select nothing.
+      my $sth;
+      eval { # This can fail if the table doesn't exist, INFORMATION_SCHEMA doesn't exist, etc.
+         my $cols = $dbh->selectall_arrayref(q{SHOW /*innotop*/ COLUMNS FROM INFORMATION_SCHEMA.TABLE_STATISTICS});
+         if ( @$cols ) {
+            $sth = $dbh->prepare(q{SELECT /*innotop*/ * FROM INFORMATION_SCHEMA.TABLE_STATISTICS});
+         }
+      };
+      $sth ||= $dbh->prepare(q{SELECT /*innotop*/ '' FROM DUAL WHERE 1 = 0});
+      return $sth;
+   },
+);
+
+# Plugins!
+my %plugins = (
+);
+
+# ###########################################################################
+# Run the program {{{1
+# ###########################################################################
+sub main {
+   # 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();
+         }
+
+         # RECON: Try to reconnect failed connections, while the user sees no lag.
+         foreach my $cxn ( grep { $dbhs{$_}->{failed} } keys %dbhs ) {
+            eval { connect_to_db($cxn); }; # Ignore errors entirely here.
+         }
+
+         # 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();
+}
+main() unless caller(); # make me testable!
+
+# 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;
+}
+
+# noecho_password {{{3
+# read password for command line parameters with noecho
+sub noecho_password {
+   my $prompt = shift @_;
+   local $OUTPUT_AUTOFLUSH = 1;
+   my $response;
+   eval {
+      if ( $windows ) {
+         require Win32::Console::ANSI;
+      }
+      require Term::ANSIColor;
+      import Term::ANSIColor qw(colored);
+      $response = prompt_noecho($prompt);
+      print "\n" or die
+         "Cannot print: $OS_ERROR";
+   };
+
+   if ( $EVAL_ERROR ) {
+      die "Cannot read response; is Term::ReadKey installed? $EVAL_ERROR";
+   }
+   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;
+   my $distill = distill($info->{query} || '');
+   $distill = " running '$distill'" if $distill;
+   return unless pause("Kill $info->{id} ("
+      . ($info->{user} || '')
+      . '@'
+      . ($info->{host} || '')
+      . ")$distill ? ") =~ 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);
+
+      # disable binary logging for this session
+      $dbh->do("set SQL_LOG_BIN=0");
+
+      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_A {{{3
+sub display_A {
+   my @display_lines;
+   my @cxns  = get_connections();
+   get_processlist_stats(@cxns);
+   get_status_info(@cxns);
+   get_master_slave_status(@cxns);
+   my @visible = get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+   my @health_dashboard;
+   my %rows_for = (
+      health_dashboard => \@health_dashboard,
+   );
+
+   foreach my $cxn ( @cxns ) {
+      # Get the status variables
+      my $set  = $vars{$cxn}->{$clock};
+      my $pre  = $vars{$cxn}->{$clock-1} || $set;
+      my $hash = extract_values($set, $set, $pre, 'health_dashboard');
+      # Make QPS and Miss show now, not overall.
+      if ( exists $vars{$cxn}->{$clock - 1} ) {
+         my $inc   = inc(0, $cxn);
+         my $hash2 = extract_values($inc, $set, $pre, 'health_dashboard');
+         map { $hash->{$_} = $hash2->{$_} } qw(qps miss_rate);
+      }
+      push @health_dashboard, $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_B {{{3
+sub display_B {
+   my @display_lines;
+   my @cxns = get_connections();
+   get_status_info(@cxns);
+   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_status_info(@cxns);
+   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_status_info($cxn);
+   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} || 'unknown');
+
+      # 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_status_info(@cxns);
+   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_K {{{3
+sub display_K {
+   my @display_lines;
+   my @cxns = get_connections();
+
+   my %rows_for = (
+      innodb_blocked_blocker => [],
+   );
+
+   my @visible = get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+
+   # Get info on locks
+   if ( $wanted{innodb_blocked_blocker} ) {
+      my @rows = get_innodb_blocked_blocker(@cxns);
+      push @{$rows_for{innodb_blocked_blocker}}, map { extract_values($_, $_, $_, 'innodb_blocked_blocker') } @rows;
+   }
+
+   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 user host db query time) }
+         = @{$_}{ qw(cxn blocking_thread blocking_user blocking_host blocking_db blocking_query blocking_age) };
+      # time is in fuzzy-time format; convert into something ascii-sortable.
+      $hash{time} = sprintf('%012s', fuzzy_to_secs($hash{time}));
+      $hash{host} =~ s/:.*$// if $hash{host};
+      \%hash;
+   } @{$rows_for{innodb_blocked_blocker}};
+
+   draw_screen(\@display_lines);
+}
+
+# display_L {{{3
+sub display_L {
+   my @display_lines;
+   my @cxns = get_connections();
+   get_status_info(@cxns);
+   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} => $_ } grep { defined $_->{mysql_thread_id} } @$cur_txns;
+         my %pre_txns = map { $_->{mysql_thread_id} => $_ } grep { defined $_->{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 $linecount=0;
+                my $sth = do_stmt($cxn, 'GET_CHANNELS');
+                my ( $channel );
+            $sth->execute();
+            $sth->bind_columns( \$channel );
+                while ( $sth->fetch() ) {
+                       $linecount=$linecount+1;
+                       if ( length $channel < 1 ) {
+                               $channel = 'no_channels';
+                       }
+                       my $chcxn = $channel . '=' . $cxn;
+                       get_slave_status($cxn,$channel);
+                       my $set  = $config{status_inc}->{val} ? inc(0, $chcxn) : $vars{$chcxn}->{$clock};
+                       my $pre  = $vars{$chcxn}->{$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 ( $linecount < 1 ) {
+                       $channel = 'no_channels';
+                       my $chcxn = $channel . '=' . $cxn;
+                       get_slave_status($cxn,$channel);
+                       my $set  = $config{status_inc}->{val} ? inc(0, $chcxn) : $vars{$chcxn}->{$clock};
+                       my $pre  = $vars{$chcxn}->{$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');
+                       }
+                }
+               my $set  = $config{status_inc}->{val} ? inc(0, $cxn) : $vars{$cxn}->{$clock};
+               my $pre  = $vars{$cxn}->{$clock - 1} || $set;
+               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_P {{{3
+sub display_P {
+   my @display_lines;
+
+   my @table_statistics;
+   my @index_statistics;
+   my @index_table_statistics;
+   my %rows_for = (
+      table_statistics => \@table_statistics,
+      index_statistics => \@index_statistics,
+      index_table_statistics => \@index_table_statistics,
+   );
+
+   my @visible = $opts{n} ? 'index_table_statistics' : get_visible_tables();
+   my %wanted  = map { $_ => 1 } @visible;
+
+   # Get the data
+   my @cxns = get_connections();
+
+   if ( $wanted{table_statistics} ) {
+      my @rows = get_table_statistics(@cxns);
+      push @table_statistics, map { extract_values($_, $_, $_, 'table_statistics') } @rows;
+   }
+   elsif ( $wanted{index_statistics} ) {
+      my @rows = get_index_statistics(@cxns);
+      push @index_statistics, map { extract_values($_, $_, $_, 'index_statistics') } @rows;
+   }
+   elsif ( $wanted{index_table_statistics} ) {
+      my @rows = get_index_table_statistics(@cxns);
+      push @index_table_statistics, map { extract_values($_, $_, $_, 'index_table_statistics') } @rows;
+   }
+
+   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++ );
+   }
+
+   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 time user host) }
+         = @{$_}{ qw(cxn mysql_thread_id db info time user hostname) };
+      # time is in seconds-to-time format; convert into something
+      # ascii-sortable.
+      $hash{time} = sprintf('%012s', $hash{time} =~ m/^([^.]*)/);
+      \%hash;
+   } @{$rows_for{processlist}};
+
+   draw_screen(\@display_lines);
+}
+
+# display_R {{{3
+sub display_R {
+   my @display_lines;
+   my @cxns = get_connections();
+   get_status_info(@cxns);
+   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();
+
+   get_status_info(@cxns);
+
+   # 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} => $_ } grep { defined $_->{mysql_thread_id} } @$cur_txns;
+         my %pre_txns = map { $_->{mysql_thread_id} => $_ } grep { defined $_->{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 time user host) }
+         = @{$_}{ qw(cxn mysql_thread_id db query_text active_secs user hostname) };
+      \%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 {
+      my $k = $action_for{$_} ? ($action_for{$_}->{key} || $_) : $_;
+      sprintf('%4s  %s', $k, $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 / hide cxn if there's only one connection being displayed
+   my (@visible, @group_by);
+   my $num_cxn = scalar get_connections();
+   if ($num_cxn <= 1) {
+      map { push @visible, $_ if $_ !~ /^cxn$/ } @{$meta->{visible}};
+      $meta->{visible} = \@visible;
+      map { push @group_by, $_ if $_ !~ /^cxn$/ } @{$meta->{group_by}};
+      $meta->{group_by} = \@group_by;
+   }
+   # if cxn is not visible and there is now more than one connection,
+   # make cxn visible again.  assume it's not in group_by if it's not
+   # visible
+   else {
+      my $has_cxn = 0;
+      foreach my $column (@{$meta->{visible}}) {
+         if ($column eq "cxn") {
+           $has_cxn = 1;
+           last;
+         }
+      }
+      if (not $has_cxn) {
+         map { push @visible, $_ if $_ !~ /^cxn$/ } @{$meta->{visible}};
+         $meta->{visible} = \@visible;
+         map { push @group_by, $_ if $_ !~ /^cxn$/ } @{$meta->{group_by}};
+         $meta->{group_by} = \@group_by;
+      }
+   }
+
+   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} } @{$meta->{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, and suppress 'agghide' columns.
+      if ( $aggregated ) {
+         my %is_group = map { $_ => 1 } @{$meta->{group_by}};
+         $fmt_cols = [ @{$meta->{group_by}}, grep { !$is_group{$_} } @$fmt_cols ];
+         $fmt_cols = [ grep { !$meta->{cols}->{$_}->{agghide} } @$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 ) = @_;
+   $num = 0 unless defined $num;
+   $precision = $config{num_digits}->{val} if !defined $precision;
+   if ( $num eq "" ) {
+       $num = int(0);
+   }
+   sprintf("%.${precision}f", $num);
+}
+
+# percent {{{3
+# Convert to percent
+sub percent {
+   my ( $num ) = @_;
+   $num = 0 unless defined $num;
+   if ( $num eq "" ) {
+       $num = int(0);
+   }
+   my $digits = $config{num_digits}->{val};
+   return sprintf("%.${digits}f", $num * 100)
+      . ($config{show_percent}->{val} ? '%' : '');
+}
+
+# sparkify {{{3
+# Find the range (min to max) and divide it up.  Each value then gets put into
+# a bucket and represented by one of these characters: _.-=^
+sub sparkify {
+   my @vals  = @_;
+   my @chars = qw(_ . - = ^);
+   my $min   = min(@vals);
+   my $max   = max(@vals);
+   my $range = ($max - $min) / 4;
+   return "_" x scalar(@vals) if !$min || !$max || $max == $min || !$range;
+   my $result = "";
+   foreach my $v ( @vals ) {
+      $result .= $chars[ int(($v - $min) / $range) ];
+   }
+   return $result;
+}
+
+# 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 $num =~ m/\./ || $n || $force
+     ? sprintf("%.${num_digits}f%s", $num, ($pad,'k','M','G','T')[$n])
+     : $num;
+}
+
+# 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 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;
+      my $ts = $opts{t} ? POSIX::strftime($config{timeformat}->{val}, localtime) : '';
+      if ( $opts{t} ) {
+         if ( $opts{t} == 1 ) {
+            print "\n$ts\n\n";
+            $ts = ""; # Prevent it from being written on every line.
+            $num_lines++;
+         }
+         else {
+            $ts .= " ";
+         }
+      }
+      print join("\n",
+         map {
+            $num_lines++;
+            ref $_
+               ? colored($ts . $_->[0], $_->[1])
+               : $ts . $_;
+         }
+         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]);
+   }
+}
+
+# fuzzy_time {{{3
+sub fuzzy_time {
+   my ( $secs ) = @_;
+   return '' unless $secs;
+   return sprintf('%.2f', $secs) if $secs =~ m/^.\./;
+   $secs =~ s/\..*$//;
+   return $secs < 180      ? "${secs}s"
+        : $secs < 3600     ? sprintf("%dm", $secs / 60)
+        : $secs < 3600 * 3 ? sprintf("%dh%dm", $secs / 3600, ($secs % 3600) / 60)
+        : $secs < 86400    ? sprintf("%dh", $secs / 3600)
+        : $secs < 86400* 3 ? sprintf("%dd%dh", $secs / 86400, ($secs % 86400) / 3600)
+        :                    sprintf("%dd", $secs / 86400);
+}
+
+sub fuzzy_to_secs {
+   my ($t) = @_;
+   return 0 unless $t;
+   my ($num, $suffix) = $t =~ m/(\d+)([a-z])?$/;
+   return $num unless $suffix;
+   return       $suffix eq 's' ? $num            # Seconds
+              : $suffix eq 'm' ? $num * 60       # Minutes
+              : $suffix eq 'h' ? $num * 3600     # Hours
+              :                  $num * 86400;   # Days
+}
+
+# distill {{{3
+sub distill {
+   my ( $query ) = @_;
+   return "" unless $query;
+   my $orig_query = $query;
+
+   $query =~ m/\A\s*call\s+(\S+)\(/i && return "CALL $1";
+   $query =~ m/\A\s*use\s+/          && return "USE";
+   $query =~ m/\A\s*UNLOCK TABLES/i  && return "UNLOCK";
+   $query =~ m/\A\s*xa\s+(\S+)/i     && return "XA_$1";
+
+   # Strip out comments
+   my $olc_re = qr/(?:--|#)[^'"\r\n]*(?=[\r\n]|\Z)/;  # One-line comments
+   my $mlc_re = qr#/\*[^!].*?\*/#sm;                  # But not /*!version */
+   my $vlc_re = qr#/\*.*?[0-9+].*?\*/#sm;             # For SHOW + /*!version */
+   my $vlc_rf = qr#^(SHOW).*?/\*![0-9+].*?\*/#sm;     # Variation for SHOW
+   $query =~ s/$olc_re//go;
+   $query =~ s/$mlc_re//go;
+   if ( $query =~ m/$vlc_rf/i ) { # contains show + version
+      $query =~ s/$vlc_re//go;
+   }
+
+   # Handle SHOW queries
+   if ( $query =~ m/\A\s*SHOW\s+/i ) {
+      $query = uc $query;
+      $query =~ s/\s+(?:GLOBAL|SESSION|FULL|STORAGE|ENGINE)\b/ /g;
+      $query =~ s/\s+COUNT[^)]+\)//g;
+      $query =~ s/\s+(?:FOR|FROM|LIKE|WHERE|LIMIT|IN)\b.+//ms;
+      $query =~ s/\A(SHOW(?:\s+\S+){1,2}).*\Z/$1/s;
+      $query =~ s/\s+/ /g;
+   }
+
+   # Find verbs and tables.
+   my ($verbs, $table);
+
+   # Handle DDL operations (dds)
+   my $tbl_ident = qr/(?:`[^`]+`|\w+)(?:\.(?:`[^`]+`|\w+))?/;
+   my $tbl_regex = qr{
+            \b(?:FROM|JOIN|(?<!KEY\s)UPDATE|INTO(?!\s+TABLE)|INTO\s+TABLE) # Words that precede table names
+            \b\s*
+            \(?                                                            # Optional paren around tables
+            ($tbl_ident
+               (?: (?:\s+ (?:AS\s+)? \w+)?, \s*$tbl_ident )*
+            )
+         }xio;
+   my ( $ddl ) = $query =~ m/^\s*((?:CREATE|ALTER|TRUNCATE|DROP|RENAME|CHECK|REPAIR))\b/i;
+   if ( $ddl ) {
+      my ( $obj ) = $query =~ m/$ddl.+(DATABASE|EVENT|FUNCTION|INDEX|LOGFILE GROUP|PROCEDURE|SERVER|TABLE|TABLESPACE|TRIGGER|VIEW)\b/i;
+      if ( $obj ) {
+         $query =~ s/$obj\s*if\s*(?:not\s*)?exists/$obj/i;
+         $verbs = uc($ddl . ($obj ? " $obj" : ''));
+         ($table) = $query =~ m/(?:TABLE|DATABASE)\s+($tbl_ident)(\s+.*)?/i;
+      }
+   }
+   else {
+      my $verbs_pat = qr{^SHOW|^FLUSH|^COMMIT|^ROLLBACK|^BEGIN|SELECT|INSERT
+                  |UPDATE|DELETE|REPLACE|^SET|UNION|^START|^LOCK|^LOAD}xi;
+      my @verbs = $query =~ m/\b($verbs_pat)\b/gio;
+      @verbs    = do {
+         my $last = '';
+         grep { my $pass = $_ ne $last; $last = $_; $pass } map { uc } @verbs;
+      };
+
+      if ( ($verbs[0] || '') eq 'SELECT' && @verbs > 1 ) {
+         # False-positive verbs after SELECT
+         my $union = grep { $_ eq 'UNION' } @verbs;
+         @verbs    = $union ? qw(SELECT UNION) : qw(SELECT);
+      }
+
+      my %seen;
+      $verbs = join(q{ }, grep { !$seen{$_}++ } @verbs);
+   }
+
+   if ( $verbs && $verbs =~ m/^SHOW/ ) {
+      my %alias_for = qw(
+         SCHEMA   DATABASE
+         KEYS     INDEX
+         INDEXES  INDEX
+      );
+      map { $verbs =~ s/$_/$alias_for{$_}/ } keys %alias_for;
+      $query = $verbs;
+   }
+   else {
+      my @tables;
+      $query =~ s/ (?:LOW_PRIORITY|IGNORE|STRAIGHT_JOIN)//ig;
+      if ( $query =~ /^\s*LOCK\s+TABLES/i ) {
+         $query =~ s/^(\s*LOCK\s+TABLES\s+)//i;
+         $query =~ s/\s+(?:READ|WRITE|LOCAL)+\s*//gi;
+         $query = "FROM $query";
+      }
+      $query =~ s/\\["']//g;                # quoted strings
+      $query =~ s/".*?"/?/sg;               # quoted strings
+      $query =~ s/'.*?'/?/sg;               # quoted strings
+
+      foreach my $tbls ( $query =~ m/$tbl_regex/gio ) {
+         next if $tbls =~ m/\ASELECT\b/i;
+         foreach my $tbl ( split(',', $tbls) ) {
+            $tbl =~ s/\s*($tbl_ident)(\s+.*)?/$1/gio;
+            if ( $tbl !~ m/[a-zA-Z]/ ) {
+               # Skip suspicious table name
+               next;
+            }
+            push @tables, $tbl;
+         }
+      }
+
+      # If we have a bunch of tables like db1.tbl1 db1.tbl2, convert to
+      # db1.tbl1 -.tbl2 etc. Also remove repeated tables, and strip `quotes`.
+      $query = $verbs;
+      my $prev = '';
+      foreach my $t ( @tables, $table ) {
+         next unless $t;
+         $t =~ s/`//g;
+         next if $t eq $prev;
+         my ($prefix, undef) = split(/\./, $prev);
+         $prev = $t;
+         if ( $prefix ) {
+            $t =~ s/^$prefix\./-./;
+         }
+         $query .= " " . $t;
+      }
+   }
+
+   # die $orig_query if $query eq 'LOCK lock';
+   return $query;
+}
+
+# secs_to_time {{{3
+sub secs_to_time {
+   my ( $secs, $fmt ) = @_;
+   $secs ||= 0;
+
+   # If the inbound value has a decimal point, then format the seconds with milliseconds.
+   my $hires = $secs =~ m/\./ ? '%06.3f' : '%02d';
+
+   if ( !$secs ) {
+      return sprintf("00:$hires", $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:$hires",
+         int($secs / 86_400),
+         int(($secs % 86_400) / 3_600),
+         int(($secs % 3_600) / 60),
+         $secs % 60 + ($secs - int($secs)))
+      : $fmt eq 'h' ? sprintf(
+         "%02d:%02d:$hires",
+         int(($secs % 86_400) / 3_600),
+         int(($secs % 3_600) / 60),
+         $secs % 60 + ($secs - int($secs)))
+      : sprintf(
+         "%02d:$hires",
+         int(($secs % 3_600) / 60),
+         $secs % 60 + ($secs - int($secs)));
+}
+
+# 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}->{mariadb_serverinfo} || '';
+   }
+   else {
+      if ( $modes{$mode}->{server_group} ) {
+         $cxn = "Servers: " . $modes{$mode}->{server_group};
+         my $err_count = grep { $dbhs{$_} && $dbhs{$_}->{failed} } @cxns;
+         if ( $err_count ) {
+            $cxn .= "(" . ( scalar(@cxns) - $err_count ) . "/" . scalar(@cxns) . ")";
+         }
+      }
+      else {
+         $cxn = join(' ', map { ($dbhs{$_}->{failed} ? '!' : '') . $_ }
+            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 = fuzzy_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:MariaDB:;host=hostname;port=port\n"
+            . "The db and port are optional and can usually be omitted.\n"
+            . "If you specify 'mariadb_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:MariaDB:;mariadb_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] : ();
+   }
+   # If the connections are the same as a server group, we set the mode's
+   # group to that group.
+   if ( ! $modes{$mode}->{server_group} ) {
+      my $maybe_group = join(',', sort @connections);
+      foreach my $g ( keys %server_groups ) {
+         my $group_conns = join(',', sort @{$server_groups{$g}});
+         if ( $maybe_group eq $group_conns ) {
+            $modes{$mode}->{server_group} = $g;
+            last;
+         }
+      }
+   }
+   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 { $_ } $choices =~ m/(\S+)/g);
+   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 if $file;
+
+   # Test if the cxn should not even be tried
+   return if $dbhs{$cxn}
+      && $dbhs{$cxn}->{failed}
+      && ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} );
+
+   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;
+   }
+}
+
+# Marks a connection as failed. When we sleep between redraws, we try to
+# reopen.
+sub handle_cxn_error {
+   my ( $cxn, $err ) = @_;
+   my $meta = $dbhs{$cxn};
+   $meta->{failed} = 1;
+
+   # 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;
+   if ( $config{show_cxn_errors}->{val} ) {
+      print STDERR "DB error: $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 if $file;
+
+   # Test if the cxn should not even be tried
+   return if $dbhs{$cxn}
+      && $dbhs{$cxn}->{failed}
+      && ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} );
+
+   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.
+      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 failed start_time stmts)} = ($dbh, 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->{mariadb_serverinfo} =~ m/^(\d+).(\d+).(\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}->{mariadb_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 MariaDB 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 mariadb_read_default_group=client is in the DSN
+   if ( !defined $dsn->{have_user} and $dsn->{dsn} !~ /mariadb_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 mariadb_read_default_group=client is in the DSN
+   if ( !defined $dsn->{have_pass} and $dsn->{dsn} !~ /mariadb_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{$_}->{failed} && $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();
+   foreach my $cxn ( values %dbhs ) {
+      eval {
+         foreach my $sth ( values %{$cxn->{stmts}} ) {
+            $sth->finish;
+         }
+         $cxn->{dbh}->disconnect;
+      };
+      # Ignore eval errors, we just don't care
+   }
+   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} or $opts{S} ) {
+     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};
+   }
+   # If we don't have a new config file but we do have an old one,
+   # innotop got upgraded and this is an old config file. Convert it, but
+   # don't overwrite something existing.
+   elsif ( ! -f $default_home_conf && ( -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 mariadb_read_default_group=client
+      if (!%connections) {
+         add_new_dsn('localhost',
+                     'DBI:MariaDB:;host=localhost;mariadb_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 (glob($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}) ) {
+            # Make it default to whatever's in col_props.
+            $parts{$prop} = $col_props{$prop};
+         }
+
+         # 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;
+}
+
+# set_visible_table {{{3
+sub set_visible_table {
+   my ( $tbl ) = @_;
+   my $mode = $config{mode}->{val};
+   my @tbls = grep { $_ eq $tbl } @{$modes{$mode}->{tables}};
+   if ( @tbls == 1 ) {
+      $modes{$mode}->{visible_tables} = [ $tbl ];
+      $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($val =~ m/(\S+)/g);
+   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 { my @tmparray = sort keys %stmt_maker_for; return @tmparray });
+   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{$_} } $new_cxns =~ m/(\S+)/g);
+   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}
+   get_connections(); # This will set the server group if it matches connections just chosen
+}
+
+# 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.  If we've gotten this info before, skip and re-use.
+         if ( $show_variables{$cxn} ) {
+            $res = $show_variables{$cxn};
+         }
+         else {
+            $sth = do_stmt($cxn, 'SHOW_VARIABLES') or next;
+            $res = $sth->fetchall_arrayref();
+            $res = {map { $_->[0] => $_->[1] || 0 } @$res};
+            $show_variables{$cxn} = $res;
+         }
+         @{$vars}{keys %$res} = values %$res;
+
+         # Create sparklines for QPS and Threads_running. As a consequence of
+         # this, we get QPS for free. TODO: remove QPS computation from
+         # elsewhere.
+         my $pre = $vars{$cxn}->{$clock - 1};
+         if ( $pre && $pre->{Uptime_hires} ) {
+            my @prev_qps = ($pre->{SPARK_store_qps} || '') =~ m/(\S+)/g;
+            my @prev_run = ($pre->{SPARK_store_run} || '') =~ m/(\S+)/g;
+
+            # Find out the values; throw away if too many; sparkify; store.
+            my $this_qps = (($vars->{Questions} || 0) - ($pre->{Questions} || 0))/
+                           ($vars->{Uptime_hires} - $pre->{Uptime_hires});
+            push @prev_qps, $this_qps;
+            shift @prev_qps if @prev_qps > $config{spark}->{val};
+            my $qps_spark = sparkify(@prev_qps);
+            $vars->{SPARK_qps} = $qps_spark;
+            $vars->{SPARK_store_qps} = join(' ', @prev_qps);
+            my $this_run = $vars->{Threads_running};
+            push @prev_run, $this_run;
+            shift @prev_run if @prev_run > $config{spark}->{val};
+            my $run_spark = sparkify(@prev_run);
+            $vars->{SPARK_run} = $run_spark;
+            $vars->{SPARK_store_run} = join(' ', @prev_run);
+         }
+      }
+   }
+}
+
+# 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 ) = @_;
+
+   my %thread_for = map {
+      # Eliminate innotop's own threads.
+      $_ => $dbhs{$_}->{dbh} ? $dbhs{$_}->{dbh}->{mariadb_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) cmp ($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/ && ($pre->{$_} || '') =~ 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_processlist_stats {{{3
+# Inserts special values as though they are SHOW STATUS counters.
+sub get_processlist_stats {
+   my @cxns = @_;
+   @current_queries = ();
+   if ( !$info_gotten{processlist_stats}++ ) {
+      foreach my $cxn ( @cxns ) {
+         my $max_query_time = 0;
+         my ($user_threads, $slaves, $longest_sql, $slave_sql, $locked);
+         $vars{$cxn}->{$clock} ||= {};
+         my $vars = $vars{$cxn}->{$clock};
+         $vars->{cxn} = $cxn;
+         my $stmt = do_stmt($cxn, 'PROCESSLIST_NO_IS') or next;
+         my $arr = $stmt->fetchall_arrayref({});
+         my $cur = undef;
+         foreach my $thread ( @$arr ) {
+            if ( ($thread->{state} || '') =~ m/lock/i ) {
+               $locked++;
+            }
+            # Ignore non-user threads, but remember the SQL in case there is
+            # no user SQL.  Ignore sleeping threads and SHOW PROCESSLIST
+            # threads.
+            if ( ($thread->{user} || '') =~ m/system user/ ) {
+               if ( $thread->{info} && $thread->{time} ) {
+                  $slave_sql = $thread->{info};
+               }
+               next;
+            }
+            next unless $thread->{command};
+            if ( $thread->{command} eq 'Binlog Dump' ) {
+               $slaves++;
+               next;
+            }
+            next unless $thread->{command} eq 'Query';
+            next unless $thread->{state} && $thread->{info};
+            next if     $thread->{info} =~ m#/\*innotop#;
+            $user_threads++;
+            if ( $thread->{time} > $max_query_time ) {
+               $max_query_time = $thread->{time};
+               $longest_sql    = $thread->{info};
+               if ( $thread->{state} eq 'Checking table' ) {
+                  $longest_sql = 'CHECK TABLE ' . $thread->{info};
+               }
+               $cur = {
+                  cxn => $cxn,
+                  id => $thread->{id},
+                  db => $thread->{db},
+                  query => $thread->{info},
+                  time => $thread->{time},
+                  user => $thread->{user},
+                  host => $thread->{host},
+               };
+               $thread->{host} =~ s/:.*$//;
+            }
+         }
+         $vars->{Max_query_time}       = $max_query_time;
+         $vars->{User_threads_running} = $user_threads;
+         $vars->{Slaves}               = $slaves || 0;
+         $vars->{Longest_sql}          = $longest_sql || $slave_sql || '';
+         $vars->{Locked_count}         = $locked || 0;
+         $vars->{Uptime_hires}       ||= get_uptime($cxn);
+         push @current_queries, $cur if $cur;
+      }
+   }
+}
+
+# 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_index_statistics {{{3
+sub get_index_statistics {
+   my @cxns = @_;
+   my @result;
+   foreach my $cxn ( @cxns ) {
+      my $stmt = do_stmt($cxn, 'INDEX_STATISTICS') or next;
+      my $arr  = $stmt->fetchall_arrayref({});
+      push @result, map { $_->{cxn} = $cxn; $_ } @$arr;
+   }
+   return @result;
+}
+
+# get_index_table_statistics {{{3
+sub get_index_table_statistics {
+   my @cxns = @_;
+   my @result;
+   foreach my $cxn ( @cxns ) {
+      my $stmt = do_stmt($cxn, 'INDEX_TABLE_STATISTICS') or next;
+      my $arr  = $stmt->fetchall_arrayref({});
+      push @result, map { $_->{cxn} = $cxn; $_ } @$arr;
+   }
+   return @result;
+}
+
+# get_table_statistics {{{3
+sub get_table_statistics {
+   my @cxns = @_;
+   my @result;
+   foreach my $cxn ( @cxns ) {
+      my $stmt = do_stmt($cxn, 'TABLE_STATISTICS') or next;
+      my $arr  = $stmt->fetchall_arrayref({});
+      push @result, map { $_->{cxn} = $cxn; $_ } @$arr;
+   }
+   return @result;
+}
+
+# get_innodb_blocked_blocker {{{3
+sub get_innodb_blocked_blocker {
+   my @cxns = @_;
+   my @result;
+   foreach my $cxn ( @cxns ) {
+      my $stmt = do_stmt($cxn, 'INNODB_BLOCKED_BLOCKER') 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 {
+            next if ($show_variables{$cxn}->{have_innodb} || 'YES') eq 'NO';
+            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
+               $show_variables{$cxn}->{version}
+            )
+         );
+         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 {
+      # disable binary logging for the session
+      do_query($cxn, "set SQL_LOG_BIN=0");
+
+      # 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");
+
+      # enable binary logging for the session again
+      # the session by itself will not be used anymore, but this is clean :)
+      do_query($cxn, "set SQL_LOG_BIN=1");
+
+   };
+   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
+# Inserts special counters as though they are SHOW STATUS counters.
+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;
+         $vars->{Uptime_hires} ||= get_uptime($cxn);
+
+         my $stmt = do_stmt($cxn, 'SHOW_MASTER_STATUS') or next;
+         my $res = $stmt->fetchall_arrayref({})->[0];
+         @{$vars}{ keys %$res } = values %$res;
+
+      }
+   }
+}
+
+# get_slave_status {{{3
+# Separated handling of slave status to support 5.7 and replication channels
+sub get_slave_status {
+   my ($cxn, $channel) = @_;
+                my $chcxn = $channel . '=' . $cxn;
+         $vars{$chcxn}->{$clock} ||= {};
+         my $vars = $vars{$chcxn}->{$clock};
+         $vars->{chcxn} = $chcxn;
+         $vars->{Uptime_hires} ||= get_uptime($chcxn);
+
+                if ( $channel =~ /no_channels/ ) {
+               my $stmt = do_stmt($cxn, 'SHOW_SLAVE_STATUS') or next;
+               my $res = $stmt->fetchall_arrayref({});
+               if ( $res && @$res ) {
+                       $res = $res->[0];
+                       @{$vars}{ keys %$res } = values %$res;
+               $vars->{Slave_ok} =
+                               (($res->{slave_sql_running} || 'Yes') eq 'Yes'
+                               && ($res->{slave_io_running} || 'Yes') eq 'Yes') ? 'Yes' : 'No';
+               }
+               else {
+               $vars->{Slave_ok} = 'Off';
+               }
+                } else {
+                                my $dbh = connect_to_db($cxn);
+                                my $sql = 'SHOW SLAVE STATUS FOR CHANNEL \'' . $channel . '\'';
+                                my $stmt = $dbh->prepare($sql ) ;
+                                $stmt->execute();
+                        my $res = $stmt->fetchall_arrayref({});
+                        if ( $res && @$res ) {
+                           $res = $res->[0];
+                           @{$vars}{ keys %$res } = values %$res;
+                           $vars->{Slave_ok} =
+                              (($res->{slave_sql_running} || 'Yes') eq 'Yes'
+                              && ($res->{slave_io_running} || 'Yes') eq 'Yes') ? 'Yes' : 'No';
+                        }
+                        else {
+                                        $vars->{Slave_ok} = 'Off';
+                        }
+                       }
+       }
+
+
+
+
+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 mariadb_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 --timestamp
+
+In -n mode, write a timestamp either before every screenful of output, or if
+the option is given twice, at the start of every line.  The format is controlled
+by the timeformat config variable.
+
+=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 A: Health Dashboard
+
+This mode displays a single table with one row per monitored server. The
+columns show essential overview information about the server's health, and
+coloration rules show whether replication is running or if there are any very
+long-running queries or excessive replication delay.
+
+=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, unparsable 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 K: InnoDB Lock Waits
+
+This mode shows information from InnoDB plugin's transaction and locking tables.
+You can use it to find when a transaction is waiting for another, and kill the
+blocking transaction. It displays the L<"innodb_blocked_blocker>" table.
+
+=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 U: User Statistics
+
+This mode displays data that's available in Percona's enhanced version of MySQL
+(also known as Percona Server with XtraDB).  Specifically, it makes it easy to
+enable and disable the so-called "user statistics."  This feature gathers stats
+on clients, threads, users, tables, and indexes and makes them available as
+INFORMATION_SCHEMA tables.  These are invaluable for understanding what your
+server is doing.  They are also available in MariaDB.
+
+The statistics supported so far are only from the TABLE_STATISTICS and
+INDEX_STATISTICS tables added by Percona.  There are three views: one of table stats,
+one of index stats (which can be aggregated with the = key), and one of both.
+
+The server doesn't gather these stats by default.  You have to set the variable
+userstat_running to turn it on.  You can do this easily with innotop from U mode,
+with the 's' key.
+
+=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.
+
+in L<"U: User Statistics"> mode, you can use the 's' key to start and stop
+the collection of the statistics data for TABLE_STATISTICS and similar.
+
+=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:MariaDB:;mariadb_read_default_group=mysql;host=HOSTNAME
+
+Since this DSN is passed to the DBD::MariaDB driver, you should read the driver's
+documentation at L<https://metacpan.org/pod/DBD::MariaDB> 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 mariadb_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 spark
+
+Specifies how wide a spark chart is. There are two ASCII spark charts in A
+mode, showing QPS and User_threads_running.
+
+=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.
+
+=item timeformat
+
+The C-style strftime()-compatible format for the timestamp line to be printed
+in -n mode when -t is set.
+
+=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 health_dashboard
+
+Displays an overall summary of servers, one server per line, for monitoring.
+Data source: L<"STATUS_VARIABLES">, L<"MASTER_SLAVE">, L<"PROCESSLIST_STATS">.
+
+=item index_statistics
+
+Displays data from the INDEX_STATISTICS table in Percona-enhanced servers.
+
+=item index_table_statistics
+
+Displays data from the INDEX_STATISTICS and TABLE_STATISTICS tables in
+Percona-enhanced servers.  It joins the two together, grouped by the database
+and table name.  It is the default view in L<"U: User Statistics"> mode,
+and makes it easy to see what tables are hot, how many rows are read from indexes,
+how many changes are made, and how many changes are made to indexes.
+
+=item innodb_blocked_blocker
+
+Displays InnoDB locks and lock waits. Data source: L<"INNODB_BLOCKED_BLOCKER">.
+
+=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 table_statistics
+
+Displays data from the TABLE_STATISTICS table in Percona-enhanced servers.
+
+=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.
+
+=item *
+
+agghide: the reverse of aggonly.  The column is hidden when grouping is enabled.
+
+=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'.  Internally,
+the filter is compiled into a subroutine like this:
+
+ sub filter {
+    my ( $set ) = @_;
+    $set->{info} =~ m/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.
+
+What if you want the filter to discard matching rows, rather than showing
+matching rows?  If you're familiar with Perl regular expressions, you might
+guess how to do this.  You have to use a zero-width negative lookahead
+assertion.  If you don't know what that means, don't worry.  Let's filter out
+all rows where the command is Gandalf.  Type the following:
+
+ 1. /
+ 2. cmd ^(?!Gandalf)
+
+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
+generating execution plans for your statements.  Something is wrong; it should
+normally take milliseconds to plan 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 distill
+
+Distills SQL into verb-noun-noun format for quick comprehension.
+
+=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 fuzzy_time
+
+Converts a number of seconds into a friendly, readable value like "1h35m".
+
+=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   Additional 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 (.pm) file 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 files named C<*.pm>.  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 such as Foo::Bar, with double colons (::) 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.  (If you copy and paste this example code, be sure to remove
+the first space from each line; lines such as '# description' must not start with
+whitespace).
+
+ 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
+ =================== ===============================
+ INDEX_STATISTICS    SELECT * FROM INFORMATION_SCHEMA.INDEX_STATISTICS
+ 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
+ TABLE_STATISTICS    SELECT * FROM INFORMATION_SCHEMA.TABLE_STATISTICS
+
+=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_BLOCKED_BLOCKER
+
+This data is from the INFORMATION_SCHEMA tables related to InnoDB locks and
+the processlist.
+
+=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 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 MASTER_SLAVE
+
+This data is from the combination of SHOW MASTER STATUS and SHOW SLAVE STATUS.
+
+=item OPEN_TABLES
+
+This data is from SHOW OPEN TABLES.
+
+=item PROCESSLIST
+
+This data is from SHOW FULL PROCESSLIST.
+
+=item PROCESSLIST_STATS
+
+This data is from SHOW FULL PROCESSLIST and computes stats such as the maximum time
+a user query has been running, and how many user queries are running. A "user
+query" excludes replication threads.
+
+=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::MariaDB,  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.
+
+Aaron Racine,
+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., 51 Franklin
+Street, Fifth Floor, Boston, MA 02110-1335 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<https://github.com/innotop/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/additions/innotop/innotop.1 b/additions/innotop/innotop.1
new file mode 100644 (file)
index 0000000..b0e21b5
--- /dev/null
@@ -0,0 +1,2200 @@
+.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.28)
+.\"
+.\" 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" ''
+.    ds C`
+.    ds C'
+'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.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{
+.    if \nF \{
+.        de IX
+.        tm Index:\\$1\t\\n%\t"\\$2"
+..
+.        if !\nF==2 \{
+.            nr % 0
+.            nr F 2
+.        \}
+.    \}
+.\}
+.rr rF
+.\"
+.\" 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 "2017-01-23" "perl v5.20.2" "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 mariadb_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 A FILE\*(R"\s0 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\*(R"\s0 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 "\-\-timestamp" 4
+.IX Item "--timestamp"
+In \-n mode, write a timestamp either before every screenful of output, or if
+the option is given twice, at the start of every line.  The format is controlled
+by the timeformat config variable.
+.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 "A: Health Dashboard" 4
+.IX Item "A: Health Dashboard"
+This mode displays a single table with one row per monitored server. The
+columns show essential overview information about the server's health, and
+coloration rules show whether replication is running or if there are any very
+long-running queries or excessive replication delay.
+.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 INNODB STATUS.\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\*(R"\s0.  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 VARIABLES LIKE \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
+INNODB STATUS\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 INNODB
+STATUS\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
+CONNECTIONS\*(R"\s0).
+.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, unparsable 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 "K: InnoDB Lock Waits" 4
+.IX Item "K: InnoDB Lock Waits"
+This mode shows information from InnoDB plugin's transaction and locking tables.
+You can use it to find when a transaction is waiting for another, and kill the
+blocking transaction. It displays the "innodb_blocked_blocker" table.
+.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 INNODB STATUS,\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 INNODB STATUS\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 12,\s0 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 SLAVE STATUS\s0 and \s-1SHOW MASTER STATUS\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 OPEN TABLES\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 "U: User Statistics" 4
+.IX Item "U: User Statistics"
+This mode displays data that's available in Percona's enhanced version of MySQL
+(also known as Percona Server with XtraDB).  Specifically, it makes it easy to
+enable and disable the so-called \*(L"user statistics.\*(R"  This feature gathers stats
+on clients, threads, users, tables, and indexes and makes them available as
+\&\s-1INFORMATION_SCHEMA\s0 tables.  These are invaluable for understanding what your
+server is doing.  They are also available in MariaDB.
+.Sp
+The statistics supported so far are only from the \s-1TABLE_STATISTICS\s0 and
+\&\s-1INDEX_STATISTICS\s0 tables added by Percona.  There are three views: one of table stats,
+one of index stats (which can be aggregated with the = key), and one of both.
+.Sp
+The server doesn't gather these stats by default.  You have to set the variable
+userstat_running to turn it on.  You can do this easily with innotop from U mode,
+with the 's' key.
+.IP "Q: Query List" 4
+.IX Item "Q: Query List"
+This mode displays the output from \s-1SHOW FULL PROCESSLIST,\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 EXTENDED. \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 SERVER\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 INNODB STATUS\s0 output used to render the
+screen.  The first word is the number of seconds since the last \s-1SHOW INNODB
+STATUS,\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 SERVERS\s0"
+.IX Subsection "MULTIPLE SERVERS"
+If you are monitoring multiple servers (see \*(L"\s-1SERVER CONNECTIONS\*(R"\s0), 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 GROUPS\*(R"\s0), 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 HANDLING\*(R"\s0 for more details about innotop's error handling.
+.SS "\s-1MONITORING A FILE\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 QUERY\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 SLAVE\s0 or \s-1STOP SLAVE\s0
+for you, but you can actually edit the command and send anything you wish, such
+as \s-1SET GLOBAL\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 MASTER LOGS\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 MASTER LOGS.\s0
+.PP
+in \*(L"U: User Statistics\*(R" mode, you can use the 's' key to start and stop
+the collection of the statistics data for \s-1TABLE_STATISTICS\s0 and similar.
+.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:MariaDB:;mariadb_read_default_group=mysql;host=HOSTNAME
+.Ve
+.Sp
+Since this \s-1DSN\s0 is passed to the DBD::MariaDB driver, you should read the driver's
+documentation at <https://metacpan.org/pod/DBD::MariaDB> 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 mariadb_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 BETWEEN CONNECTIONS\*(R"\s0.
+.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 GROUPS\*(R"\s0) 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 STATUS\*(R"\s0.
+.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\*(R"\s0.  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 STATUS\*(R"\s0).
+.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 STATEMENTS\*(R"\s0 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 GLOBAL STATUS. \s0 If innotop calls
+\&\s-1SHOW FULL PROCESSLIST\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 GLOBAL STATUS\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 EDITOR\*(R"\s0.
+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\*(R"\s0).  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\*(R"\s0 for details.
+.IP "p: Manage Plugins" 4
+.IX Item "p: Manage Plugins"
+Starts the plugin configuration editor.  See \*(L"\s-1PLUGINS\*(R"\s0 for details.
+.IP "s: Server Groups" 4
+.IX Item "s: Server Groups"
+Lets you create and edit server groups.  See \*(L"\s-1SERVER GROUPS\*(R"\s0.
+.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\*(R"\s0 and
+\&\*(L"\s-1TABLES\*(R"\s0.
+.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 SETS\*(R"\s0.
+.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\*(R"\s0.
+.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 VARIABLES\s0 and \s-1SHOW STATUS. \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\*(R"\s0.
+.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 HANDLING\*(R"\s0.
+.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 HANDLING\*(R"\s0.
+.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
+STATUS\*(R"\s0.
+.IP "skip_innodb" 4
+.IX Item "skip_innodb"
+Disables fetching \s-1SHOW INNODB STATUS,\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 INNODB STATUS.\s0
+.IP "spark" 4
+.IX Item "spark"
+Specifies how wide a spark chart is. There are two \s-1ASCII\s0 spark charts in A
+mode, showing \s-1QPS\s0 and User_threads_running.
+.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.
+.IP "timeformat" 4
+.IX Item "timeformat"
+The C\-style \fIstrftime()\fR\-compatible format for the timestamp line to be printed
+in \-n mode when \-t is set.
+.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\*(R"\s0 for more information.
+.IP "filters" 4
+.IX Item "filters"
+This section holds user-defined filters (see \*(L"\s-1FILTERS\*(R"\s0).  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\*(R"\s0).
+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 CONNECTIONS\*(R"\s0.
+.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 GROUPS\*(R"\s0.
+.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\*(R"\s0.
+.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\*(R"\s0.
+.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\*(R"\s0.
+.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 SETS\*(R"\s0.
+.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\*(R"\s0.
+.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\*(R"\s0.
+.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 EDITOR\*(R"\s0).
+.PP
+You can choose which tables to show by pressing the '$' key.  See \*(L"\s-1MODES\*(R"\s0 and
+\&\*(L"\s-1TABLES\*(R"\s0.
+.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\*(R"\s0).  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\*(R"\s0.
+.IP "\(bu" 4
+innotop sorts the rows.  See \*(L"\s-1SORTING\*(R"\s0.
+.IP "\(bu" 4
+innotop groups the rows together, if specified.  See \*(L"\s-1GROUPING\*(R"\s0.
+.IP "\(bu" 4
+innotop colorizes the rows.  See \*(L"\s-1COLORS\*(R"\s0.
+.IP "\(bu" 4
+innotop transforms the column values in each row.  See \*(L"\s-1TRANSFORMATIONS\*(R"\s0.
+.IP "\(bu" 4
+innotop optionally pivots the rows (see \*(L"\s-1PIVOTING\*(R"\s0), 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\*(R"\s0.
+.IP "buffer_pool" 4
+.IX Item "buffer_pool"
+Displays data about InnoDB's buffer pool.  Data source: \*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.IP "cmd_summary" 4
+.IX Item "cmd_summary"
+Displays weighted status variables.  Data source: \*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.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\*(R"\s0.
+.IP "deadlock_transactions" 4
+.IX Item "deadlock_transactions"
+Shows transactions involved in the last detected deadlock.  Data source:
+\&\*(L"\s-1DEADLOCK_TRANSACTIONS\*(R"\s0.
+.IP "explain" 4
+.IX Item "explain"
+Shows the output of \s-1EXPLAIN. \s0 Data source: \*(L"\s-1EXPLAIN\*(R"\s0.
+.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\*(R"\s0.
+.IP "fk_error" 4
+.IX Item "fk_error"
+Displays various data about InnoDB's last foreign key error.  Data source:
+\&\*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.IP "health_dashboard" 4
+.IX Item "health_dashboard"
+Displays an overall summary of servers, one server per line, for monitoring.
+Data source: \*(L"\s-1STATUS_VARIABLES\*(R"\s0, \*(L"\s-1MASTER_SLAVE\*(R"\s0, \*(L"\s-1PROCESSLIST_STATS\*(R"\s0.
+.IP "index_statistics" 4
+.IX Item "index_statistics"
+Displays data from the \s-1INDEX_STATISTICS\s0 table in Percona-enhanced servers.
+.IP "index_table_statistics" 4
+.IX Item "index_table_statistics"
+Displays data from the \s-1INDEX_STATISTICS\s0 and \s-1TABLE_STATISTICS\s0 tables in
+Percona-enhanced servers.  It joins the two together, grouped by the database
+and table name.  It is the default view in \*(L"U: User Statistics\*(R" mode,
+and makes it easy to see what tables are hot, how many rows are read from indexes,
+how many changes are made, and how many changes are made to indexes.
+.IP "innodb_blocked_blocker" 4
+.IX Item "innodb_blocked_blocker"
+Displays InnoDB locks and lock waits. Data source: \*(L"\s-1INNODB_BLOCKED_BLOCKER\*(R"\s0.
+.IP "innodb_locks" 4
+.IX Item "innodb_locks"
+Displays InnoDB locks.  Data source: \*(L"\s-1INNODB_LOCKS\*(R"\s0.
+.IP "innodb_transactions" 4
+.IX Item "innodb_transactions"
+Displays data about InnoDB's current transactions.  Data source:
+\&\*(L"\s-1INNODB_TRANSACTIONS\*(R"\s0.
+.IP "insert_buffers" 4
+.IX Item "insert_buffers"
+Displays data about InnoDB's insert buffer.  Data source: \*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.IP "io_threads" 4
+.IX Item "io_threads"
+Displays data about InnoDB's I/O threads.  Data source: \*(L"\s-1IO_THREADS\*(R"\s0.
+.IP "log_statistics" 4
+.IX Item "log_statistics"
+Displays data about InnoDB's logging system.  Data source: \*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.IP "master_status" 4
+.IX Item "master_status"
+Displays replication master status.  Data source: \*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.IP "open_tables" 4
+.IX Item "open_tables"
+Displays open tables.  Data source: \*(L"\s-1OPEN_TABLES\*(R"\s0.
+.IP "page_statistics" 4
+.IX Item "page_statistics"
+Displays InnoDB page statistics.  Data source: \*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.IP "pending_io" 4
+.IX Item "pending_io"
+Displays InnoDB pending I/O operations.  Data source: \*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.IP "processlist" 4
+.IX Item "processlist"
+Displays current MySQL processes (threads/connections).  Data source:
+\&\*(L"\s-1PROCESSLIST\*(R"\s0.
+.IP "q_header" 4
+.IX Item "q_header"
+Displays various status values.  Data source: \*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.IP "row_operation_misc" 4
+.IX Item "row_operation_misc"
+Displays data about InnoDB's row operations.  Data source:
+\&\*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.IP "row_operations" 4
+.IX Item "row_operations"
+Displays data about InnoDB's row operations.  Data source:
+\&\*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.IP "semaphores" 4
+.IX Item "semaphores"
+Displays data about InnoDB's semaphores and mutexes.  Data source:
+\&\*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.IP "slave_io_status" 4
+.IX Item "slave_io_status"
+Displays data about the slave I/O thread.  Data source:
+\&\*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.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\*(R"\s0.
+.IP "table_statistics" 4
+.IX Item "table_statistics"
+Displays data from the \s-1TABLE_STATISTICS\s0 table in Percona-enhanced servers.
+.IP "t_header" 4
+.IX Item "t_header"
+Displays various InnoDB status values.  Data source: \*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.IP "var_status" 4
+.IX Item "var_status"
+Displays user-configurable data.  Data source: \*(L"\s-1STATUS_VARIABLES\*(R"\s0.
+.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\*(R"\s0.
+.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 EDITOR\*(R"\s0 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 SOURCES\*(R"\s0).  See \*(L"\s-1EXPRESSIONS\*(R"\s0 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\*(R"\s0.
+.IP "\(bu" 4
+agg: an aggregate function.  See \*(L"\s-1GROUPING\*(R"\s0.  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\*(R"\s0).  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.
+.IP "\(bu" 4
+agghide: the reverse of aggonly.  The column is hidden when grouping is enabled.
+.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'.  Internally,
+the filter is compiled into a subroutine like this:
+.PP
+.Vb 4
+\& sub filter {
+\&    my ( $set ) = @_;
+\&    $set\->{info} =~ m/product/;
+\& }
+.Ve
+.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
+What if you want the filter to discard matching rows, rather than showing
+matching rows?  If you're familiar with Perl regular expressions, you might
+guess how to do this.  You have to use a zero-width negative lookahead
+assertion.  If you don't know what that means, don't worry.  Let's filter out
+all rows where the command is Gandalf.  Type the following:
+.PP
+.Vb 2
+\& 1. /
+\& 2. cmd ^(?!Gandalf)
+.Ve
+.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 EDITOR\*(R"\s0 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 GROUP BY\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
+generating execution plans for your statements.  Something is wrong; it should
+normally take milliseconds to plan 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\*(R"\s0.  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 STATUS:\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 "distill" 4
+.IX Item "distill"
+Distills \s-1SQL\s0 into verb-noun-noun format for quick comprehension.
+.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 "fuzzy_time" 4
+.IX Item "fuzzy_time"
+Converts a number of seconds into a friendly, readable value like \*(L"1h35m\*(R".
+.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 EDITOR\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   Additional 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\*(R"\s0).
+.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\*(R"\s0) 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\*(R"\s0.
+.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 SELECT\s0 list.
+.PP
+The data source for variable sets, and indeed the entire S mode, is the
+combination of \s-1SHOW STATUS, SHOW VARIABLES,\s0 and \s-1SHOW INNODB STATUS. \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\*(R"\s0 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 (.pm) file 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 files named \f(CW\*(C`*.pm\*(C'\fR.  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 such as Foo::Bar, with double colons (::) 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\*(R"\s0.
+.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\*(R"\s0 for more.
+.IP "modes" 4
+.IX Item "modes"
+A hashref of modes.  See \*(L"\s-1MODES\*(R"\s0 for more.
+.IP "server_groups" 4
+.IX Item "server_groups"
+A hashref of server groups.  See \*(L"\s-1SERVER GROUPS\*(R"\s0.
+.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\*(R"\s0 for more information).
+.IP "trans_funcs" 4
+.IX Item "trans_funcs"
+A hashref of transformation functions.  See \*(L"\s-1TRANSFORMATIONS\*(R"\s0.
+.IP "var_sets" 4
+.IX Item "var_sets"
+A hashref of variable sets.  See \*(L"\s-1VARIABLE SETS\*(R"\s0.
+.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.  (If you copy and paste this example code, be sure to remove
+the first space from each line; lines such as '# description' must not start with
+whitespace).
+.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 ENGINE INNODB STATUS\*(R",\s0 while on earlier versions it executes
+\&\*(L"\s-1SHOW INNODB STATUS\*(R". \s0 The statements are as follows:
+.PP
+.Vb 10
+\& Statement           SQL executed
+\& =================== ===============================
+\& INDEX_STATISTICS    SELECT * FROM INFORMATION_SCHEMA.INDEX_STATISTICS
+\& 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
+\& TABLE_STATISTICS    SELECT * FROM INFORMATION_SCHEMA.TABLE_STATISTICS
+.Ve
+.SH "DATA SOURCES"
+.IX Header "DATA SOURCES"
+Each time innotop extracts values to create a table (see \*(L"\s-1EXPRESSIONS\*(R"\s0 and
+\&\*(L"\s-1TABLES\*(R"\s0), it does so from a particular data source.  Largely because of the
+complex data extracted from \s-1SHOW INNODB STATUS,\s0 this is slightly messy.  \s-1SHOW
+INNODB STATUS\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 STATUS\s0 and \s-1SHOW VARIABLES,\s0 but other sources
+may be included as needed, for example, \s-1SHOW MASTER STATUS\s0 and \s-1SHOW SLAVE
+STATUS,\s0 as well as many of the non-repeated values from \s-1SHOW INNODB STATUS.\s0
+.IP "\s-1DEADLOCK_LOCKS\s0" 4
+.IX Item "DEADLOCK_LOCKS"
+This data is extracted from the transaction list in the \s-1LATEST DETECTED DEADLOCK\s0
+section of \s-1SHOW INNODB STATUS. \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 DETECTED DEADLOCK\s0
+section of \s-1SHOW INNODB STATUS. \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_BLOCKED_BLOCKER\s0" 4
+.IX Item "INNODB_BLOCKED_BLOCKER"
+This data is from the \s-1INFORMATION_SCHEMA\s0 tables related to InnoDB locks and
+the processlist.
+.IP "\s-1INNODB_TRANSACTIONS\s0" 4
+.IX Item "INNODB_TRANSACTIONS"
+This data is from the \s-1TRANSACTIONS\s0 section of \s-1SHOW INNODB STATUS.\s0
+.IP "\s-1IO_THREADS\s0" 4
+.IX Item "IO_THREADS"
+This data is from the list of threads in the \s-1FILE I/O\s0 section of \s-1SHOW INNODB
+STATUS.\s0
+.IP "\s-1INNODB_LOCKS\s0" 4
+.IX Item "INNODB_LOCKS"
+This data is from the \s-1TRANSACTIONS\s0 section of \s-1SHOW INNODB STATUS\s0 and is nested
+two levels deep.
+.IP "\s-1MASTER_SLAVE\s0" 4
+.IX Item "MASTER_SLAVE"
+This data is from the combination of \s-1SHOW MASTER STATUS\s0 and \s-1SHOW SLAVE STATUS.\s0
+.IP "\s-1OPEN_TABLES\s0" 4
+.IX Item "OPEN_TABLES"
+This data is from \s-1SHOW OPEN TABLES.\s0
+.IP "\s-1PROCESSLIST\s0" 4
+.IX Item "PROCESSLIST"
+This data is from \s-1SHOW FULL PROCESSLIST.\s0
+.IP "\s-1PROCESSLIST_STATS\s0" 4
+.IX Item "PROCESSLIST_STATS"
+This data is from \s-1SHOW FULL PROCESSLIST\s0 and computes stats such as the maximum time
+a user query has been running, and how many user queries are running. A \*(L"user
+query\*(R" excludes replication threads.
+.IP "\s-1OS_WAIT_ARRAY\s0" 4
+.IX Item "OS_WAIT_ARRAY"
+This data is from the \s-1SEMAPHORES\s0 section of \s-1SHOW INNODB STATUS\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 CONNECTIONS\*(R"\s0).
+.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::MariaDB,  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.  I\s0
+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
+Aaron Racine,
+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 PROGRAM IS PROVIDED \*(L"AS IS\*(R" AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\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., 51 Franklin
+Street, Fifth Floor, Boston, \s-1MA 02110-1335 USA\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
+<https://github.com/innotop/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/additions/mariadb-report b/additions/mariadb-report
new file mode 100755 (executable)
index 0000000..b95f226
--- /dev/null
@@ -0,0 +1,1595 @@
+#!/usr/bin/perl
+
+# mariadb-report v4.0 Oct 23 2015
+# renamed to from mysqlreport in 2020
+# http://hackmysql.com/mysqlreport
+
+# mariadb-report makes an easy-to-read report of important MySQL/MariaDB status values.
+# Copyright 2006-2008 Daniel Nichter
+# Copyright 2012-2015 Jean Weisbuch
+#
+# 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;
+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 ($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
+my ($pagecache_read_ratio, $pagecache_write_ratio, $pagecache_block_size, $pagecache_buffer_used, $pagecache_buffer_usage); # AriaDB pagecache stats
+my ($binlog_cache_ratio, $binlog_stmt_cache_ratio); # binary log cache
+my $dbms;
+my ($rows, $rows_using_indexes);
+
+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 "mariadb-report has forked and detached.\n";
+      print "While running detached, mariadb-report 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/MariaDB
+if(!$op{'infile'} && !$relative_infiles)
+{
+   connect_to_MySQL();
+}
+
+my $have_innodb_vals = 1; # This might be set to 0 later in get_MySQL_version()
+my $have_aria_vals = 0;
+my $have_subquerycache_vals = 0;
+my $have_binlog_vals = 0;
+my $use_thread_pool = 0;
+
+if(defined $op{'r'})
+{
+   if($relative_live)
+   {
+      print STDERR "mariadb-report 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;
+   set_aria_vals() if $have_aria_vals;
+   set_subquerycache_vals() if $have_subquerycache_vals;
+   set_binlog_vals() if $have_binlog_vals;
+
+   write_report();
+}
+
+exit_tasks_and_cleanup();
+
+exit;
+
+#
+# Subroutines
+#
+sub show_help_and_exit
+{
+   print <<"HELP";
+mariadb-report v4.0 Oct 23 2015
+mariadb-report makes an easy-to-read report of important MySQL/MariaDB 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};
+
+    if(my @driverList = grep {/mariadb|mysql/i} DBI->available_drivers()) {
+        my $dsn;
+        my $driver = undef;
+
+        if(grep {/mariadb/i} @driverList)
+        {
+            $driver = "DBI:MariaDB";
+        }
+        elsif(grep {/mysql/i} @driverList)
+        {
+            $driver = "DBI:mysql";
+        }
+
+        if($mycnf{'socket'} && -S $mycnf{'socket'})
+        {
+            if(grep {/mariadb/i} @driverList)
+            {
+                $dsn = $driver . ":mariadb_socket=$mycnf{socket}";
+            }
+            elsif(grep {/mysql/i} @driverList)
+            {
+                $dsn = $driver . ":mysql_socket=$mycnf{socket}";
+            }
+        }
+        elsif($mycnf{'host'})
+        {
+            $dsn = $driver . ":host=$mycnf{host}" . ($mycnf{port} ? ";port=$mycnf{port}" : "");
+        }
+        else
+        {
+            $dsn = $driver . ":host=localhost";
+        }
+
+        print "connect_to_MySQL: DBI DSN: " . $dsn . "\n" if $op{debug};
+
+        $dbh = DBI->connect($dsn, $mycnf{'user'}, $mycnf{'pass'}) or die;
+    }
+    else
+    {
+        print STDERR "Install Perl 5.x driver: DBD:mysql or DBD:MariaDB\n";
+        print STDERR "currently installed Perl DBD drivers:\n";
+        foreach my $driver (DBI->available_drivers())
+        {
+            print STDERR " * " . $driver . "\n";
+        }
+        print STDERR "\n";
+        die("Exit as no MariaDB DBI driver found!\n");
+    }
+}
+
+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;
+   set_aria_vals() if $have_aria_vals;
+   set_subquerycache_vals() if $have_subquerycache_vals;
+   set_binlog_vals() if $have_binlog_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 separate 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 occurrence of Aborted_clients indicates the beginning
+            # of the first set of status values if no sets have occurred 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;
+      set_aria_vals() if $have_aria_vals;
+      set_subquerycache_vals() if $have_subquerycache_vals;
+      set_binlog_vals() if $have_binlog_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, $query);
+
+   # Get status values
+   if($MySQL_version >= 50002)
+   {
+      $query = $dbh->prepare("SHOW GLOBAL STATUS;");
+   }
+   else
+   {
+      $query = $dbh->prepare("SHOW STATUS;");
+   }
+   $query->execute();
+   # To avoid problems if the variable capitalization would change (eg. TokuDB on MariaDB 5.5 => 10.0), the $stats index is forced to have its first char uppercase and the rest lowercase
+   while(@row = $query->fetchrow_array()) { $stats{ucfirst(lc($row[0]))} = $row[1]; }
+   $query->finish();
+
+   $real_uptime = $stats{'Uptime'};
+}
+
+sub get_vars
+{
+   print "get_vars\n" if $op{debug};
+
+   my (@row, $query);
+
+   # Get server system variables
+   $query = $dbh->prepare("SHOW VARIABLES;");
+   $query->execute();
+   while(@row = $query->fetchrow_array()) { $vars{$row[0]} = $row[1]; }
+   $query->finish();
+   # table_cache was renamed to table_open_cache in MySQL 5.1.3
+   if($MySQL_version >= 50103)
+   {
+      $vars{'table_cache'} = $vars{'table_open_cache'};
+   }
+   # log_slow_queries was renamed to slow_query_log in MySQL 5.1.29
+   if($MySQL_version >= 50129)
+   {
+      $vars{'log_slow_queries'} = $vars{'slow_query_log'};
+   }
+}
+
+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})/);
+      if($vars{'version'} =~ /^\d{1,2}\.\d{1,2}\.\d{1,2}-MariaDB/) {
+        print "MariaDB detected\n" if $op{debug};
+        $dbms = "MariaDB";
+      } else {
+        $dbms = "MySQL";
+      }
+   }
+   else
+   {
+      my (@row, $query);
+
+      $query = $dbh->prepare("SHOW VARIABLES LIKE 'version';");
+      $query->execute();
+      @row = $query->fetchrow_array();
+      $query->finish();
+      ($major, $minor, $patch) = ($row[1] =~ /^(\d{1,2})\.(\d{1,2})\.(\d{1,2})/);
+      if($row[1] =~ /^\d{1,2}\.\d{1,2}\.\d{1,2}-MariaDB/)
+      {
+         print "MariaDB detected\n" if $op{debug};
+         $dbms = "MariaDB";
+      }
+      else
+      {
+         $dbms = "MySQL";
+      }
+   }
+
+   # The major version number is kept as is while the minor version and the revision number are forced to 2 digits
+   # e.g.: 5.5.9 will be 50509, 10.0.5 will be 100005 and 10.1.23 will be 100123
+   $MySQL_version = sprintf("%d%02d%02d", $major, $minor, $patch);
+   print "Version $MySQL_version\n" if $op{debug};
+
+   # 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};
+   } else {
+      $have_innodb_vals = $dbh->selectall_arrayref("SELECT SUPPORT FROM information_schema.engines WHERE ENGINE = 'InnoDB';", undef)->[0][0];
+      if(defined($have_innodb_vals) && ($have_innodb_vals eq "YES" || $have_innodb_vals eq "DEFAULT"))
+      {
+         print "InnoDB detected\n" if $op{debug};
+         $have_innodb_vals = 1;
+      } else {
+         print "InnoDB is not activated\n" if $op{debug};
+         $have_innodb_vals = 0;
+      }
+   }
+
+   if($dbms eq "MariaDB") {
+      $have_aria_vals = $dbh->selectall_arrayref("SELECT SUPPORT FROM information_schema.engines WHERE ENGINE = 'Aria';", undef)->[0][0];
+      if(defined($have_aria_vals) && $have_aria_vals eq "YES")
+      {
+         print "Aria engine detected\n" if $op{debug};
+         $have_aria_vals = 1;
+      } else {
+         $have_aria_vals = 0;
+      }
+
+      # MariaDB 5.3+, activated by default since 5.3.2
+      $have_subquerycache_vals = $dbh->selectall_arrayref("SELECT VARIABLE_VALUE REGEXP ',subquery_cache=on,|^subquery_cache=on,|,subquery_cache=on\$' AS SUBQUERY_CACHE FROM information_schema.global_variables WHERE VARIABLE_NAME = 'optimizer_switch';", undef)->[0][0];
+      if(defined($have_subquerycache_vals) && $have_subquerycache_vals eq "1")
+      {
+         print "Subquery cache is activated\n" if $op{debug};
+         $have_subquerycache_vals = 1;
+      } else {
+         $have_subquerycache_vals = 0;
+      }
+   }
+
+   if($MySQL_version >= 50000)
+   {
+      # These checks use the 'information_schema' virtual database that has been added on MySQL 5.0
+
+      # MariaDB 5.5.21+ and Percona Server 5.5.30+ use the same thread pool implementation
+      $use_thread_pool = $dbh->selectall_arrayref("SELECT VARIABLE_VALUE FROM information_schema.global_variables WHERE VARIABLE_NAME = 'thread_handling';", undef)->[0][0];
+      if(defined($use_thread_pool) && $use_thread_pool eq "pool-of-threads") {
+         print "Thread pool is used\n" if $op{debug};
+         $use_thread_pool = 1;
+      } else {
+         $use_thread_pool = 0;
+      }
+
+      $have_binlog_vals = $dbh->selectall_arrayref("SELECT VARIABLE_VALUE FROM information_schema.global_variables WHERE VARIABLE_NAME = 'log_bin';", undef)->[0][0];
+      if(defined($have_binlog_vals) && $have_binlog_vals eq "ON")
+      {
+         print "Binary log is activated\n" if $op{debug};
+         $have_binlog_vals = 1;
+      } else {
+         $have_binlog_vals = 0;
+      }
+   }
+}
+
+sub set_myisam_vals
+{
+   print "set_myisam_vals\n" if $op{debug};
+
+# should be moved elsewhere
+   $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 set_aria_vals
+{
+   print "set_aria_vals\n" if $op{debug};
+
+   $pagecache_read_ratio = sprintf "%.2f",
+                     ($stats{'Aria_pagecache_read_requests'} ?
+                      100 - ($stats{'Aria_pagecache_reads'} / $stats{'Aria_pagecache_read_requests'}) * 100 :
+                      0);
+
+   $pagecache_write_ratio = sprintf "%.2f",
+                      ($stats{'Aria_pagecache_write_requests'} ?
+                       100 - ($stats{'Aria_pagecache_writes'} / $stats{'Aria_pagecache_write_requests'}) * 100 :
+                       0);
+
+   $pagecache_block_size = (defined $vars{'aria_block_size'} ?
+                            $vars{'aria_block_size'} :
+                            1024);
+
+   $pagecache_buffer_used = $stats{'Aria_pagecache_blocks_used'} * $pagecache_block_size;
+
+   $pagecache_buffer_usage =  $vars{'aria_pagecache_buffer_size'} -
+                      ($stats{'Aria_pagecache_blocks_unused'} * $pagecache_block_size);
+}
+
+sub set_subquerycache_vals
+{
+   print "set_subquerycache_vals\n" if $op{debug};
+}
+
+sub set_binlog_vals
+{
+   print "set_binlog_vals\n" if $op{debug};
+
+   if($stats{'Binlog_cache_use'} gt 0) { $binlog_cache_ratio = $stats{'Binlog_cache_disk_use'} / $stats{'Binlog_cache_use'}; }
+   else { $binlog_cache_ratio = 0; }
+
+   if(defined($stats{'Binlog_stmt_cache_use'}) && $stats{'Binlog_stmt_cache_use'} gt 0) { $binlog_stmt_cache_ratio = $stats{'Binlog_stmt_cache_disk_use'} / $stats{'Binlog_stmt_cache_use'}; }
+   else { $binlog_stmt_cache_ratio = 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'};
+      }
+   }
+  if($have_aria_vals)
+  {
+     $stats{'Aria_pagecache_blocks_used'} = $stats_present{'Aria_pagecache_blocks_used'};
+  }
+
+   get_Com_values();
+
+   %stats_past = %stats_present;
+
+   set_myisam_vals();
+   set_ib_vals() if $have_innodb_vals;
+   set_aria_vals() if $have_aria_vals;
+   set_subquerycache_vals() if $have_subquerycache_vals;
+   set_binlog_vals() if $have_binlog_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();
+   write_Rows();
+   $~ = 'SAS', write;
+   write_qcache();
+   $~ = 'REPORT_END', write;
+   $~ = 'THREADS', write;
+   if($use_thread_pool)
+   {
+      $~ = 'THREADPOOL', write;
+   } else {
+      $~ = 'THREADPERCONNECTION', write;
+   }
+   $~ = 'TAB', write;
+
+   write_InnoDB() if $have_innodb_vals;
+   write_Aria() if $have_aria_vals;
+   write_Subquerycache() if $have_subquerycache_vals;
+   write_Binlog() if $have_binlog_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+ 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
+#
+# 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: mariadb-report\n";
+   print SENDMAIL "To: $op{email}\n";
+   print SENDMAIL "Subject: $dbms 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;
+   return if defined($vars{'query_cache_type'}) and $vars{'query_cache_type'} eq 'OFF';
+
+   $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_Subquerycache
+{
+   print "write_Subquerycache\n" if $op{debug};
+
+   return if not defined $stats{'Subquery_cache_hit'};
+   return if $stats{'Subquery_cache_hit'} == 0 && $stats{'Subquery_cache_miss'} == 0;
+
+   $~ = 'SUBQUERYCACHE';
+   write;
+}
+
+sub write_Binlog
+{
+   print "write_Binlog\n" if $op{debug};
+
+   return if $binlog_cache_ratio == 0 && $binlog_stmt_cache_ratio == 0;
+   $~ = 'BINLOG';
+   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 write_Aria
+{
+   print "write_Aria\n" if $op{debug};
+
+   return if not defined $stats{'Aria_pagecache_blocks_used'};
+
+   $~ = 'PAGECACHE_BUFF_MAX';
+   write;
+
+   if($pagecache_buffer_usage != -1) { $~ = 'PAGECACHE_BUFF_USAGE', write }
+
+   $~ = 'PAGECACHE_RATIOS';
+   write;
+}
+
+sub write_Rows
+{
+   print "write_Rows\n" if $op{debug};
+
+   $rows_using_indexes = $stats{'Handler_read_first'} + $stats{'Handler_read_key'} + $stats{'Handler_read_next'} + $stats{'Handler_read_prev'};
+   $rows = $rows_using_indexes + $stats{'Handler_read_rnd'} + $stats{'Handler_read_rnd_next'} + $stats{'Sort_rows'};
+
+   $~ = 'ROWS';
+   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
+   {
+      unlink $tmpfile;
+   }
+
+   if(!$op{'infile'} && !$relative_infiles)
+   {
+      if($op{'flush-status'})
+      {
+         my $query = $dbh->prepare("FLUSH STATUS;");
+         $query->execute();
+         $query->finish();
+      }
+      $dbh->disconnect();
+   }
+}
+
+#
+# Formats
+#
+
+format MYSQL_TIME =
+@<<<<<< @<<<<<<<<<<<<<<<<<< uptime @<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<
+$dbms, $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  @>>>>>>  %Usage: @>>>>>
+make_short($qc_mem_used, 1), make_short($vars{'query_cache_size'}, 1), perc($qc_mem_used, $vars{'query_cache_size'})
+Block Fragment @>>>>>%
+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)
+.
+
+format SUBQUERYCACHE =
+
+__ Subquery Cache ______________________________________________________
+Hit ratio     @>>>>>%
+perc($stats{'Subquery_cache_hit'} / ($stats{'Subquery_cache_hit'} + $stats{'Subquery_cache_miss'}))
+Hits          @>>>>>>   @>>>>>/s
+make_short($stats{'Subquery_cache_hit'}), t($stats{'Subquery_cache_hit'})
+Miss          @>>>>>>   @>>>>>/s
+make_short($stats{'Subquery_cache_miss'}), t($stats{'Subquery_cache_miss'})
+.
+
+# 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   %Disk: @>>>>>
+make_short($stats{'Created_tmp_disk_tables'}), t($stats{'Created_tmp_disk_tables'}), perc($stats{'Created_tmp_disk_tables'}, $stats{'Created_tmp_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 THREADS =
+
+__ Threads _____________________________________________________________
+Running     @>>>>>>>> of @>>>>>
+$stats{'Threads_running'}, $stats{'Threads_connected'}
+Created     @>>>>>>>>    @>>>>>/s
+make_short($stats{'Threads_created'}), t($stats{'Threads_created'})
+Slow        @>>>>>>>>    @>>>>>/s
+$stats{'Slow_launch_threads'}, t($stats{'Slow_launch_threads'})
+.
+
+format THREADPERCONNECTION =
+Cached      @>>>>>>>> of @>>>>>      %Hit: @>>>>>
+$stats{'Threads_cached'}, $vars{'thread_cache_size'}, make_short(100 - perc($stats{'Threads_created'}, $stats{'Connections'}))
+.
+
+format THREADPOOL =
+Threadpool  @>>>>>>>> of @>>>>>     %Used: @>>>>>
+$stats{'Threadpool_threads'} + $stats{'Threadpool_idle_threads'}, $vars{'thread_pool_max_threads'}, make_short(perc($stats{'Threadpool_threads'} + $stats{'Threadpool_idle_threads'}, $vars{'thread_pool_max_threads'}))
+  Running   @>>>>>>>> of @>>>>>  %Running: @>>>>>
+$stats{'Threadpool_threads'}, $vars{'thread_pool_max_threads'}, make_short(perc($stats{'Threadpool_threads'}, $vars{'thread_pool_max_threads'}))
+  Idle      @>>>>>>>> of @>>>>>     %Idle: @>>>>>
+$stats{'Threadpool_idle_threads'}, $vars{'thread_pool_max_threads'}, make_short(perc($stats{'Threadpool_idle_threads'}, $vars{'thread_pool_max_threads'}))
+.
+
+format TAB =
+
+__ 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  @>>>>>>  %Usage: @>>>>>
+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 disk @>>>>>>>>    @>>>>>/s   %Disk: @>>>>>
+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'})
+Wait Free   @>>>>>>>>    @>>>>>/s   %Wait: @>>>>>
+$stats{'Innodb_buffer_pool_wait_free'}, t($stats{'Innodb_buffer_pool_wait_free'}), perc($stats{'Innodb_buffer_pool_wait_free'}, $stats{'Innodb_buffer_pool_write_requests'})
+Flushes     @>>>>>>>>    @>>>>>/s
+make_short($stats{'Innodb_buffer_pool_pages_flushed'}), t($stats{'Innodb_buffer_pool_pages_flushed'})
+.
+
+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'})
+.
+
+format PAGECACHE_BUFF_MAX =
+
+__ Aria Pagecache ______________________________________________________
+Buffer used   @>>>>>> of  @>>>>>>   %Used: @>>>>>
+make_short($pagecache_buffer_used, 1), make_short($vars{'aria_pagecache_buffer_size'}, 1), perc($pagecache_buffer_used, $vars{'aria_pagecache_buffer_size'})
+.
+
+format PAGECACHE_BUFF_USAGE =
+  Current     @>>>>>>              %Usage: @>>>>>
+make_short($pagecache_buffer_usage, 1), perc($pagecache_buffer_usage, $vars{'aria_pagecache_buffer_size'})
+.
+
+format PAGECACHE_RATIOS =
+Write hit     @>>>>>%
+$pagecache_write_ratio
+Read hit      @>>>>>%
+$pagecache_read_ratio
+.
+
+format BINLOG =
+
+__ Binary Log Cache _____________________________________________________
+Disk use
+  Transactional                @>>>>>%
+perc($binlog_cache_ratio)
+  Non transactional    @>>>>>%
+perc($binlog_stmt_cache_ratio)
+.
+
+format ROWS =
+
+__ Rows ________________________________________________________________
+Rows        @>>>>>>>>    @>>>>>/s
+make_short($rows), t($rows)
+  Using idx @>>>>>>>>    @>>>>>/s  %Index: @>>>>>
+make_short($rows_using_indexes), t($rows_using_indexes), perc($rows_using_indexes,$rows)
+Rows/question @>>>>>>
+make_short($rows/$questions)
+.
diff --git a/additions/mariadb-report.1 b/additions/mariadb-report.1
new file mode 100644 (file)
index 0000000..2943519
--- /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::MariaDB::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/additions/mariadb.cnf b/additions/mariadb.cnf
new file mode 100644 (file)
index 0000000..62b4ea8
--- /dev/null
@@ -0,0 +1,29 @@
+# The MariaDB configuration file
+#
+# The MariaDB/MySQL tools read configuration files in the following order:
+# 0. "/etc/mysql/my.cnf" symlinks to this file, reason why all the rest is read.
+# 1. "/etc/mysql/mariadb.cnf" (this file) to set global defaults,
+# 2. "/etc/mysql/conf.d/*.cnf" to set global options.
+# 3. "/etc/mysql/mariadb.conf.d/*.cnf" to set MariaDB-only options.
+# 4. "~/.my.cnf" to set user-specific options.
+#
+# If the same option is defined multiple times, the last one will apply.
+#
+# 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.
+#
+# If you are new to MariaDB, check out https://mariadb.com/kb/en/basic-mariadb-articles/
+
+#
+# This group is read both by the client and the server
+# use it for options that affect everything
+#
+[client-server]
+# Port or socket location where to connect
+# port = 3306
+socket = /run/mysqld/mysqld.sock
+
+# Import all .cnf files from configuration directory
+!includedir /etc/mysql/conf.d/
+!includedir /etc/mysql/mariadb.conf.d/
diff --git a/additions/mariadb.conf.d/50-client.cnf b/additions/mariadb.conf.d/50-client.cnf
new file mode 100644 (file)
index 0000000..1fd4685
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# This group is read by the client library
+# Use it for options that affect all clients, but not the server
+#
+
+[client]
+# Example of client certificate usage
+#ssl-cert = /etc/mysql/client-cert.pem
+#ssl-key  = /etc/mysql/client-key.pem
+#
+# Allow only TLS encrypted connections
+#ssl-verify-server-cert = on
+
+# This group is *never* read by mysql client library, though this
+# /etc/mysql/mariadb.cnf.d/client.cnf file is not read by Oracle MySQL
+# client anyway.
+# If you use the same .cnf file for MySQL and MariaDB,
+# use it for MariaDB-only client options
+[client-mariadb]
diff --git a/additions/mariadb.conf.d/50-mysql-clients.cnf b/additions/mariadb.conf.d/50-mysql-clients.cnf
new file mode 100644 (file)
index 0000000..2f5a360
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# These groups are read by MariaDB command-line tools
+# Use it for options that affect only one utility
+#
+
+[mysql]
+
+[mysql_upgrade]
+
+[mysqladmin]
+
+[mysqlbinlog]
+
+[mysqlcheck]
+
+[mysqldump]
+
+[mysqlimport]
+
+[mysqlshow]
+
+[mysqlslap]
diff --git a/additions/mariadb.conf.d/50-mysqld_safe.cnf b/additions/mariadb.conf.d/50-mysqld_safe.cnf
new file mode 100644 (file)
index 0000000..e24f96a
--- /dev/null
@@ -0,0 +1,28 @@
+# NOTE: THIS FILE IS READ ONLY BY THE TRADITIONAL SYSV INIT SCRIPT, NOT SYSTEMD.
+# MARIADB SYSTEMD DOES _NOT_ UTILIZE MYSQLD_SAFE NOR READ THIS FILE.
+#
+# For similar behavior, systemd users should create the following file:
+# /etc/systemd/system/mariadb.service.d/migrated-from-my.cnf-settings.conf
+#
+# To achieve the same result as the default 50-mysqld_safe.cnf, please create
+# /etc/systemd/system/mariadb.service.d/migrated-from-my.cnf-settings.conf
+# with the following contents:
+#
+# [Service]
+# User = mysql
+# StandardOutput = syslog
+# StandardError = syslog
+# SyslogFacility = daemon
+# SyslogLevel = err
+# SyslogIdentifier = mysqld
+#
+# For more information, please read https://mariadb.com/kb/en/mariadb/systemd/
+
+[mysqld_safe]
+# This will be passed to all mysql clients
+# It has been reported that passwords should be enclosed with ticks/quotes
+# especially if they contain "#" chars...
+
+nice = 0
+skip_log_error
+syslog
diff --git a/additions/mariadb.conf.d/50-server.cnf b/additions/mariadb.conf.d/50-server.cnf
new file mode 100644 (file)
index 0000000..4805c55
--- /dev/null
@@ -0,0 +1,119 @@
+#
+# These groups are read by MariaDB server.
+# Use it for options that only the server (but not clients) should see
+
+# this is read by the standalone daemon and embedded servers
+[server]
+
+# this is only for the mysqld standalone daemon
+[mysqld]
+
+#
+# * Basic Settings
+#
+
+#user                    = mysql
+pid-file                = /run/mysqld/mysqld.pid
+basedir                 = /usr
+#datadir                 = /var/lib/mysql
+#tmpdir                  = /tmp
+
+# Broken reverse DNS slows down connections considerably and name resolve is
+# safe to skip if there are no "host by domain name" access grants
+#skip-name-resolve
+
+# 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_size        = 128M
+#max_allowed_packet     = 1G
+#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_options = BACKUP
+#max_connections        = 100
+#table_cache            = 64
+
+#
+# * Logging and Replication
+#
+
+# Note: The configured log file or its directory need to be created
+# and be writable by the mysql user, e.g.:
+# $ sudo mkdir -m 2750 /var/log/mysql
+# $ sudo chown mysql /var/log/mysql
+
+# Both location gets rotated by the cronjob.
+# Be aware that this log type is a performance killer.
+# Recommend only changing this at runtime for short testing periods if needed!
+#general_log_file       = /var/log/mysql/mysql.log
+#general_log            = 1
+
+# When running under systemd, error logging goes via stdout/stderr to journald
+# and when running legacy init error logging goes to syslog due to
+# /etc/mysql/conf.d/mariadb.conf.d/50-mysqld_safe.cnf
+# Enable this if you want to have error logging into a separate file
+#log_error = /var/log/mysql/error.log
+# Enable the slow query log to see queries with especially long duration
+#log_slow_query_file    = /var/log/mysql/mariadb-slow.log
+#log_slow_query_time    = 10
+#log_slow_verbosity     = query_plan,explain
+#log-queries-not-using-indexes
+#log_slow_min_examined_row_limit = 1000
+
+# The following can be used as easy to replay backup logs or for replication.
+# note: if you are setting up a replica, 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
+
+#
+# * SSL/TLS
+#
+
+# For documentation, please read
+# https://mariadb.com/kb/en/securing-connections-for-client-and-server/
+#ssl-ca = /etc/mysql/cacert.pem
+#ssl-cert = /etc/mysql/server-cert.pem
+#ssl-key = /etc/mysql/server-key.pem
+#require-secure-transport = on
+
+#
+# * Character sets
+#
+
+# MySQL/MariaDB default is Latin1, but in Debian we rather default to the full
+# utf8 4-byte character set. See also client.cnf
+character-set-server  = utf8mb4
+collation-server      = utf8mb4_general_ci
+
+#
+# * 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!
+# Most important is to give InnoDB 80 % of the system RAM for buffer use:
+# https://mariadb.com/kb/en/innodb-system-variables/#innodb_buffer_pool_size
+#innodb_buffer_pool_size = 8G
+
+# this is only for embedded server
+[embedded]
+
+# This group is only read by MariaDB servers, not by MySQL.
+# If you use the same .cnf file for MySQL and MariaDB,
+# you can put MariaDB-only options here
+[mariadb]
+
+# This group is only read by MariaDB-10.11 servers.
+# If you use the same .cnf file for MariaDB of different versions,
+# use this group for options that older servers don't understand
+[mariadb-10.11]
diff --git a/additions/mariadb.conf.d/60-galera.cnf b/additions/mariadb.conf.d/60-galera.cnf
new file mode 100644 (file)
index 0000000..274891b
--- /dev/null
@@ -0,0 +1,21 @@
+#
+# * Galera-related settings
+#
+# See the examples of server wsrep.cnf files in /usr/share/mysql
+# and read more at https://mariadb.com/kb/en/galera-cluster/
+
+[galera]
+# Mandatory settings
+#wsrep_on                 = ON
+#wsrep_cluster_name       = "MariaDB Galera Cluster"
+#wsrep_cluster_address    = gcomm://
+#binlog_format            = row
+#default_storage_engine   = InnoDB
+#innodb_autoinc_lock_mode = 2
+
+# Allow server to accept connections on all interfaces.
+#bind-address = 0.0.0.0
+
+# Optional settings
+#wsrep_slave_threads = 1
+#innodb_flush_log_at_trx_commit = 0
diff --git a/additions/source_mariadb.py b/additions/source_mariadb.py
new file mode 100644 (file)
index 0000000..74c3633
--- /dev/null
@@ -0,0 +1,54 @@
+'''apport package hook for mariadb
+
+(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, 'mariadb-server', 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 'mariadbd' 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/mariadbd')
+    attach_file(report,'/etc/apparmor.d/usr.sbin.mariadbd')
+    _add_my_conf_files(report, '/etc/mysql/mariadb.cnf')
+    for f in os.listdir('/etc/mysql/conf.d'):
+        _add_my_conf_files(report, os.path.join('/etc/mysql/conf.d', f))
+    for f in os.listdir('/etc/mysql/mariadb.conf.d'):
+        _add_my_conf_files(report, os.path.join('/etc/mysql/mariadb.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/apparmor-profile b/apparmor-profile
new file mode 100644 (file)
index 0000000..b1f229b
--- /dev/null
@@ -0,0 +1,15 @@
+# This file is intentionally empty to disable apparmor by default for newer
+# versions of MariaDB, while providing seamless upgrade from older versions
+# and from mysql, where apparmor is used.
+#
+# By default, we do not want to have any apparmor profile for the MariaDB
+# server. It does not provide much useful functionality/security, and causes
+# several problems for users who often are not even aware that apparmor
+# exists and runs on their system.
+#
+# Users can modify and maintain their own profile, and in this case it will
+# be used.
+#
+# When upgrading from previous version, users who modified the profile
+# will be prompted to keep or discard it, while for default installs
+# we will automatically disable the profile.
diff --git a/autobake-deb.sh b/autobake-deb.sh
new file mode 100755 (executable)
index 0000000..afe7181
--- /dev/null
@@ -0,0 +1,251 @@
+#!/bin/bash
+#
+# Build MariaDB .deb packages for test and release at mariadb.org
+#
+# Purpose of this script:
+# Always keep the actual packaging as up-to-date as possible following the latest
+# Debian policy and targeting Debian Sid. Then case-by-case run in autobake-deb.sh
+# tests for backwards compatibility and strip away parts on older builders or
+# specific build environments.
+
+# Exit immediately on any error
+set -e
+
+# On Buildbot, don't run the mysql-test-run test suite as part of build.
+# It takes a lot of time, and we will do a better test anyway in
+# Buildbot, running the test suite from installed .debs on a clean VM.
+export DEB_BUILD_OPTIONS="nocheck $DEB_BUILD_OPTIONS"
+
+# shellcheck source=/dev/null
+source ./VERSION
+
+# General CI optimizations to keep build output smaller
+if [[ $GITLAB_CI ]]
+then
+  # On Gitlab the output log must stay under 4MB so make the
+  # build less verbose
+  sed '/Add support for verbose builds/,/^$/d' -i debian/rules
+elif [ -d storage/columnstore/columnstore/debian ]
+then
+  # ColumnStore is explicitly disabled in the native Debian build. Enable it
+  # now when build is triggered by autobake-deb.sh (MariaDB.org) and when the
+  # build is not running on Gitlab-CI.
+  sed '/-DPLUGIN_COLUMNSTORE=NO/d' -i debian/rules
+  # Take the files and part of control from MCS directory
+  if [ ! -f debian/mariadb-plugin-columnstore.install ]
+  then
+    cp -v storage/columnstore/columnstore/debian/mariadb-plugin-columnstore.* debian/
+    echo >> debian/control
+    sed "s/-10.6//" <storage/columnstore/columnstore/debian/control >> debian/control
+  fi
+fi
+
+# Look up distro-version specific stuff
+#
+# Always keep the actual packaging as up-to-date as possible following the latest
+# Debian policy and targeting Debian Sid. Then case-by-case run in autobake-deb.sh
+# tests for backwards compatibility and strip away parts on older builders.
+
+remove_rocksdb_tools()
+{
+  sed '/rocksdb-tools/d' -i debian/control
+  sed '/sst_dump/d' -i debian/not-installed
+  if ! grep -q sst_dump debian/mariadb-plugin-rocksdb.install
+  then
+    echo "usr/bin/sst_dump" >> debian/mariadb-plugin-rocksdb.install
+  fi
+}
+
+add_lsb_base_depends()
+{
+  # Make sure one can run this multiple times remove
+  # lines 'sysvinit-utils' and 'lsb-base'.
+  sed -e '/sysvinit-utils/d' -e '/lsb-base/d' -i debian/control
+  # Add back lsb-base before lsof
+  sed -e 's#lsof #lsb-base (>= 3.0-10),\n         lsof #' -i debian/control
+}
+
+replace_uring_with_aio()
+{
+  sed 's/liburing-dev/libaio-dev/g' -i debian/control
+  sed -e '/-DIGNORE_AIO_CHECK=ON/d' \
+      -e '/-DWITH_URING=ON/d' -i debian/rules
+}
+
+disable_pmem()
+{
+  sed '/libpmem-dev/d' -i debian/control
+  sed '/-DWITH_PMEM=ON/d' -i debian/rules
+}
+
+disable_libfmt()
+{
+  # 7.0+ required
+  sed '/libfmt-dev/d' -i debian/control
+}
+
+architecture=$(dpkg-architecture -q DEB_BUILD_ARCH)
+
+# Parse release name and number from Linux standard base release
+# Example:
+#   $ lsb_release -a
+#   No LSB modules are available.
+#   Distributor ID:    Debian
+#   Description:       Debian GNU/Linux bookworm/sid
+#   Release:   n/a
+#   Codename:  n/a
+LSBID="$(lsb_release -si  | tr '[:upper:]' '[:lower:]')"
+LSBVERSION="$(lsb_release -sr | sed -e "s#\.##g")"
+LSBNAME="$(lsb_release -sc)"
+
+# If 'n/a', assume 'sid'
+if [ "${LSBVERSION}" == "n/a" ] || [ "${LSBNAME}" == "n/a" ]
+then
+  LSBVERSION="sid"
+  LSBNAME="sid"
+fi
+
+# If not known, use 'unknown' in .deb version identifier
+if [ -z "${LSBID}" ]
+then
+  LSBID="unknown"
+fi
+
+case "${LSBNAME}"
+in
+  # Debian
+  "buster")
+    disable_libfmt
+    replace_uring_with_aio
+    if [ ! "$architecture" = amd64 ]
+    then
+      disable_pmem
+    fi
+    ;&
+  "bullseye")
+    add_lsb_base_depends
+    ;&
+  "bookworm")
+    # mariadb-plugin-rocksdb in control is 4 arches covered by the distro rocksdb-tools
+    # so no removal is necessary.
+    if [[ ! "$architecture" =~ amd64|arm64|ppc64el ]]
+    then
+      disable_pmem
+    fi
+    if [[ ! "$architecture" =~ amd64|arm64|armel|armhf|i386|mips64el|mipsel|ppc64el|s390x ]]
+    then
+      replace_uring_with_aio
+    fi
+    ;&
+  "trixie"|"sid")
+    # The default packaging should always target Debian Sid, so in this case
+    # there is intentionally no customizations whatsoever.
+    ;;
+  # Ubuntu
+  "bionic")
+    remove_rocksdb_tools
+    [ "$architecture" != amd64 ] && disable_pmem
+    ;&
+  "focal")
+    replace_uring_with_aio
+    disable_libfmt
+    ;&
+  "jammy"|"kinetic")
+    add_lsb_base_depends
+    ;&
+  "lunar"|"mantic")
+    # mariadb-plugin-rocksdb s390x not supported by us (yet)
+    # ubuntu doesn't support mips64el yet, so keep this just
+    # in case something changes.
+    if [[ ! "$architecture" =~ amd64|arm64|ppc64el|s390x ]]
+    then
+      remove_rocksdb_tools
+    fi
+    if [[ ! "$architecture" =~ amd64|arm64|ppc64el ]]
+    then
+      disable_pmem
+    fi
+    if [[ ! "$architecture" =~ amd64|arm64|armhf|ppc64el|s390x ]]
+    then
+      replace_uring_with_aio
+    fi
+    ;;
+  *)
+    echo "Error: Unknown release '$LSBNAME'" >&2
+    exit 1
+esac
+
+if [ -n "${AUTOBAKE_PREP_CONTROL_RULES_ONLY:-}" ]
+then
+  exit 0
+fi
+
+# Adjust changelog, add new version
+echo "Incrementing changelog and starting build scripts"
+
+# Find major.minor version
+UPSTREAM="${MYSQL_VERSION_MAJOR}.${MYSQL_VERSION_MINOR}.${MYSQL_VERSION_PATCH}${MYSQL_VERSION_EXTRA}"
+PATCHLEVEL="+maria"
+LOGSTRING="MariaDB build"
+EPOCH="1:"
+VERSION="${EPOCH}${UPSTREAM}${PATCHLEVEL}~${LSBID:0:3}${LSBVERSION}"
+
+dch -b -D "${LSBNAME}" -v "${VERSION}" "Automatic build with ${LOGSTRING}." --controlmaint
+
+echo "Creating package version ${VERSION} ... "
+
+BUILDPACKAGE_DPKGCMD=()
+
+# Fakeroot test
+if fakeroot true; then
+  BUILDPACKAGE_DPKGCMD+=( "fakeroot" "--" )
+fi
+
+# Use eatmydata is available to build faster with less I/O, skipping fsync()
+# during the entire build process (safe because a build can always be restarted)
+if command -v eatmydata > /dev/null
+then
+  BUILDPACKAGE_DPKGCMD+=("eatmydata")
+fi
+
+BUILDPACKAGE_DPKGCMD+=("dpkg-buildpackage")
+
+# Using dpkg-buildpackage args
+# -us Allow unsigned sources
+# -uc Allow unsigned changes
+# -I  Tar ignore
+BUILDPACKAGE_DPKGCMD+=(-us -uc -I)
+
+# There can be also extra flags that are appended to args
+if [ -n "$BUILDPACKAGE_FLAGS" ]
+then
+  read -ra BUILDPACKAGE_TMP_ARGS <<< "$BUILDPACKAGE_FLAGS"
+  BUILDPACKAGE_DPKGCMD+=( "${BUILDPACKAGE_TMP_ARGS[@]}" )
+fi
+
+# Build the package
+# Pass -I so that .git and other unnecessary temporary and source control files
+# will be ignored by dpkg-source when creating the tar.gz source package.
+"${BUILDPACKAGE_DPKGCMD[@]}"
+
+# If the step above fails due to missing dependencies, you can manually run
+#   sudo mk-build-deps debian/control -r -i
+
+# Don't log package contents on Gitlab-CI to save time and log size
+if [[ ! $GITLAB_CI ]]
+then
+  echo "List package contents ..."
+  cd ..
+  for package in *.deb
+  do
+    echo "$package" | cut -d '_' -f 1
+    # shellcheck disable=SC2034
+    dpkg-deb -c "$package" | while IFS=" " read -r col1 col2 col3 col4 col5 col6 col7 col8
+    do
+        echo "$col1 $col2 $col6 $col7 $col8" | sort -k 3
+    done
+    echo "------------------------------------------------"
+  done
+fi
+
+echo "Build complete"
diff --git a/changelog b/changelog
new file mode 100644 (file)
index 0000000..9596360
--- /dev/null
+++ b/changelog
@@ -0,0 +1,2498 @@
+mariadb (1:10.11.8-1) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.11.8. Includes fixes for several severe regressions
+    as noted at https://mariadb.com/kb/en/mariadb-10-11-8-release-notes/ as well
+    as security issues:
+    - CVE-2024-21096
+  * Add CMake flag to ignore libfmt exit code so cross-building works
+  * Extend skip test list for latest failures in reproducible builds on armhf
+  * Disable tests that fail on armhf when full test suite is run
+  * Remove temporary exceptions for bugs that should by now be fixed
+  * MDEV-31530 Localizations for Swahili language
+  * Update Innotop to be compatible with MariaDB 11.x series
+  * Replace use of trailing line `| \` with just `|` in Bash scripts
+  * Remove libmariadb file no longer present in MariaDB Connector C v3.3
+  * Replace autopkgtest smoke test dependency hack with arch list
+  * Update client program 'mariadb' trace to match new libmariadb v3.3
+    - New parameter 'sandbox' to fix a vulnerability and new mariadb-dump
+      output that always has the sandbox header and is backwards incompatible
+  * Update server trace to include new parameters innodb-log-spin-wait-delay
+    and innodb-snapshot-isolation
+  [ Michael Biebl ]
+  * Ensure debconf database is purged after it has been used in postrm
+
+  [ Svante Signell ]
+  * Make hurd-i386 build fully pass (Closes: #1069094)
+
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 16 May 2024 22:02:04 -0700
+
+mariadb (1:10.11.7-4) unstable; urgency=medium
+
+  [ Michael Biebl ]
+  * Drop unnecessary mariadb-server.prerm (Closes: #1067491)
+  * Rely on dh_installsystemd to stop the service in postrm
+
+  [ Otto Kekäläinen ]
+  * Remove direct dependencies on libcurl4 (Closes: #1068403, #1068404)
+  * Make tests compatible with OpenSSL 3.2.0
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 13 Apr 2024 11:07:08 -0700
+
+mariadb (1:10.11.7-3) unstable; urgency=medium
+
+  * Add 'dpkg-dev (>= 1.22.5)' to Build-Depends for time_t transition
+    (Closes: #1065275)
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 02 Mar 2024 08:26:26 -0800
+
+mariadb (1:10.11.7-2) unstable; urgency=medium
+
+  [ Graham Inggs ]
+  * Rename libraries for 64-bit time_t transition (Closes: #1062841)
+
+  [ Otto Kekäläinen ]
+  * Salsa-CI: Adopt new libmariadbd19t64 library name in CI
+  * Remove obsolete Lintian override:
+    package-supports-alternative-init-but-no-init.d-script
+  * Disable more tests not passing for sparc64 on Debian
+  * Add patch to fix hurd-i386 build failure (Closes: #1063739)
+  * Add patch to partially revert upstream c432c9ef (Closes: #1063738)
+  * Disable table_value_constr failing on armhf on Launchpad
+  * Backport patch for MDEV-32975 (collation fix for PHP connector)
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 01 Mar 2024 17:43:11 -0800
+
+mariadb (1:10.11.7-1) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.11.7. Includes fixes for several regressions
+    as noted at https://mariadb.com/kb/en/mariadb-10-11-7-release-notes/
+  * Add missing ${misc:Depends} to Depends for mariadb-server-10.5
+  * Re-export upstream signing key without extra signatures
+  * Remove field Priority on binary package mariadb-server-10.5 that duplicates
+    source
+  * Update debian/copyright for 2024
+  * Delete test plugin pam_mariadb_mtr.so to keep mariadb-test-data clean
+  * Clean away unused Lintian overrides
+  * Remove unneeded CMAKE_SYSTEM_PROCESSOR from debian/rules
+  * Add patch to skip building AUTH_SOCKET on Hurd (Related: #1006531)
+  * Use Pre-Depends to ensure init-system-helpers is present
+
+  [ Michael Biebl ]
+  * Install PAM module and systemd files into /usr (Closes: #1061348)
+  * Install .service files via .install and let dh_installinit/dh_systemd
+    generate the maintscript code
+  * Switch to dh_installsystemd and debhelper compat 13
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 06 Feb 2024 20:14:49 -0800
+
+mariadb (1:10.11.6-2) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Make the transitional dummy package description explicit
+  * Ensure 'clean' target works
+  * Use upstream patch to fix subselect test regressions (Closes: #1059904)
+  * Disable innodb_ext_key crashing on ppc64el (Related: #1059904)
+  * Apply upstream patch to use RDTIME in RISC-V (Closes: #1060007)
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 05 Jan 2024 16:32:12 +0800
+
+mariadb (1:10.11.6-1) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.11.6. Includes fixes for several severe regressions
+    as noted at https://mariadb.com/kb/en/mariadb-10-11-6-release-notes/ as well
+    as security issues:
+    - CVE-2023-22084
+  * Upstream MariaDB Server 10.11.6 included fix for fmtlib 10 compatibility
+    (Closes: #1056387)
+  * Drop STACK_DIRECTION customization as upstream CMake code now handles it
+  * Update traces to match these changes in MariaDB 10.11.6:
+    - New option 'ALL' to multiple parameters as a way to define that all
+      possible values/options are selected
+    - New variables log-slow-max-warnings, note-verbosity and
+      optimizer-max-sel-args
+    - Default value for innodb-purge-batch-size increased to 1000
+    - Support for TLSv1.1 has been dropped
+
+  [ Guillem Jover ]
+  * Remove tilegx support removed from dpkg 1.22.0 (Closes: #1056748)
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 26 Nov 2023 18:54:33 -0800
+
+mariadb (1:10.11.5-3) unstable; urgency=medium
+
+  * Bugfix: Rewrite 0300a91 again to retain original autopkgtest behavior
+  * Disable more tests not passing on Debian post-build test or Launchpad
+  * Fix misc spelling
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 13 Oct 2023 21:48:03 -0700
+
+mariadb (1:10.11.5-2) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Make SysV init more verbose in case of MariaDB start failures
+  * Test & QA related changes:
+    * Bugfix: Rewrite 0300a9157cc to retain original autopkgtest behavior
+    * Switch autopkgtest upstream job to use '--skip-rpl --suite=main' again
+    * Include type_test.so and others in mariadb-test package
+    * Revert "Skip upstream MTR run on armel/armhf where lxcfs upgrade broke CPU check"
+    * Partially revert fc1358087b3 about MDEV-30728 to see if it still occurs
+    * Remove overrides for test failures that should be fixed now
+    * Add patch to fix disk.disk{_notembedded} tests and re-enable them
+    * Disable tests not passing on Debian CI, Salsa CI or Launchpad builds
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 07 Oct 2023 16:00:43 -0700
+
+mariadb (1:10.11.5-1) unstable; urgency=medium
+
+  [ Helmut Grohne ]
+  * Fix FTCBFS: Do not pass host CFLAGS to the native build. (Closes: #1051222)
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.11.5. Includes fixes for several severe regressions
+    as noted at https://mariadb.com/kb/en/mariadb-10-11-5-release-notes/ such as
+    - MDEV-31642: Upgrade may crash if innodb_log_file_buffering=OFF
+      (Closes: #1040784)
+  * Update configuration tracing to match what is expected for 10.11.5
+  * Include trailing slash in watch file to be compatible with latest uscan
+  * Re-apply "Limit check of running mysqld/mariadbd to system users (Closes: #1032047)"
+  * Re-apply "Add patches to fix spelling in MariaDB and components (Closes: #1032860)"
+  * Sync downstream (where applicable) with upstream 10.11 debian/* contents
+  * Complement upstream commits with more complete mysql->mariadb conversion
+  * Misc fixes to Debian scripts to satisfy Shellcheck
+  * Fix blocksize check to use $mysql_datadir/$datadir correctly
+  * Make sure that datadir always has some value and exists
+
+  [ Tuukka Pasanen ]
+  * MDEV-30951: Fix small perlcritic and enable modern Perl
+  * Remove usage of AWK from Debian init and postinst scripts
+
+  [ Anel Husakovic ]
+  * MDEV-31358: Update description for MariaDB deb packages
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 03 Oct 2023 20:59:30 -0700
+
+mariadb (1:10.11.4-1) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.11.4. Includes fixes for several severe regressions,
+    see details at https://mariadb.com/kb/en/mariadb-10-11-4-release-notes/
+
+  [ Andreas Beckmann ]
+  * Introduce transitional mariadb-server-10.5 (Closes: #1035949)
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 04 Jun 2023 11:22:27 -0700
+
+mariadb (1:10.11.3-1) unstable; urgency=medium
+
+  * New upstream version 10.11.3. Includes security fixes for
+    - CVE-2022-47015 (Closes: #1034889)
+  * This is the first bug fixing maintenance release from upstream in the 10.11
+    series as the 10.11.2 release was the first one announced GA (general
+    availability). For a full list of all bug fixes see release notes at
+    https://mariadb.com/kb/en/mariadb-10-11-3-release-notes/.
+  * Update libmariadb3.symbols to include new ABI changes in 3.3.5
+    and fix DPKG_GENSYMBOLS_CHECK_LEVEL so it actually takes effect and in
+    build will properly fail if there are unaccounted symbol changes in
+    future upstream maintenance releases
+  * Update Lintian overrides after 10.11.3 import
+  * Use new log_slow_* configuration variable names in configuration examples
+    to be aligned with upstream and have least amount of surprises for users
+    of MariaDB 10.11 where these variables changed names
+  * Clean away unnecessary mariadb-test.links, no functional effect
+  * Delete all embedded zlib copies to fix crossbuilds and improve security
+  * Use native zlib to make crossbuilds work again after recent zlib 1.2.13
+    update regressed crossbuilds
+  * Revert fixes from February/March 2023 that the Debian release team
+    deemed unfit/too late for Bookworm (Bug#1033811):
+    - Revert "Add patch to fix upgrades from MySQL 5.7 to MariaDB 10.11..."
+    - Revert "Limit check of running mysqld/mariadbd to system users..."
+    - Revert "MDEV-21303: Fix man page packaging for new mariadb-* named..."
+    - Revert "Add patches to fix spelling in MariaDB and components..."
+    - Revert "Add patch to better diagnose failures in main.order_by_innodb..."
+    - Revert "Add patch to fix misc compiler warnings in upstream build"
+    - Revert "Add patch to emit warnings if mariadb-upgrade was not run..."
+
+  [ Mathias Gibbens ]
+  * Silence superfluous warnings in mariadb-server preinst (Closes: #1034684)
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 27 May 2023 23:16:42 -0700
+
+mariadb (1:10.11.2-3) unstable; urgency=medium
+
+  * Fix typo in autopkgtests configuration-tracing affecting armhf and armel
+  * Revert: Sync downstream (where applicable) with upstream 10.11 debian/*
+    contents so that using diff/meld to compare changes are easier
+    - Revert on suggestion by Debian release managers the changes done by
+      upstreams devs in https://github.com/MariaDB/server/commit/952af4a1
+      for MariaDB 10.5.19, 10.6.12, 10.11.2 etc. It was deemed too invasive
+      for the Debian 12 "Bookworm" release this late in the release cycle.
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 20 Apr 2023 21:48:51 -0700
+
+mariadb (1:10.11.2-2) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * SUMMARY: This version has a lot of bug fixes, quality fixes, documentation
+    and translation updates and it is tailored for the Debian 12 "Bookworm"
+    release and all potentially functional changes have been left out and
+    are pending review and merge post-Bookworm release at
+    https://salsa.debian.org/mariadb-team/mariadb-server/-/merge_requests,
+    where contributions both as reviews and new submissions are welcome!
+  * Update NEWS to summarize what is new in MariaDB 10.11 (compared to 10.6)
+  * Update and activate configuration tracing in autopkgtests to ensure that
+    for the Debian 12 "Bookworm" release cycle no upstream server config change
+    would slip in unnoticed
+  * Enable mariadb-plugin-rocksdb for riscv64 (fixes autopkgtests for riscv64)
+  * Sync downstream (where applicable) with upstream 10.11 debian/* contents
+    so that using diff/meld to compare changes are easier
+  * Add important upstream 10.11.2+ fixes as packes:
+    * Stack overflow in pinbox allocator (PR#2541)
+    * Upgrades from MySQL 5.7 to MariaDB 10.11 (MDEV-30483) (Closes: #866751)
+    * Misc compiler warnings in upstream build
+    * Incomplete stack traces if MariaDB crashes
+    * Make mariadbd emit warnings if mariadb-upgrade was not run
+    * Binlog failures due to 'character_set_client' (MDEV-30824)
+  * Prevent mariadb-test-run from using native I/O on ppc64el and s390x due to
+    Linux kernel bug (Related: #1031656)
+  * Add patch to better diagnose potential failures in main.order_by_innodb
+  * Add patch to fix cross-compilation failure on uca-dump (Closes: #1029165)
+  * Update mariadb-test-run skip test lists to not run tests that are known
+    to be broken or unstable, and that have been reported upstream
+  * Limit check of running mysqld/mariadbd to system users (Closes: #1032047)
+  * Make error more helpful in case server restart fails (Related: #1033234)
+  * Update Lintian overrides after rigorous review of all Lintian issues
+    * Remove incorrect Multi-Arch definitions
+    * Fix man pages syntax issues (Closes: #1032861)
+    * Fix spelling in MariaDB and components (Closes: #1032860)
+    * Refresh patches metadata
+    * Update upstream signing key
+    * Fix dependency of obsolete libncurses5-dev
+
+  [ Ekaterine Papava ]
+  * Add Georgian translation (error messages)
+
+  [ Tuukka Pasanen ]
+  * Update README files to correct versions
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 25 Mar 2023 23:26:42 -0700
+
+mariadb (1:10.11.2-1) unstable; urgency=medium
+
+  * New upstream release MariaDB 10.11.2 has been announced GA
+    (general availability) with long-term support and security updates
+    until spring 2028
+  * Autopkgetest improvements
+    - Fix incomplete variable rename in a3b6f3d7f4b
+    - Extend tracing to include MariaDB client and move traces to subdirectory
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 16 Feb 2023 23:53:02 -0800
+
+mariadb (1:10.11.1-5) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Packages mariadb-plugin-provider-* must depend at least on MariaDB 10.11
+  * Make postinstall check work with more than one result (Closes: #1031244)
+  * Revert "Compression plugins as Depends for mariadb-server" (Closes: #1031116)
+    to not break the Cacti autopkgtests and allow the mariadb-10.6 autopkgtest
+    to fail instead (re-introducing Bug#1031116)
+
+  [ Bubu ]
+  * Update French translation of debconf messages (Closes: #1030581)
+
+  [ Adriano Rafael Gomes ]
+  * Update Brazilian translation of debconf messages (Closes: #1030908)
+
+ -- Otto Kekäläinen <otto@debian.org>  Wed, 15 Feb 2023 22:57:46 -0800
+
+mariadb (1:10.11.1-4) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Have all compression plugins as Depends for mariadb-server (Closes: #1030604)
+  * Update existing patch with latest upstream PR#2448 version 0284207
+  * Temporarily disable MTR on s390x as Debian buildd seems unstable
+    (Related: #1030510)
+  * Add upstream patch to fix build failure on HPPA (Closes: #1006529)
+  * Refresh patches and include references to Debian bugs they should fix
+
+  [ Gianfranco Costamagna ]
+  * Drop riscv64 rules latomic hack, use upstream PR#2477 instead
+    (Related: #1024041)
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 09 Feb 2023 08:40:34 -0800
+
+mariadb (1:10.11.1-3) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Customize dh_installinit to keep service enabled (Closes: #1029136)
+  * Fix alpha compilation error in GPREL16/wsrep_* (Closes: #1024040)
+  * Skip tests that have bug reports and known to fail on 1:10.11.1-2
+  * Review and polish autopkgtests
+
+  [ Tianyu Chen ]
+  * Add simplified Chinese translation of debconf messages
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 05 Feb 2023 15:21:04 -0800
+
+mariadb (1:10.11.1-2) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Add upstream patch for main.explain_json_format_partitions (MDEV-30411)
+    (Closes: 1029163)
+  * Fix riscv64 compilation error in RocksDB atomic functions (Closes: #1024041)
+  * Stop skipping tests that are marked fixed upstream
+  * Don't ship any mysql-tests/unstable-tests as neither does upstream
+  * Skip test main.func_json_notembedded on s390x due to MDEV-30518
+  * Implement configuration tracing as an autopkgtest test
+  * Drop obsolete dependency on package lsb-release
+  * Clean away outdated mentions of mariadb-10.6 and even mysql-dfsg-5.1
+  * Update more Lintian overrides syntax to follow latest Lintian 2.115
+  * Update standards version to 4.6.2, no changes needed
+  * Update watch file format version to 4
+
+  [ MichaIng ]
+  * Do not create /var/log/mysql in postinst
+
+  [ Salman Mohammadi ]
+  * mariadb-plugin-connect: introduce curl as recommends
+
+  [ Remus-Gabriel Chelu ]
+  * Update Romanian translation of debconf messages
+
+  [ Faustin Lammler ]
+  * Cover the full-upgrade scenario in CI
+
+  [ Pablo ]
+  * Update Galician translation of debconf messages
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 31 Jan 2023 00:19:17 -0800
+
+mariadb (1:10.11.1-1) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * New major upstream release: 10.11
+    - Introduce new packages called 'providers', each one providing
+      a particular features, though so far only various compression
+      methods.
+    - New plugin package for Hashicorp Vault
+    - Upstream 10.11 series is intended to be a long-term supported
+      version with 5 years of security releases
+    - The other major versions 10.7/8/9/10 releases after 10.6
+      are all short-term releases, and thus not suitable for inclusion
+      in Debian but still worth noting as a guide on how to read
+      upstream relases notes, as all apply for what is now new in
+      Debian with the introduction of this 10.11
+  * Remove version suffix from Debian packages and rename source
+    package to just 'mariadb', dropping the 10.6 suffix.
+  * Emit warning from SysV init script if mysqld_safe is missing
+  * Ignore some EXPLAIN JSON test failures on armel/armhf (MDEV-30411)
+  * Add custom dh_installinit to keep /etc/init.d/mariadb enabled
+    when upgrading from mariadb-server-10.6 to mariadb-server (10.11)
+
+  [ Sunil Mohan Adapa ]
+  * Workaround failure to create DB with libpam-tmpdir (Closes: #1022994)
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 15 Jan 2023 14:45:21 -0800
+
+mariadb-10.6 (1:10.6.11-2) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Standardize on using capitalized 'ON' in CMake build options
+  * Fix Breaks/Replaces for smoother upgrades from MySQL 5.5
+    and update maintainer documentation on how to do comprehensive
+    upgrade testing
+  * Enable automatic datadir move also on upgrades from MySQL.com packages
+    and make upgrades from MySQL Community (Cluster) 8.0 not get
+    stuck on dpkg and server restart
+
+  [ Eric Lindblad ]
+  * Fix typos
+
+ -- Otto Kekäläinen <otto@debian.org>  Mon, 02 Jan 2023 22:42:46 -0800
+
+mariadb-10.6 (1:10.6.11-1) unstable; urgency=medium
+
+  * New upstream version 10.6.11.
+  * Align with upstream 10.6 debian/ contents
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 13 Nov 2022 22:27:08 -0800
+
+mariadb-10.6 (1:10.6.10-1) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.6.10. Includes several important fixes for
+    issues that regressed in previous release. See details in:
+    https://mariadb.org/regressions-in-recent-mariadb-server-releases/
+  * Update Lintian overrides syntax to follow latest Lintian 2.115
+    - Biggest change in Lintian 2.115 is a new syntax to use brackets in file
+      paths.
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 25 Sep 2022 15:43:39 -0700
+
+mariadb-10.6 (1:10.6.9-1) unstable; urgency=medium
+
+  * New upstream version 10.6.8. Includes security fixes for
+    - CVE-2018-25032
+    - CVE-2022-32081
+    - CVE-2022-32082
+    - CVE-2022-32084
+    - CVE-2022-32089
+    - CVE-2022-32091
+
+ -- Otto Kekäläinen <otto@debian.org>  Wed, 17 Aug 2022 07:28:05 -0700
+
+mariadb-10.6 (1:10.6.8-1) unstable; urgency=medium
+
+  * New upstream version 10.6.8. Includes security fixes for
+    - CVE-2021-46669
+    - CVE-2022-27376
+    - CVE-2022-27377
+    - CVE-2022-27378
+    - CVE-2022-27379
+    - CVE-2022-27380
+    - CVE-2022-27381
+    - CVE-2022-27382
+    - CVE-2022-27383
+    - CVE-2022-27384
+    - CVE-2022-27386
+    - CVE-2022-27387
+    - CVE-2022-27444
+    - CVE-2022-27445
+    - CVE-2022-27446
+    - CVE-2022-27447
+    - CVE-2022-27448
+    - CVE-2022-27449
+    - CVE-2022-27451
+    - CVE-2022-27452
+    - CVE-2022-27455
+    - CVE-2022-27456
+    - CVE-2022-27457
+    - CVE-2022-27458
+    - CVE-2022-32085
+    - CVE-2022-32086
+    - CVE-2022-32087
+    - CVE-2022-32088
+
+  [ Daniel Black ]
+  * Move client programs to client package from MariaDB server package
+
+  [ Tuukka Pasanen ]
+  * MDEV-12275: Add switch '--silent' to SySV init upgrade
+  * Allow to use Perl DBD::mysl with mariadb-report (MDEV-28376)
+
+  [ Andreas Hasenack ]
+  * Disable LTO on Ubuntu
+
+  [ Faustin Lammler ]
+  * Use archive.mariadb.org as official watch source
+
+  [ Laurent Bigonville ]
+  * Fix pmem availability check (Closes: #1006530)
+
+  [ Otto Kekäläinen ]
+  * Update breaks/replaces to accommodate the moved mariadb-binlog et al
+  * Use pmem also on riscv64
+  * Add Bulgarian and Chinese translations for error messages
+  * Use proper pid namespace
+  * Add upstream PR#2129 to fix wsrep_sst_backup packaging
+  * Deb: Move my_print_defaults to MariaDB client core package
+  * Deb: Ensure the not-installed list is up-to-date
+  * Install all available man pages in appropriate packages
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 22 May 2022 16:44:02 -0700
+
+mariadb-10.6 (1:10.6.7-3) unstable; urgency=medium
+
+  * Fix syntax error in unstable tests lists
+  * Forward patches upstream and update metadata for them
+  * Bugfix: Include missing sql_parse.cc in ER_KILL_DENIED_ERROR patch
+  * Fix mysql_install_db by reverting recent addition (MDEV-27980)
+  * Fix htm use on PowerPC to fix build failure (might close #1006527)
+  * Revert "Strip path from Mroonga to make the build reproducible"
+
+ -- Otto Kekäläinen <otto@debian.org>  Wed, 09 Mar 2022 22:26:32 -0800
+
+mariadb-10.6 (1:10.6.7-2) unstable; urgency=medium
+
+  * Backport OpenSSL 3.0 support for MariaDB 10.6 series (Closes: #1005950)
+  * Clean away most Lintian overrides and unstable-tests to see full
+    QA results in Debian experimental
+  * Add upstream PR#2028 to fix main.grant_kill test failure
+  * Update unstable-tests skip lists after review of 1:10.6.7-2~exp1 builds
+  * Fix more spelling errors
+  * Fix misc Lintian issues and add overrides
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 01 Mar 2022 20:40:07 -0800
+
+mariadb-10.6 (1:10.6.7-1) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.6.7. Includes security fixes for
+    - CVE-2021-46661
+    - CVE-2021-46663
+    - CVE-2021-46664
+    - CVE-2021-46665
+    - CVE-2021-46668
+  * New upstream version 10.6.6. Includes security fixes for
+    - CVE-2021-46659
+    - CVE-2022-24048
+    - CVE-2022-24050
+    - CVE-2022-24051
+    - CVE-2022-24052
+  * Previous release 10.6.5 included security fixes for:
+    - CVE-2021-46662
+    - CVE-2021-46667
+  * Notable upstream functional changes in 10.6.6 and 10.6.7:
+    - New default value for innodb_change_buffering is 'none' instead of old
+      value 'all' (MDEV-27734). This change should improve crash safety but
+      might cause performance regressions on systems that use old spinning disks
+      (HDD) where seek latency is higher.
+    - New default value for innodb_read_only_compressed is 'OFF' instead of
+      'ON'. Upstream originally intended to deprecate ROW_FORMAT=COMPRESSED but
+      abandoned the plan.
+    - New default minimum value for innodb_buffer_pool_size is 20 MB (from 2 MB)
+  * Drop MIPS and CTE patches applied now upstream
+  * Add upstream patch to make Mroonga builds reproducible (Closes: #976984)
+  * Add patch for potential kfreebsd-amd64 build failure (Closes: #994665)
+  * Remove useless libaio-dev dependency from d/control (Closes: #1001649)
+
+  [ Faustin Lammler ]
+  * Salsa-CI: use a mirror redirector for the CI
+
+  [ Bas Couwenberg ]
+  * Don't require debian.cnf to be executable in logrotate (Closes: #1005186)
+
+  [ Tuukka Pasanen ]
+  * Remove unneeded path from MariaDB server postinst script
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 19 Feb 2022 16:00:00 -0800
+
+mariadb-10.6 (1:10.6.5-2) unstable; urgency=medium
+
+  * Fix misc failures in 10.6 detected by Debian QA systems
+    - Revert systemd extra and socket files to fix build=all
+    - Backport fix for test cte_nonrecursive failure
+    - Disable test main.func_math on more platforms
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 14 Dec 2021 20:05:25 -0800
+
+mariadb-10.6 (1:10.6.5-1) unstable; urgency=medium
+
+  * New upstream version 10.6.5.
+  * Drop MIPS and libatomic patches applied now upstream
+  * Enable Numa support (Closes: #861553)
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 27 Nov 2021 13:48:25 -0800
+
+mariadb-10.6 (1:10.6.4-1) unstable; urgency=medium
+
+  [ Bas Couwenberg ]
+  * Don't require debian.cnf to be executable in logrotate (Closes: #994284)
+
+  [ Otto Kekäläinen ]
+  * Add new overrides to be clean on Lintian v2.105.0
+  * Salsa-CI: Add workarounds for Stretch->Bookworm upgrade bugs
+  * Salsa-CI: Add testing for Bullseye upgrades and backports
+  * Extend README.Contributor to include more QA and debugging tips
+  * Make RocksDB plugin depend on python3:any to be Lintian clean
+  * Adopt DEP-14 for the git repository layout
+  * Import new upstream major release MariaDB 10.6.4
+  * Update Debian packaging for MariaDB 10.6 series
+  * Clean up d/copyright and remove obsolete licence-reconcile config
+  * Extend Breaks/Replaces to cover all known MySQL variants
+  * Skip upstream tests that are permanently broken
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 21 Oct 2021 11:02:17 +0300
+
+mariadb-10.5 (1:10.5.12-1) unstable; urgency=medium
+
+  * New upstream version 10.5.12. Includes security fixes for:
+    - CVE-2021-2389
+    - CVE-2021-2372
+  * Drop patches applied upstream in MariaDB S3 plugin
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 08 Aug 2021 20:33:47 -0700
+
+mariadb-10.5 (1:10.5.11-1) unstable; urgency=medium
+
+  * New upstream version 10.5.11. Includes several important bug fixes,
+    including a replication hang (Closes: #991399, Closes: #989400)
+  * Cleanup, documentation and testing:
+    * Drop backported patch for armfh build now in 10.5.11 from upstream.
+    * Drop patch no longer needed with latest gcc-10 (Closes: #972564)
+    * Save autopkgtests results as JUnit-compatible XML-report
+    * Salsa-CI: Verify wrap-and-sort usage and correctness of patches/series
+  * Remove rocksdb_build_git_date from RocksDB binaries to make them
+    build in a reproducible way, thus making the entire MariaDB finally
+    reproducible (Closes: #976985)
+
+  [ Andreas Beckmann ]
+  * Ease switching from galera-3 to galera-4 on upgrades from buster
+    (Closes: #990708, Closes: #976147, Closes: #977137)
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 25 Jul 2021 15:38:34 -0700
+
+mariadb-10.5 (1:10.5.10-2) unstable; urgency=medium
+
+  * Bugfix: Revert upstream code change to fix armhf build (Closes: #988629)
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 23 May 2021 21:04:38 -0700
+
+mariadb-10.5 (1:10.5.10-1) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.5.10. Includes security fixes for (Closes: #988428):
+    - CVE-2021-2154
+    - CVE-2021-2166
+  * Previous release 10.5.9 included security fixes additionally for:
+    - CVE-2021-27928
+  * Previous release 10.5.7 included security fixes additionally for:
+    - CVE-2021-2194
+  * Previous release 10.5.5 included security fixes additionally for:
+    - CVE-2021-2022
+  * Update symbols to include new one from MariaDB Client 3.1.13
+  * Misc Salsa-CI fixes for better QA
+  * Innotop: Add support for MariaDB 10.5+ (Closes: #941986)
+  * Bugfix: Ensure upstream 1556 patch is included fully (Closes: 987231)
+  * Bugfix: Don't create /usr/share/mysql/*.flag files (Closes: #985870)
+  * Misc spelling fixes
+
+  [ Glenn Strauss ]
+  * Mark systemd files [linux-any] in debian/*.install
+
+  [ Arnaud Rebillout ]
+  * Fix postinst trigger when systemd is not running (Closes: #983563)
+
+  [ Faustin Lammler ]
+  * GitLab CI now supports timeout for specific jobs
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 16 May 2021 11:36:38 -0700
+
+mariadb-10.5 (1:10.5.9-1) unstable; urgency=medium
+
+  * New upstream version 10.5.9
+  * Remove transitional libmariadbclient-dev empty metapackage
+
+ -- Otto Kekäläinen <otto@debian.org>  Mon, 22 Feb 2021 21:32:47 +0200
+
+mariadb-10.5 (1:10.5.8-3) unstable; urgency=medium
+
+  * Re-introduce deprecated transitional libmariadbclient-dev package
+    so that the libmariadbclient-dev from 10.5 can replace the existing
+    libmariadbclient-dev form 10.3 and thus allow MariaDB 10.5 to
+    migrate from Debian unstable to testing.
+
+ -- Otto Kekäläinen <otto@debian.org>  Mon, 23 Nov 2020 22:14:57 +0200
+
+mariadb-10.5 (1:10.5.8-2) unstable; urgency=medium
+
+  * Fix FTBFS on mipsel/mips64el due to test main.drop failure
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 17 Nov 2020 17:07:55 +0200
+
+mariadb-10.5 (1:10.5.8-1) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Revert back to 1fc0f45a as the armhf build failure was due to GCC bug
+  * Salsa-CI: salsa-ci-team/pipeline#173 seems fixed, stop allowing failure
+  * Filter out extra 3rd party sources directly when importing new upstream
+  * New upstream version 10.5.7. Includes security fixes for:
+    - CVE-2020-28912
+    - CVE-2020-14812
+    - CVE-2020-14789
+    - CVE-2020-14776
+    - CVE-2020-14765
+  * Clean away from d/copyright files that are no longer in the sources
+  * Sync debian/* changes from upstream 10.5.7 release
+  * Clean away columnstore sources during build and ignore all CS issues
+  * New upstream version 10.5.8
+    - Includes criticat fix for arbitrary InnoDB buffer pool and data file
+      corruption issue (MDEV-24096)
+  * Add patch to workaround armhf build failure due to gcc segfault
+
+  [ Helmut Grohne ]
+  * Fix FTCBFS: Add native libssl-dev to Build-Depends (Closes: #973388)
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 13 Nov 2020 09:20:28 +0200
+
+mariadb-10.5 (1:10.5.6-2) unstable; urgency=medium
+
+  [ Miroslav Kure ]
+  * Update Czech translation of debconf messages (Closes: #972441)
+
+  [ Otto Kekäläinen ]
+  * Salsa-CI: Circumvent Bug#972552 so upgrade tests work again
+  * Salsa-CI: Install more packages to cover more in upgrade tests
+  * Automatically remove /etc/logrotate.d/mysql-server (Closes: #971399)
+  * Fix debci: Skip main.failed_auth_unixsocket on armhf and i386
+  * Revert "Allow libnuma-dev on armhf as well"
+  * Switch to using system OpenSSL (Closes: #787118)
+
+ -- Otto Kekäläinen <otto@debian.org>  Mon, 26 Oct 2020 14:13:56 +0200
+
+mariadb-10.5 (1:10.5.6-1) unstable; urgency=medium
+
+  * New upstream version 10.5.6. Includes security fixes for:
+    - CVE-2020-15180
+  * Include debian/ when importing new upstream releases
+    - This will help to follow upstream packaging changes and prevent
+      divergence in packaging code upstream vs. downstream.
+  * Unify config file syntax style
+  * Allow libnuma-dev on armhf as well
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 15 Oct 2020 11:55:14 +0300
+
+mariadb-10.5 (1:10.5.5-3) unstable; urgency=medium
+
+  [ Helmut Grohne ]
+  * Fix cross-compilation, amend commit f0ba31e1
+
+  [ Aurelien Jarno ]
+  * Correctly link pthread so riscv64 builds pass (Closes: #933151)
+
+  [ Otto Kekäläinen ]
+  * Revert "Automatically use libatomics on 64-bit archs (Closes: #933151)"
+  * Update MTR test skip lists after full test runs in Debian experimental
+  * Clean up d/rules and patches for issues that to best knowledge were
+    temporary and not needed anymore in MariaDB 10.5.5
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 09 Oct 2020 10:06:04 +0300
+
+mariadb-10.5 (1:10.5.5-2) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Salsa-CI: Extend feature tests to ensure TLS connections work at v1.2
+  * Fix x32 compilation issue (Closes: #970662)
+  * Implement unified logrotate from upstream PR#1556 (Closes: #971399)
+  * Fix upgrade from Percona.com by ensuring server uses mariadb.cnf
+  * Revert emptying /etc/mysql/debian.cnf (Closes: #971256)
+  * Use build flag to enforce default charset as utf8mb4 (Closes: #933063)
+  * Remove "Multi-Arch: same" from libmariadbd-dev
+  * Disable flaky MTR tests to get builds pass
+  * Automatically use libatomics on 64-bit archs (Closes: #933151)
+
+  [ Daniel Black ]
+  * Fix upgrade from MySQL.com with a new 'auth_socket' rename
+
+  [ Helmut Grohne ]
+  * Fix FTCBFS so cross-compiling works (Closes: #971579)
+    - Add native dependencies on gnutls, libedit and ncurses.
+    - Use a native perl interpreter during build.
+    - Let dh_auto_configure pass -DCMAKE_SYSTEM_NAME to cmake.
+    - Keep default CMAKE_BUILD_TYPE=RelWithDebInfo instead of debhelper's None.
+    - Cache the per-architecture stack direction.
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 06 Oct 2020 14:44:39 +0300
+
+mariadb-10.5 (1:10.5.5-1) unstable; urgency=medium
+
+  * New upstream version 10.5.5 (Closes: #968895)
+    - Drop patches that are obsolete or applied upstream in 10.5
+    - Rename most occurrences of 10.4 to 10.5 after importing 10.5 series
+    - Add Breaks/Replaces for 10.5 on previous 10.4 versions
+    - Stop suggesting tinyca, upstream project does not exist anymore
+    - Sync some changes from upstream MariaDB 10.5 debian/ directory
+    - Update d/copyright for MariaDB 10.5
+    - Disable ColumnStore, not mature enough for Debian yet
+    - Remove mariadb-plugin-tokudb as upstream TokuDB is not maintained anymore
+    - Introduce new package mariadb-plugin-s3 new in MariaDB 10.5
+    - Include caching_sha2_password.so plugin for libmariadb3 (Closes: #962597)
+    - Remove unnecessary charset stanza from client config (Closes: #879099)
+  * Remove deprecated transitional libmariadbclient-dev package
+  * Correct documentation about systemd using debian-start (Closes: #866782)
+  * Add NEWS item about MySQL 8.0 in-place binary incompatibility
+  * Add Provides: libmysqld-dev now as the mysql-8.0 stopped providing it
+  * Install Spider with a simple spider.cnf (Closes: #917818)
+  * Remove faulty encryption.preset file installed in subdirectory
+  * Salsa-CI: Refactor common parts into reusable sections
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 25 Sep 2020 19:56:59 +0300
+
+mariadb-10.4 (1:10.4.14-1~exp1) experimental; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.4.14
+    - Includes fix for RocksDB build failure on arch riscv64
+  * Add Breaks/Replaces for mysql-client-core-8.0 that ships myisam_ftdump
+
+  [ Christian Göttsche ]
+  * Prevent executable stack due to objects compiled from assembly
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 23 Aug 2020 13:20:04 +0300
+
+mariadb-10.4 (1:10.4.13-1~exp1) experimental; urgency=medium
+
+  * New upstream version 10.4.13. Includes security fixes for:
+    - CVE-2020-2752
+    - CVE-2020-2760
+    - CVE-2020-2812
+    - CVE-2020-2814
+    - CVE-2020-13249
+  - Includes fix for MDEV-21586: Server does not start if lc_messages setting
+    was not English (Closes: #951059)
+  * Restructure and extend d/copyright to cover libmariadb (Closes: #962541)
+  * Simplify autopkgtest 'smoke' to be easier to debug
+  * Add patch to fix RocksDB detection of ZSTD
+  * Update libmariadb symbols for upstream release 3.1.8
+
+ -- Otto Kekäläinen <otto@debian.org>  Mon, 29 Jun 2020 09:47:07 +0300
+
+mariadb-10.4 (1:10.4.12-1~exp3) experimental; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Make mariadb-client-10.4 Recommends libdbd-mariadb-perl as primary option
+  * Detect MySQL 8.0 based on undo_001 file as *.flag is buggy in mysql-8.0
+
+  [ Faustin Lammler ]
+  * Fix systemd aliases (Closes: #932289)
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 10 Apr 2020 11:03:02 +0300
+
+mariadb-10.4 (1:10.4.12-1~exp2) experimental; urgency=medium
+
+  [ Christian Göttsche ]
+  * Prevent executable stack due to objects compiled from assembly
+
+  [ Bastian Germann ]
+  * Link with libedit instead of readline5 (Closes: #940879)
+
+  [ Otto Kekäläinen ]
+  * Fix mysqld crash on s390x that stemmed from WolfSSL
+  * Extend contributor README with debugging tips
+  * Clean up -dev packages from excess private files
+  * Make full contents, also header files, explicit in -dev packages
+  * Remove entire sql-bench in debian/rules to simplify not-installed listings
+  * Remove obsolete AUTH_SOCKET build flag
+  * Add missing mariadb-ldb to mariadb-plugin-rocksdb
+  * Install files that belong to mariadb-test instead of not-installed
+  * Ignore mariadb-config.1 since there is no mariadb-config binary
+  * Enforce --fail-missing in debian/rules to not miss any uninstalled files
+  * Unify server preinst and postrm server stopping function
+  * Move mariadb-upgrade to same package as mysql-upgrade and manpage
+  * Update package to use debhelper level 10
+  * Install arch dependent mariadb.pc in lib/ with patch from upstream
+  * Move binary mariadb-tzinfo-to-sql to server package like upstream has
+  * Don't install useless extra logrotate script or test config helper
+  * Add patch for man page fixes from upstream 10.5 pull request
+  * Add patch to backport spelling fixes from upstream 10.5 pull request
+  * Include new man pages for mytop and myrocks_hotbackup in packaging
+  * Use https protected nluug.nl server for upstream repo to watch
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 17 Mar 2020 15:05:39 +0200
+
+mariadb-10.4 (1:10.4.12-1~exp1) experimental; urgency=medium
+
+  * New upstream version 10.4.12
+    - Drop patches applied upstream in 10.4
+    - Sync debian/* improvements done in upstream MariaDB 10.4 release
+    - Update Galera to version 4
+    - Update debian/copyright for MariaDB 10.4
+    - Sync non-functional delta from upstream 10.4
+    - Sync AppArmor profile handling from MariaDB 10.4
+    - Sync server stopping logic from MariaDB 10.4 preinst/postinst/postrm
+    - Package PAM tool and user map introduced in upstream MariaDB 10.4
+    - Clean away versioned breaks/replaces on older generation packages
+    - Update maintainer and contributor docs for MariaDB 10.4
+    - Add patch from MDEV-21691 so mysql-test-run works out-of-source tree
+  - Upstream release 10.4.12 included security fixes for:
+    - CVE-2020-2574
+    - CVE-2020-7221
+  - Previous version 10.4.9 included security fixes for:
+    - CVE-2020-2780
+  - Previous version 10.4.7 included security fixes for:
+    - CVE-2020-2922
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 18 Feb 2020 20:24:40 +0200
+
+mariadb-10.3 (1:10.3.22-1) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.3.22. Includes security fixes for:
+    - CVE-2020-2574
+  * Update conflicts/breaks/replaces for MySQL 8.0
+  * Add Rules-Requires-Root definition to control file
+  * Activate NO_UPDATE_BUILD_VERSION to make RocksDB build reproducible
+  * Strip path from Mroonga to make the build reproducible
+  * Update Debian Policy version
+  * Simplify and extend Gitlab-CI testing by using more of Salsa-CI features
+  * Prefer salsa-ci.yml naming over gitlab-ci.yml since we inherit Salsa-CI
+  * Add Breaks/Replaces for mysql-client-5.7 that ships myisam_ftdump
+
+  [ Christian Göttsche ]
+  * Set correct SELinux contexts on package installation (Closes: #948424)
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 28 Jan 2020 22:12:28 +0200
+
+mariadb-10.3 (1:10.3.21-2) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Update Python dependencies and recommends to Python 3 (Closes: #945697)
+  * Remove deprecated basedir config from debian.cnf (Closes: #947553)
+
+  [ James Clarke ]
+  * Fix RocksDB on GNU/kFreeBSD (Closes: #920994)
+  * Use versioned symbols on GNU/kFreeBSD
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 07 Jan 2020 09:01:10 +0200
+
+mariadb-10.3 (1:10.3.21-1) unstable; urgency=low
+
+  [ Faustin Lammler ]
+  * Remove no more needed lintian overrides
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.3.21
+
+ -- Otto Kekäläinen <otto@debian.org>  Wed, 11 Dec 2019 18:01:43 +0200
+
+mariadb-10.3 (1:10.3.20-1) unstable; urgency=high
+
+  * New upstream version 10.3.20. Includes fix for regression:
+    - MDEV-20987: InnoDB fails to start when FTS table has FK relation
+  * Remove obsolete fields Name, Contact from debian/upstream/metadata
+  * Gitlab-CI: Print artifact sizes to ensure it stays under 100 MB
+  * Gitlab-CI: Adapt CI jobs for Debian Sid work
+  * Update README.Maintainer with current Debian and Ubuntu release statuses
+
+ -- Otto Kekäläinen <otto@debian.org>  Mon, 11 Nov 2019 23:55:37 +0200
+
+mariadb-10.3 (1:10.3.19-1) unstable; urgency=high
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.3.17. Includes security fixes for:
+    - CVE-2019-2938
+    - CVE-2019-2974
+  * Update symbols to match latest libmariadb_3
+  * Drop systemd service patch applied upstream
+
+  [ Faustin Lammler ]
+  * Fix typo in Readme
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 07 Nov 2019 21:26:49 +0200
+
+mariadb-10.3 (1:10.3.18-1) unstable; urgency=medium
+
+  * New upstream version 10.3.18. Fixes regression introduced in 10.3.17
+    (MDEV-20247: Replication hangs with "preparing" and never starts)
+    (Closes: #939819)
+  * Minort Gitlab-CI improvements
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 12 Sep 2019 15:51:04 +0300
+
+mariadb-10.3 (1:10.3.17-1) unstable; urgency=high
+
+  * New upstream version 10.3.17. Includes security fixes for:
+    - CVE-2019-2737
+    - CVE-2019-2739
+    - CVE-2019-2740
+    - CVE-2019-2758
+    - CVE-2019-2805
+  * Multiple Gitlab-CI/Salsa-CI improvements
+  * Dependency in resolveip is still included (Closes: #910902)
+  * Update libmariadb3 symbols to match MariaDB Connector C 3.1 API
+  * Add Lintian override for new test binary wsrep_check_version
+  * Gitlab-CI: Clean away one excess comment left from b9d633b38
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 02 Aug 2019 17:53:22 +0100
+
+mariadb-10.3 (1:10.3.16-1) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.3.16
+  * Make libzstd dependency versioned as RocksDB need at least 1.3.3.
+    This fixes build errors across different build environments.
+  * Update Gitlab CI for better quality control and long-term maintenance.
+
+  [ Helmut Grohne ]
+  * Improve cross building (Closes: #930314)
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 22 Jun 2019 16:45:18 +0200
+
+mariadb-10.3 (1:10.3.15-2) unstable; urgency=medium
+
+  [ Julien Muchembled ]
+  * Fixup RocksDB test on s390x, not available there
+
+  [ Otto Kekäläinen ]
+  * Purge deleted translations from debian/po
+  * Rename 'mariadbcheck' to 'mariadb-check' as upstream is doing in 10.4
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 07 Jun 2019 09:13:35 +0300
+
+mariadb-10.3 (1:10.3.15-1) unstable; urgency=high
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.3.15. Includes security fixes for (Closes: #928393):
+    - CVE-2019-2628
+    - CVE-2019-2627
+    - CVE-2019-2614
+  * Includes upstream fix for MDEV-18721: Host option in configuration file is
+    ignored (Closes: #921599)
+
+  [ Gregor Riepl ]
+  * Extend mariadb/mysql_config to support --libmysqld-libs (Closes: #928230)
+
+  [ Julien Muchembled ]
+  * Enable LZ4&Snappy for InnoDB and LZ4&Snappy&ZSTD for RocksDB
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 21 May 2019 10:45:37 +0300
+
+mariadb-10.3 (1:10.3.14-1) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Rename and re-organize gitlab-ci.yml stages
+  * Refactor gitlab-ci.yml to be optimal for a life in Buster
+  * Ensure cmake builds also apply CPPFLAGS flags for hardening to fully work
+  * New upstream version 10.3.14. Includes MariaDB Connector C 3.0.10 which
+    includes an improved impelemntation of mysql_real_connect() that respects
+    the my.cnf "host" option (Closes: #921599). This upstream release also
+    fixes an indexes problem on import dump SQL (MDEV-18577) and many other
+    InnoDB corruption issues (Closes: #924498).
+  * Enable automatic restarts from maint scripts in gitlab-ci.yml
+  * Automate renaming MySQL auth_socket correctly in mysql_upgrade
+    (Closes: #926231)
+
+  [ Andreas Beckmann ]
+  * Use piuparts with --testdebs-repo so dependencies of each install resolve
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 19 Apr 2019 14:38:26 +0300
+
+mariadb-10.3 (1:10.3.13-2) unstable; urgency=medium
+
+  [ Olaf ]
+  * Use upstream conf defaults (Closes: #905599). This is critically important
+    so that nothing defined in the configuration would hold back upstream
+    improvements in default option values.
+
+  [ Otto Kekäläinen ]
+  * Extend gitlab-ci.yml to include MySQL to MariaDB upgrade testing and also
+    refine automatic testing in many ways to ensure as little regressions as
+    possible.
+  * Automatically rename 'auth_socket' to 'unix_socket' when upgrading from
+    MySQL 5.7 which otherwise would completely fail.
+  * Drop the transitional libmariadbclient18 package (Closes: #925117)
+  * Move resolveip from mariadb-server-10.3 to -core-10.3 (Closes: #910902)
+  * Move all mariadb-server-x.x *.sql files to mariadb-server-core-x.x package
+
+ -- Otto Kekäläinen <otto@debian.org>  Mon, 01 Apr 2019 23:05:31 +0300
+
+mariadb-10.3 (1:10.3.13-1) unstable; urgency=medium
+
+  * New upstream version 10.3.13
+  * Includes fixes for the following security vulnerabilities
+    (Closes: #920933):
+    - CVE-2019-2537
+    - CVE-2019-2529
+  * Update symbols list to match latest MariaDB Connector C release
+  * Use bundled SSL libraries instead of system OpenSSL (Closes: #921488)
+  * Fix 'Multi-Arch: same' stanzas (Closes: #920364)
+  * Implement proper version detection in maintainer scripts (Closes: #920415)
+  * Make libmariadb-dev depend on libgnutls28-dev (Closes: #917135)
+  * Extend Gitlab-CI significantly and update READMEs
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 24 Feb 2019 21:14:15 +0200
+
+mariadb-10.3 (1:10.3.12-2) unstable; urgency=medium
+
+  [ Adrian Bunk ]
+  * mariadb-plugin-tokudb: Properly generate the libjemalloc dependency
+
+  [ Otto Kekäläinen ]
+  * Re-enable jemalloc as Debian#843926 is now fixed (Closes: #918798)
+  * Update gitlab-ci.yml
+    * Follow upstream 'build' and 'lintian' steps
+    * Extend upgrade testing to upgrade from buster->sid (10.1 -> 10.3)
+  * Make libmariadb-dev-compat also Breaks+Replaces old libmariadbclient-dev
+    (Closes: #863675)
+  * Revert "Update libmariadb-dev.links to restore /usr/include/mysql.."
+
+  [ Andreas Beckmann ]
+  * Reintroduce libmariadbclient-dev as a transitional package
+  * Drop obsolete libmariadbclient18 symbols file
+  * Add Build-Depends-Package field to symbols file
+  * Minimize the upstream signing key by dropping all signatures
+  * Fix multiple Lintian issues
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 24 Jan 2019 20:56:46 +0200
+
+mariadb-10.3 (1:10.3.12-1) unstable; urgency=low
+
+  [ Otto Kekäläinen ]
+  * New upstream version 10.3.12
+  * Create the mysqlclient.pc symlink at correct path with /pkgconfig/
+    (Closes: #878340)
+  * Add libjemalloc2 as alternative dep for mariadb-plugin-tokudb
+  * Prevent mysql_upgrade from being triggered on every server restart
+  * Automate VERSION variable in mariadb-server installer scripts
+  * Improve logging and tag syslog messages with postinstall filename
+  * Make libmariadbclient18 Breaks old libpam-mysql and libdbd-mysql-perl
+
+  [ Samuel Thibault ]
+  * Do not try to install disks.so file not built on non-Linux
+  * Tune symbol visibility on GNU/Hurd too
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 08 Jan 2019 22:52:16 +0100
+
+mariadb-10.3 (1:10.3.11-3) unstable; urgency=low
+
+  [ Otto Kekäläinen ]
+  * Use sst_dump from package rocksdb-tools (Closes: #886853)
+  * Remove wsrep_sst_xtrabackup(-v2) already deprecated in upstream
+  * Make gitlab-ci.yml upgrade test specifically run mariadb-server-10.1->10.3
+  * Fix upstream RocksDB patch to fix Lintian complaints about source code
+  * Drop the MIPS Innobase patch that it is already fixed upstream
+  * Extend gitlab-ci.yml to test libmysql* interactions
+  * Ensure libmariadbd19 does not breaks/replace anything
+  * Make libmariadb-dev-compat break what is replaces
+  * Make libmariadb-dev breaks/replaces libmysqlclient-dev (Closes: #863675)
+  * Update Dutch translation by Frans Spiesschaert (Closes: #895461)
+
+  [ Faustin Lammler ]
+  * Fix 2 typo error in README contributor
+  * Lintian some complaints
+
+  [ Helge Deller ]
+  * Skip failing test on HPPA, it's not too important (Closes: #917395)
+
+  [ Scott Kitterman ]
+  * Update libmariadb-dev.links to restore /usr/include/mysql compatibility
+    symlinks lost when the default switched from 10.1 to 10.3 (Closes: #917266)
+
+ -- Otto Kekäläinen <otto@debian.org>  Mon, 31 Dec 2018 16:39:33 +0200
+
+mariadb-10.3 (1:10.3.11-2) unstable; urgency=low
+
+  [ Vicențiu Ciorbaru ]
+  * Update c11_atomics patch to include mysys. This should fix both
+    mips and armel build failures.
+
+  [ Otto Kekäläinen ]
+  * Make libmariadb-dev depend on libssl-dev (Closes: #917135)
+  * Remove "Conflicts: libmariadbclient18 (<< 10.2.0)" (Closes: #917075)
+
+ -- Otto Kekäläinen <otto@debian.org>  Mon, 24 Dec 2018 18:50:31 +0200
+
+mariadb-10.3 (1:10.3.11-1) unstable; urgency=low
+
+  [ Otto Kekäläinen ]
+  * Import to Debian latest major release of MariaDB (Closes: #867892)
+  * Packaging carries on all impromevements done on to the latest MariaDB
+    10.1.x packages in Debian unstable up until Dec 15th 2018.
+  * Drop the Hurd socket patch that it is already applied upstream
+  * Update SSL/TLS keys as OpenSSL since 1.1.0 rejects weak keys by default
+  * Remove innodb_* options from server config that are default in 10.3
+  * Remove --skip-auth-anonymous-user deprecated in 10.3
+  * Include also arch specific skiplists in CI tests
+  * Make TokuDB explicitly depend on libjemalloc1
+  * Follow Salsa-CI changes and update build image name to 'dockerbuilder'
+  * Extend gitlab-ci to test installation and upgrade of MariaDB
+
+  [ Vicențiu Ciorbaru ]
+  * Refresh c11_atomics patch for 10.3
+  * Fix MEMORY storage engine test
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 20 Dec 2018 21:52:42 +0200
+
+mariadb-10.1 (1:10.1.37-3) unstable; urgency=low
+
+  [ Otto Kekäläinen ]
+  * Update translation templates
+  * Fix typo in commit 33d853128 so skip list is not reset when adding lines
+
+  [ Vicențiu Ciorbaru ]
+  * Fix mips compilation failure (__bss_start symbol missing)
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 08 Dec 2018 18:50:43 +0200
+
+mariadb-10.1 (1:10.1.37-2) unstable; urgency=low
+
+  [ Samuel Thibault ]
+  * Do not depend on libsystemd-dev on non-Linux
+  * On non-Linux, do not install files not built there
+  * Add hurd cmake configuration (Closes: #912902)
+
+  [ Otto Kekäläinen ]
+  * Add Gitlab-CI definition file that can test each commit to this repository
+  * Utilize upstream unstable-tests list in tests/upstream mysql-test-run.
+    This will make ci.debian.net pass as it will correctly ignore tests.
+  * Disable test unit.pcre_test on s390x that was failing in stretch-security
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 01 Dec 2018 18:17:18 +0200
+
+mariadb-10.1 (1:10.1.37-1) unstable; urgency=high
+
+  * New upstream version 10.1.37. Includes security fixes for:
+    - CVE-2018-3282
+    - CVE-2018-3251
+    - CVE-2018-3174
+    - CVE-2018-3156
+    - CVE-2018-3143
+    - CVE-2016-9843
+  * Update README.Contributor based on recent feedback
+  * Update README.Maintainer to match current best practices
+  * Move my_print_defaults to mariadb-server-core (Closes: #898367)
+  * Update Debian standards version to 4.2.1 (no changes)
+  * Fix minor Lintian complaints
+  * Add (and rename) new man pages
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 04 Nov 2018 19:11:19 +0200
+
+mariadb-10.1 (1:10.1.35-1) unstable; urgency=medium
+
+  * New upstream version 10.1.35. Includes security fixes for:
+    - CVE-2018-3066
+    - CVE-2018-3064
+    - CVE-2018-3063
+    - CVE-2018-3058
+  * Fix wrong-path-for-interpreter in innotop script
+  * Update Debian standards version
+  * Revert "Remove the mariadb-test-* packages" (Closes: #888956)
+  * Omit test plugins as they are not used by the tests and already deleted
+  * Define autopkgtest with isolation-container (Closes: #870408)
+  * Ship config examples et al in /usr/share/mysql (Closes: #878223)
+  * Extend the server README to clarify misunderstandings (Closes: #878215)
+  * Introduce mariadb-backup as a separate binary package, just like in upstream
+  * Fix bash syntax issues detected by Shellcheck
+  * Fix 'max key length is 767 bytes' errors (Closes: #886756)
+  * Remove GNU Hurd FTBFS patch that's been applied upstream (Closes: #882062)
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 07 Aug 2018 22:18:20 +0300
+
+mariadb-10.1 (1:10.1.34-1) unstable; urgency=medium
+
+  * New upstream release 10.1.34.
+  * Previous upstream version 10.1.33 included fixes for the following
+    security vulnerabilities:
+    - CVE-2018-2819
+    - CVE-2018-2817
+    - CVE-2018-2813
+    - CVE-2018-2787
+    - CVE-2018-2784
+    - CVE-2018-2782
+    - CVE-2018-2781
+    - CVE-2018-2771
+    - CVE-2018-2766
+    - CVE-2018-2761
+    - CVE-2018-2755
+  * Previous upstream version 10.1.31 included fixes for the following
+    security vulnerabilities:
+    - CVE-2018-2668
+    - CVE-2018-2665
+    - CVE-2018-2640
+    - CVE-2018-2622
+    - CVE-2018-2612
+    - CVE-2018-2562
+  * Previous upstream version 10.1.30 included fixes for the following
+    security vulnerabilities:
+    - CVE-2017-15365
+
+  [ Otto Kekäläinen ]
+  * Update VCS-* links to point to the new source repository
+  * Delete unnecessary systemd files introduced by upstream
+  * Add new files introduced by upstream to correct packages
+  * Mark selected tests as unstable so they don't stop the whole upload in vain
+  * Update d/control Uploaders to match current affairs
+  * Various minor Lintian fixes
+  [ Otto Kekäläinen ]
+  * Use the ccache symlinks made by update-ccache-symlinks, if available
+
+  [ Vicențiu Ciorbaru ]
+  * Extend libmariadbclient-rename.patch to cover TokuDB as well
+  * Disable disks.disks test
+
+  [ Rui Branco ]
+  * Updated Portuguese translation by Rui Branco (Closes: #871052)
+
+  [ Takuma Yamada ]
+  Updated Japanese translation by Takuma Yamada (Closes: #859481)
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 31 Jul 2018 21:52:16 +0800
+
+mariadb-10.1 (1:10.1.29-6) unstable; urgency=high
+
+  * Ignore failed tests on more non-release platforms (kfreebsd-i386,
+    kfreebsd-amd64 and sparc64)
+
+ -- Ondřej Surý <ondrej@debian.org>  Thu, 23 Nov 2017 07:03:47 +0000
+
+mariadb-10.1 (1:10.1.29-5) unstable; urgency=high
+
+  * Update the -O3 -> -O2 patch to include more cmake files
+
+ -- Ondřej Surý <ondrej@debian.org>  Wed, 22 Nov 2017 22:48:13 +0000
+
+mariadb-10.1 (1:10.1.29-4) unstable; urgency=high
+
+  * Change the default optimization from -O3 to -O2 in mysql_release.cmake
+    BUILD_CONFIG profile
+
+ -- Ondřej Surý <ondrej@debian.org>  Wed, 22 Nov 2017 20:33:17 +0000
+
+mariadb-10.1 (1:10.1.29-3) unstable; urgency=medium
+
+  * Change the default optimization level to -O2 to fix arm64 build
+
+ -- Ondřej Surý <ondrej@debian.org>  Wed, 22 Nov 2017 15:33:21 +0000
+
+mariadb-10.1 (1:10.1.29-2) unstable; urgency=medium
+
+  [ Otto Kekäläinen ]
+  * Update the d/changelog with CVEs
+
+  [ Ondřej Surý ]
+  * Revert to using system pcre library (Closes: #882329)
+  * Bump the epoch to fix the mess created by mariadb-10.2 upload
+    (Closes: #881898)
+
+  [ Christian Ehrhardt ]
+  * d/t/upstream: skip func_regexp_pcre on s390x
+
+ -- Ondřej Surý <ondrej@debian.org>  Wed, 22 Nov 2017 06:03:17 +0000
+
+mariadb-10.1 (10.1.29-1) unstable; urgency=medium
+
+  * New upstream version 10.1.29, includes fixes for the following
+    security vulnerabilities:
+    - [CVE-2017-10378]: Optimizer component to cause denial of service
+      conditions
+    - [CVE-2017-10268]: Replication component to access data
+    - [MDEV-13819]: Server crashes in Item_func_in::val_int or Assertion
+      `in_item' failed in virtual longlong Item_func_in::val_int
+  * Remove the mariadb-test-* packages as they are now provided by
+    mariadb-10.2 (Closes: #881898)
+  * Rebase patches for new upstream version.
+
+ -- Ondřej Surý <ondrej@debian.org>  Thu, 16 Nov 2017 15:24:36 +0000
+
+mariadb-10.1 (10.1.28-2) unstable; urgency=high
+
+  * Add libconfig-inifiles-perl to mariadb-client-10.1 depends to fix
+    mytop (Closes: #875708)
+  * Add mips64el to the list of platforms that are allowed to fail test
+    suite (Closes: #879637)
+
+ -- Ondřej Surý <ondrej@debian.org>  Sun, 12 Nov 2017 11:03:20 +0000
+
+mariadb-10.1 (10.1.28-1) unstable; urgency=medium
+
+  * New upstream version 10.1.28
+  * Rebase patches on top of MariaDB 10.1.28
+  * Add extra symbols aliases for libmariadbclient_16
+
+ -- Ondřej Surý <ondrej@debian.org>  Mon, 09 Oct 2017 22:07:43 +0000
+
+mariadb-10.1 (10.1.26-1) unstable; urgency=medium
+
+  * Ignore upstream debian/ directory when importing upstream tarball
+  * New upstream version 10.1.26
+  * Refresh patches for MariaDB 10.1.26
+  * Remove unstable tests patches for unstable build, so we see what is
+    really failing and what is not
+
+ -- Ondřej Surý <ondrej@debian.org>  Thu, 10 Aug 2017 20:41:46 +0200
+
+mariadb-10.1 (10.1.25-1) unstable; urgency=medium
+
+  * New upstream version 10.1.25
+  * Update quilt patches on top of mariadb-10.1.25 release
+  * Explicitly add dh_systemd_start snippets to mariadb-server-10.1
+    because it's all messed up with different name for sysvinit ('mysql')
+    and systemd ('mariadb') (Closes: #865870)
+  * Don't disable PIE, it's enabled by upstream anyway (Closes: #865737)
+  * Add default socket location for client (Closes: #864662)
+
+ -- Ondřej Surý <ondrej@debian.org>  Sun, 30 Jul 2017 14:15:48 +0200
+
+mariadb-10.1 (10.1.24-6) unstable; urgency=medium
+
+  * Run invoke-rc.d mysql maintscript snippets only when running under
+    sysvinit (Closes: #864593)
+
+ -- Ondřej Surý <ondrej@debian.org>  Wed, 21 Jun 2017 11:12:16 +0200
+
+mariadb-10.1 (10.1.24-5) unstable; urgency=medium
+
+  * Add @SYSTEMD_EXECSTARTPOST@ replacement token to mariadb@.service, so
+    the /var/run/mysqld directory is created even for multi-server setup
+    (Closes: #865083)
+
+ -- Ondřej Surý <ondrej@debian.org>  Mon, 19 Jun 2017 08:52:26 +0200
+
+mariadb-10.1 (10.1.24-4) unstable; urgency=medium
+
+  [ James Cowgill ]
+  * Disable jemalloc on mips*. (Closes: #864340)
+  * Update C11 atomics to have correct semantics (Closes: #864774)
+
+  [ Ondřej Surý ]
+  * Refresh patches after C11 atomics patch update
+  * Merge mytop script improvements from src:mytop package (Original
+    patches by Philipp Matthias Hahn, Werner Detter, Olaf van der Spek,
+    and Steffen Zieger) (Closes: #864762)
+
+  [ Svante Signell ]
+  * Fix FTBFS on Debian GNU/Hurd (Closes: #861166)
+
+ -- Ondřej Surý <ondrej@debian.org>  Mon, 19 Jun 2017 07:09:50 +0200
+
+mariadb-10.1 (10.1.24-3) unstable; urgency=medium
+
+  * Team upload.
+  * Add mips-innobase-atomic.patch, fixing FTBFS on 32-bit mips*, thanks to
+    James Cowgill.  (Closes: #864298)
+
+ -- Andreas Beckmann <anbe@debian.org>  Wed, 07 Jun 2017 02:23:44 +0200
+
+mariadb-10.1 (10.1.24-2) unstable; urgency=medium
+
+  * Add Breaks: cqrlog (<< 1.9.0-5~) to ensure correct upgrade order
+    (Closes: #864159)
+
+ -- Ondřej Surý <ondrej@debian.org>  Tue, 06 Jun 2017 14:29:52 +0200
+
+mariadb-10.1 (10.1.24-1) unstable; urgency=medium
+
+  * New upstream version 10.1.24, includes fixes for the following
+    high-priority regression fixes:
+    + MDEV-11842: Fail to insert on a table where a field has no default
+    + MDEV-12075: innodb_use_fallocate does not work in MariaDB
+      Server 10.1.21
+  * Refresh patches on top of MariaDB 10.1.24
+  * Fix FTBFS in tests: Add cracklib-runtime to Build-Depends
+
+ -- Ondřej Surý <ondrej@debian.org>  Tue, 06 Jun 2017 09:25:19 +0200
+
+mariadb-10.1 (10.1.23-9+deb9u1) stretch; urgency=medium
+
+  [ Ondřej Surý ]
+  * Add Breaks: cqrlog (<< 1.9.0-5~) to ensure correct upgrade order
+    (Closes: #864159)
+
+ -- Andreas Beckmann <anbe@debian.org>  Wed, 07 Jun 2017 21:11:23 +0200
+
+mariadb-10.1 (10.1.23-9) unstable; urgency=medium
+
+  * Fix the invalid location of insserv configuration snippet
+    (Thanks Michael Biebl for catching that)
+
+ -- Ondřej Surý <ondrej@debian.org>  Fri, 26 May 2017 09:26:33 +0200
+
+mariadb-10.1 (10.1.23-8) unstable; urgency=medium
+
+  * Use /etc/insserv.conf.d/mariadb to provide $database system facility
+    (Closes: #862447)
+
+ -- Ondřej Surý <ondrej@debian.org>  Sat, 13 May 2017 11:08:43 +0200
+
+mariadb-10.1 (10.1.23-7) unstable; urgency=medium
+
+  * Remove hard Breaks/Replaces with mysql-server and mysql-client
+  * Move virtual packages from Breaks to Conflicts (Debian Policy 7.6.2)
+
+ -- Ondřej Surý <ondrej@debian.org>  Fri, 12 May 2017 12:21:33 +0200
+
+mariadb-10.1 (10.1.23-6) unstable; urgency=medium
+
+  * Also fix the same assertion failure in xtradb (Closes: #862103)
+
+ -- Ondřej Surý <ondrej@debian.org>  Mon, 08 May 2017 19:51:47 +0200
+
+mariadb-10.1 (10.1.23-5) unstable; urgency=medium
+
+  * Add upstream patch to fix assertion failure in InnoDB storage engine
+    (Closes: #862103)
+
+ -- Ondřej Surý <ondrej@debian.org>  Mon, 08 May 2017 17:21:55 +0200
+
+mariadb-10.1 (10.1.23-4) unstable; urgency=medium
+
+  * Properly declare conflict on mytop (Closes: #861913)
+
+ -- Ondřej Surý <ondrej@debian.org>  Mon, 08 May 2017 11:31:13 +0200
+
+mariadb-10.1 (10.1.23-3) unstable; urgency=medium
+
+  * Remove two internal symbols (ll2str and longlong2str) from
+    kfrebsd-amd64 symbols file
+
+ -- Ondřej Surý <ondrej@debian.org>  Thu, 04 May 2017 13:19:00 +0200
+
+mariadb-10.1 (10.1.23-2) unstable; urgency=medium
+
+  * Add CVE list for 10.1.23 release
+  * Fix FTBFS on kfrebsd-any due missing .service files
+
+ -- Ondřej Surý <ondrej@debian.org>  Thu, 04 May 2017 10:55:06 +0200
+
+mariadb-10.1 (10.1.23-1) unstable; urgency=medium
+
+  * New upstream version 10.1.23, includes fixes for the following
+    security vulnerabilities:
+   - [CVE-2017-3302]: use-after-free in C client library for MySQL
+   - [CVE-2017-3313]: unauthorized (local) access to critical data or
+     complete access to all MySQL Server accessible data
+   - [CVE-2017-3308]: unauthorized (network) ability to cause a hang or
+     frequently repeatable crash
+   - [CVE-2017-3309]: unauthorized (network) ability to cause a hang or
+     frequently repeatable crash
+   - [CVE-2017-3453]: unauthorized (network) ability to cause a hang or
+     frequently repeatable crash
+   - [CVE-2017-3456]: unauthorized (network) ability to cause a hang or
+     frequently repeatable crash
+   - [CVE-2017-3464]: unauthorized update, insert or delete access to some
+     of MySQL Server accessible data
+  * Refresh debian/patches on top of MariaDB 10.1.23 release
+  * debian/gbp.conf: Filter most common cruft in the orig tarball
+  * debian/rules: Use --fail-missing to catch extra upstream files
+  * debian/*.manpages: Merge into debian/*.install
+  * debian/*.install: Add few missing binaries into various packages
+  * Declare mariadb-plugin-tokudb as available only on (linux-)amd64
+    to fix FTBFS on kfreebsd-amd64
+  * Remove the extra sanity check as it is already there via standard
+    dh_installinit (|| exit 0) (Closes: #861782)
+  * Stop /usr/sbin/mysqld in prerm script even with systemd
+  * Move mariadb.pc into proper multiarch directory (Closes: #852621)
+  * Add libarchive-dev needed by mariabackup to Build-Depends
+  * debian/control: run wrap-and-sort -a
+  * Move mysql_install_db from mariadb-server-10.1 to
+    mariadb-server-core-10.1 (Closes: #840646)
+  * Add Provides: $database to mysql.init - this partially addresses
+    #852776
+  * Call dh_systemd_start with --no-restart-after-upgrade
+    (Closes: #853137)
+  * d/rules: Remove dh_prep override (legacy cruft)
+
+ -- Ondřej Surý <ondrej@debian.org>  Thu, 04 May 2017 07:23:23 +0200
+
+mariadb-10.1 (10.1.22-4) unstable; urgency=medium
+
+  * Fix small typo in d/rules that caused MySQL version suffix to not
+    contain information about Debian build
+
+ -- Ondřej Surý <ondrej@debian.org>  Sat, 29 Apr 2017 21:56:23 +0200
+
+mariadb-10.1 (10.1.22-3) unstable; urgency=medium
+
+  * Use pidof instead of pgrep, so we don't have to depend on procps
+  * Stop stopping mariadb server that many times and just add a simple
+    check to preinst that it has been really stopped (Closes: #852495)
+  * Fix small typo in gettid patch
+  * Disable TokuDB on kfreebsd-amd64
+
+ -- Ondřej Surý <ondrej@debian.org>  Tue, 28 Mar 2017 22:59:06 +0200
+
+mariadb-10.1 (10.1.22-2) unstable; urgency=medium
+
+  [ Ondřej Surý ]
+  * Add correct kfreebsd-i386 symbols file (but this needs to be fixed in
+    how upstream uses linker)
+  * Update italian translation (Closes: #858300)
+
+  [ Otto Kekäläinen ]
+  * Add Vietnamese translation by Trần Ngọc Quân
+  * Add Finnish translation by Antti Järvinen
+
+  [ Ondřej Surý ]
+  * Disable test suite on hppa, don't fail test suite on more unstable
+    platforms: alpha, powerpc, and x32
+  * Add swedish debconf translation (Closes: #858536)
+  * Add Catalan debconf translation (Closes: #858632)
+  * Use thr_self() as gettid implementation onf __FreeBSD_kernel__
+  * Make mariadb-server-10.1 installable on kFreeBSD and Hurd (Closes: #851687)
+  * Update Turkish debconf translation (Closes: #858340)
+  * Disable specific tests on hppa to make the build succeed (Courtesy of
+    John David Anglin) (Closes: #858869)
+
+ -- Ondřej Surý <ondrej@debian.org>  Tue, 28 Mar 2017 22:59:01 +0200
+
+mariadb-10.1 (10.1.22-1) unstable; urgency=high
+
+  [ Otto Kekäläinen ]
+  * New upstream release 10.1.22. Includes fixes for the following
+    security vulnerabilities:
+    - CVE-2017-3313
+    - CVE-2017-3302
+  * New upstream also includes fix to logrotate so that it no longer
+    risks interrupting binary/relay log processing on the server.
+    https://github.com/MariaDB/server/commit/156cf86defdc59353f37f6
+  * Add a NEWS.Debian item with same contents as the Stretch release notes
+
+  [ Ondřej Surý ]
+  * Add myself to Uploaders
+  * Use https URI for Homepage
+  * Use /usr/share/dpkg/default.mk to define dpkg-architecture and other
+    build variables
+  * Install and use non-versioned symbols files for kFreeBSD and Hurd
+    architectures
+  * Make mysql_config and mariadb.pc return -lmariadbclient instead of
+    missing -lmysqlclient
+  * Add mysqlclient.pc -> mariadb.pc symlink into
+    libmariadbclient-dev-compat package
+  * MDEV-11884: Fix logrotate failing if mysqld is not running (Closes: #830976)
+
+ -- Ondřej Surý <ondrej@debian.org>  Sun, 19 Mar 2017 15:23:26 +0100
+
+mariadb-10.1 (10.1.21-5) unstable; urgency=low
+
+  [ James Clarke ]
+  * Make debian/mariadb-server-10.1.install executable (Closes: #852728)
+  * Allow mariadb-plugin-tokudb/mroonga on non-linux and non-release arches
+  * Detect whether libatomic is needed rather than hard-coding for mips
+  * Use host architecture, not build architecture, and clean up variables
+  * General clean-up in d/rules
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 27 Jan 2017 20:42:36 +0200
+
+mariadb-10.1 (10.1.21-4) unstable; urgency=low
+
+  * Hotfix to full build failure: Add missing galera_new_cluster.1 to patch
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 26 Jan 2017 23:33:32 +0200
+
+mariadb-10.1 (10.1.21-3) unstable; urgency=low
+
+  [ Ian Gilfillan ]
+  * Extend WSREP and Galera man pages patch to cover all commands
+
+  [ Dieter Adriaenssens ]
+  * Specify Architecture for mariadb-plugin-mroonga and mariadb-plugin-tokudb
+    (Closes: #852709)
+
+  [ James Clarke ]
+  * Fix FTBFS on non-Linux architectures (Closes: #852728)
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 26 Jan 2017 22:18:26 +0200
+
+mariadb-10.1 (10.1.21-2) unstable; urgency=low
+
+  [ Otto Kekäläinen ]
+  * Implement systemd packaging the Debian way
+  * Extend README.Debian regarding new systemd files
+  * Add config file comments about SysV init and systemd differences
+  * Extend Debian.README with section about mixing with packages MariaDB.org
+  * Update /etc/init.d/mysql after comparison with upstream MariaDB 10.1.21
+  * Run chown much faster on the datadir during install/update
+  * Check if /var/lib/mysql exists before running 'find' on it
+  * Skip mysqld stopping if no mysqld process is running at all
+  * Update French debconf translation by Baptiste Jammet (Closes: #850066)
+  * Remove unnecessary XS-Testsuite field (as instructed by Lintian)
+  * Add a modified version of upstream autobake-deb script to utilize CI tools
+  * Fix server config example on how to enable SSL with YaSSL (Closes: #851132)
+  * Make commands mariadb and mariadbcheck available with symlinks
+
+  [ Jean Weisbuch ]
+  * Update Innotop to latest version
+
+  [ Ian Gilfillan ]
+  * Add wsrep_* man pages
+
+ -- Otto Kekäläinen <otto@debian.org>  Wed, 25 Jan 2017 10:42:45 +0200
+
+mariadb-10.1 (10.1.21-1) unstable; urgency=low
+
+  [ Otto Kekäläinen ]
+  * New upstream release 10.0.28. Includes fixes for the following
+    security vulnerabilities (Closes: #851759, Closes: ##849435):
+    - CVE-2017-3318
+    - CVE-2017-3317
+    - CVE-2017-3312
+    - CVE-2017-3291
+    - CVE-2017-3265
+    - CVE-2017-3258
+    - CVE-2017-3257
+    - CVE-2017-3244
+    - CVE-2017-3243
+    - CVE-2017-3238
+    - CVE-2016-6664
+  * Add new program introduced in upstream 10.1.21: mysqld_safe_helper
+  * Deb-CI: remove parameter --skip-ndbcluster not available in 10.1 any more
+  * Make libmariadbclient18 depend on mysql-common only (Closes: #850216)
+  * Fix misleading config file comment (Closes: #677223)
+  * Update preinst variable $this_version from 10.0 to 10.1 (Closes: #851257)
+
+  [ Kristian Nielsen ]
+  * Re-implement passwordless root login (Closes: #851131)
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 19 Jan 2017 11:33:01 +0200
+
+mariadb-10.1 (10.1.20-3) unstable; urgency=low
+
+  [ Vicențiu Ciorbaru ]
+  * Update debian rules to also account for mipsel
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 24 Dec 2016 20:23:23 +0200
+
+mariadb-10.1 (10.1.20-2) unstable; urgency=low
+
+  [ Otto Kekäläinen ]
+  * Upload to unstable
+  * Previous version string should had been ~exp1, thus this
+    first upload to unstable is -2 and not -1 as normal
+  * Disable test suite temporairly due to false regressions
+
+  [ Dieter Adriaenssens ]
+  * fix Vcs-git link format and repo name
+  * update 10.0 to 10.1 in README files
+
+  [ Vicențiu Ciorbaru ]
+  * Fix mips missing atomics primitives
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 24 Dec 2016 09:54:59 +0200
+
+mariadb-10.1 (10.1.20-1) experimental; urgency=low
+
+  * Upgrade package to new MariaDB 10.1.x series:
+    - New upstream release  10.1.20
+    - Refresh patches after 10.1.20 import
+    - Update strings 10.0 -> 10.1 after importing 10.1.20
+    - Refresh patches after 10.1.20 import
+    - Update d/control after 10.1 import
+    - Use https protected git url in d/control
+    - Backwards compatible XS-Testsuite syntax in d/control
+    - Import debian/* changes done in upstream 10.1
+    - Replace deprecated iproute with iproute2
+    - Remove unnecessary dependencies as packages are Essential anyway
+    - Remove unnecessary and big file mysql_embedded
+    - Switch to 10.1 style build flag for unix socket auth module in d/rules
+    - Update d/copyright after 10.1 import
+    - Add missing aria_add_gis_sp.sql to mariadb-server-10.1
+    - Ship SELinux and AppArmor files with the server, but as inactive
+    - New package from upstream 10.1: GSS API (Kerberos) client and server
+    - Extend GSSAPI plugin descriptions to satisfy Lintian
+    - New plugin from upstream 10.1: Cracklib password validation
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 20 Dec 2016 22:46:59 +0200
+
+mariadb-10.0 (10.0.28-3) unstable; urgency=low
+
+  [ Otto Kekäläinen ]
+  * Move libmariadbd and -dev next to each other for a more logical flow in d/control
+  * Move mariadb-test to last in file for a more logical flow in d/control
+  * Clean away unused Lintian overrides
+  * Add Lintian override for impossible mysql_config multi-arch requirement
+  * Update Debian copyright based on the 2016 git log author list
+  * Remove unnecessary /var/lib/mysql-upgrade (Closes: #848620)
+
+  [ Vicențiu Ciorbaru ]
+  * Fix connect.upd test in armhf
+  * Fix mroonga/storage.index_read_multiple_double test in armhf
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 20 Dec 2016 21:59:47 +0200
+
+mariadb-10.0 (10.0.28-2) unstable; urgency=low
+
+  [ Samuel Thibault ]
+  * patches/hurd_socket.patch: Also avoid non-working socket path length check
+    on hurd-i386.
+  * rules: Drop symbols on hurd-i386 too (Closes: #842696).
+
+  [ Daniel Black ]
+  * Don't install private mysql header files in libmariadbclient-dev
+
+  [ Otto Kekäläinen ]
+  * Update libmariadbd18 description and contents to match latest upstream
+  * Mark missing Multi-Arch as suggested by Multiarch hinter
+  * Move plugins to $ARCH/*/mariadb18 to meet multiarch needs (Closes: #739452)
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 11 Nov 2016 22:03:33 +0200
+
+mariadb-10.0 (10.0.28-1) unstable; urgency=low
+
+  [ Vicențiu Ciorbaru ]
+  * Fix tokudb jemalloc linking
+
+  [ Otto Kekäläinen ]
+  * New upstream release 10.0.28. Includes fixes for the following
+    security vulnerabilities:
+    - CVE-2016-8283
+    - CVE-2016-7440
+    - CVE-2016-6663
+    - CVE-2016-5629
+    - CVE-2016-5626
+    - CVE-2016-5624
+    - CVE-2016-5616
+    - CVE-2016-5584
+    - CVE-2016-3492
+  * Drop 4 patches that have been applied upstream.
+  * Delete runnable files from mariadb-test-data as they were only
+    needed at build time to generate tests.
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 28 Oct 2016 22:51:14 +0300
+
+mariadb-10.0 (10.0.27-2) unstable; urgency=low
+
+  [ Dieter Adriaenssens ]
+  * Fix typo in README.Contributor
+  * Improve documentation on how to clean the build env
+
+  [ James Cowgill ]
+  * Mips build and testsuite fixes (Closes: #838557, Closes: #838914)
+    - Permit 93 as a valid value of the ENOTEMPTY error in the testsuite
+    - Correctly fix mips64 multiplication in taocrypt
+    - Ensure groonga is built with libatomic
+    - Handle unaligned buffers in connect's TYPBLK class
+    - Fix DEFAULT_MACHINE on mips
+    - Remove various tests from unstable-tests which now pass on MIPS
+    - Update debian/unstable-tests.mips*
+
+  [ Kristian Nielsen ]
+  * Fix missing path for perl in autopkgtest (Closes: #809022)
+  * Fix test failures on hppa due to wrong enoempty (Closes: #837369)
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 02 Oct 2016 09:22:59 +0300
+
+mariadb-10.0 (10.0.27-1) unstable; urgency=low
+
+  * New upstream release 10.0.27
+  * Remove 3 patches after 10.0.27 import as they have been applied
+    upstream.
+
+ -- Otto Kekäläinen <otto@debian.org>  Wed, 07 Sep 2016 23:05:28 +0300
+
+mariadb-10.0 (10.0.26-3) unstable; urgency=low
+
+  [ Dieter Adriaenssens ]
+  * Add DEP-12 formatted upstream metadata file (Closes: #808421)
+
+  [ Vicențiu Ciorbaru ]
+  * Update innodb_xtradb patch to introduce memory barrier after lock
+  * Fix failing shutdown with gcc v6
+
+  [ Otto Kekäläinen ]
+  * Extend commit d5af196 with old name of package libmariadb-dev-compat
+  * Extend commit 8d2a7c9 and actually install the tokuftdump man page
+  * Update mariadb-test dependencies to include also libmariadbclient18
+  * Add path to fix for sporadically failing test main.information_schema_stats
+  * d/rules: NUMJOBS must have a default value
+
+ -- Otto Kekäläinen <otto@debian.org>  Wed, 17 Aug 2016 00:31:02 +0300
+
+mariadb-10.0 (10.0.26-2) unstable; urgency=low
+
+  [ Vicențiu Ciorbaru ]
+  * Add patch to correctly revert changes from 10.0.26 that caused
+    build failure regression on PPC64el
+
+  [ Paul Gevers ]
+  * Add autopkg tests for MariaDB 10.0 (Closes: #809022)
+
+  [ Axel Beckert ]
+  * Extend mariadb-server to purge gracefully if datadir is a mountpoint
+    (Closes: #829491)
+
+  [ Ian Gilfillan ]
+  * Add a patch to provide a man page for tokuftdump
+
+  [ Robie Basak ]
+  * Re-add libmariadbclient18 and libmariadbclient-dev
+  * Add libmariadbclient-dev-compat package
+
+  [ Otto Kekäläinen ]
+  * d/control: libmariadbclient18 must be 'Multi-Arch: same'
+  * Make libmariadbclient-dev-compat conflict with libmariadb-dev-compat
+    (Closes: #831229)
+  * Add libmariadbclient-dev as dependency for libmariadbd-dev
+  * Replace hacky sed of libmysqlclient->libmariadbclient with proper patch
+  * Update symbols file to match newest libmariadbclient18
+  * Updated Danish translation by Joe Hansen (Closes: #830592)
+  * Remove mariadb-plugin-cassandra until libthrif-dev lands in unstable
+  * Make libdbd-mysql-perl and friends Recommends instead of strict Depends
+    (Closes: #793787)
+  * Documentation and spelling fixes
+  * Remove mysqlbug binary as it is not used for MariaDB
+  * Update default config files with more secure TLS examples
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 29 Jul 2016 21:42:50 +0300
+
+mariadb-10.0 (10.0.26-1) unstable; urgency=low
+
+  * Updated French translation by Baptiste Jammet (Closes: #826879)
+  * New upstream release 10.0.26. Includes fixes for the following
+    security vulnerabilities:
+    - CVE-2016-5440
+    - CVE-2016-3615
+    - CVE-2016-3521
+    - CVE-2016-3477
+  * Updated old changelog entries to include new CVE identifiers.
+  * Refresh patches after 10.0.26 import
+
+ -- Otto Kekäläinen <otto@debian.org>  Fri, 24 Jun 2016 17:05:44 +0300
+
+mariadb-10.0 (10.0.25-1) unstable; urgency=low
+
+  [ Otto Kekäläinen ]
+  * Revert previous changes tailored for Ubuntu 16.04 compatibility.
+  * New upstream release 10.0.25. Includes fixes for the following
+    security vulnerabilities (Closes: #823325):
+    - CVE-2016-0666
+    - CVE-2016-0655
+    - CVE-2016-0648
+    - CVE-2016-0647
+    - CVE-2016-0643
+    - CVE-2016-5444
+    - CVE-2016-3459
+    - CVE-2016-3452
+  * Updated old changelog entries to include new CVE identifiers.
+  * Upstream included changes to logrotate script that supports systems that
+    has multiple mysqld processes running (Closes: #810968).
+  * Updated Dutch translation by Frans Spiesschaert (Closes: #822894).
+  * Updated Spanish translation by Javier Fernández-Sanguino Peña
+    (Closes: #823099).
+  * Updated Russian translation by Yuri Kozlov (Closes: #823422).
+  * Updated German translation by Chris Leick (Closes: #824487).
+  * Updated Brazilian Portuguese translation (Closes: #824644).
+  * Updated Turkish translation by Atila KOÇ (Closes: #825802).
+  * Add patch to provide passwordless root accounts for test suite.
+  * Updated Japanese translation by Takuma Yamada (Closes: #825813).
+
+  [ Vicențiu Ciorbaru ]
+  * Backport upstream MDEV-9479 fix: oqgraph fails to build with boost 1.60
+
+ -- Otto Kekäläinen <otto@debian.org>  Mon, 30 May 2016 22:43:30 +0300
+
+mariadb-10.0 (10.0.24-7) unstable; urgency=low
+
+  * Temporarily remove mariadb-plugin-cassandra as Debian FTP bot thinks
+    it wasn't there before 10.0.24-6 and put the package in the NEW queue.
+
+ -- Otto Kekäläinen <otto@debian.org>  Wed, 13 Apr 2016 13:24:28 +0300
+
+mariadb-10.0 (10.0.24-6) unstable; urgency=low
+
+  * Move mysql_embedded from client package to client-core package,
+    equally as is in mysql-client-core-5.6 and -5.7 (LP: #1568077).
+  * Add breaks/replaces for mariadb-client to accommodate the above.
+  * Add conflicts/breaks/replaces for MySQL 5.7 series packages now
+    when mysql-5.7 entered the Ubuntu repositories (LP: #1568285).
+  * Detect properly if there is an incompatible data directory from 5.7,
+    save it to another location and initialize a new data directory so that the
+    installation can complete properly without leaving dpkg in an inconsistent
+    state.
+  * Remove all old passwordless root account lines to close a potential
+    security vulnerability (LP: #1561062).
+
+ -- Otto Kekäläinen <otto@debian.org>  Wed, 13 Apr 2016 10:56:10 +0300
+
+mariadb-10.0 (10.0.24-5) unstable; urgency=low
+
+  * Disable sporadically failing rpl_binlog_index test on PowerPC.
+  * Disable another sporadic on amd64 and update all Jira links.
+  * Fix typo in Mroonga prerm script.
+
+ -- Otto Kekäläinen <otto@debian.org>  Sat, 12 Mar 2016 10:08:23 +0200
+
+mariadb-10.0 (10.0.24-4) unstable; urgency=low
+
+  * Update contributor documentation to match git-buildpackage version in sid.
+  * Add libxml and unixOBDC as build-depends for ConnectSE as done by in
+    upstream (Closes: #814944).
+  * Upload to via NEW as mariadb-10.0 was accidentally removed from Debian
+    unstable archives.
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 10 Mar 2016 18:40:51 +0200
+
+mariadb-10.0 (10.0.24-3) unstable; urgency=low
+
+  * Fix typo in rules file about Mroonga control section
+  * Add main.delayed test exception to more platforms
+  * Install mysql_embedded man page correctly
+
+ -- Otto Kekäläinen <otto@debian.org>  Sun, 06 Mar 2016 22:20:52 +0200
+
+mariadb-10.0 (10.0.24-2) unstable; urgency=low
+
+  * Make new plugin packages breaks+replaces mariadb-server-10.0 as
+    the files used to reside there (Closes: #815377).
+  * Disable main.delayed that has been confirmed to be a false positive
+    caused by built platform resource limits.
+  * Disable multiple s390x tests that only fail on Ubuntu/Launchpad and
+    cannot be reproduced anywhere else.
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 04 Mar 2016 08:38:25 +0200
+
+mariadb-10.0 (10.0.24-1) unstable; urgency=low
+
+  [ Otto Kekäläinen ]
+  * New upstream release 10.0.24
+    - Drop auth_socket patches as MDEV-8375 was partially fixed upstream
+    - Refresh other patches
+  * New upstream release includes fixes for the following security
+    vulnerabilities:
+    - CVE-2016-0668
+    - CVE-2016-0650
+    - CVE-2016-0649
+    - CVE-2016-0646
+    - CVE-2016-0644
+    - CVE-2016-0641
+    - CVE-2016-0640
+  * Update filenames in d/copyright
+
+  [ Ian Gilfillan ]
+  * Add missing mysql_embedded man page
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Sat, 20 Feb 2016 14:23:50 +0200
+
+mariadb-10.0 (10.0.23-3) unstable; urgency=low
+
+  * Add Lintian overrides for TokuDB sources that indeed need autotools files
+  * Split TokuDB, Mroonga, Spider and Cassandra into their own packages and
+    start using new naming scheme 'mariadb-plugin-xzy' and rename existing
+    Connect and OQGraph packages accordingly (Closes: #773727)
+  * There is no need for mariadb-test packages to contain the version in the
+    package name, so remove it. It only makes sense to keep the version number
+    in the client and server packages, which users actually want to pin to.
+  * Update standards version
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Tue, 26 Jan 2016 11:34:48 +0200
+
+mariadb-10.0 (10.0.23-2) unstable; urgency=low
+
+  * Skip unstable Spider tests on Launchpad s390x builds
+  * Extend install lists with missing files after reviewing the list
+    of files produced by the build process
+  * Update server README.Debian to match current unix socekt authentication
+  * Lintian fixes and more updates to TokuDB plugin copyright paths
+  * Move mysql_upgrade to server core package so that Akonadi and similar
+    core package consumers can upgrade the database. Also update control file
+    with breaks/replaces to allow smooth upgrades (Closes: #793977).
+  * Update slow_query_log_file configuration syntax to match upstream's. Also
+    fixes #677222 in MariaDB packages.
+  * Rename and install Apport hook correctly
+  * Remove Taocrypt workaround fixed upstream long since #627208
+  * Removed CFLAGS and CXXFLAGS as suggested by Lars Tangvald and also done
+    in mysql-5.6 packaging commit id 16a64e810e28f1d0b66ede274cd4c2b1a425fecb
+  * Unmask the systemd mysql.service if left behind by a mysql-server-5.6
+    installation, otherwise the MariaDB service would remain masked too.
+  * Add gdb to build-deps as suggested in #627208 to get automatic stack traces
+  * Updated Turkish translation by Atila KOÇ (Closes: #811414)
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Sat, 23 Jan 2016 23:07:15 +0200
+
+mariadb-10.0 (10.0.23-1) unstable; urgency=low
+
+  * New upstream release 10.0.23. Includes fixes for the following
+    security vulnerabilities:
+    - CVE-2016-2047
+    - CVE-2016-0651
+    - CVE-2016-0642
+    - CVE-2016-0616
+    - CVE-2016-0609
+    - CVE-2016-0608
+    - CVE-2016-0606
+    - CVE-2016-0600
+    - CVE-2016-0598
+    - CVE-2016-0597
+    - CVE-2016-0596
+    - CVE-2016-0546
+    - CVE-2016-0505
+  * Ignore test suite exit code on unstable platforms (mips, mipsel)
+  * Update TokuDB plugin install and copyright paths to match latest
+    release done under Percona ownership
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Sun, 20 Dec 2015 14:18:33 +0200
+
+mariadb-10.0 (10.0.22-6) unstable; urgency=low
+
+  * Add patches to make passwordless root login default on all new
+    installs in all situations. Make auth_socket a built-in plugin.
+  * Clean up previous passwordless root implementation so that it
+    applies only to new installs and existing databases continue
+    to operate with the passwords defined in their user tables
+  * As disabled.def intrepreted test names in a special way, switch
+    back to using --skip-test-list option
+  * Make the watch file to make it better suited for the
+    git-buildpackage workflow and remove call to uupdate
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Sat, 19 Dec 2015 22:28:23 +0200
+
+mariadb-10.0 (10.0.22-5) unstable; urgency=low
+
+  * Fix non-working path of unstable-test in d/rules
+  * Add unstable test for amd64 to fix reproducible builds
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Thu, 17 Dec 2015 13:31:56 +0200
+
+mariadb-10.0 (10.0.22-4) unstable; urgency=low
+
+  * Upload to unstable
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Mon, 14 Dec 2015 00:49:14 +0200
+
+mariadb-10.0 (10.0.22-4~exp1) experimental; urgency=low
+
+  * Rewrite unstable tests section in d/rules that was not working
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Sun, 13 Dec 2015 21:36:48 +0200
+
+mariadb-10.0 (10.0.22-3) unstable; urgency=low
+
+  * Fix typo in d/rules
+  * Extend list of unstable tests for arch mips, mipsel64 and alpha
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 11 Dec 2015 21:57:23 +0200
+
+mariadb-10.0 (10.0.22-2) unstable; urgency=low
+
+  * Escape d/rules file correctly to avoid parse error.
+  * Remove patches/os_sync_Free patch that is not intended for production use.
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 20 Nov 2015 23:11:09 +0200
+
+mariadb-10.0 (10.0.22-2~exp2) experimental; urgency=low
+
+  [ Alexander Barkov ]
+  * Backport patch from upstream to fix MDEV-9091: mysqld crashes on shutdown
+    after running TokuDB tests on Ubuntu
+  * Backport patch from upstream to fix MDEV-8692: prefschema test failures
+
+  [ Otto Kekäläinen ]
+  * Replace old 'make test' structure with direct call on mysql-test-run and
+    parallelize the test suite run in the Debian build.
+  * Print in build log env info to help debug builds on different platforms.
+  * Keep a list of unstable tests that are to be skipped on official builds.
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 13 Nov 2015 22:08:49 +0200
+
+mariadb-10.0 (10.0.22-2~exp1) experimental; urgency=low
+
+  * Add diagnostics to find out the problem in os_sync_free()
+  * Backport fix for TokuDB crashes in build tests on Launchpad
+    and enable TokuDB builds
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 13 Nov 2015 08:54:05 +0200
+
+mariadb-10.0 (10.0.22-1) unstable; urgency=low
+
+  [ Otto Kekäläinen ]
+  * New upstream release. Includes fixes for the following security
+    vulnerabilities (Closes: #802874):
+    - CVE-2016-0610
+    - CVE-2016-3471
+    - CVE-2015-7744
+    - CVE-2015-4802
+    - CVE-2015-4807
+    - CVE-2015-4815
+    - CVE-2015-4826
+    - CVE-2015-4830
+    - CVE-2015-4836
+    - CVE-2015-4858
+    - CVE-2015-4861
+    - CVE-2015-4870
+    - CVE-2015-4913
+    - CVE-2015-4792
+  * New release includes updated man pages (Closes: #779992)
+  * Update the most recent patches with proper DEP-3 compliant headers
+  * Add CVE IDs to previous changelog entries
+
+  [ Jean Weisbuch ]
+  * Update mysqlreport to version 4.0
+
+  [ Otto Kekäläinen ]
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 30 Oct 2015 11:42:30 +0200
+
+mariadb-10.0 (10.0.21-3) unstable; urgency=low
+
+  * Updated Brazilian Portuguese translation (Closes: #798048)
+  * Upload 10.0.21 and all changes tested initially in experimental
+    to unstable. Now sensible as mysql-5.6 has entered testing.
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 18 Sep 2015 23:04:53 +0300
+
+mariadb-10.0 (10.0.21-2) experimental; urgency=low
+
+  * Update gdb.conf to have tags signed by default
+  * Add CVE IDs to previous changelog entries
+  * Pass DEB_BUILD_ARCH to CMake options to enhance buils on some platforms
+  * Test suite failures are now fatal on all platforms and not ignored anywhere
+  * Revert most of commit 579282f and re-enable Mroonga
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Wed, 26 Aug 2015 18:20:54 +0300
+
+mariadb-10.0 (10.0.21-1) experimental; urgency=low
+
+  [ Otto Kekäläinen ]
+  * Created libmariadbd18 and moved .so file from libmariadbd-dev there
+  * Reproducible build improvement: Add LC_ALL=C to mysql.sym sort command
+  * New upstream release.
+    - Upstream added skip_log_error to mysqld_safe config (Closes: #781945)
+    - Diffie-Helman modulus increased to 2048-bits (Closes: #788905)
+  * New upstream release fixes the following security vulnerabilities:
+    - CVE-2015-4816
+    - CVE-2015-4819
+    - CVE-2015-4879
+    - CVE-2015-4895
+  * Split mariadb-test-data-10.0 out of the main test package. This will save
+    disk space in Debian archives as the arch independent data files are
+    in one single package that can be used on all platforms and the package
+    that is built on multiple platform shrinks significantly.
+
+  [ Jean Weisbuch ]
+  * The MYCHECK_RCPT variable can now be set from the default file.
+  * The check_for_crashed_tables() function on the debian-start script has been
+    fixed to be able to log (and email) the errors it encountered : Errors are
+    sent to stderr by the CLI while only stdout was captured by the function.
+  * The same function now also checks Aria tables along with MyISAM ones.
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Thu, 13 Aug 2015 10:08:38 +0200
+
+mariadb-10.0 (10.0.20-3) unstable; urgency=medium
+
+  [ Andreas Beckmann ]
+  * mariadb-common: Depend on a version of mysql-common that ships
+    /usr/share/mysql-common/configure-symlinks.  (Closes: #787533)
+  * mariadb-common.postinst: Drop fallback my.cnf symlink management.
+  * mariadb-common.preinst: Clean up my.cnf/my.cnf.old from the fallback.
+
+  [ Otto Kekäläinen ]
+  * Clean up old cruft from rules file after review by Sergei Golubchik
+  * Unified config file layout with upstream .cnf layout
+  * Recover mysql-upgrade dir/link handlig wrongly removed in f7caa041db
+  * Minor Lintian and documentation fixes
+  * Switch 'nm -n' to 'nm --defined-only' to improve reproducible builds
+
+  [ Olaf van der Spek ]
+  * Minor spell checking (Closes: #792123)
+
+  [ Israel Tsadok ]
+  * Fix mariadb-server-10.0.preinst script that failed to save a new
+    /var/lib/mysql-upgrade/DATADIR.link if a previous DATADIR.link existed and
+    the /var/lib/mysql directory was a symbolic link with an absolute path
+    as target (Closes: #792918)
+
+  [ Jean Weisbuch ]
+  * Added a Debian default file for the mariadb-server-10.0 package which allows
+    one to set the MYSQLD_STARTUP_TIMEOUT variable used in the init script
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 24 Jul 2015 23:00:00 +0300
+
+mariadb-10.0 (10.0.20-2) unstable; urgency=low
+
+  * Fix bash test logic in postinstall (Closes: #789589)
+  * Add extra sort in d/rules mysqld.sym.gz command to satisfy Debian
+    reproducible build requirements
+  * Switch to utf8mb4 as default character set
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 03 Jul 2015 17:11:01 +0300
+
+mariadb-10.0 (10.0.20-1) unstable; urgency=low
+
+  * New upstream release. Includes fixes for the following security
+    vulnerabilities:
+    - CVE-2015-2582
+    - CVE-2015-2620
+    - CVE-2015-2643
+    - CVE-2015-2648
+    - CVE-2015-3152: Client command line option --ssl-verify-server-cert (and
+      MYSQL_OPT_SSL_VERIFY_SERVER_CERT option of the client API) when used
+      together with --ssl will ensure that the established connection is
+      SSL-encrypted and the MariaDB server has a valid certificate.
+    - CVE-2015-4752
+    - CVE-2015-4864
+  * New release includes fix for memory corruption on arm64 (Closes: #787221)
+  * Added patch to enhance build reproducibility regarding the file INFO_BIN
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 19 Jun 2015 13:01:56 +0300
+
+mariadb-10.0 (10.0.19-1) unstable; urgency=low
+
+  * New upstream release. Fixed the server crash caused by mysql_upgrade
+    (MDEV-8115).
+  * Upload to unstable from master branch as Jessie is not released.
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Sat, 09 May 2015 22:24:03 +0300
+
+mariadb-10.0 (10.0.18-1~exp1) experimental; urgency=low
+
+  * New upstream release. Includes fixes for the following security
+    vulnerabilities:
+    - CVE-2015-4866
+    - CVE-2014-8964 bundled PCRE contained heap-based buffer overflow
+      vulnerability that allowed the server to crash or have other unspecified
+      impact via a crafted regular expression made possible with the
+      REGEXP_SUBSTR function (MDEV-8006).
+    - CVE-2015-0501
+    - CVE-2015-2571
+    - CVE-2015-0505
+    - CVE-2015-0499
+    - CVE-2015-4757
+    - CVE-2015-4866
+  * Cleanup in d/copyright
+  * Make the mariadb-common depends versioned to guarantee that latest
+    config files are installed
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Thu, 07 May 2015 23:21:20 +0300
+
+mariadb-10.0 (10.0.17-1~exp2) experimental; urgency=low
+
+  * d/control: Related to innochecksum manpage move, also break/replace
+    the mysql-client-5.5/6 packages (Closes: #779873)
+  * Add automatic fallback to the new /etc/mysql/my.cnf management scheme
+    for cases where mysql-common/configure-symlinks is not yet available
+    and users complain the installation ends up broken.
+  * New release confirmed to build with GCC-5 (Closes: #777996)
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 06 Mar 2015 16:42:21 +0200
+
+mariadb-10.0 (10.0.17-1~exp1) experimental; urgency=low
+
+  [ Jan Wagner ]
+  * Adding mysqld_multi.server_lsb-header.patch, provides LSB headers for
+    example initscript (Closes: #778762)
+  * Adding mysqld_multi_confd.patch, makes mysqld_multi reading conf.d
+    (Closes: #778761)
+
+  [ Robie Basak ]
+  * Move innochecksum back to mariadb-server-core-10.0 to align with other
+    variants (LP: #1421520).
+  * Fix typo in mariadb-server-10.0.postinst.
+  * Fix typo in postinst mktemp call (LP: #1420831).
+
+  [ Arnaud Fontaine ]
+  * d/control: innochecksum manpage has been moved to mariadb-client-10.0 in
+    10.0.13-1 (ba97056), thus add Breaks/Replaces in mariadb-client-10.0
+    against mariadb-server-10.0 << 10.0.13-1~.
+
+  [ Otto Kekäläinen ]
+  * Follow to new /etc/mysql/my.cnf management scheme
+  * Remove the my.cnf move command as it increases complexity too much and might
+    emit an error code if mariadb-common is upgraded before mysql-common is.
+  * Add patch to enhance build reproducibility
+  * Remove /var/log/mysql.log from logrotate. Everything should be inside
+    the mysql directory (/var/log/mysql/) and not directly on plain /var/log
+  * New upstream release. Includes fixes for the following security
+    vulnerabilities (changelog updated post release):
+    - CVE-2015-2568
+    - CVE-2015-2573
+    - CVE-2015-0433
+    - CVE-2015-0441
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Mon, 02 Mar 2015 20:01:13 +0200
+
+mariadb-10.0 (10.0.16-1~exp3) experimental; urgency=low
+
+  * Update the mail.ssl test to match new cacert.pem
+  * Stop asking and setting a database root user password. Instead enable
+    the auth_socket plugin and let unix user root access MariaDB without
+    a separate password. Admins using sudo or cron scripts can use the
+    same access too, and there is no debian-sys-maint password either anymore.
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 30 Jan 2015 18:52:55 +0200
+
+mariadb-10.0 (10.0.16-1~exp2) experimental; urgency=low
+
+  * Fix typo in preinstall script (Closes: #776494).
+  * Backported new cacert.pem etc from 5.5 the replace the expired ones.
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Wed, 28 Jan 2015 20:57:23 +0200
+
+mariadb-10.0 (10.0.16-1~exp1) experimental; urgency=low
+
+  * New upstream release. Includes fixes for the following security
+    vulnerabilities:
+    - CVE-2015-0411
+    - CVE-2015-0382
+    - CVE-2015-0381
+    - CVE-2015-0432
+    - CVE-2014-6568
+    - CVE-2015-0374
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Tue, 27 Jan 2015 17:04:21 +0200
+
+mariadb-10.0 (10.0.15-2~exp1) experimental; urgency=low
+
+  * Fix mariadb-server-10.0.postinst so that the flag removal will not emit
+    an error code if there are no previous debian-*.flag files. This will
+    fix a dpkg issue caught by piuparts testing.
+  * Increase the debconf downgrade warning dialog priority to critical to make
+    sure all users see it and understand why their system broke after downgrade.
+  * Attempt to fix FTBFS on mips, mipsel, powerpc introduced by upstream
+    release 10.0.15 (Closes: #772964).
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Fri, 12 Dec 2014 14:07:50 +0200
+
+mariadb-10.0 (10.0.15-1) unstable; urgency=low
+
+  [ Arnaud Fontaine ]
+  * Bump libpcre3-dev Build-Depends to >= 2:8.35-3.2~ (Closes: #767903).
+
+  [ Otto Kekäläinen }
+  * New upstream release, includes fixes for the following security issues:
+    - CVE-2014-6507
+    - CVE-2014-6491
+    - CVE-2014-6500
+    - CVE-2014-6469
+    - CVE-2014-6555
+    - CVE-2014-6559
+    - CVE-2014-6494
+    - CVE-2014-6496
+    - CVE-2014-6464
+  * Disable on non-amd64 platforms the new Mroonga storage engine which
+    was introduced in the new upstream release.
+  * Allow mariadb-server-10.0 to overwrite file man1/mysql_plugin.1.gz in
+    mysql-client-5.5 with breaks and replaces (Closes: #771213).
+  * Clean up old debian-*.flag files from datadir to avoid unexpected
+    behavior at later upgrades (Closes: #770177).
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Tue, 25 Nov 2014 21:45:43 +0200
+
+mariadb-10.0 (10.0.14-4) unstable; urgency=low
+
+  * Updated patch d/username-in-tests-replace.patch to fix the
+    obfuscation done by anti-spam measures in the MariaDB
+    commit message view (Closes: #769865).
+  * Unified indentantion to two spaces in init file for easier
+    debugging of #609537
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Mon, 17 Nov 2014 11:45:11 +0200
+
+mariadb-10.0 (10.0.14-3) unstable; urgency=low
+
+  * Added patch d/username-in-tests-replace.patch to fix
+    test failure (Closes: #769212).
+  * Added versioned dependency on libpcre3 (Closes: #767903).
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Wed, 12 Nov 2014 15:00:11 +0300
+
+mariadb-10.0 (10.0.14-2) unstable; urgency=low
+
+  [ Tobias Frost ]
+  * Fix two lintian warnings in d/copyright (missing "-" between GPL and 2)
+  * Always be verbose when building the package and show compiler args
+
+  [ Otto Kekäläinen ]
+  * Upload to unstable
+  * Updated German translation by Chris Leick and Holger Wansing
+    (Closes: #763952)
+  * Updated Dutch translation by Frans Spiesschaert (Closes: #764013)
+  * Removed libssl-dev from build dependencies in favour of using
+    bundled YaSSL instead (Closes: #761911)
+  * Fixed debconf value saving (Closes: #761452)
+  * Re-enabled TokuDB after backporting upstream fix in MDEV-6815
+  * Removed libmariadbclient packages that provided the Debian-only
+    libmariadbclient.so library that nobody used. Instead developers are
+    encouraged to use the libraries from the package libmariadb-client-lgpl
+    instead (Closes: #739452) (Closes: #742172).
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Sat, 18 Oct 2014 19:00:11 +0300
+
+mariadb-10.0 (10.0.14-1) experimental; urgency=low
+
+  * New upstream release. (Closes: #757026)
+  * d/control: Removed Provides: libmysqlclient-dev (Closes: #759309)
+  * d/control: Removed Provides: libmysqld-dev with same motivation
+  * Updated Swedish translation by Martin Bagge
+    and Anders Jonsson (Closes: #762795)
+  * Updated Spanish translation by Javier Fernandez-Sanguino (Closes: #762751)
+  * Updated Portuguese translation by Miguel Figueiredo (Closes: #763194)
+  * Updated Czech translation by Miroslav Kure (Closes: #763309)
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Thu, 28 Aug 2014 00:39:02 +0300
+
+mariadb-10.0 (10.0.10-1) experimental; urgency=low
+
+  * Initial Upload (Closes: #740473)
+
+ -- Otto Kekäläinen <otto@seravo.fi>  Tue, 01 Apr 2014 09:56:38 +0300
diff --git a/control b/control
new file mode 100644 (file)
index 0000000..c2b5213
--- /dev/null
+++ b/control
@@ -0,0 +1,972 @@
+Source: mariadb
+Section: database
+Priority: optional
+Maintainer: Debian MySQL Maintainers <pkg-mysql-maint@lists.alioth.debian.org>
+Uploaders:
+ Otto Kekäläinen <otto@debian.org>,
+Build-Depends:
+ bison,
+ cmake,
+ cracklib-runtime <!nocheck>,
+ debhelper-compat (= 13),
+ dh-exec,
+ dpkg-dev (>= 1.22.5),
+ gdb <!nocheck>,
+ libboost-dev,
+ libbz2-dev,
+ libcrack2-dev (>= 2.9.0),
+ libcurl4-openssl-dev | libcurl4-dev,
+ libedit-dev,
+ libedit-dev:native,
+ libfmt-dev (>= 10.2.2) | libfmt-dev (<< 10),
+ libjemalloc-dev [linux-any],
+ libjudy-dev,
+ libkrb5-dev,
+ liblz4-dev,
+ liblzma-dev,
+ liblzo2-dev,
+ libncurses-dev,
+ libnuma-dev [linux-any],
+ libpam0g-dev,
+ libpcre2-dev,
+ libpmem-dev [amd64 arm64 ppc64el riscv64],
+ libsnappy-dev,
+ libssl-dev,
+ libssl-dev:native,
+ libsystemd-dev [linux-any],
+ liburing-dev [linux-any],
+ libxml2-dev,
+ libzstd-dev (>= 1.3.3),
+ lsb-release,
+ perl:any,
+ po-debconf,
+ psmisc,
+ unixodbc-dev,
+ uuid-dev,
+ zlib1g-dev (>= 1:1.1.3-5~),
+ zlib1g-dev:native,
+Rules-Requires-Root: no
+Standards-Version: 4.6.2
+Homepage: https://mariadb.org/
+Vcs-Browser: https://salsa.debian.org/mariadb-team/mariadb-server
+Vcs-Git: https://salsa.debian.org/mariadb-team/mariadb-server.git
+
+Package: libmariadb-dev
+Architecture: any
+Section: libdevel
+Depends:
+ libmariadb3 (= ${binary:Version}),
+ libssl-dev,
+ zlib1g-dev,
+ ${misc:Depends},
+ ${shlibs:Depends},
+Breaks:
+ libmariadb-client-lgpl-dev,
+ libmariadb-dev-compat (<< ${source:Version}),
+ libmariadbclient-dev (<< 1:10.3),
+ libmysqlclient-dev,
+ libmysqld-dev (<< ${source:Version}),
+Replaces:
+ libmariadb-client-lgpl-dev,
+ libmariadb-dev-compat (<< ${source:Version}),
+ libmariadbclient-dev (<< 1:10.3),
+ libmysqlclient-dev,
+ libmysqld-dev (<< ${source:Version}),
+Conflicts:
+ libmariadbclient16-dev,
+ libmysqlclient-dev,
+Description: MariaDB database development files
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package includes development libraries and header files. To allow sources
+ expecting the MariaDB Connector/C to build. Sources that expect the MySQL
+ Client libraries should use files from the libmariadb-dev-compat package.
+
+Package: libmariadb-dev-compat
+Architecture: any
+Section: libdevel
+Depends:
+ libmariadb-dev (= ${binary:Version}),
+ ${misc:Depends},
+Conflicts:
+ libmariadb-client-lgpl-dev-compat,
+ libmariadbclient-dev-compat,
+ libmysqlclient-dev,
+Provides:
+ libmariadb-client-lgpl-dev-compat,
+ libmariadbclient-dev-compat,
+Breaks:
+ libmariadb-client-lgpl-dev-compat,
+ libmariadbclient-dev (<< 1:10.3),
+ libmariadbclient-dev-compat,
+ libmysqlclient-dev,
+Replaces:
+ libmariadb-client-lgpl-dev-compat,
+ libmariadbclient-dev (<< 1:10.3),
+ libmariadbclient-dev-compat,
+ libmysqlclient-dev,
+Description: MariaDB Connector/C, compatibility symlinks
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package includes compatibility symlinks to allow sources expecting the
+ MySQL client libraries to be built against MariaDB Connector/C.
+
+Package: libmariadb3
+Architecture: any
+Multi-Arch: same
+Section: libs
+Depends:
+ mariadb-common,
+ ${misc:Depends},
+ ${shlibs:Depends},
+Conflicts:
+ mariadb-galera-server-10.0,
+ mariadb-galera-server-5.5,
+ mariadb-server-10.0,
+ mariadb-server-5.1,
+ mariadb-server-5.2,
+ mariadb-server-5.3,
+ mariadb-server-5.5,
+Breaks:
+ libmariadbclient18,
+Replaces:
+ libmariadbclient18,
+Description: MariaDB database client library
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package includes the client library.
+
+Package: libmariadbd19t64
+Provides:
+ ${t64:Provides},
+Replaces:
+ libmariadbd19,
+Breaks:
+ libmariadbd19 (<< ${source:Version}),
+Architecture: any
+Section: libs
+Depends:
+ ${misc:Depends},
+ ${shlibs:Depends},
+Multi-Arch: same
+Description: MariaDB embedded database, shared library
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package includes a shared library for embedded MariaDB applications.
+
+Package: libmariadbd-dev
+Architecture: any
+Section: libdevel
+Provides:
+ libmysqld-dev,
+Pre-Depends:
+ ${misc:Pre-Depends},
+Depends:
+ libmariadb-dev (= ${binary:Version}),
+ libmariadbd19t64 (= ${binary:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Breaks:
+ libmariadb-dev (<< 1:10.4),
+ libmysqld-dev,
+Replaces:
+ libmariadb-dev (<< 1:10.4),
+ libmysqld-dev,
+Description: MariaDB embedded database, development files
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package includes the MariaDB embedded server library development and
+ header files.
+
+Package: mariadb-common
+Architecture: all
+Depends:
+ mysql-common (>= 5.6.25),
+ ${misc:Depends},
+Multi-Arch: foreign
+Description: MariaDB database common config files (/etc/mysql/mariadb.conf.d/)
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package includes configuration files common to all MariaDB programs.
+
+Package: mariadb-client-core
+Architecture: any
+Depends:
+ libmariadb3 (>= 10.5.4),
+ mariadb-common (>= ${source:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Conflicts:
+ mysql-client-5.5,
+ mysql-client-5.6,
+ mysql-client-5.7,
+ mysql-client-8.0,
+ virtual-mysql-client-core,
+Breaks:
+ mariadb-client-10.0,
+ mariadb-client-core-10.0,
+ mariadb-client-core-10.1,
+ mariadb-client-core-10.2,
+ mariadb-client-core-10.3,
+ mariadb-client-core-10.4,
+ mariadb-client-core-10.5,
+ mariadb-client-core-10.6,
+ mariadb-client-core-5.5,
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+ mariadb-server-core (<< ${source:Version}),
+ mariadb-server-core-10.3,
+ mariadb-server-core-10.4,
+ mariadb-server-core-10.5,
+ mariadb-server-core-10.6,
+ mysql-client-core-5.5,
+ mysql-client-core-5.6,
+ mysql-client-core-5.7,
+ mysql-client-core-8.0,
+ mysql-cluster-community-client-plugins,
+ mysql-server-core-5.5,
+ mysql-server-core-5.6,
+ mysql-server-core-5.7,
+ mysql-server-core-8.0,
+ percona-server-server-5.6,
+ percona-server-server-5.7,
+ percona-server-server-8.0,
+ percona-xtradb-cluster-server-5.6,
+ percona-xtradb-cluster-server-5.7,
+ percona-xtradb-cluster-server-8.0,
+Replaces:
+ mariadb-client-10.0,
+ mariadb-client-core-10.0,
+ mariadb-client-core-10.1,
+ mariadb-client-core-10.2,
+ mariadb-client-core-10.3,
+ mariadb-client-core-10.4,
+ mariadb-client-core-10.5,
+ mariadb-client-core-10.6,
+ mariadb-client-core-5.5,
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+ mariadb-server-core (<< ${source:Version}),
+ mariadb-server-core-10.3,
+ mariadb-server-core-10.4,
+ mariadb-server-core-10.5,
+ mariadb-server-core-10.6,
+ mysql-client-core-5.5,
+ mysql-client-core-5.6,
+ mysql-client-core-5.7,
+ mysql-client-core-8.0,
+ mysql-cluster-community-client-plugins,
+ mysql-server-core-5.5,
+ mysql-server-core-5.6,
+ mysql-server-core-5.7,
+ mysql-server-core-8.0,
+ percona-server-server-5.6,
+ percona-server-server-5.7,
+ percona-server-server-8.0,
+ percona-xtradb-cluster-server-5.6,
+ percona-xtradb-cluster-server-5.7,
+ percona-xtradb-cluster-server-8.0,
+ virtual-mysql-client-core,
+Provides:
+ virtual-mysql-client-core,
+Description: MariaDB database core client binaries
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package includes the core client files, as used by Akonadi.
+
+Package: mariadb-client
+Architecture: any
+Depends:
+ debianutils (>=1.6),
+ libconfig-inifiles-perl,
+ mariadb-client-core (>= ${source:Version}),
+ ${misc:Depends},
+ ${perl:Depends},
+ ${shlibs:Depends},
+Conflicts:
+ mysql-client-core-5.5,
+ mysql-client-core-5.6,
+ mysql-client-core-5.7,
+ mysql-client-core-8.0,
+ mytop,
+ virtual-mysql-client,
+Breaks:
+ mariadb-client-10.0,
+ mariadb-client-10.1,
+ mariadb-client-10.2,
+ mariadb-client-10.3,
+ mariadb-client-10.4,
+ mariadb-client-10.5,
+ mariadb-client-10.6,
+ mariadb-client-5.5,
+ mariadb-client-core (<< ${source:Version}),
+ mariadb-client-core-10.0,
+ mariadb-client-core-10.1,
+ mariadb-client-core-10.2,
+ mariadb-client-core-10.3,
+ mariadb-client-core-10.4,
+ mariadb-client-core-10.5,
+ mariadb-client-core-10.6,
+ mariadb-server (<< ${source:Version}),
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+ mariadb-server-10.2,
+ mariadb-server-10.3,
+ mariadb-server-10.4,
+ mariadb-server-10.5 (<< 1:10.11),
+ mariadb-server-10.6,
+ mysql-client-5.5,
+ mysql-client-5.6,
+ mysql-client-5.7,
+ mysql-client-8.0,
+ mysql-server-5.5,
+ mysql-server-5.7,
+ mysql-server-core-8.0,
+ percona-server-server-5.6,
+ percona-xtradb-cluster-server-5.6,
+ percona-xtradb-cluster-server-5.7,
+Replaces:
+ mariadb-client-10.0,
+ mariadb-client-10.1,
+ mariadb-client-10.2,
+ mariadb-client-10.3,
+ mariadb-client-10.4,
+ mariadb-client-10.5,
+ mariadb-client-10.6,
+ mariadb-client-5.5,
+ mariadb-client-core (<< ${source:Version}),
+ mariadb-client-core-10.0,
+ mariadb-client-core-10.1,
+ mariadb-client-core-10.2,
+ mariadb-client-core-10.3,
+ mariadb-client-core-10.4,
+ mariadb-client-core-10.5,
+ mariadb-client-core-10.6,
+ mariadb-server (<< ${source:Version}),
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+ mariadb-server-10.2,
+ mariadb-server-10.3,
+ mariadb-server-10.4,
+ mariadb-server-10.5 (<< 1:10.11),
+ mariadb-server-10.6,
+ mysql-client-5.5,
+ mysql-client-5.6,
+ mysql-client-5.7,
+ mysql-client-8.0,
+ mysql-server-5.5,
+ mysql-server-5.7,
+ mysql-server-core-8.0,
+ mytop,
+ percona-server-server-5.6,
+ percona-xtradb-cluster-server-5.6,
+ percona-xtradb-cluster-server-5.7,
+ virtual-mysql-client,
+Provides:
+ virtual-mysql-client,
+Recommends:
+ libdbd-mariadb-perl | libdbd-mysql-perl,
+ libdbi-perl,
+ libterm-readkey-perl,
+Description: MariaDB database client binaries
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package includes the client binaries and the additional tools
+ innotop and mariadb-report (mysqlreport).
+
+Package: mariadb-server-core
+Architecture: any
+Depends:
+ mariadb-common (>= ${source:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Conflicts:
+ mariadb-galera-server-5.5,
+ mysql-server-5.5,
+ mysql-server-5.6,
+ mysql-server-5.7,
+ mysql-server-8.0,
+ virtual-mysql-server-core,
+Breaks:
+ mariadb-client-10.1,
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+ mariadb-server-10.2,
+ mariadb-server-10.3,
+ mariadb-server-10.4,
+ mariadb-server-10.5 (<< 1:10.11),
+ mariadb-server-core-10.0,
+ mariadb-server-core-10.1,
+ mariadb-server-core-10.2,
+ mariadb-server-core-10.3,
+ mariadb-server-core-10.4,
+ mariadb-server-core-10.5,
+ mariadb-server-core-10.6,
+ mariadb-server-core-5.5,
+ mysql-client-5.5,
+ mysql-client-5.6,
+ mysql-server-core-5.5,
+ mysql-server-core-5.6,
+ mysql-server-core-5.7,
+ mysql-server-core-8.0,
+ percona-server-server-5.6,
+ percona-xtradb-cluster-server-5.6,
+ percona-xtradb-cluster-server-5.7,
+Replaces:
+ mariadb-client-10.1,
+ mariadb-server (<< ${source:Version}),
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+ mariadb-server-10.2,
+ mariadb-server-10.3,
+ mariadb-server-10.4,
+ mariadb-server-10.5 (<< 1:10.11),
+ mariadb-server-10.6,
+ mariadb-server-core-10.0,
+ mariadb-server-core-10.1,
+ mariadb-server-core-10.2,
+ mariadb-server-core-10.3,
+ mariadb-server-core-10.4,
+ mariadb-server-core-10.5,
+ mariadb-server-core-10.6,
+ mariadb-server-core-5.5,
+ mysql-client-5.5,
+ mysql-client-5.6,
+ mysql-client-5.7,
+ mysql-client-8.0,
+ mysql-server-core-5.5,
+ mysql-server-core-5.6,
+ mysql-server-core-5.7,
+ mysql-server-core-8.0,
+ percona-server-server-5.6,
+ percona-xtradb-cluster-server-5.6,
+ percona-xtradb-cluster-server-5.7,
+ virtual-mysql-server-core,
+Provides:
+ virtual-mysql-server-core,
+Description: MariaDB database core server files
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package includes the core server files, as used by Akonadi.
+
+Package: mariadb-server
+Architecture: any
+Suggests:
+ mailx,
+ mariadb-test,
+ netcat-openbsd,
+Recommends:
+ libhtml-template-perl,
+ mariadb-plugin-provider-bzip2,
+ mariadb-plugin-provider-lz4,
+ mariadb-plugin-provider-lzma,
+ mariadb-plugin-provider-lzo,
+ mariadb-plugin-provider-snappy,
+ pv,
+Pre-Depends:
+ adduser (>= 3.40),
+ debconf,
+ mariadb-common (>= ${source:Version}),
+ ${misc:Pre-Depends},
+Depends:
+ galera-4 (>= 26.4),
+ gawk,
+ iproute2 [linux-any],
+ libdbi-perl,
+ lsof [linux-any],
+ mariadb-client (>= ${source:Version}),
+ mariadb-server-core (>= ${server:Version}),
+ passwd,
+ perl (>= 5.6),
+ procps,
+ psmisc,
+ rsync,
+ socat,
+ ${misc:Depends},
+ ${shlibs:Depends},
+Conflicts:
+ handlersocket-mysql-5.5,
+ mariadb-tokudb-engine-10.0,
+ mariadb-tokudb-engine-10.1,
+ mariadb-tokudb-engine-5.5,
+ mysql-server-core-5.5,
+ mysql-server-core-5.6,
+ mysql-server-core-5.7,
+ mysql-server-core-8.0,
+ percona-server-server-5.6,
+ percona-xtradb-cluster-server-5.6,
+ percona-xtradb-cluster-server-5.7,
+ virtual-mysql-server,
+Breaks:
+ cqrlog (<< 1.9.0-5~),
+ galera-3 (<< 26.4),
+ handlersocket-mysql-5.5,
+ mariadb-galera-server,
+ mariadb-galera-server-10.0,
+ mariadb-galera-server-5.5,
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+ mariadb-server-10.2,
+ mariadb-server-10.3,
+ mariadb-server-10.4,
+ mariadb-server-10.5 (<< 1:10.11),
+ mariadb-server-10.6,
+ mariadb-server-5.5,
+ mariadb-tokudb-engine-10.0,
+ mariadb-tokudb-engine-10.1,
+ mariadb-tokudb-engine-5.5,
+ mysql-client-5.5,
+ mysql-client-5.7,
+ mysql-client-core-8.0,
+ mysql-server-5.5,
+ mysql-server-5.6,
+ mysql-server-5.7,
+ mysql-server-8.0,
+Replaces:
+ handlersocket-mysql-5.5,
+ mariadb-galera-server,
+ mariadb-galera-server-10.0,
+ mariadb-galera-server-5.5,
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+ mariadb-server-10.2,
+ mariadb-server-10.3,
+ mariadb-server-10.4,
+ mariadb-server-10.5 (<< 1:10.11),
+ mariadb-server-10.6,
+ mariadb-server-5.5,
+ mariadb-tokudb-engine-10.0,
+ mariadb-tokudb-engine-10.1,
+ mariadb-tokudb-engine-5.5,
+ mysql-client-5.5,
+ mysql-client-5.7,
+ mysql-client-core-8.0,
+ mysql-server-5.5,
+ mysql-server-5.6,
+ mysql-server-5.7,
+ mysql-server-8.0,
+ percona-server-server-5.6,
+ percona-xtradb-cluster-server-5.6,
+ percona-xtradb-cluster-server-5.7,
+ virtual-mysql-server,
+Provides:
+ virtual-mysql-server,
+Description: MariaDB database server binaries
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package includes the server binaries.
+
+Package: mariadb-server-10.5
+Architecture: any
+Depends:
+ mariadb-server (>= 1:10.11),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: MariaDB database server binaries (transitional dummy package)
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package is a transitional dummy package designed to make upgrades
+ from previous MariaDB versions seamless.
+
+Package: mariadb-backup
+Architecture: any
+Breaks:
+ mariadb-backup-10.1,
+ mariadb-backup-10.2,
+ mariadb-backup-10.3,
+ mariadb-client-10.1,
+Replaces:
+ mariadb-backup-10.1,
+ mariadb-backup-10.2,
+ mariadb-backup-10.3,
+ mariadb-client-10.1,
+Depends:
+ mariadb-client-core (= ${binary:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: Backup tool for MariaDB server
+ Based on Xtrabackup, but improved to work with MariaDB server.
+ This backup tool is guaranteed to be compatible with MariaDB server.
+ .
+ Please refer to the MariaDB Knowledge Base on more information on
+ how to use this tool.
+
+Package: mariadb-plugin-connect
+Architecture: any
+Depends:
+ libxml2,
+ mariadb-server (= ${server:Version}),
+ unixodbc,
+ ${misc:Depends},
+ ${shlibs:Depends},
+Recommends:
+ curl,
+Conflicts:
+ mariadb-connect-engine-10.0,
+ mariadb-connect-engine-10.1,
+Breaks:
+ mariadb-connect-engine-10.0,
+ mariadb-connect-engine-10.1,
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+Replaces:
+ mariadb-connect-engine-10.0,
+ mariadb-connect-engine-10.1,
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+Description: Connect storage engine for MariaDB server
+ Connect engine supports a number of file formats (dbf, xml, txt, bin, etc),
+ connections to ODBC tables and remote MySQL tables, as well as a number of
+ other interesting features.
+ This package contains the Connect plugin for MariaDB server.
+
+Package: mariadb-plugin-s3
+Architecture: any
+Depends:
+ mariadb-server (= ${server:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: Amazon S3 archival storage engine for MariaDB
+ The S3 storage engine allows one to archive MariaDB tables in Amazon S3 (or any
+ third-party public or private cloud that implements S3 API), but still have
+ them accessible in MariaDB in read-only mode.
+
+Package: mariadb-plugin-rocksdb
+Architecture: amd64 arm64 mips64el ppc64el riscv64
+Depends:
+ mariadb-server (= ${server:Version}),
+ python3:any,
+ rocksdb-tools,
+ ${misc:Depends},
+ ${shlibs:Depends},
+Breaks:
+ mariadb-rocksdb-engine-10.2,
+ mariadb-rocksdb-engine-10.3,
+Replaces:
+ mariadb-rocksdb-engine-10.2,
+ mariadb-rocksdb-engine-10.3,
+Recommends:
+ python3-mysqldb,
+Description: RocksDB storage engine for MariaDB server
+ The RocksDB storage engine is a high performance storage engine, aimed
+ at maximising storage efficiency while maintaining InnoDB-like performance.
+ This package contains the RocksDB plugin for MariaDB server.
+
+Package: mariadb-plugin-oqgraph
+Architecture: any
+Depends:
+ libjudydebian1,
+ mariadb-server (= ${server:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Conflicts:
+ mariadb-oqgraph-engine-10.0,
+ mariadb-oqgraph-engine-10.1,
+Breaks:
+ mariadb-oqgraph-engine-10.0,
+ mariadb-oqgraph-engine-10.1,
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+Replaces:
+ mariadb-oqgraph-engine-10.0,
+ mariadb-oqgraph-engine-10.1,
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+Description: OQGraph storage engine for MariaDB server
+ The OQGraph engine is a computation engine plugin for handling hierarchies
+ (trees) and graphs (friend-of-a-friend, etc) cleanly through standard SQL.
+ This package contains the OQGraph plugin for MariaDB server.
+
+Package: mariadb-plugin-mroonga
+Architecture: any-alpha any-amd64 any-arm any-arm64 any-i386 any-ia64 any-mips64el any-mips64r6el any-mipsel any-mipsr6el any-nios2 any-powerpcel any-ppc64el any-sh3 any-sh4
+Depends:
+ mariadb-server (= ${server:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Breaks:
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+Replaces:
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+Description: Mroonga storage engine for MariaDB server
+ Mroonga (formerly named Groonga Storage Engine) is a storage engine that
+ provides fast CJK-ready full text searching using column store.
+ This package contains the Mroonga plugin for MariaDB server.
+
+Package: mariadb-plugin-spider
+Architecture: any
+Depends:
+ mariadb-server (= ${server:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Breaks:
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+Replaces:
+ mariadb-server-10.0,
+ mariadb-server-10.1,
+Description: Spider storage engine for MariaDB server
+ The Spider storage engine with built-in sharding features. It supports
+ partitioning and xa transactions, and allows tables of different MariaDB server
+ instances to be handled as if they were on the same instance. It refers to one
+ possible implementation of ISO/IEC 9075-9:2008 SQL/MED.
+
+Package: mariadb-plugin-gssapi-server
+Architecture: any
+Depends:
+ libgssapi-krb5-2,
+ mariadb-server,
+ ${misc:Depends},
+ ${shlibs:Depends},
+Breaks:
+ mariadb-gssapi-server-10.1,
+ mariadb-gssapi-server-10.2,
+Replaces:
+ mariadb-gssapi-server-10.1,
+ mariadb-gssapi-server-10.2,
+Description: GSSAPI authentication plugin for MariaDB server
+ This plugin includes support for Kerberos on Unix, but can also be used for
+ Windows authentication with or without domain environment.
+ .
+ This package contains the server parts.
+
+Package: mariadb-plugin-gssapi-client
+Architecture: any
+Depends:
+ libgssapi-krb5-2,
+ mariadb-client (= ${binary:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Breaks:
+ mariadb-gssapi-client-10.1,
+ mariadb-gssapi-client-10.2,
+Replaces:
+ mariadb-gssapi-client-10.1,
+ mariadb-gssapi-client-10.2,
+Description: GSSAPI authentication plugin for MariaDB client
+ This plugin includes support for Kerberos on Unix, but can also be used for
+ Windows authentication with or without domain environment.
+ .
+ This package contains the client parts.
+
+Package: mariadb-plugin-cracklib-password-check
+Architecture: any
+Depends:
+ libcrack2 (>= 2.9.0),
+ mariadb-server (= ${server:Version}),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: CrackLib Password Validation Plugin for MariaDB server
+ This password validation plugin uses cracklib to allow only
+ sufficiently secure (as defined by cracklib) user passwords in MariaDB server.
+ .
+ Install and configure this to enforce stronger passwords for MariaDB server
+ users.
+
+Package: mariadb-plugin-hashicorp-key-management
+Architecture: any
+Depends:
+ mariadb-server,
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: Hashicorp Key Management plugin for MariaDB
+ This encryption plugin uses Hashicorp Vault for storing encryption
+ keys for MariaDB Data-at-Rest encryption.
+
+Package: mariadb-plugin-provider-bzip2
+Architecture: any
+Depends:
+ mariadb-server (>= 1:10.11.1-1),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: BZip2 compression support in the server and storage engines
+ The various MariaDB storage engines, such as InnoDB, RocksDB, Mroonga,
+ can use different compression libraries.
+ .
+ Plugin provides BZip2 (https://sourceware.org/bzip2/) compression
+ .
+ Note that these affect InnoDB and Mroonga only;
+ RocksDB still uses the compression algorithms from its own library
+
+Package: mariadb-plugin-provider-lz4
+Architecture: any
+Depends:
+ mariadb-server (>= 1:10.11.1-1),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: LZ4 compression support in the server and storage engines
+ The various MariaDB storage engines, such as InnoDB, RocksDB, Mroonga,
+ can use different compression libraries.
+ .
+ Plugin provides LZ4 (http://lz4.github.io/lz4/) compression
+ .
+ Note that these affect InnoDB and Mroonga only;
+ RocksDB still uses the compression algorithms from its own library
+
+Package: mariadb-plugin-provider-lzma
+Architecture: any
+Depends:
+ mariadb-server (>= 1:10.11.1-1),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: LZMA compression support in the server and storage engines
+ The various MariaDB storage engines, such as InnoDB, RocksDB, Mroonga,
+ can use different compression libraries.
+ .
+ Plugin provides LZMA (https://tukaani.org/lzma/) compression
+ .
+ Note that these affect InnoDB and Mroonga only;
+ RocksDB still uses the compression algorithms from its own library
+
+Package: mariadb-plugin-provider-lzo
+Architecture: any
+Depends:
+ mariadb-server (>= 1:10.11.1-1),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: LZO compression support in the server and storage engines
+ The various MariaDB storage engines, such as InnoDB, RocksDB, Mroonga,
+ can use different compression libraries.
+ .
+ Plugin provides LZO (http://www.oberhumer.com/opensource/lzo/) compression
+ .
+ Note that these affect InnoDB and Mroonga only;
+ RocksDB still uses the compression algorithms from its own library
+
+Package: mariadb-plugin-provider-snappy
+Architecture: any
+Depends:
+ mariadb-server (>= 1:10.11.1-1),
+ ${misc:Depends},
+ ${shlibs:Depends},
+Description: Snappy compression support in the server and storage engines
+ The various MariaDB storage engines, such as InnoDB, RocksDB, Mroonga,
+ can use different compression libraries.
+ .
+ Plugin provides Snappy (https://github.com/google/snappy) compression
+ .
+ Note that these affect InnoDB and Mroonga only;
+ RocksDB still uses the compression algorithms from its own library
+
+Package: mariadb-test
+Architecture: any
+Depends:
+ mariadb-client (= ${binary:Version}),
+ mariadb-server (= ${server:Version}),
+ mariadb-test-data (= ${source:Version}),
+ virtual-mysql-testsuite,
+ ${misc:Depends},
+ ${shlibs:Depends},
+Breaks:
+ mariadb-test-10.0,
+ mariadb-test-10.1,
+ mariadb-test-5.5,
+ mysql-client-5.5,
+ mysql-server-5.5,
+ mysql-server-5.7,
+ mysql-server-core-8.0,
+ mysql-testsuite,
+ mysql-testsuite-5.5,
+ mysql-testsuite-5.6,
+ mysql-testsuite-5.7,
+ mysql-testsuite-8.0,
+ percona-server-server-5.6,
+ percona-xtradb-cluster-server-5.6,
+ percona-xtradb-cluster-server-5.7,
+Replaces:
+ mariadb-test-10.0,
+ mariadb-test-10.1,
+ mariadb-test-5.5,
+ mysql-client-5.5,
+ mysql-server-5.5,
+ mysql-server-5.7,
+ mysql-server-core-8.0,
+ mysql-testsuite,
+ mysql-testsuite-5.5,
+ mysql-testsuite-5.6,
+ mysql-testsuite-5.7,
+ mysql-testsuite-8.0,
+ percona-server-server-5.6,
+ percona-xtradb-cluster-server-5.6,
+ percona-xtradb-cluster-server-5.7,
+ virtual-mysql-testsuite,
+Provides:
+ virtual-mysql-testsuite,
+Suggests:
+ patch,
+Description: MariaDB database regression test suite
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package includes the regression test suite.
+
+Package: mariadb-test-data
+Architecture: all
+Multi-Arch: foreign
+Depends:
+ ${misc:Depends},
+ ${perl:Depends},
+ ${shlibs:Depends},
+Breaks:
+ mariadb-test-10.0,
+ mariadb-test-10.1,
+ mariadb-test-5.5,
+ mariadb-test-data-10.0,
+ mysql-testsuite,
+ mysql-testsuite-5.5,
+ mysql-testsuite-5.6,
+ mysql-testsuite-5.7,
+ mysql-testsuite-8.0,
+Replaces:
+ mariadb-test-10.0,
+ mariadb-test-10.1,
+ mariadb-test-5.5,
+ mariadb-test-data-10.0,
+ mysql-testsuite,
+ mysql-testsuite-5.5,
+ mysql-testsuite-5.6,
+ mysql-testsuite-5.7,
+ mysql-testsuite-8.0,
+Description: MariaDB database regression test suite - data files
+ MariaDB 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 MariaDB are speed, robustness and
+ ease of use.
+ .
+ This package has the architecture independent data files for the test suite.
diff --git a/copyright b/copyright
new file mode 100644 (file)
index 0000000..380cac3
--- /dev/null
+++ b/copyright
@@ -0,0 +1,1040 @@
+Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: MariaDB Server
+Upstream-Contact: https://jira.mariadb.org
+Source: https://github.com/MariaDB/server
+Comment:
+ 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. The file
+ has been rechecked against the source using the development version
+ of license-reconcile, see #686485.
+ .
+ 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
+ <https://www.mysql.com/about/legal/licensing/foss-exception/>.
+ .
+ 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: *
+Copyright:
+ 2000-2016, Oracle and/or its affiliates. All rights reserved.
+ 2008-2013 Monty Program AB
+ 2008-2014 SkySQL Ab
+ 2013-2016 MariaDB Corporation
+ 2012-2016 MariaDB Foundation
+License: GPL-2
+
+Files: debian/*
+Copyright:
+ 1997-1998, Scott Hanson <shanson@debian.org>
+ 1997 Christian Schwarz <schwarz@debian.org>
+ 1999-2007, 2009, Christian Hammers <ch@debian.org>
+ 2000-2001, Christopher C. Chimelis <chris@debian.org>
+ 2001 Matthew Wilcox <willy@debian.org>
+ 2005-2007, Sean Finney <seanius@debian.org>
+ 2006 Adam Conrad <adconrad@0c3.net>
+ 2007-2011, Norbert Tretkowski <norbert@tretkowski.de>
+ 2007-2008, Monty Taylor <mordred@inaugust.com>
+ 2008 Devin Carraway <devin@debian.org>
+ 2008 Steffen Joeris <white@debian.org>
+ 2009 Canonical Ltd
+ 2010 Xavier Oswald <xoswald@debian.org>
+ 2011 Clint Byrum <clint@ubuntu.com>
+ 2011 Ondřej Surý <ondrej@debian.org>
+ 2012 Nicholas Bamber <nicholas@periapt.co.uk>
+ 2013,2016 Kristian Nielsen <knielsen@askmonty.org>
+ 2013-2024 Otto Kekäläinen <otto@debian.org>
+ 2014 Daniel Schepler <schepler@debian.org>
+ 2014 Julien Muchembled <jm@jmuchemb.eu>
+ 2014 Tobias Frost <tobi@coldtobi.de>
+ 2015 Andreas Beckmann <anbe@debian.org>
+ 2015-2016 Arnaud Fontaine <arnau@debian.org>
+ 2015-2016 Daniel Black <daniel.black@openquery.com.au>
+ 2015 Israel Tsadok <itsadok@gmail.com>
+ 2015 Jan Wagner <waja@cyconet.org>
+ 2015 Jean Weisbuch <jean@phpnet.org>
+ 2015 Olaf van der Spek <olafvdspek@gmail.com>
+ 2015-2106 Robie Basak <robie.basak@canonical.com>
+ 2016 Axel Beckert <abe@debian.org>
+ 2016 Dieter Adriaenssens <dieter.adriaenssens@gmail.com>
+ 2016 Ian Gilfillan <ian@mariadb.org>
+ 2016 James Cowgill <jcowgill@debian.org>
+ 2016 Paul Gevers <elbrus@debian.org>
+ 2016 Samuel Thibault <sthibault@debian.org>
+ 2016 Vicențiu Ciorbaru <vicentiu@mariadb.org>
+License: GPL-2+
+
+Files: plugin/feedback/*
+Copyright: 2010 Sergei Golubchik and Monty Program Ab
+License: GPL-2
+
+Files: debian/additions/mariadb-report*
+Copyright: 2006-2008 Daniel Nichter <public@codenode.com>
+ 2012-2015 Jean Weisbuch
+License: GPL-2+
+
+Files:
+ 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
+ mysql-test/*
+ support-files/binary-configure.sh
+ support-files/mysqld_multi.server.sh
+ Docs/*
+Copyright: UNKNOWN
+Comment: These files fall under the blanket license specified in the file
+ COPYING and README
+ 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.
+License: GPL-2
+
+Files: BUILD/*
+ client/*
+ cmake/*
+ dbug/dbug_add_tags.pl
+ extra/*
+ include/*
+ libmysqld/*
+ libservices/*
+ mysql-test/include/have_perfschema.inc
+ mysql-test/lib/mtr_cases.pm
+ mysql-test/lib/mtr_gprof.pl
+ mysql-test/lib/mtr_io.pl
+ mysql-test/lib/mtr_match.pm
+ 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/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/safe_kill_win.cc
+ mysql-test/lib/My/SafeProcess/safe_process.cc
+ 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_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/mysql-test-run.pl
+ mysql-test/lib/v1/mtr_misc.pl
+ mysql-test/mariadb-stress-test.pl
+ mysql-test/mariadb-test-run.pl
+ mysql-test/std_data/*
+ mysql-test/suite/perfschema/include/*
+ mysql-test/suite/perfschema_stress/include/*
+ mysys/*
+ win/packaging/ca/*
+ plugin/audit_null/*
+ plugin/auth_*
+ plugin/daemon_example/*
+ plugin/fulltext/*
+ scripts/*
+ sql/*
+ sql-common/*
+ storage/*
+ strings/*
+ support-files/MacOSX/*
+ support-files/compiler_warnings.supp
+ support-files/mysql.*
+ support-files/dtrace/*
+ tests/*
+ unittest/*
+ vio/*
+Copyright: 1979-2009 MySQL AB
+           1995-2010 Sun Microsystems Inc
+           1994-1997,2000-2014 Oracle and/or its affiliates
+           2010 Kristian Nielsen
+           2012 MariaDB Services
+           2013 MariaDB Foundation
+           2010,2013 Sergei Golubchik
+           1985,1995,2008-2011,2012-2014 Monty Program AB
+           2008-2014 SykSQL Ab
+           1993-2014 Olivier Bertrand
+           2008-2014 Kentoku Shiba
+           2013 Sergey Vojtovich and MariaDB Foundation
+           2006 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+           2012 Michael Widenius
+           2010-2011 DeNA Co.,Ltd.
+           2011 Kentoku SHIBA
+License: GPL-2
+
+Files: include/maria.h include/myisamchk.h
+Copyright: 2006-2008 MySQL AB
+ 2008-2009 Sun Microsystems, Inc
+ 2009, 2013, Monty Program Ab
+License: GPL-2+
+
+Files: plugin/auth_pam/testing/pam_mariadb_mtr.c
+Copyright: none
+License: public-domain
+
+Files:  plugin/locale_info/locale_info.cc
+Copyright: 2013, Spaempresarial - Brazil, Roberto Spadim
+License: BSD-3-clause
+
+Files:  plugin/qc_info/qc_info.cc
+Copyright:  2008, Roland Bouman
+License: BSD-3-clause
+
+Files: tests/async_queries.c tests/nonblock-wrappers.h
+Copyright: 2011 Kristian Nielsen and Monty Program Ab
+License: LGPL-2.1+
+
+Files: include/ma_dyncol.h include/queues.h mysys/ma_dyncol.c mysys/queues.c
+ unittest/mysys/ma_dyncol-t.c
+Copyright: 2010,2011,2013 Monty Program Ab
+ 2011,2012 Oleksandr Byelkin
+License: BSD-2-clause
+
+Files: mysys/my_port.c
+Copyright: 2002 MySQL AB
+License: LGPL-2
+
+Files: mysys/my_safehash.*
+Copyright: 2003-2007 MySQL AB
+License: GPL-2+
+
+Files: strings/bmove_upp.c strings/is_prefix.c strings/llstr.c
+ strings/longlong2str.c strings/strcont.c strings/strfill.c strings/strmov.c
+ strings/strnmov.c strings/bchange.c strings/int2str.c strings/my_strtoll10.c
+ strings/str2int.c strings/strappend.c strings/strcend.c
+Copyright: 2009-2013, Monty Program Ab
+           2000,2003 TXT DataKonsult Ab & Monty Program Ab
+License: BSD-2-clause
+
+Files: strings/strxmov.c
+ strings/strxnmov.c
+ strings/strnlen.c
+Copyright: 2009-2011, Monty Program Ab
+           2000 TXT DataKonsult Ab & Monty Program Ab
+           Richard A. O'Keefe
+License: BSD-2-clause
+
+Files: client/async_example.c
+Copyright: 2011 Kristian Nielsen and Monty Program Ab
+License: LGPL-2.1+
+
+Files: storage/oqgraph/*
+Copyright:
+ 2007-2013 Arjen G Lentz & Antony T Curtis for Open Query
+ 2000-2006 MySQL AB
+License: GPL-2+
+
+Files: storage/connect/connect.cc
+Copyright: 2004-2012 Olivier Bertrand
+License: GPL-2+
+
+Files: storage/oqgraph/ha_oqgraph.*
+ storage/oqgraph/oqgraph_probes.d
+Copyright:
+ 2007-2013 Arjen G Lentz & Antony T Curtis for Open Query
+ 2000-2006 MySQL AB
+License: GPL-2
+
+Files: extra/*/INSTALL
+Copyright: 1994-1996, 1999-2002, 2004-2006, Free Software Foundation, Inc.
+License: unlimited-free-doc
+ This file is free documentation; the Free Software Foundation gives
+ unlimited permission to copy, distribute and modify it.
+
+Files: mysql-test/lib/mtr_misc.pl
+ mysql-test/lib/My/SafeProcess.pm
+Copyright: 2004, 2007, 2011, Oracle and/or its affiliates
+License: LGPL
+
+Files:
+ storage/myisam/ft_update.c
+ storage/myisam/fulltext.h
+ storage/myisam/ft_boolean_search.c
+ storage/myisam/ft_stopwords.c
+ storage/myisam/ft_nlq_search.c
+ storage/myisam/ft_parser.c
+ storage/myisam/myisam_ftdump.c
+Copyright:
+ 2000, 2001, 2010, 2011, Oracle and/or its affiliates
+ Sergei A. Golubchik
+License: GPL-2
+
+Files: storage/myisam/ft_myisam.c
+Copyright: 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+License: GPL-2+
+
+Files: storage/innobase/*
+Copyright:
+ 1994-2011 Sergei A. Golubchik
+ 1996 Michael Widenius
+ 1994-2014 Oracle and/or its affiliates
+ 2008-2009 Google Inc
+ 2009 Sun Microsystems, Inc
+ 2009 Percona Inc
+ 2013, 2014 SkySQL Ab
+ 2012 Facebook Inc
+License: GPL-2
+
+Files: storage/maria/*
+Copyright:
+ 2008-2009 Sun Microsystems, Inc
+ 2008 Sun AB
+ 2006 MySQL Finland AB
+ 2006 TCX DataKonsult AB
+ 2003-2008 MySQL AB
+ 2007-2008 Michael Widenius
+ 2007 Guilhem Bichot
+ 2006 Sergei A. Golubchik
+ 2007 Sanja Belkin
+ 2006 Ramil Kalimullin
+ 2006 Alexey Botchkov
+ 2008-2011 Monty Program Ab
+ 2004-2008 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+License: GPL-2
+
+Files: storage/sphinx/*
+Copyright: 2001-2014 Andrew Aksyonoff
+ 2008-2014 Sphinx Technologies Inc
+License: GPL-2
+
+Files: extra/readline/*
+Copyright: 1987-2006 Free Software Foundation Inc
+License: GPL-2+
+
+Files: sql-bench/*.sh
+Copyright: 2009 Sun Microsystems, Inc
+           2000-2007 MySQL AB
+License: LGPL
+
+Files: client/completion_hash.h
+ scripts/mysqlaccess.sh
+ scripts/mysql_fix_extensions.sh
+ scripts/mysql_setpermission.sh
+ storage/myisam/ftbench/ft-test-run.sh
+ storage/myisam/mi_test_all.sh
+ strings/ctype-uca.c
+ strings/ctype-ucs2.c
+ strings/ctype-utf8.c
+ support-files/MacOSX/postflight.sh
+ support-files/MacOSX/preflight.sh
+ mysql-test/lib/My/ConfigFactory.pm
+ BUILD/*.sh
+ BUILD/compile-solaris-amd64
+ BUILD/compile-amd64-valgrind-max
+ BUILD/compile-pentium64-max
+ BUILD/compile-pentium64
+ scripts/mysqlhotcopy.sh
+ scripts/mysqld_multi.sh
+ mysql-test/std_data/checkDBI_DBD-MariaDB.pl
+Copyright: 2000-2013 Oracle and/or its affiliates
+           2000-2007 MySQL AB
+           2009 Sun Microsystems Inc
+License: LGPL
+
+Files: BUILD/util.sh
+Copyright: 2010 Kristian Nielsen and Monty Program AB
+License: GPL-2
+
+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/myisam/rt_index.h
+ storage/myisam/rt_key.*
+ storage/myisam/rt_mbr.*
+ storage/myisam/sp_defs.h
+Copyright:
+ 2000,2002-2007 MySQL AB
+ Ramil Kalimullin
+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
+
+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
+
+Files: storage/innobase/include/pars0grm.h storage/innobase/pars/pars0grm.cc
+Copyright: 1995-2009 Innobase Oy.
+ 1984,1989-1990,2000-2004 Free Software Foundation Inc.
+License: GPL-2+-with-bison-exception
+ 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, 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.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+ .
+ As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton.  Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+ .
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison.
+
+Files: storage/innobase/fts/fts0pars.cc
+ storage/innobase/include/fts0pars.h
+Copyright: 1984, 1989-1990, 2000-2006  Free Software Foundation, Inc.
+License: GPL-3+-with-bison-exception
+
+License: GPL-3+-with-bison-exception
+ 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 3 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.
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ .
+ As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton.  Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+ .
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison.
+
+
+Files: include/t_ctype.h
+ strings/t_ctype.h
+Copyright: 2000 MySQL AB
+ 1998 Theppitak Karoonboonyanan
+ 1998-1999 Pruet Boonma
+License: GPL-2
+
+Files: strings/strend.c
+Copyright: Richard A. O'Keefe.
+   2000 TXT DataKonsult Ab & Monty Program Ab
+   2009-2011, Monty Program Ab
+License: BSD-2-clause
+
+Files: dbug/dbug.c
+ dbug/dbug_long.h
+Copyright: 1987 Abandoned Fred Fish
+License: public-domain
+
+Files: scripts/dheadgen.pl
+Copyright: 2008-2009 Sun Microsystems Inc
+License: BSD-3-clause
+
+Files: plugin/handler_socket/*
+Copyright:
+ 2010 DeNA Co.,Ltd.
+License: BSD-3-clause
+
+Files: plugin/auth_gssapi/*
+Copyright: 2015 Shuang Qiu
+ 2015 Robbie Harwood
+License: BSD-2-clause
+
+Files: plugin/file_key_management/*
+Copyright: 2002-2012 eperi GmbH
+License: GPL-2
+
+Files: storage/mroonga/*
+Copyright: 2011-2015 Kouhei Sutou <kou@clear-code.com>
+ 2011-2013 Kentoku SHIBA
+ 2010 Tetsuro IKEDA
+ 2014 Kenji Maruyama <mmmaru777@gmail.com>
+ 2014-2015 Naoya Murakami <naoya@createfield.com>
+License: LGPL-2.1+
+
+Files: storage/mroonga/vendor/groonga/vendor/plugins/groonga-normalizer-mysql/*
+Copyright: 2009-2015 Brazil
+License: LGPL-2.1+
+
+Files: storage/spider/*
+Copyright: 2008-2015 Kentoku Shiba
+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-2012 Oracle and/or its affiliates.
+ 1991,2000-2001 Lucent Technologies
+License: LGPL
+
+Files: scripts/mysqldumpslow.sh
+Copyright:
+ 2000-2002,2005-2008 MySQL AB
+ 2008-2009 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
+
+Files: scripts/mysqlaccess.conf
+Copyright: 1997, Yves.Carlier@rug.ac.be
+License: GPL-2
+
+Files: debian/additions/innotop/*
+Copyright: 2006-2009, Baron Schwartz <baron@xaprb.com>
+License: GPL-2 or Artistic
+
+Files: include/mysql_version.h.in
+Copyright: 1996, 1999, 2001 MySQL AB
+License: public-domain
+
+Files: storage/federatedx/*
+Copyright:
+ 2007 Antony T Curtis
+ 2008-2009 Patrick Galbraith
+License: BSD-3-clause
+
+Files: cmake/systemd.cmake
+ scripts/mariadb-service-convert
+Copyright: 2015 Daniel Black
+License: GPL-2
+
+Files: wsrep-lib/*
+ sql/wsrep_*
+ scripts/wsrep_*
+Copyright: 2008-2019 Codership Oy <https://www.codership.com>
+License: GPL-2
+
+Files: libmariadb/*
+Copyright:
+ 2000-2012 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+ 2006-2011 The PHP Group
+ 2012-2013 Monty Program AB
+ 2014-2020 MariaDB Corporation Ab
+ 2014 Kristian Nielsen & MariaDB Corporation
+License: LGPL-2+
+
+Files: libmariadb/libmariadb/mariadb_dyncol.*
+Copyright:
+ 2011-2012 Oleksandr Byelkin
+ 2011-2013 Monty Program Ab
+License: BSD-2-clause
+
+Files: libmariadb/libmariadb/ma_dtoa.*
+Copyright:
+ 1991, 2000-2001, Lucent Technologies
+ 2007, 2012, Oracle and/or its affiliates.
+License: LGPL
+
+Files: libmariadb/unittest/libmariadb/getopt.*
+Copyright:
+ 1989-1994, Free Software Foundation, Inc
+License: LGPL-2+
+
+Files: libmariadb/cmake/FindIconv.cmake
+Copyright:
+ 2010, Michael Bell <michael.bell@web.de>
+License: BSD-2-Clause
+
+Files: storage/archive/azio.c
+ storage/archive/azlib.h
+ zlib/*
+Copyright:
+ 1995-2005 Jean-loup Gailly
+ 1995-2005 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: mysys/CMakeLists.txt
+Copyright: 2006, 2014, Oracle and/or its affiliates
+License: GPL-2
+
+Files: plugin/server_audit/CMakeLists.txt
+Copyright: 2013 Alexey Botchkov and SkySQL Ab
+License: GPL-2
+
+Files: zlib/CMakeLists.txt
+Copyright: 2006, 2014, Oracle and/or its affiliates
+License: GPL-2
+
+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.
+ .
+ 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`
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+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; 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.
+ .
+ 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`
+ .
+ You should have received a copy of the GNU General Public License
+ along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+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: LGPL-2
+ 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: LGPL-2+
+ 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; either
+ version 2 of the License, or (at your option) any later version.
+ .
+ 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 see <https://www.gnu.org/licenses>
+ or write to the Free Software Foundation, Inc.,
+ 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
+ .
+ On Debian systems, the complete text of the GNU Library General Public
+ License version 2 can be found in "/usr/share/common-licenses/LGPL-2".
+
+License: LGPL-2.1+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details.
+ .
+ You should have received a copy of the GNU Lesser General Public License along
+ with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+ .
+ On Debian and systems the full text of the GNU Library General Public
+ License version 2.1 can be found in the file
+ `/usr/share/common-licenses/LGPL-2.1`
+
+License: BSD-2-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 the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+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.
+
+License: Artistic
+ The "Artistic License"
+ .
+ Preamble
+ .
+ The intent of this document is to state the conditions under which a
+ Package may be copied, such that the Copyright Holder maintains some
+ semblance of artistic control over the development of the package,
+ while giving the users of the package the right to use and distribute
+ the Package in a more-or-less customary fashion, plus the right to make
+ reasonable modifications.
+ .
+ Definitions:
+ .
+ "Package" refers to the collection of files distributed by the
+ Copyright Holder, and derivatives of that collection of files
+ created through textual modification.
+ .
+ "Standard Version" refers to such a Package if it has not been
+ modified, or has been modified in accordance with the wishes
+ of the Copyright Holder as specified below.
+ .
+ "Copyright Holder" is whoever is named in the copyright or
+ copyrights for the package.
+ .
+ "You" is you, if you're thinking about copying or distributing
+ this Package.
+ .
+ "Reasonable copying fee" is whatever you can justify on the
+ basis of media cost, duplication charges, time of people involved,
+ and so on.  (You will not be required to justify it to the
+ Copyright Holder, but only to the computing community at large
+ as a market that must bear the fee.)
+ .
+ "Freely Available" means that no fee is charged for the item
+ itself, though there may be fees involved in handling the item.
+ It also means that recipients of the item may redistribute it
+ under the same conditions they received it.
+ .
+ 1. You may make and give away verbatim copies of the source form of the
+ Standard Version of this Package without restriction, provided that you
+ duplicate all of the original copyright notices and associated disclaimers.
+ .
+ 2. You may apply bug fixes, portability fixes and other modifications
+ derived from the Public Domain or from the Copyright Holder.  A Package
+ modified in such a way shall still be considered the Standard Version.
+ .
+ 3. You may otherwise modify your copy of this Package in any way, provided
+ that you insert a prominent notice in each changed file stating how and
+ when you changed that file, and provided that you do at least ONE of the
+ following:
+ .
+     a) place your modifications in the Public Domain or otherwise make them
+     Freely Available, such as by posting said modifications to Usenet or
+     an equivalent medium, or placing the modifications on a major archive
+     site such as uunet.uu.net, or by allowing the Copyright Holder to include
+     your modifications in the Standard Version of the Package.
+ .
+     b) use the modified Package only within your corporation or organization.
+ .
+     c) rename any non-standard executables so the names do not conflict
+     with standard executables, which must also be provided, and provide
+     a separate manual page for each non-standard executable that clearly
+     documents how it differs from the Standard Version.
+ .
+     d) make other distribution arrangements with the Copyright Holder.
+ .
+ 4. You may distribute the programs of this Package in object code or
+ executable form, provided that you do at least ONE of the following:
+ .
+     a) distribute a Standard Version of the executables and library files,
+     together with instructions (in the manual page or equivalent) on where
+     to get the Standard Version.
+ .
+     b) accompany the distribution with the machine-readable source of
+     the Package with your modifications.
+ .
+     c) give non-standard executables non-standard names, and clearly
+     document the differences in manual pages (or equivalent), together
+     with instructions on where to get the Standard Version.
+ .
+     d) make other distribution arrangements with the Copyright Holder.
+ .
+ 5. You may charge a reasonable copying fee for any distribution of this
+ Package.  You may charge any fee you choose for support of this
+ Package.  You may not charge a fee for this Package itself.  However,
+ you may distribute this Package in aggregate with other (possibly
+ commercial) programs as part of a larger (possibly commercial) software
+ distribution provided that you do not advertise this Package as a
+ product of your own.  You may embed this Package's interpreter within
+ an executable of yours (by linking); this shall be construed as a mere
+ form of aggregation, provided that the complete Standard Version of the
+ interpreter is so embedded.
+ .
+ 6. The scripts and library files supplied as input to or produced as
+ output from the programs of this Package do not automatically fall
+ under the copyright of this Package, but belong to whoever generated
+ them, and may be sold commercially, and may be aggregated with this
+ Package.  If such scripts or library files are aggregated with this
+ Package via the so-called "undump" or "unexec" methods of producing a
+ binary executable image, then distribution of such an image shall
+ neither be construed as a distribution of this Package nor shall it
+ fall under the restrictions of Paragraphs 3 and 4, provided that you do
+ not represent such an executable image as a Standard Version of this
+ Package.
+ .
+ 7. C subroutines (or comparably compiled subroutines in other
+ languages) supplied by you and linked into this Package in order to
+ emulate subroutines and variables of the language defined by this
+ Package shall not be considered part of this Package, but are the
+ equivalent of input as in Paragraph 6, provided these subroutines do
+ not change the language in any way that would cause it to fail the
+ regression tests for the language.
+ .
+ 8. Aggregation of this Package with a commercial distribution is always
+ permitted provided that the use of this Package is embedded; that is,
+ when no overt attempt is made to make this Package's interfaces visible
+ to the end user of the commercial distribution.  Such use shall not be
+ construed as a distribution of this Package.
+ .
+ 9. The name of the Copyright Holder may not be used to endorse or promote
+ products derived from this software without specific prior written permission.
+ .
+ 10. THIS PACKAGE 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.
+ .
+ The End
+
+License: public-domain
+ The work is public domain (no license).
diff --git a/gbp.conf b/gbp.conf
new file mode 100644 (file)
index 0000000..fd0fdf6
--- /dev/null
+++ b/gbp.conf
@@ -0,0 +1,21 @@
+[DEFAULT]
+# Ignore requirement to use branch name 'master' to make it easier
+# for contributors to work with feature and bugfix branches
+ignore-branch = True
+
+# Always use pristine tar
+pristine-tar = True
+
+# Always sign everything
+sign-tags = True
+upstream-signatures = on
+
+# DEP-14 format
+debian-branch = debian/latest
+upstream-branch = upstream/latest
+
+# Upstream tag format
+upstream-vcs-tag = mariadb-%(version)s
+
+# MariaDB has submodules
+submodules = True
diff --git a/libmariadb-dev-compat.install b/libmariadb-dev-compat.install
new file mode 100644 (file)
index 0000000..7fe10c5
--- /dev/null
@@ -0,0 +1,4 @@
+usr/lib/*/libmysqlclient.a
+usr/lib/*/libmysqlclient.so
+usr/lib/*/libmysqlclient_r.a
+usr/lib/*/libmysqlclient_r.so
diff --git a/libmariadb-dev-compat.links b/libmariadb-dev-compat.links
new file mode 100755 (executable)
index 0000000..2ae10e4
--- /dev/null
@@ -0,0 +1,4 @@
+#!/usr/bin/dh-exec
+usr/bin/mariadb_config usr/bin/mysql_config
+usr/include/mariadb usr/include/mysql
+usr/lib/${DEB_HOST_MULTIARCH}/pkgconfig/libmariadb.pc usr/lib/${DEB_HOST_MULTIARCH}/pkgconfig/mysqlclient.pc
diff --git a/libmariadb-dev.README.Maintainer b/libmariadb-dev.README.Maintainer
new file mode 100644 (file)
index 0000000..4094282
--- /dev/null
@@ -0,0 +1,6 @@
+The examples directory includes files that might be needed by some
+developers:
+- the example file udf_example.c
+
+For more information, see MariaDB Connector/C docs at:
+https://github.com/MariaDB/mariadb-connector-c/wiki/libmysql_libmariadb
diff --git a/libmariadb-dev.examples b/libmariadb-dev.examples
new file mode 100644 (file)
index 0000000..f1649c3
--- /dev/null
@@ -0,0 +1 @@
+sql/udf_example.c
diff --git a/libmariadb-dev.install b/libmariadb-dev.install
new file mode 100644 (file)
index 0000000..8bf8245
--- /dev/null
@@ -0,0 +1,35 @@
+usr/bin/mariadb-config
+usr/bin/mariadb_config
+usr/include/mariadb/errmsg.h
+usr/include/mariadb/ma_list.h
+usr/include/mariadb/ma_pvio.h
+usr/include/mariadb/ma_tls.h
+usr/include/mariadb/mariadb/ma_io.h
+usr/include/mariadb/mariadb_com.h
+usr/include/mariadb/mariadb_ctype.h
+usr/include/mariadb/mariadb_dyncol.h
+usr/include/mariadb/mariadb_rpl.h
+usr/include/mariadb/mariadb_stmt.h
+usr/include/mariadb/mariadb_version.h
+usr/include/mariadb/my_alloca.h
+usr/include/mariadb/my_config.h
+usr/include/mariadb/my_global.h
+usr/include/mariadb/my_sys.h
+usr/include/mariadb/mysql.h
+usr/include/mariadb/mysql/
+usr/include/mariadb/mysql/client_plugin.h
+usr/include/mariadb/mysql/plugin_auth.h
+usr/include/mariadb/mysql_com.h
+usr/include/mariadb/mysql_version.h
+usr/include/mariadb/mysqld_error.h
+usr/lib/*/libmariadb.a
+usr/lib/*/libmariadb.so
+usr/lib/*/libmariadbclient.a
+usr/lib/*/libmariadbclient.so
+usr/lib/*/libmysqlservices.a
+usr/lib/*/pkgconfig/libmariadb.pc
+usr/lib/*/pkgconfig/mariadb.pc
+usr/share/aclocal/mysql.m4
+usr/share/man/man1/mariadb_config.1
+usr/share/man/man1/mysql_config.1
+usr/share/man/man3/*.3
diff --git a/libmariadb-dev.links b/libmariadb-dev.links
new file mode 100644 (file)
index 0000000..b6d84cc
--- /dev/null
@@ -0,0 +1 @@
+usr/share/man/man1/mariadb_config.1.gz usr/share/man/man1/mariadb-config.1.gz
diff --git a/libmariadb-dev.lintian-overrides b/libmariadb-dev.lintian-overrides
new file mode 100644 (file)
index 0000000..1a3c0d5
--- /dev/null
@@ -0,0 +1,7 @@
+# This is how upstream does it, wont' fix
+repeated-path-segment mariadb [usr/include/mariadb/mariadb/]
+# Man page syntax needs to be fixed upstream
+groff-message an.tmac:<standard input>:*: warning: tbl preprocessor failed, or it or soelim was not run; table(s) likely not rendered (TE macro called with TW register undefined) [usr/share/man/*
+groff-message troff:<standard input>:*: warning: cannot select font 'C' [usr/share/man/*]
+# mysql_config and mariadb_config location is this by old convention
+development-package-ships-elf-binary-in-path [usr/bin/mariadb_config]
diff --git a/libmariadb3.install b/libmariadb3.install
new file mode 100644 (file)
index 0000000..5cd0aad
--- /dev/null
@@ -0,0 +1,6 @@
+usr/lib/*/libmariadb.so.*
+usr/lib/*/libmariadb3/plugin/caching_sha2_password.so
+usr/lib/*/libmariadb3/plugin/client_ed25519.so
+usr/lib/*/libmariadb3/plugin/dialog.so
+usr/lib/*/libmariadb3/plugin/mysql_clear_password.so
+usr/lib/*/libmariadb3/plugin/sha256_password.so
diff --git a/libmariadb3.lintian-overrides b/libmariadb3.lintian-overrides
new file mode 100644 (file)
index 0000000..f7ebae3
--- /dev/null
@@ -0,0 +1,4 @@
+# Most likely false positive
+hardening-no-fortify-functions [usr/lib/x86_64-linux-gnu/libmariadb3/plugin/caching_sha2_password.so]
+hardening-no-fortify-functions [usr/lib/x86_64-linux-gnu/libmariadb3/plugin/dialog.so]
+hardening-no-fortify-functions [usr/lib/x86_64-linux-gnu/libmariadb3/plugin/sha256_password.so]
diff --git a/libmariadb3.symbols b/libmariadb3.symbols
new file mode 100644 (file)
index 0000000..38d8927
--- /dev/null
@@ -0,0 +1,342 @@
+libmariadb.so.3 libmariadb3 #MINVER#
+* Build-Depends-Package: libmariadb-dev
+ libmariadb_3@libmariadb_3 3.0.0
+ libmariadb_3_3_5@libmariadb_3_3_5 3.3.5
+ libmariadbclient_18@libmariadbclient_18 3.0.0
+ libmysqlclient_18@libmysqlclient_18 3.0.0
+ ma_pvio_register_callback@libmariadb_3 3.0.0
+ mariadb_cancel@libmariadb_3 3.0.0
+ mariadb_connection@libmariadb_3 3.0.0
+ mariadb_convert_string@libmariadb_3 3.0.0
+ mariadb_deinitialize_ssl@libmariadb_3 3.0.0
+ mariadb_field_attr@libmariadb_3 3.1.8
+ mariadb_free_rpl_event@libmariadb_3 3.1.0
+ mariadb_get_charset_by_name@libmariadb_3 3.0.0
+ mariadb_get_charset_by_nr@libmariadb_3 3.0.0
+ mariadb_get_info@libmariadb_3 3.0.0
+ mariadb_get_infov@libmariadb_3 3.0.0
+ mariadb_reconnect@libmariadb_3 3.0.0
+ mariadb_rpl_close@libmariadb_3 3.1.0
+ mariadb_rpl_errno@libmariadb_3_3_5 3.3.5
+ mariadb_rpl_error@libmariadb_3_3_5 3.3.5
+ mariadb_rpl_extract_rows@libmariadb_3_3_5 3.3.5
+ mariadb_rpl_fetch@libmariadb_3 3.1.0
+ mariadb_rpl_get_optionsv@libmariadb_3 3.1.0
+ mariadb_rpl_init_ex@libmariadb_3 3.1.13
+ mariadb_rpl_open@libmariadb_3 3.1.0
+ mariadb_rpl_optionsv@libmariadb_3 3.1.0
+ mariadb_stmt_execute_direct@libmariadb_3 3.0.0
+ mariadb_stmt_fetch_fields@libmariadb_3 3.1.0
+ mysql_affected_rows@libmariadbclient_18 3.0.0
+ mysql_affected_rows@libmysqlclient_18 3.0.0
+ mysql_autocommit_cont@libmariadb_3 3.0.0
+ mysql_autocommit@libmariadbclient_18 3.0.0
+ mysql_autocommit@libmysqlclient_18 3.0.0
+ mysql_autocommit_start@libmariadb_3 3.0.0
+ mysql_change_user_cont@libmariadb_3 3.0.0
+ mysql_change_user@libmariadbclient_18 3.0.0
+ mysql_change_user@libmysqlclient_18 3.0.0
+ mysql_change_user_start@libmariadb_3 3.0.0
+ mysql_character_set_name@libmariadbclient_18 3.0.0
+ mysql_character_set_name@libmysqlclient_18 3.0.0
+ mysql_client_find_plugin@libmariadbclient_18 3.0.0
+ mysql_client_find_plugin@libmysqlclient_18 3.0.0
+ mysql_client_register_plugin@libmariadbclient_18 3.0.0
+ mysql_client_register_plugin@libmysqlclient_18 3.0.0
+ mysql_close_cont@libmariadb_3 3.0.0
+ mysql_close@libmariadbclient_18 3.0.0
+ mysql_close@libmysqlclient_18 3.0.0
+ mysql_close_start@libmariadb_3 3.0.0
+ mysql_commit_cont@libmariadb_3 3.0.0
+ mysql_commit@libmariadbclient_18 3.0.0
+ mysql_commit@libmysqlclient_18 3.0.0
+ mysql_commit_start@libmariadb_3 3.0.0
+ mysql_data_seek@libmariadbclient_18 3.0.0
+ mysql_data_seek@libmysqlclient_18 3.0.0
+ mysql_debug@libmariadbclient_18 3.0.0
+ mysql_debug@libmysqlclient_18 3.0.0
+ mysql_dump_debug_info_cont@libmariadb_3 3.0.0
+ mysql_dump_debug_info@libmariadbclient_18 3.0.0
+ mysql_dump_debug_info@libmysqlclient_18 3.0.0
+ mysql_dump_debug_info_start@libmariadb_3 3.0.0
+ mysql_embedded@libmariadbclient_18 3.0.0
+ mysql_embedded@libmysqlclient_18 3.0.0
+ mysql_eof@libmariadbclient_18 3.0.0
+ mysql_eof@libmysqlclient_18 3.0.0
+ mysql_errno@libmariadbclient_18 3.0.0
+ mysql_errno@libmysqlclient_18 3.0.0
+ mysql_error@libmariadbclient_18 3.0.0
+ mysql_error@libmysqlclient_18 3.0.0
+ mysql_escape_string@libmariadbclient_18 3.0.0
+ mysql_escape_string@libmysqlclient_18 3.0.0
+ mysql_fetch_field_direct@libmariadbclient_18 3.0.0
+ mysql_fetch_field_direct@libmysqlclient_18 3.0.0
+ mysql_fetch_field@libmariadbclient_18 3.0.0
+ mysql_fetch_field@libmysqlclient_18 3.0.0
+ mysql_fetch_fields@libmariadbclient_18 3.0.0
+ mysql_fetch_fields@libmysqlclient_18 3.0.0
+ mysql_fetch_lengths@libmariadbclient_18 3.0.0
+ mysql_fetch_lengths@libmysqlclient_18 3.0.0
+ mysql_fetch_row_cont@libmariadb_3 3.0.0
+ mysql_fetch_row@libmariadbclient_18 3.0.0
+ mysql_fetch_row@libmysqlclient_18 3.0.0
+ mysql_fetch_row_start@libmariadb_3 3.0.0
+ mysql_field_count@libmariadbclient_18 3.0.0
+ mysql_field_count@libmysqlclient_18 3.0.0
+ mysql_field_seek@libmariadbclient_18 3.0.0
+ mysql_field_seek@libmysqlclient_18 3.0.0
+ mysql_field_tell@libmariadbclient_18 3.0.0
+ mysql_field_tell@libmysqlclient_18 3.0.0
+ mysql_free_result_cont@libmariadb_3 3.0.0
+ mysql_free_result@libmariadbclient_18 3.0.0
+ mysql_free_result@libmysqlclient_18 3.0.0
+ mysql_free_result_start@libmariadb_3 3.0.0
+ mysql_get_character_set_info@libmariadbclient_18 3.0.0
+ mysql_get_character_set_info@libmysqlclient_18 3.0.0
+ mysql_get_charset_by_name@libmariadbclient_18 3.0.0
+ mysql_get_charset_by_name@libmysqlclient_18 3.0.0
+ mysql_get_charset_by_nr@libmariadbclient_18 3.0.0
+ mysql_get_charset_by_nr@libmysqlclient_18 3.0.0
+ mysql_get_client_info@libmariadbclient_18 3.0.0
+ mysql_get_client_info@libmysqlclient_18 3.0.0
+ mysql_get_client_version@libmariadbclient_18 3.0.0
+ mysql_get_client_version@libmysqlclient_18 3.0.0
+ mysql_get_host_info@libmariadbclient_18 3.0.0
+ mysql_get_host_info@libmysqlclient_18 3.0.0
+ mysql_get_option@libmariadbclient_18 3.0.0
+ mysql_get_option@libmysqlclient_18 3.0.0
+ mysql_get_optionv@libmariadbclient_18 3.0.0
+ mysql_get_optionv@libmysqlclient_18 3.0.0
+ mysql_get_parameters@libmariadbclient_18 3.0.0
+ mysql_get_parameters@libmysqlclient_18 3.0.0
+ mysql_get_proto_info@libmariadbclient_18 3.0.0
+ mysql_get_proto_info@libmysqlclient_18 3.0.0
+ mysql_get_server_info@libmariadbclient_18 3.0.0
+ mysql_get_server_info@libmysqlclient_18 3.0.0
+ mysql_get_server_name@libmariadbclient_18 3.0.0
+ mysql_get_server_name@libmysqlclient_18 3.0.0
+ mysql_get_server_version@libmariadbclient_18 3.0.0
+ mysql_get_server_version@libmysqlclient_18 3.0.0
+ mysql_get_socket@libmariadbclient_18 3.0.0
+ mysql_get_socket@libmysqlclient_18 3.0.0
+ mysql_get_ssl_cipher@libmariadbclient_18 3.0.0
+ mysql_get_ssl_cipher@libmysqlclient_18 3.0.0
+ mysql_get_timeout_value@libmariadb_3 3.0.19
+ mysql_get_timeout_value_ms@libmariadb_3 3.0.19
+ mysql_hex_string@libmariadbclient_18 3.0.0
+ mysql_hex_string@libmysqlclient_18 3.0.0
+ mysql_info@libmariadbclient_18 3.0.0
+ mysql_info@libmysqlclient_18 3.0.0
+ mysql_init@libmariadbclient_18 3.0.0
+ mysql_init@libmysqlclient_18 3.0.0
+ mysql_insert_id@libmariadbclient_18 3.0.0
+ mysql_insert_id@libmysqlclient_18 3.0.0
+ mysql_kill_cont@libmariadb_3 3.0.0
+ mysql_kill@libmariadbclient_18 3.0.0
+ mysql_kill@libmysqlclient_18 3.0.0
+ mysql_kill_start@libmariadb_3 3.0.0
+ mysql_list_dbs@libmariadbclient_18 3.0.0
+ mysql_list_dbs@libmysqlclient_18 3.0.0
+ mysql_list_fields_cont@libmariadb_3 3.0.0
+ mysql_list_fields@libmariadbclient_18 3.0.0
+ mysql_list_fields@libmysqlclient_18 3.0.0
+ mysql_list_fields_start@libmariadb_3 3.0.0
+ mysql_list_processes@libmariadbclient_18 3.0.0
+ mysql_list_processes@libmysqlclient_18 3.0.0
+ mysql_list_tables@libmariadbclient_18 3.0.0
+ mysql_list_tables@libmysqlclient_18 3.0.0
+ mysql_load_plugin@libmariadbclient_18 3.0.0
+ mysql_load_plugin@libmysqlclient_18 3.0.0
+ mysql_load_plugin_v@libmariadbclient_18 3.0.0
+ mysql_load_plugin_v@libmysqlclient_18 3.0.0
+ mysql_more_results@libmariadbclient_18 3.0.0
+ mysql_more_results@libmysqlclient_18 3.0.0
+ mysql_net_field_length@libmariadbclient_18 3.0.0
+ mysql_net_field_length@libmysqlclient_18 3.0.0
+ mysql_net_read_packet@libmariadbclient_18 3.0.0
+ mysql_net_read_packet@libmysqlclient_18 3.0.0
+ mysql_next_result_cont@libmariadb_3 3.0.0
+ mysql_next_result@libmariadbclient_18 3.0.0
+ mysql_next_result@libmysqlclient_18 3.0.0
+ mysql_next_result_start@libmariadb_3 3.0.0
+ mysql_num_fields@libmariadbclient_18 3.0.0
+ mysql_num_fields@libmysqlclient_18 3.0.0
+ mysql_num_rows@libmariadbclient_18 3.0.0
+ mysql_num_rows@libmysqlclient_18 3.0.0
+ mysql_options4@libmariadbclient_18 3.0.0
+ mysql_options4@libmysqlclient_18 3.0.0
+ mysql_options@libmariadbclient_18 3.0.0
+ mysql_options@libmysqlclient_18 3.0.0
+ mysql_optionsv@libmariadb_3 3.0.0
+ mysql_ping_cont@libmariadb_3 3.0.0
+ mysql_ping@libmariadbclient_18 3.0.0
+ mysql_ping@libmysqlclient_18 3.0.0
+ mysql_ping_start@libmariadb_3 3.0.0
+ mysql_ps_fetch_functions@libmariadb_3 3.0.0
+ mysql_query_cont@libmariadb_3 3.0.0
+ mysql_query@libmariadbclient_18 3.0.0
+ mysql_query@libmysqlclient_18 3.0.0
+ mysql_query_start@libmariadb_3 3.0.0
+ mysql_read_query_result_cont@libmariadb_3 3.0.0
+ mysql_read_query_result@libmariadbclient_18 3.0.0
+ mysql_read_query_result@libmysqlclient_18 3.0.0
+ mysql_read_query_result_start@libmariadb_3 3.0.0
+ mysql_real_connect_cont@libmariadb_3 3.0.0
+ mysql_real_connect@libmariadbclient_18 3.0.0
+ mysql_real_connect@libmysqlclient_18 3.0.0
+ mysql_real_connect_start@libmariadb_3 3.0.0
+ mysql_real_escape_string@libmariadbclient_18 3.0.0
+ mysql_real_escape_string@libmysqlclient_18 3.0.0
+ mysql_real_query_cont@libmariadb_3 3.0.0
+ mysql_real_query@libmariadbclient_18 3.0.0
+ mysql_real_query@libmysqlclient_18 3.0.0
+ mysql_real_query_start@libmariadb_3 3.0.0
+ mysql_refresh_cont@libmariadb_3 3.0.0
+ mysql_refresh@libmariadbclient_18 3.0.0
+ mysql_refresh@libmysqlclient_18 3.0.0
+ mysql_refresh_start@libmariadb_3 3.0.0
+ mysql_reset_connection_cont@libmariadb_3 3.0.0
+ mysql_reset_connection@libmariadbclient_18 3.0.0
+ mysql_reset_connection@libmysqlclient_18 3.0.0
+ mysql_reset_connection_start@libmariadb_3 3.0.0
+ mysql_rollback_cont@libmariadb_3 3.0.0
+ mysql_rollback@libmariadbclient_18 3.0.0
+ mysql_rollback@libmysqlclient_18 3.0.0
+ mysql_rollback_start@libmariadb_3 3.0.0
+ mysql_row_seek@libmariadbclient_18 3.0.0
+ mysql_row_seek@libmysqlclient_18 3.0.0
+ mysql_row_tell@libmariadbclient_18 3.0.0
+ mysql_row_tell@libmysqlclient_18 3.0.0
+ mysql_select_db_cont@libmariadb_3 3.0.0
+ mysql_select_db@libmariadbclient_18 3.0.0
+ mysql_select_db@libmysqlclient_18 3.0.0
+ mysql_select_db_start@libmariadb_3 3.0.0
+ mysql_send_query_cont@libmariadb_3 3.0.0
+ mysql_send_query@libmariadbclient_18 3.0.0
+ mysql_send_query@libmysqlclient_18 3.0.0
+ mysql_send_query_start@libmariadb_3 3.0.0
+ mysql_server_end@libmariadbclient_18 3.0.0
+ mysql_server_end@libmysqlclient_18 3.0.0
+ mysql_server_init@libmariadbclient_18 3.0.0
+ mysql_server_init@libmysqlclient_18 3.0.0
+ mysql_session_track_get_first@libmariadbclient_18 3.0.0
+ mysql_session_track_get_first@libmysqlclient_18 3.0.0
+ mysql_session_track_get_next@libmariadbclient_18 3.0.0
+ mysql_session_track_get_next@libmysqlclient_18 3.0.0
+ mysql_set_character_set_cont@libmariadb_3 3.0.0
+ mysql_set_character_set@libmariadbclient_18 3.0.0
+ mysql_set_character_set@libmysqlclient_18 3.0.0
+ mysql_set_character_set_start@libmariadb_3 3.0.0
+ mysql_set_local_infile_default@libmariadbclient_18 3.0.0
+ mysql_set_local_infile_default@libmysqlclient_18 3.0.0
+ mysql_set_local_infile_handler@libmariadbclient_18 3.0.0
+ mysql_set_local_infile_handler@libmysqlclient_18 3.0.0
+ mysql_set_server_option_cont@libmariadb_3 3.0.0
+ mysql_set_server_option@libmariadbclient_18 3.0.0
+ mysql_set_server_option@libmysqlclient_18 3.0.0
+ mysql_set_server_option_start@libmariadb_3 3.0.0
+ mysql_shutdown_cont@libmariadb_3 3.0.0
+ mysql_shutdown@libmariadbclient_18 3.0.0
+ mysql_shutdown@libmysqlclient_18 3.0.0
+ mysql_shutdown_start@libmariadb_3 3.0.0
+ mysql_sqlstate@libmariadbclient_18 3.0.0
+ mysql_sqlstate@libmysqlclient_18 3.0.0
+ mysql_ssl_set@libmariadbclient_18 3.0.0
+ mysql_ssl_set@libmysqlclient_18 3.0.0
+ mysql_stat_cont@libmariadb_3 3.0.0
+ mysql_stat@libmariadbclient_18 3.0.0
+ mysql_stat@libmysqlclient_18 3.0.0
+ mysql_stat_start@libmariadb_3 3.0.0
+ mysql_stmt_affected_rows@libmariadbclient_18 3.0.0
+ mysql_stmt_affected_rows@libmysqlclient_18 3.0.0
+ mysql_stmt_attr_get@libmariadbclient_18 3.0.0
+ mysql_stmt_attr_get@libmysqlclient_18 3.0.0
+ mysql_stmt_attr_set@libmariadbclient_18 3.0.0
+ mysql_stmt_attr_set@libmysqlclient_18 3.0.0
+ mysql_stmt_bind_param@libmariadbclient_18 3.0.0
+ mysql_stmt_bind_param@libmysqlclient_18 3.0.0
+ mysql_stmt_bind_result@libmariadbclient_18 3.0.0
+ mysql_stmt_bind_result@libmysqlclient_18 3.0.0
+ mysql_stmt_close_cont@libmariadb_3 3.0.0
+ mysql_stmt_close@libmariadbclient_18 3.0.0
+ mysql_stmt_close@libmysqlclient_18 3.0.0
+ mysql_stmt_close_start@libmariadb_3 3.0.0
+ mysql_stmt_data_seek@libmariadbclient_18 3.0.0
+ mysql_stmt_data_seek@libmysqlclient_18 3.0.0
+ mysql_stmt_errno@libmariadbclient_18 3.0.0
+ mysql_stmt_errno@libmysqlclient_18 3.0.0
+ mysql_stmt_error@libmariadbclient_18 3.0.0
+ mysql_stmt_error@libmysqlclient_18 3.0.0
+ mysql_stmt_execute_cont@libmariadb_3 3.0.0
+ mysql_stmt_execute@libmariadbclient_18 3.0.0
+ mysql_stmt_execute@libmysqlclient_18 3.0.0
+ mysql_stmt_execute_start@libmariadb_3 3.0.0
+ mysql_stmt_fetch_column@libmariadbclient_18 3.0.0
+ mysql_stmt_fetch_column@libmysqlclient_18 3.0.0
+ mysql_stmt_fetch_cont@libmariadb_3 3.0.0
+ mysql_stmt_fetch@libmariadbclient_18 3.0.0
+ mysql_stmt_fetch@libmysqlclient_18 3.0.0
+ mysql_stmt_fetch_start@libmariadb_3 3.0.0
+ mysql_stmt_field_count@libmariadbclient_18 3.0.0
+ mysql_stmt_field_count@libmysqlclient_18 3.0.0
+ mysql_stmt_free_result_cont@libmariadb_3 3.0.0
+ mysql_stmt_free_result@libmariadbclient_18 3.0.0
+ mysql_stmt_free_result@libmysqlclient_18 3.0.0
+ mysql_stmt_free_result_start@libmariadb_3 3.0.0
+ mysql_stmt_init@libmariadbclient_18 3.0.0
+ mysql_stmt_init@libmysqlclient_18 3.0.0
+ mysql_stmt_insert_id@libmariadbclient_18 3.0.0
+ mysql_stmt_insert_id@libmysqlclient_18 3.0.0
+ mysql_stmt_more_results@libmariadbclient_18 3.0.0
+ mysql_stmt_more_results@libmysqlclient_18 3.0.0
+ mysql_stmt_next_result_cont@libmariadb_3 3.0.0
+ mysql_stmt_next_result@libmariadbclient_18 3.0.0
+ mysql_stmt_next_result@libmysqlclient_18 3.0.0
+ mysql_stmt_next_result_start@libmariadb_3 3.0.0
+ mysql_stmt_num_rows@libmariadbclient_18 3.0.0
+ mysql_stmt_num_rows@libmysqlclient_18 3.0.0
+ mysql_stmt_param_count@libmariadbclient_18 3.0.0
+ mysql_stmt_param_count@libmysqlclient_18 3.0.0
+ mysql_stmt_param_metadata@libmariadbclient_18 3.0.0
+ mysql_stmt_param_metadata@libmysqlclient_18 3.0.0
+ mysql_stmt_prepare_cont@libmariadb_3 3.0.0
+ mysql_stmt_prepare@libmariadbclient_18 3.0.0
+ mysql_stmt_prepare@libmysqlclient_18 3.0.0
+ mysql_stmt_prepare_start@libmariadb_3 3.0.0
+ mysql_stmt_reset_cont@libmariadb_3 3.0.0
+ mysql_stmt_reset@libmariadbclient_18 3.0.0
+ mysql_stmt_reset@libmysqlclient_18 3.0.0
+ mysql_stmt_reset_start@libmariadb_3 3.0.0
+ mysql_stmt_result_metadata@libmariadbclient_18 3.0.0
+ mysql_stmt_result_metadata@libmysqlclient_18 3.0.0
+ mysql_stmt_row_seek@libmariadbclient_18 3.0.0
+ mysql_stmt_row_seek@libmysqlclient_18 3.0.0
+ mysql_stmt_row_tell@libmariadbclient_18 3.0.0
+ mysql_stmt_row_tell@libmysqlclient_18 3.0.0
+ mysql_stmt_send_long_data_cont@libmariadb_3 3.0.0
+ mysql_stmt_send_long_data@libmariadbclient_18 3.0.0
+ mysql_stmt_send_long_data@libmysqlclient_18 3.0.0
+ mysql_stmt_send_long_data_start@libmariadb_3 3.0.0
+ mysql_stmt_sqlstate@libmariadbclient_18 3.0.0
+ mysql_stmt_sqlstate@libmysqlclient_18 3.0.0
+ mysql_stmt_store_result_cont@libmariadb_3 3.0.0
+ mysql_stmt_store_result@libmariadbclient_18 3.0.0
+ mysql_stmt_store_result@libmysqlclient_18 3.0.0
+ mysql_stmt_store_result_start@libmariadb_3 3.0.0
+ mysql_stmt_warning_count@libmariadb_3 3.0.0
+ mysql_store_result_cont@libmariadb_3 3.0.0
+ mysql_store_result@libmariadbclient_18 3.0.0
+ mysql_store_result@libmysqlclient_18 3.0.0
+ mysql_store_result_start@libmariadb_3 3.0.0
+ mysql_thread_end@libmariadbclient_18 3.0.0
+ mysql_thread_end@libmysqlclient_18 3.0.0
+ mysql_thread_id@libmariadbclient_18 3.0.0
+ mysql_thread_id@libmysqlclient_18 3.0.0
+ mysql_thread_init@libmariadbclient_18 3.0.0
+ mysql_thread_init@libmysqlclient_18 3.0.0
+ mysql_thread_safe@libmariadbclient_18 3.0.0
+ mysql_thread_safe@libmysqlclient_18 3.0.0
+ mysql_use_result@libmariadbclient_18 3.0.0
+ mysql_use_result@libmysqlclient_18 3.0.0
+ mysql_warning_count@libmariadbclient_18 3.0.0
+ mysql_warning_count@libmysqlclient_18 3.0.0
diff --git a/libmariadb3.symbols.README b/libmariadb3.symbols.README
new file mode 100644 (file)
index 0000000..b6e8c95
--- /dev/null
@@ -0,0 +1,42 @@
+The libmariadb3.symbols files is used to track the libmariadb3 ABI.
+
+If a symbol is removed or changed, the Debian build will fail unless the same change has also explicitly been made in the libmariadb3.symbols file.
+
+If a symbol is added, the Debian build will issue a warning like:
+
+   dh_makeshlibs -O--parallel
+       rm -f debian/libmariadb3/DEBIAN/shlibs
+       echo "libmariadb 3 libmariadb3" >> debian/libmariadb3/DEBIAN/shlibs
+       chmod 0644 -- debian/libmariadb3/DEBIAN/shlibs
+       chown 0:0 -- debian/libmariadb3/DEBIAN/shlibs
+       dpkg-gensymbols -plibmariadb3 -Idebian/libmariadb3.symbols -Pdebian/libmariadb3 -edebian/libmariadb3/usr/lib/x86_64-linux-gnu/libmariadb.so.3
+  dpkg-gensymbols: warning: some new symbols appeared in the symbols file: see diff output below
+  dpkg-gensymbols: warning: debian/libmariadb3/DEBIAN/symbols doesn't match completely debian/libmariadb3.symbols
+  --- debian/libmariadb3.symbols (libmariadb3_10.2.32+maria~sid_amd64)
+  +++ dpkg-gensymbolsUfTky5    2020-02-20 11:27:03.815551573 +0000
+  @@ -12,6 +12,7 @@
+    mariadb_get_charset_by_name@libmariadb_3 3.0.0
+    mariadb_get_charset_by_nr@libmariadb_3 3.0.0
+    mariadb_get_info@libmariadb_3 3.0.0
+  + mariadb_get_infov@libmariadb_3 10.2.32+maria~sid
+    mariadb_reconnect@libmariadb_3 3.0.0
+    mariadb_rpl_close@libmariadb_3 3.1.0
+    mariadb_rpl_fetch@libmariadb_3 3.1.0
+
+
+When this happens, please add the symbol to the libmariadb3.symbols file.
+Unlike the automatic diff above, don't use the server version for the symbols.
+
+Instead use the client library version, which can be viewed with:
+
+  $ grep 'SET(CPACK_PACKAGE_VERSION_' libmariadb/CMakeLists.txt 
+  SET(CPACK_PACKAGE_VERSION_MAJOR 3)
+  SET(CPACK_PACKAGE_VERSION_MINOR 1)
+  SET(CPACK_PACKAGE_VERSION_PATCH 7)
+
+In this example, the line to add would be:
+
+  mariadb_get_infov@libmariadb_3 3.1.7
+
+
+Remember to not break the ABI in a stable release!
diff --git a/libmariadbd-dev.install b/libmariadbd-dev.install
new file mode 100644 (file)
index 0000000..3eebe63
--- /dev/null
@@ -0,0 +1,5 @@
+usr/include/mariadb/server
+usr/lib/*/libmariadbd.a
+usr/lib/*/libmariadbd.so
+usr/lib/*/libmysqld.a
+usr/lib/*/libmysqld.so
diff --git a/libmariadbd19t64.install b/libmariadbd19t64.install
new file mode 100644 (file)
index 0000000..cb62720
--- /dev/null
@@ -0,0 +1 @@
+usr/lib/*/libmariadbd.so.*
diff --git a/libmariadbd19t64.lintian-overrides b/libmariadbd19t64.lintian-overrides
new file mode 100644 (file)
index 0000000..fb5b944
--- /dev/null
@@ -0,0 +1,13 @@
+# MyISAM stopwords that cannot be changed and spelling errors remain
+spelling-error-in-binary noone no one [usr/lib/*/libmariadbd.so.19]
+spelling-error-in-binary thats that's [usr/lib/*/libmariadbd.so.19]
+spelling-error-in-binary theres there's [usr/lib/*/libmariadbd.so.19]
+# This cannot be found in sources, seems like some artifact
+spelling-error-in-binary AfE Safe [usr/lib/*/libmariadbd.so.19]
+# Intentional package and soname difference
+libmariadbd19t64: package-name-doesnt-match-sonames libmariadbd19
+# libmariadbd cannot have a symbols file as it would be massively large with all
+# the _ZNK* prefixed symbols leaking
+no-symbols-control-file usr/lib/x86_64-linux-gnu/libmariadbd.so.19
+# Probably due to leaking ABI symbols
+exit-in-shared-library [usr/lib/x86_64-linux-gnu/libmariadbd.so.19]
diff --git a/mariadb-backup.install b/mariadb-backup.install
new file mode 100644 (file)
index 0000000..e450f8f
--- /dev/null
@@ -0,0 +1,6 @@
+usr/bin/mariabackup
+usr/bin/mariadb-backup
+usr/bin/mbstream
+usr/share/man/man1/mariabackup.1
+usr/share/man/man1/mariadb-backup.1
+usr/share/man/man1/mbstream.1
diff --git a/mariadb-backup.lintian-overrides b/mariadb-backup.lintian-overrides
new file mode 100644 (file)
index 0000000..1dd2eeb
--- /dev/null
@@ -0,0 +1,6 @@
+# MyISAM stopwords that cannot be changed and spelling errors remain
+spelling-error-in-binary noone no one [usr/bin/*]
+spelling-error-in-binary thats that's [usr/bin/*]
+spelling-error-in-binary theres there's [usr/bin/*]
+# False positive from Lintian, these strings are nowhere in test in source code
+spelling-error-in-binary AfE Safe [usr/bin/*]
diff --git a/mariadb-client-core.install b/mariadb-client-core.install
new file mode 100644 (file)
index 0000000..bcc3515
--- /dev/null
@@ -0,0 +1,9 @@
+usr/bin/mariadb
+usr/bin/mariadb-check
+usr/bin/my_print_defaults
+usr/bin/mysql
+usr/share/man/man1/mariadb-check.1
+usr/share/man/man1/mariadb.1
+usr/share/man/man1/my_print_defaults.1
+usr/share/man/man1/mysql.1
+usr/share/man/man1/mysqlcheck.1
diff --git a/mariadb-client-core.links b/mariadb-client-core.links
new file mode 100644 (file)
index 0000000..5134dd8
--- /dev/null
@@ -0,0 +1 @@
+usr/bin/mariadb usr/bin/mysql
diff --git a/mariadb-client-core.lintian-overrides b/mariadb-client-core.lintian-overrides
new file mode 100644 (file)
index 0000000..a20ba26
--- /dev/null
@@ -0,0 +1,2 @@
+# Man syntax needs to be fixed upstream
+groff-message troff:<standard input>:*: warning: macro 'an-trap' not defined [usr/share/man/*]
diff --git a/mariadb-client.README.Debian b/mariadb-client.README.Debian
new file mode 100644 (file)
index 0000000..64f0f50
--- /dev/null
@@ -0,0 +1,4 @@
+FAQ:
+
+Q: My <tab> completion is gone, why?
+A: You have "no-auto-rehash" in the "[mysql]" section of /etc/mysql/my.cnf!
diff --git a/mariadb-client.docs b/mariadb-client.docs
new file mode 100644 (file)
index 0000000..c090926
--- /dev/null
@@ -0,0 +1,2 @@
+README.md
+debian/additions/innotop/changelog.innotop
diff --git a/mariadb-client.install b/mariadb-client.install
new file mode 100644 (file)
index 0000000..fba8d09
--- /dev/null
@@ -0,0 +1,79 @@
+debian/additions/innotop/innotop usr/bin/
+debian/additions/mariadb-report usr/bin/
+debian/additions/mariadb.conf.d/50-client.cnf etc/mysql/mariadb.conf.d
+debian/additions/mariadb.conf.d/50-mysql-clients.cnf etc/mysql/mariadb.conf.d
+debian/additions/mariadb.conf.d/60-galera.cnf etc/mysql/mariadb.conf.d
+usr/bin/mariadb-access
+usr/bin/mariadb-admin
+usr/bin/mariadb-binlog
+usr/bin/mariadb-conv
+usr/bin/mariadb-convert-table-format
+usr/bin/mariadb-dump
+usr/bin/mariadb-dumpslow
+usr/bin/mariadb-find-rows
+usr/bin/mariadb-fix-extensions
+usr/bin/mariadb-hotcopy
+usr/bin/mariadb-import
+usr/bin/mariadb-plugin
+usr/bin/mariadb-secure-installation
+usr/bin/mariadb-setpermission
+usr/bin/mariadb-show
+usr/bin/mariadb-slap
+usr/bin/mariadb-tzinfo-to-sql
+usr/bin/mariadb-waitpid
+usr/bin/msql2mysql
+usr/bin/mysql_find_rows
+usr/bin/mysql_fix_extensions
+usr/bin/mysql_waitpid
+usr/bin/mysqlaccess
+usr/bin/mysqladmin
+usr/bin/mysqlcheck
+usr/bin/mysqldump
+usr/bin/mysqldumpslow
+usr/bin/mysqlimport
+usr/bin/mysqlshow
+usr/bin/mysqlslap
+usr/bin/mytop
+usr/bin/perror
+usr/bin/replace
+usr/bin/resolve_stack_dump
+usr/share/man/man1/mariadb-access.1
+usr/share/man/man1/mariadb-admin.1
+usr/share/man/man1/mariadb-binlog.1
+usr/share/man/man1/mariadb-conv.1
+usr/share/man/man1/mariadb-convert-table-format.1
+usr/share/man/man1/mariadb-dump.1
+usr/share/man/man1/mariadb-dumpslow.1
+usr/share/man/man1/mariadb-find-rows.1
+usr/share/man/man1/mariadb-fix-extensions.1
+usr/share/man/man1/mariadb-hotcopy.1
+usr/share/man/man1/mariadb-import.1
+usr/share/man/man1/mariadb-plugin.1
+usr/share/man/man1/mariadb-secure-installation.1
+usr/share/man/man1/mariadb-setpermission.1
+usr/share/man/man1/mariadb-show.1
+usr/share/man/man1/mariadb-slap.1
+usr/share/man/man1/mariadb-tzinfo-to-sql.1
+usr/share/man/man1/mariadb-waitpid.1
+usr/share/man/man1/msql2mysql.1
+usr/share/man/man1/mysql_convert_table_format.1
+usr/share/man/man1/mysql_find_rows.1
+usr/share/man/man1/mysql_fix_extensions.1
+usr/share/man/man1/mysql_plugin.1
+usr/share/man/man1/mysql_secure_installation.1
+usr/share/man/man1/mysql_setpermission.1
+usr/share/man/man1/mysql_tzinfo_to_sql.1
+usr/share/man/man1/mysql_waitpid.1
+usr/share/man/man1/mysqlaccess.1
+usr/share/man/man1/mysqladmin.1
+usr/share/man/man1/mysqlbinlog.1
+usr/share/man/man1/mysqldump.1
+usr/share/man/man1/mysqldumpslow.1
+usr/share/man/man1/mysqlhotcopy.1
+usr/share/man/man1/mysqlimport.1
+usr/share/man/man1/mysqlshow.1
+usr/share/man/man1/mysqlslap.1
+usr/share/man/man1/mytop.1
+usr/share/man/man1/perror.1
+usr/share/man/man1/replace.1
+usr/share/man/man1/resolve_stack_dump.1
diff --git a/mariadb-client.links b/mariadb-client.links
new file mode 100644 (file)
index 0000000..62e3651
--- /dev/null
@@ -0,0 +1,17 @@
+usr/bin/mariadb-check usr/bin/mariadb-analyze
+usr/bin/mariadb-check usr/bin/mariadb-optimize
+usr/bin/mariadb-check usr/bin/mariadb-repair
+usr/bin/mariadb-check usr/bin/mariadbcheck
+usr/bin/mariadb-check usr/bin/mysqlanalyze
+usr/bin/mariadb-check usr/bin/mysqlcheck
+usr/bin/mariadb-check usr/bin/mysqloptimize
+usr/bin/mariadb-check usr/bin/mysqlrepair
+usr/bin/mariadb-report usr/bin/mysqlreport
+usr/share/man/man1/mariadb-check.1.gz usr/share/man/man1/mariadb-analyze.1.gz
+usr/share/man/man1/mariadb-check.1.gz usr/share/man/man1/mariadb-optimize.1.gz
+usr/share/man/man1/mariadb-check.1.gz usr/share/man/man1/mariadb-repair.1.gz
+usr/share/man/man1/mariadb-check.1.gz usr/share/man/man1/mariadbcheck.1.gz
+usr/share/man/man1/mariadb-check.1.gz usr/share/man/man1/mysqlanalyze.1.gz
+usr/share/man/man1/mariadb-check.1.gz usr/share/man/man1/mysqloptimize.1.gz
+usr/share/man/man1/mariadb-check.1.gz usr/share/man/man1/mysqlrepair.1.gz
+usr/share/man/man1/mariadb-report.1.gz usr/share/man/man1/mysqlreport.1.gz
diff --git a/mariadb-client.lintian-overrides b/mariadb-client.lintian-overrides
new file mode 100644 (file)
index 0000000..1e0263b
--- /dev/null
@@ -0,0 +1,4 @@
+# The Innotop changelog has this name for a valid reason
+wrong-name-for-upstream-changelog [usr/share/doc/mariadb-client/changelog.innotop.gz]
+# Man syntax needs to be fixed upstream
+groff-message troff:<standard input>:*: warning: macro 'an-trap' not defined [usr/share/man/*]
diff --git a/mariadb-client.manpages b/mariadb-client.manpages
new file mode 100644 (file)
index 0000000..8735cae
--- /dev/null
@@ -0,0 +1,2 @@
+debian/additions/innotop/innotop.1
+debian/additions/mariadb-report.1
diff --git a/mariadb-client.menu b/mariadb-client.menu
new file mode 100644 (file)
index 0000000..b452218
--- /dev/null
@@ -0,0 +1,3 @@
+# According to /usr/share/menu/ policy 1.4, not /usr/share/doc/debian-policy/
+?package(mariadb-client):needs="text" section="Applications/Data Management"\
+  title="Innotop" command="/usr/bin/innotop"
diff --git a/mariadb-common.dirs b/mariadb-common.dirs
new file mode 100644 (file)
index 0000000..8aba956
--- /dev/null
@@ -0,0 +1 @@
+etc/mysql/mariadb.conf.d
diff --git a/mariadb-common.install b/mariadb-common.install
new file mode 100644 (file)
index 0000000..611c7d4
--- /dev/null
@@ -0,0 +1 @@
+debian/additions/mariadb.cnf etc/mysql/
diff --git a/mariadb-common.postinst b/mariadb-common.postinst
new file mode 100644 (file)
index 0000000..53d131a
--- /dev/null
@@ -0,0 +1,41 @@
+#!/bin/sh
+
+set -e
+
+case "$1" in
+  configure)
+    # New packaging paradigm for my.cnf handling among MySQL variants
+    # Used in Ubuntu since Dec-2014 and in Debian since Jul-2015
+    #
+    # If the new mysql-common package does not provide
+    # the update-alternatives facility, notify user about manual fall back
+    if [ -f /usr/share/mysql-common/configure-symlinks ]
+    then
+      /usr/share/mysql-common/configure-symlinks install mariadb "/etc/mysql/mariadb.cnf"
+    else
+      # As configure can be called many times, don't re-create the symlink
+      # if it is there already
+      if [ ! -L /etc/mysql/my.cnf ]
+      then
+        echo "Notice: configure-symlinks trigger could not be called."
+        echo "Please manually create symlinks by running: "
+        echo "  mv -f /etc/mysql/my.cnf /etc/mysql/my.cnf.old"
+        echo "  ln -sf mariadb.cnf /etc/mysql/my.cnf"
+      fi
+    fi
+
+    # Note that MySQL in Debian runs the configure-symlinks from the
+    # mysql-server-x.x.postinst and postrm files, while the MySQL.com (and
+    # Percona.com) packaging triggers update-alternatives directly form the
+    # mysql-common (and percona-x-common) package using priority 200.
+    #
+    # Thus, we need to ensure here that mariadb.cnf indeed became the primary
+    # alternative and override with priority 500 if needed.
+    if ! update-alternatives --query my.cnf | grep --quiet "Value: /etc/mysql/mariadb.cnf"
+    then
+      update-alternatives --install /etc/mysql/my.cnf my.cnf "/etc/mysql/mariadb.cnf" 500 || true
+    fi
+    ;;
+esac
+
+#DEBHELPER#
diff --git a/mariadb-common.postrm b/mariadb-common.postrm
new file mode 100644 (file)
index 0000000..2548733
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+set -e
+
+case "$1" in
+  remove|disappear)
+    # New packaging paradigm for my.cnf handling among MySQL variants
+    # Used in Ubuntu since Dec-2014 and in Debian since Jul-2015
+    if [ -f /usr/share/mysql-common/configure-symlinks ]
+    then
+      /usr/share/mysql-common/configure-symlinks remove mariadb "/etc/mysql/mariadb.cnf"
+    fi
+    ;;
+esac
+
+#DEBHELPER#
diff --git a/mariadb-common.preinst b/mariadb-common.preinst
new file mode 100644 (file)
index 0000000..09ef451
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh
+set -e
+
+if [ "$1" = "install" ] || [ "$1" = "upgrade" ]
+then
+  if dpkg --compare-versions "$2" lt-nl "10.0.20-3~"
+  then
+    # revert fallback my.cnf symlink setup performed by mariadb-common
+    # from 10.0.17-1~exp2 up to 10.0.20-2
+    if [ -L /etc/mysql/my.cnf ] && [ -f /etc/mysql/my.cnf.old ]
+    then
+      if [ "$(readlink /etc/mysql/my.cnf)" = "mariadb.cnf" ]
+      then
+        echo "Reverting my.cnf -> mariadb.cnf symlink setup by mariadb-common"
+        rm /etc/mysql/my.cnf
+        mv /etc/mysql/my.cnf.old /etc/mysql/my.cnf
+      fi
+    fi
+  fi
+fi
+
+#DEBHELPER#
diff --git a/mariadb-plugin-connect.install b/mariadb-plugin-connect.install
new file mode 100644 (file)
index 0000000..e250026
--- /dev/null
@@ -0,0 +1,2 @@
+etc/mysql/mariadb.conf.d/connect.cnf
+usr/lib/mysql/plugin/ha_connect.so
diff --git a/mariadb-plugin-cracklib-password-check.install b/mariadb-plugin-cracklib-password-check.install
new file mode 100644 (file)
index 0000000..6592c7f
--- /dev/null
@@ -0,0 +1,2 @@
+etc/mysql/mariadb.conf.d/cracklib_password_check.cnf
+usr/lib/mysql/plugin/cracklib_password_check.so
diff --git a/mariadb-plugin-gssapi-client.install b/mariadb-plugin-gssapi-client.install
new file mode 100644 (file)
index 0000000..4486070
--- /dev/null
@@ -0,0 +1 @@
+usr/lib/*/libmariadb3/plugin/auth_gssapi_client.so
diff --git a/mariadb-plugin-gssapi-server.install b/mariadb-plugin-gssapi-server.install
new file mode 100644 (file)
index 0000000..8261db7
--- /dev/null
@@ -0,0 +1,2 @@
+etc/mysql/mariadb.conf.d/auth_gssapi.cnf
+usr/lib/mysql/plugin/auth_gssapi.so
diff --git a/mariadb-plugin-hashicorp-key-management.install b/mariadb-plugin-hashicorp-key-management.install
new file mode 100644 (file)
index 0000000..ca63f3d
--- /dev/null
@@ -0,0 +1,3 @@
+etc/mysql/mariadb.conf.d/hashicorp_key_management.cnf
+usr/lib/mysql/plugin/hashicorp_key_management.so
+usr/share/doc/mariadb-plugin-hashicorp-key-management/hashicorp_key_management.txt
diff --git a/mariadb-plugin-mroonga.install b/mariadb-plugin-mroonga.install
new file mode 100644 (file)
index 0000000..fedcf62
--- /dev/null
@@ -0,0 +1,5 @@
+usr/lib/mysql/plugin/ha_mroonga.so
+usr/share/mysql/mroonga/AUTHORS
+usr/share/mysql/mroonga/COPYING
+usr/share/mysql/mroonga/install.sql
+usr/share/mysql/mroonga/uninstall.sql
diff --git a/mariadb-plugin-mroonga.lintian-overrides b/mariadb-plugin-mroonga.lintian-overrides
new file mode 100644 (file)
index 0000000..7c8c1da
--- /dev/null
@@ -0,0 +1,5 @@
+# False positive from Lintian, these strings are nowhere in test in source code
+spelling-error-in-binary nam name [usr/lib/mysql/plugin/ha_mroonga.so]
+spelling-error-in-binary tage stage [usr/lib/mysql/plugin/ha_mroonga.so]
+# Copyright information in debian/copyright, extra file unnecessary
+extra-license-file [usr/share/mysql/mroonga/COPYING]
diff --git a/mariadb-plugin-mroonga.postinst b/mariadb-plugin-mroonga.postinst
new file mode 100644 (file)
index 0000000..a4ac6ca
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+set -e
+
+# Install Mroonga
+mariadb --defaults-file=/etc/mysql/debian.cnf < /usr/share/mysql/mroonga/install.sql || true
+# Always exit with success instead of leaving dpkg in a broken state
+
+
+#DEBHELPER#
diff --git a/mariadb-plugin-mroonga.prerm b/mariadb-plugin-mroonga.prerm
new file mode 100644 (file)
index 0000000..eed4f1a
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+set -e
+
+# Uninstall Mroonga
+mariadb --defaults-file=/etc/mysql/debian.cnf < /usr/share/mysql/mroonga/uninstall.sql || true
+# Always exit with success instead of leaving dpkg in a broken state
+
+
+#DEBHELPER#
diff --git a/mariadb-plugin-oqgraph.install b/mariadb-plugin-oqgraph.install
new file mode 100644 (file)
index 0000000..675b73c
--- /dev/null
@@ -0,0 +1,2 @@
+etc/mysql/mariadb.conf.d/oqgraph.cnf
+usr/lib/mysql/plugin/ha_oqgraph.so
diff --git a/mariadb-plugin-provider-bzip2.install b/mariadb-plugin-provider-bzip2.install
new file mode 100644 (file)
index 0000000..75a73c3
--- /dev/null
@@ -0,0 +1,2 @@
+etc/mysql/mariadb.conf.d/provider_bzip2.cnf
+usr/lib/mysql/plugin/provider_bzip2.so
diff --git a/mariadb-plugin-provider-bzip2.lintian-overrides b/mariadb-plugin-provider-bzip2.lintian-overrides
new file mode 100644 (file)
index 0000000..4729883
--- /dev/null
@@ -0,0 +1,3 @@
+# It's intentional that bzip2 compression plugin doesn't have symbols from libc
+# More info https://jira.mariadb.org/browse/MDEV-28120
+library-not-linked-against-libc [usr/lib/mysql/plugin/provider_bzip2.so]
diff --git a/mariadb-plugin-provider-lz4.install b/mariadb-plugin-provider-lz4.install
new file mode 100644 (file)
index 0000000..a3ba1d7
--- /dev/null
@@ -0,0 +1,2 @@
+etc/mysql/mariadb.conf.d/provider_lz4.cnf
+usr/lib/mysql/plugin/provider_lz4.so
diff --git a/mariadb-plugin-provider-lz4.lintian-overrides b/mariadb-plugin-provider-lz4.lintian-overrides
new file mode 100644 (file)
index 0000000..dbfde13
--- /dev/null
@@ -0,0 +1,3 @@
+# It's intentional that LZ4 compression plugin doesn't have symbols from libc
+# More info https://jira.mariadb.org/browse/MDEV-28120
+library-not-linked-against-libc [usr/lib/mysql/plugin/provider_lz4.so]
diff --git a/mariadb-plugin-provider-lzma.install b/mariadb-plugin-provider-lzma.install
new file mode 100644 (file)
index 0000000..4a4138b
--- /dev/null
@@ -0,0 +1,2 @@
+etc/mysql/mariadb.conf.d/provider_lzma.cnf
+usr/lib/mysql/plugin/provider_lzma.so
diff --git a/mariadb-plugin-provider-lzma.lintian-overrides b/mariadb-plugin-provider-lzma.lintian-overrides
new file mode 100644 (file)
index 0000000..79f6cb7
--- /dev/null
@@ -0,0 +1,3 @@
+# It's intentional that LZMA compression plugin doesn't have symbols from libc
+# More info https://jira.mariadb.org/browse/MDEV-28120
+library-not-linked-against-libc [usr/lib/mysql/plugin/provider_lzma.so]
diff --git a/mariadb-plugin-provider-lzo.install b/mariadb-plugin-provider-lzo.install
new file mode 100644 (file)
index 0000000..2bf4c09
--- /dev/null
@@ -0,0 +1,2 @@
+etc/mysql/mariadb.conf.d/provider_lzo.cnf
+usr/lib/mysql/plugin/provider_lzo.so
diff --git a/mariadb-plugin-provider-lzo.lintian-overrides b/mariadb-plugin-provider-lzo.lintian-overrides
new file mode 100644 (file)
index 0000000..ccca4e2
--- /dev/null
@@ -0,0 +1,3 @@
+# It's intentional that LZO compression plugin doesn't have symbols from libc
+# More info https://jira.mariadb.org/browse/MDEV-28120
+library-not-linked-against-libc [usr/lib/mysql/plugin/provider_lzo.so]
diff --git a/mariadb-plugin-provider-snappy.install b/mariadb-plugin-provider-snappy.install
new file mode 100644 (file)
index 0000000..26c929c
--- /dev/null
@@ -0,0 +1,2 @@
+etc/mysql/mariadb.conf.d/provider_snappy.cnf
+usr/lib/mysql/plugin/provider_snappy.so
diff --git a/mariadb-plugin-provider-snappy.lintian-overrides b/mariadb-plugin-provider-snappy.lintian-overrides
new file mode 100644 (file)
index 0000000..b62907c
--- /dev/null
@@ -0,0 +1,3 @@
+# It's intentional that Snappy compression plugin doesn't have symbols from libc
+# More info https://jira.mariadb.org/browse/MDEV-28120
+library-not-linked-against-libc [usr/lib/mysql/plugin/provider_snappy.so]
diff --git a/mariadb-plugin-rocksdb.install b/mariadb-plugin-rocksdb.install
new file mode 100644 (file)
index 0000000..67b8026
--- /dev/null
@@ -0,0 +1,8 @@
+etc/mysql/mariadb.conf.d/rocksdb.cnf
+usr/bin/mariadb-ldb
+usr/bin/myrocks_hotbackup
+usr/bin/mysql_ldb
+usr/lib/mysql/plugin/ha_rocksdb.so
+usr/share/man/man1/mariadb-ldb.1
+usr/share/man/man1/myrocks_hotbackup.1
+usr/share/man/man1/mysql_ldb.1
diff --git a/mariadb-plugin-rocksdb.lintian-overrides b/mariadb-plugin-rocksdb.lintian-overrides
new file mode 100644 (file)
index 0000000..9076695
--- /dev/null
@@ -0,0 +1,2 @@
+# Fixed upstream in https://github.com/facebook/rocksdb/pull/6481 but not yet in MariaDB
+spelling-error-in-binary COMMITED COMMITTED [usr/lib/mysql/plugin/ha_rocksdb.so]
diff --git a/mariadb-plugin-s3.install b/mariadb-plugin-s3.install
new file mode 100644 (file)
index 0000000..b951e49
--- /dev/null
@@ -0,0 +1,4 @@
+etc/mysql/mariadb.conf.d/s3.cnf
+usr/bin/aria_s3_copy
+usr/lib/mysql/plugin/ha_s3.so
+usr/share/man/man1/aria_s3_copy.1
diff --git a/mariadb-plugin-spider.install b/mariadb-plugin-spider.install
new file mode 100644 (file)
index 0000000..1ad1361
--- /dev/null
@@ -0,0 +1,2 @@
+etc/mysql/mariadb.conf.d/spider.cnf
+usr/lib/mysql/plugin/ha_spider.so
diff --git a/mariadb-server-core.install b/mariadb-server-core.install
new file mode 100644 (file)
index 0000000..b90cb0a
--- /dev/null
@@ -0,0 +1,52 @@
+usr/bin/innochecksum
+usr/bin/mariadb-install-db
+usr/bin/mariadb-upgrade
+usr/bin/mysql_install_db
+usr/bin/mysql_upgrade
+usr/bin/resolveip
+usr/sbin/mariadbd
+usr/sbin/mysqld
+usr/share/man/man1/innochecksum.1
+usr/share/man/man1/mariadb-install-db.1
+usr/share/man/man1/mariadb-upgrade.1
+usr/share/man/man1/mysql_install_db.1
+usr/share/man/man1/mysql_upgrade.1
+usr/share/man/man1/resolveip.1
+usr/share/man/man8/mariadbd.8
+usr/share/man/man8/mysqld.8
+usr/share/mysql/bulgarian
+usr/share/mysql/charsets
+usr/share/mysql/chinese
+usr/share/mysql/czech
+usr/share/mysql/danish
+usr/share/mysql/dutch
+usr/share/mysql/english
+usr/share/mysql/estonian
+usr/share/mysql/fill_help_tables.sql
+usr/share/mysql/french
+usr/share/mysql/georgian
+usr/share/mysql/german
+usr/share/mysql/greek
+usr/share/mysql/hindi
+usr/share/mysql/hungarian
+usr/share/mysql/italian
+usr/share/mysql/japanese
+usr/share/mysql/korean
+usr/share/mysql/maria_add_gis_sp_bootstrap.sql
+usr/share/mysql/mysql_performance_tables.sql
+usr/share/mysql/mysql_sys_schema.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/mysql_test_db.sql
+usr/share/mysql/norwegian
+usr/share/mysql/norwegian-ny
+usr/share/mysql/polish
+usr/share/mysql/portuguese
+usr/share/mysql/romanian
+usr/share/mysql/russian
+usr/share/mysql/serbian
+usr/share/mysql/slovak
+usr/share/mysql/spanish
+usr/share/mysql/swedish
+usr/share/mysql/ukrainian
diff --git a/mariadb-server-core.links b/mariadb-server-core.links
new file mode 100644 (file)
index 0000000..c2be98f
--- /dev/null
@@ -0,0 +1,3 @@
+usr/bin/mariadb-install-db usr/bin/mysql_install_db
+usr/bin/mariadb-upgrade usr/bin/mysql_upgrade
+usr/sbin/mariadbd usr/sbin/mysqld
diff --git a/mariadb-server-core.lintian-overrides b/mariadb-server-core.lintian-overrides
new file mode 100644 (file)
index 0000000..8d99927
--- /dev/null
@@ -0,0 +1,10 @@
+# MyISAM stopwords that cannot be changed and spelling errors remain
+spelling-error-in-binary noone no one [usr/sbin/mariadbd]
+spelling-error-in-binary thats that's [usr/sbin/mariadbd]
+spelling-error-in-binary theres there's [usr/sbin/mariadbd]
+# False positive from Lintian, these strings are nowhere in test in source code
+spelling-error-in-binary AfE Safe [usr/sbin/mariadbd]
+# Valid reason for extra documentation in context in directory
+package-contains-documentation-outside-usr-share-doc [usr/share/mysql/charsets/README]
+# Man syntax needs to be fixed upstream
+groff-message troff:<standard input>:*: warning: macro 'an-trap' not defined [usr/share/man/*]
diff --git a/mariadb-server.NEWS b/mariadb-server.NEWS
new file mode 100644 (file)
index 0000000..bdc1623
--- /dev/null
@@ -0,0 +1,227 @@
+mariadb (1:10.11.2-1) unstable; urgency=medium
+
+  MariaDB 10.11.2 was released on February 16th 2023 by the MariaDB Foundation
+  (https://mariadb.org/mariadb-10-11-2-ga-now-available/). This is the first
+  release in the 10.11 series to be announced GA (general availability). The
+  10.11 series has long-term support with commitment from the MariaDB Foundation
+  (https://mariadb.org/about/#maintenance-policy) to publish maintenance
+  versions with fixes to software defects and security vulnerabilities until
+  February 2028.
+
+  The previous major releases (10.7, 10.8, 10.9, 10.10) were not long-terms
+  supported versions and thus not imported to Debian. To learn what is new in
+  10.11 it is recommended to read all the release notes:
+
+  * https://mariadb.com/kb/en/changes-improvements-in-mariadb-1011/
+  * https://mariadb.com/kb/en/changes-improvements-in-mariadb-1010/
+  * https://mariadb.com/kb/en/changes-improvements-in-mariadb-109/
+  * https://mariadb.com/kb/en/changes-improvements-in-mariadb-108/
+  * https://mariadb.com/kb/en/changes-improvements-in-mariadb-107/
+
+  Notable new features:
+  - New datatypes UUID and INET4
+  - New functions SFORMAT (text formatting), NATURAL_SORT_KEY, RANDOM_BYTES and
+    several related to JSON
+  - New keyword AUTO in system versioned tables for partitioning
+    (https://mariadb.com/kb/en/system-versioned-tables/#automatically-creating-partitions)
+  - Unicode Collation Algorithm (UCA) upgrade to 14.0.0
+  - New privileges 'READ ONLY ADMIN' and 'GRANT TO PUBLIC'
+    (https://mariadb.org/grant-to-public-in-mariadb/)
+  - password_reuse_check plugin (part of mariadb-server package)
+  - Hashicorp Key Management Plugin for implementing encryption using keys
+    stored in the Hashicorp Vault KMS (mariadb-plugin-hashicorp-key-management
+    package)
+
+  Important packaging change: Compression libraries have been split into
+  separate packages named mariadb-provider-plugin-(bzip2/lz4/lzma/lzo/snappy).
+  If a non-zlib compression algorithm was used in InnoDB or Mroonga before
+  upgrading to 10.11, those tables will be unreadable until the appropriate
+  compression library is installed.
+
+  Things to consider when upgrading from 10.6 to 10.11 are listed on the page
+  https://mariadb.com/kb/en/upgrading-from-mariadb-10-6-to-mariadb-10-11/.
+
+  New server variables in 10.11 (compared to 10.6):
+  - binlog-alter-two-phase: When set, split ALTER at binary logging into 2
+    statements: START ALTER and COMMIT/ROLLBACK ALTER. Defaults to 'FALSE'.
+  - innodb-log-file-buffering: Whether the file system cache for ib_logfile0 is
+    enabled
+  - optimizer-extra-pruning-depth: If the optimizer needs to enumerate join
+    prefix of this size or larger, then it will try aggressively prune away the
+    search space.
+  - log-slow-min-examined-row-limit: Don't write queries to slow log that
+    examine fewer rows than that
+  - log-slow-query: Log slow queries to a table or log file. Defaults logging to
+    a file 'hostname'-slow.log or a table mysql.slow_log if --log-output=TABLE
+    is used. Must be enabled to activate other slow log options.
+  - log-slow-query-file: Log slow queries to given log file. Defaults logging to
+    'hostname'-slow.log. Must be enabled to activate other slow log options
+  - log-slow-query-time: Log all queries that have taken more than
+    log_slow_query_time seconds to execute to the slow query log file. The
+    argument will be treated as a decimal value with microsecond precision
+  - slave-max-statement-time: A query that has taken more than
+    slave_max_statement_time seconds to run on the slave will be aborted. The
+    argument will be treated as a decimal value with microsecond precision. A
+    value of 0 (default) means no timeout
+  - system-versioning-insert-history: Allows direct inserts into ROW_START and
+    ROW_END columns if secure_timestamp allows changing @@timestamp
+  - wsrep-allowlist: Allowed IP addresses split by comma delimiter
+  - wsrep-status-file: wsrep status output filename
+
+  Changed behavior in server variables in 10.11 (compared to 10.6):
+  - explicit-defaults-for-timestamp: enabled by default
+  - optimizer-prune-level: defaults to 2 (instead of 1)
+  - old-mode: new options IGNORE_INDEX_ONLY_FOR_JOIN and COMPAT_5_1_CHECKSUM
+  - wsrep-mode: new option BF_ABORT_MARIABACKUP
+  - read-only: changing value requires 'READ ONLY ADMIN' privilege
+
+  One of the most important performance related server variables
+  'innodb_log_file_size' is now dynamic so it can be changed without having to
+  restart the server.
+
+  Removed in 10.11 (compared to 10.6):
+  - innodb-log-write-ahead-size: the physical block size of the underlying
+    storage is instead detected and used
+  - wsrep-replicate-myisam: use wsrep_mode instead
+  - wsrep-strict-ddl: use wsrep_mode instead
+
+  Deprecated server variables:
+  - innodb_change_buffering
+  - innodb-buffer-pool-chunk-size: defaults to 0 (instead of 134217728) in
+    server variables because the server automatically sizes it
+  - keep_files_on_create: orphan files are now deleted automatically, so this
+    setting should never be needed
+
+  Note also that the MariaDB client settings have changed to now use SSL/TLS
+  by default.
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 16 Feb 2023 23:53:02 -0800
+
+mariadb (1:10.11.1-1) unstable; urgency=medium
+
+  Version suffixed packages (e.g. mariadb-server-10.6) have now been deprecated
+  as it made maintenance complicated and there was no known use cases or users
+  of the naming scheme, as multiple different major version MariaDB server
+  packages could not be co-installed anyway and source or the 'mariadb-server'
+  and 'mariadb-client' packages is easiest controlled by repositories and
+  package versioning, not versions in package *names*.
+
+ -- Otto Kekäläinen <otto@debian.org>  Mon, 02 Jan 2023 23:42:58 -0800
+
+mariadb-10.6 (1:10.6.4-1) unstable; urgency=medium
+
+  Import new upstream release MariaDB 10.6.4
+  - 10.6 introduces one new status variable:
+    * Innodb_buffer_pool_pages_lru_freed
+      (https://mariadb.com/kb/en/status-variables-added-in-mariadb-106/)
+    * Resultset_metadata_skipped
+      (undocumented upstream https://mariadb.com/docs/reference/mdb/status-variables/Resultset_metadata_skipped/)
+
+    Read more at https://mariadb.com/kb/en/status-variables-added-in-mariadb-106/
+
+  - 10.6 introduces several new server variables:
+    * binlog_expire_logs_seconds
+    * innodb_deadlock_report
+    * innodb_read_only_compressed
+
+    Read more at https://mariadb.com/kb/en/system-variables-added-in-mariadb-106/
+
+  - 10.6 removes several server variables:
+    * innodb_adaptive_max_sleep_delay
+    * innodb_background_scrub_data_*
+    * innodb_buffer_pool_instances
+    * innodb_commit_concurrency
+    * innodb_concurrency_tickets
+    * innodb_file_format
+    * innodb_large_prefix
+    * innodb_lock_schedule_algorithm
+    * innodb_log_checksums
+    * innodb_log_compressed_pages
+    * innodb_log_files_in_group
+    * innodb_log_optimize_ddl
+    * innodb_page_cleaners
+    * innodb_replication_delay (*not* related to https://mariadb.com/kb/en/delayed-replication/)
+    * innodb_scrub_*
+    * innodb_sync_array_size
+    * innodb_thread_*
+    * innodb_undo_logs
+
+    Read more at https://mariadb.com/kb/en/upgrading-from-mariadb-105-to-mariadb-106/#options-that-have-been-removed-or-renamed
+
+  - 10.6 introduces new default server variable values:
+    * character sets utf8 -> utf8mb3
+    * innodb_flush_method fsync -> O_DIRECT
+    * innodb_use_native_aio ON -> OFF
+    * old_mode (none) -> UTF8_IS_UTF8MB3
+
+  - 10.6 introduces new 'sys' database and several 'sys' procedures
+
+    Read more at https://mariadb.com/kb/en/sys-schema/
+
+  - Read more about above changes at
+    https://mariadb.com/kb/en/upgrading-from-mariadb-105-to-mariadb-106/
+    https://mariadb.com/kb/en/changes-improvements-in-mariadb-106/
+
+  - Update libmariadb folder to match the one in MariaDB 10.6.4
+    (MariaDB Connector C 10.6.4)
+
+ -- Otto Kekäläinen <otto@debian.org>  Mon, 06 Sep 2021 22:55:39 -0700
+
+mariadb-10.5 (1:10.5.5-1) unstable; urgency=medium
+
+   The latest version 10.5 of the MariaDB Server came out in June 2020 and is
+   guaranteed to have security releases at least until summer 2025.
+
+   For more information on what is new in MariaDB 10.5 check out:
+   https://speakerdeck.com/ottok/debconf-2020-whats-new-in-mariadb-server-10-dot-5-and-galera-4
+   or video from https://peertube.debian.social/videos/watch/bb80cf53-d9ba-4ed9-b472-a21238fb67f5.
+
+   Quick summary:
+   - Service name is now 'mariadb', e.g. /etc/init.d/mariadb and systemctl mariadb
+   - The main server binary is now running as 'mariadbd' instead of old 'mysqld'
+   - Many commands are now mariadb-* instead of old mysql*, but old names
+     continue to work as symlinks
+   - Referencing the /etc/mysql/debian.cnf file is not advised anymore. It will
+     be deprecated in a future Debian release and has been obsolete anyway for
+     several years now since MariaDB in Debian introduced Unix socket
+     authentication for the root account in 2015.
+
+   MariaDB 10.5 has been tested to be backwards compatible with all previous
+   versions of MariaDB and all previous versions of MySQL up until version 5.7.
+   Note that MySQL 8.0 introduces significant backwards incompatible changes
+   compared to MySQL 5.7, and thus in-place binary upgrades from MySQL 8.0 to
+   MariaDB 10.5 are not possible, but sysadmins need to upgrade by exporting and
+   importing SQL dumps of their databases.
+
+   If you encounter any bugs, please make sure your bug report is of highest
+   standards so we can quickly reproduce and fix the issue. Even better if you
+   find the solution yourself, and can submit it as a Merge Request at
+   https://salsa.debian.org/mariadb-team/mariadb-10.5/
+
+   If you appreciate the Debian packaging work done, please star us on Salsa!
+
+ -- Otto Kekäläinen <otto@debian.org>  Thu, 17 Sep 2020 14:37:47 +0300
+
+mariadb-10.1 (10.1.20-1) unstable; urgency=low
+
+    MariaDB is now the default MySQL variant in Debian, at version 10.1. The
+    Stretch release introduces a new mechanism for switching the default
+    variant, using metapackages created from the 'mysql-defaults' source
+    package. For example, installing the metapackage 'default-mysql-server' will
+    install 'mariadb-server-10.1'. Users who had 'mysql-server-5.5' or
+    'mysql-server-5.6' will have it removed and replaced by the MariaDB
+    equivalent. Similarly, installing 'default-mysql-client' will install
+    'mariadb-client-10.1'.
+
+    Note that the database binary data file formats are not backwards
+    compatible, so once you have upgraded to MariaDB 10.1 you will not be able
+    to switch back to any previous version of MariaDB or MySQL unless you have a
+    proper database dump. Therefore, before upgrading, please make backups of
+    all important databases with an appropriate tool such as 'mysqldump'.
+
+    The 'virtual-mysql-*' and 'default-mysql-*' packages will continue to exist.
+    MySQL continues to be maintained in Debian, in the unstable release. See the
+    page https://wiki.debian.org/Teams/MySQL more information about the
+    mysql-related software available in Debian.
+
+ -- Otto Kekäläinen <otto@debian.org>  Tue, 14 Mar 2017 16:21:58 +0200
diff --git a/mariadb-server.README.Debian b/mariadb-server.README.Debian
new file mode 100644 (file)
index 0000000..6042249
--- /dev/null
@@ -0,0 +1,204 @@
+* MYSQL WON'T START OR STOP?
+============================
+
+The most common reasons the server does not start are:
+- AppArmor is enforced and something is wrong with the confinement profile.
+- Process supervisor scripts (init, systemd etc) fail to execute normally.
+- The configuration in /etc/mysql/... is wrong and prevents server from running.
+
+First check the contents of syslog (or systemd journal) and then check the
+logs at /var/log/mysql/ for any hints of what might be wrong.
+
+Examples:
+  grep mysql /var/log/syslog
+  journalctl -u mariadb
+
+
+* NEW SERVICE NAME, PROCESS AND BINARY NAMES IN MARIADB 10.5
+============================================================
+
+Starting form MariaDB 10.5, the default SysV init service name is 'mariadb',
+and can be accessed at path /etc/init.d/mariadb. The alias 'mysql' is only
+created on upgrades.
+
+On systemd services both 'mariadb' and alias 'mysql' are available all the time.
+
+Note that the new daemon name is 'mariadbd' instead of 'mysqld' and also most
+of the binaries have been renamed to mariadb-something, yet the old mysql-something
+name has been kept as a symbolic link to the new name for backwards compatibility.
+
+
+* NATIVE SYSTEMD SERVICE INTRODUCED IN MARIADB 10.1
+===================================================
+
+From MariaDB 10.1 onward the upstream mariadb.service and mariadb@.service are
+used to provide the full systemd experience. Some features available in
+traditional /etc/init.d/mysql have been changed. For details see
+https://mariadb.com/kb/en/mariadb/systemd/
+
+
+* MIXING PACKAGES FROM MARIADB.ORG AND OFFICIAL DEBIAN REPOSITORIES
+==================================================================
+
+Please note that the MariaDB packaging in official Debian repositories are of
+a completely new generation compared to the legacy packaging used in MariaDB.org
+repositories. You cannot mix and match MariaDB 10.1 packages from official
+Debian (or Ubuntu) repositories with packages from MariaDB.org repositories.
+Packages from the MariaDB.org repositories include the revision string '+maria'.
+
+If a MariaDB.org repository is enabled, learn to use apt pinning properly.
+
+Please do not file bugs in Debian regarding packages with '+maria' in the
+revision string.
+
+
+* ROOT USER AUTHENTICATION VIA UNIX SOCKET
+==========================================
+
+On new installs no root password is set and no debian-sys-maint user is
+created anymore. Instead the MariaDB root account is set to be authenticated
+using the Unix socket, e.g. any mysqld invocation by root or via sudo will
+let the user see the mysqld prompt.
+
+You may never ever delete the mysql user "root". Although it has no password
+is set, the unix_auth plugin ensure that it can only be run locally as the root
+user.
+
+The credentials in /etc/mysql/debian.cnf specify the user which is used by the
+init scripts to stop the server and perform log rotation. This used to be the
+debian-sys-maint user which is no longer used as root can run directly.
+
+If you have start/stop problems make sure that the /etc/mysql/debian.cnf file
+specifies the root user and no password. In the long run please stop using that
+file as is has been obsoleted.
+
+
+* MARIADB IS SECURE BY DEFAULT
+==============================
+
+MariaDB in Debian is secure by default, because:
+
+- It only listens to the localhost socket and cannot be accessed remotely unless
+  the sysadmin changes the configuration in /etc/mysql to allow so.
+- There is no debian-sys-maint with password in /etc/mysql/debian.cnf anymore.
+- There is no root account with password anymore. The system admin needs to
+  create one themselves if they need it. With no password, all issues related
+  to password management and password leaking are gone. Sysadmins can access
+  the database without a password simply by running 'sudo mysql' thanks to
+  socket based authentication, which detects the system root user and allows
+  them to use the mysqld console as the mysql root user. For details see
+  https://www.slideshare.net/ottokekalainen/less-passwords-more-security-unix-socket-authentication-and-other-mariadb-hardening-tips
+- There is no test database nor test accounts in the out-of-the-box Debian
+  installation.
+
+Therefore there is also no need to run the 'mysql_secure_installation'. In fact
+that script will try to do things that are already prevented, and might fail.
+
+
+* WHAT TO DO AFTER UPGRADES
+===========================
+
+The privilege tables are automatically updated so all there is left is read
+the release notes on https://mariadb.com/kb/en/release-notes/ to see if any
+changes affect custom apps.
+
+There should not be any need to run 'mysql_upgrade' manually, as the upgrade
+scripts do that automatically.
+
+
+* 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.
+
+There should not be any need to run 'mysql_install_db' manually, as the install
+scripts do that automatically.
+
+The only thing that is left over for the admin is
+ - creating new users and databases
+ - read the rest of this text
+
+
+* 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 check your firewall rules or network routes.
+
+* WHERE IS THE DOCUMENTATION?
+=============================
+
+https://mariadb.com/kb
+
+
+* PASSWORDS
+===========
+
+It is recommended you create additional admin users for your database
+administration needs in addition to the default root user.
+
+If your local Unix account is the one you want to have local super user
+access on your database with you can create the following account that will
+only work for the local Unix user connecting to the database locally.
+
+  sudo /usr/bin/mysql -e "GRANT ALL ON *.* TO '$USER'@'localhost' IDENTIFIED VIA unix_socket WITH GRANT OPTION"
+
+To create a local machine account username=USERNAME with a password:
+
+  sudo /usr/bin/mysql -e "GRANT ALL ON *.* TO 'USERNAME'@'localhost' IDENTIFIED BY 'password' WITH GRANT OPTION"
+
+To create a USERNAME user with password 'password' admin user that can access
+the DB server over the network:
+
+  sudo /usr/bin/mysql -e "GRANT ALL ON *.* TO 'USERNAME'@'%' IDENTIFIED BY 'password' WITH GRANT OPTION"
+
+Scripts should run as a user who have the required grants and be identified via unix_socket.
+
+It is wise to run scripts as the "mysql" system user. Like root,
+mysql@localhost is created by default to have all privileges in MariaDB
+and to use unix_socket authentication. But scripts running under "mysql"
+won't have system-wide root so they won't be able to corrupt your system.
+
+If you are too tired to type the password in every time and unix_socket auth
+doesn't suit your needs, you can store it in the file $HOME/.my.cnf. It should
+be chmod 0600 (-rw------- username usergroup .my.cnf) to ensure that nobody else
+can read it.  Every other configuration parameter can be stored there, too.
+
+For more information in the MariaDB manual in/usr/share/doc/mariadb-doc or
+https://mariadb.com/kb/en/configuring-mariadb-with-mycnf/.
+
+
+* 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 file system 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.
+
+
+* DOWNGRADING
+=============
+
+Unsupported. Period.
+
+You might get lucky downgrading a few minor versions without issued. Take a
+backup first. If you break it you get to keep both pieces. Do a restore from
+backup or upgrade to the previous version.
+
+If doing a major version downgrade, take a mysqldump/maria-backup consistent
+backup using the current version and reload after downgrading and purging
+existing databases.
+
+
+* BACKUPS
+=========
+
+Backups save jobs. Don't get caught without one.
diff --git a/mariadb-server.config b/mariadb-server.config
new file mode 100644 (file)
index 0000000..9913c33
--- /dev/null
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+set -e
+
+# shellcheck source=/dev/null
+. /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}
+
+# Beware that there are two ypwhich one of them needs the 2>/dev/null!
+if test -n "$(command -v ypwhich 2>/dev/null)" && ypwhich > /dev/null 2>&1
+then
+  db_input high mariadb-server/nis_warning || true
+  db_go
+fi
diff --git a/mariadb-server.insserv.conf b/mariadb-server.insserv.conf
new file mode 100644 (file)
index 0000000..cb29a54
--- /dev/null
@@ -0,0 +1 @@
+$database      mysql
diff --git a/mariadb-server.install b/mariadb-server.install
new file mode 100755 (executable)
index 0000000..94fa75e
--- /dev/null
@@ -0,0 +1,102 @@
+#!/usr/bin/dh-exec
+debian/additions/debian-start etc/mysql
+debian/additions/debian-start.inc.sh usr/share/mysql
+debian/additions/echo_stderr usr/share/mysql
+debian/additions/mariadb.conf.d/50-mysqld_safe.cnf etc/mysql/mariadb.conf.d
+debian/additions/mariadb.conf.d/50-server.cnf etc/mysql/mariadb.conf.d
+debian/additions/source_mariadb.py usr/share/apport/package-hooks
+etc/apparmor.d/usr.sbin.mariadbd
+etc/logrotate.d/mariadb
+etc/security/user_map.conf
+usr/lib/*/security/pam_user_map.so
+[linux-any] usr/lib/systemd/system/mariadb-extra.socket
+[linux-any] usr/lib/systemd/system/mariadb-extra@.socket
+[linux-any] usr/lib/systemd/system/mariadb.service
+[linux-any] usr/lib/systemd/system/mariadb@.service
+[linux-any] usr/lib/systemd/system/mariadb.socket
+[linux-any] usr/lib/systemd/system/mariadb@.socket
+[linux-any] usr/lib/systemd/system/mariadb@bootstrap.service.d/use_galera_new_cluster.conf
+[linux-any] usr/lib/systemd/system/mysql.service
+[linux-any] usr/lib/systemd/system/mysqld.service
+usr/bin/aria_chk
+usr/bin/aria_dump_log
+usr/bin/aria_ftdump
+usr/bin/aria_pack
+usr/bin/aria_read_log
+[linux-any] usr/bin/galera_new_cluster
+[linux-any] usr/bin/galera_recovery
+[linux-any] usr/bin/mariadb-service-convert
+usr/bin/mariadbd-multi
+usr/bin/mariadbd-safe
+usr/bin/mariadbd-safe-helper
+usr/bin/myisam_ftdump
+usr/bin/myisamchk
+usr/bin/myisamlog
+usr/bin/myisampack
+usr/bin/mysql_convert_table_format
+usr/bin/mysql_plugin
+usr/bin/mysql_secure_installation
+usr/bin/mysql_setpermission
+usr/bin/mysql_tzinfo_to_sql
+usr/bin/mysqlbinlog
+usr/bin/mysqld_multi
+usr/bin/mysqld_safe
+usr/bin/mysqld_safe_helper
+usr/bin/mysqlhotcopy
+usr/bin/wsrep_sst_common
+usr/bin/wsrep_sst_backup
+usr/bin/wsrep_sst_mariabackup
+usr/bin/wsrep_sst_mysqldump
+usr/bin/wsrep_sst_rsync
+usr/bin/wsrep_sst_rsync_wan
+usr/lib/mysql/plugin/auth_ed25519.so
+usr/lib/mysql/plugin/auth_pam.so
+usr/lib/mysql/plugin/auth_pam_tool_dir/auth_pam_tool
+usr/lib/mysql/plugin/auth_pam_v1.so
+[linux-any] usr/lib/mysql/plugin/disks.so
+usr/lib/mysql/plugin/file_key_management.so
+usr/lib/mysql/plugin/ha_archive.so
+usr/lib/mysql/plugin/ha_blackhole.so
+usr/lib/mysql/plugin/ha_federated.so
+usr/lib/mysql/plugin/ha_federatedx.so
+usr/lib/mysql/plugin/ha_sphinx.so
+usr/lib/mysql/plugin/handlersocket.so
+usr/lib/mysql/plugin/locales.so
+usr/lib/mysql/plugin/metadata_lock_info.so
+usr/lib/mysql/plugin/password_reuse_check.so
+usr/lib/mysql/plugin/query_cache_info.so
+usr/lib/mysql/plugin/query_response_time.so
+usr/lib/mysql/plugin/server_audit.so
+usr/lib/mysql/plugin/simple_password_check.so
+usr/lib/mysql/plugin/sql_errlog.so
+usr/lib/mysql/plugin/type_mysql_json.so
+usr/lib/mysql/plugin/wsrep_info.so
+usr/share/doc/mariadb-server/mariadbd.sym.gz
+usr/share/man/man1/aria_chk.1
+usr/share/man/man1/aria_dump_log.1
+usr/share/man/man1/aria_ftdump.1
+usr/share/man/man1/aria_pack.1
+usr/share/man/man1/aria_read_log.1
+[linux-any] usr/share/man/man1/galera_new_cluster.1
+[linux-any] usr/share/man/man1/galera_recovery.1
+[linux-any] usr/share/man/man1/mariadb-service-convert.1
+usr/share/man/man1/mariadbd-multi.1
+usr/share/man/man1/mariadbd-safe-helper.1
+usr/share/man/man1/mariadbd-safe.1
+usr/share/man/man1/myisam_ftdump.1
+usr/share/man/man1/myisamchk.1
+usr/share/man/man1/myisamlog.1
+usr/share/man/man1/myisampack.1
+usr/share/man/man1/mysqld_multi.1
+usr/share/man/man1/mysqld_safe.1
+usr/share/man/man1/wsrep_sst_backup.1
+usr/share/man/man1/mysqld_safe_helper.1
+usr/share/man/man1/wsrep_sst_common.1
+usr/share/man/man1/wsrep_sst_mariabackup.1
+usr/share/man/man1/wsrep_sst_mysqldump.1
+usr/share/man/man1/wsrep_sst_rsync.1
+usr/share/man/man1/wsrep_sst_rsync_wan.1
+usr/share/mysql/errmsg-utf8.txt
+usr/share/mysql/mini-benchmark
+usr/share/mysql/wsrep.cnf
+usr/share/mysql/wsrep_notify
diff --git a/mariadb-server.links b/mariadb-server.links
new file mode 100644 (file)
index 0000000..9cc3a43
--- /dev/null
@@ -0,0 +1,10 @@
+usr/bin/mariadb-binlog usr/bin/mysqlbinlog
+usr/bin/mariadb-convert-table-format usr/bin/mysql_convert_table_format
+usr/bin/mariadb-hotcopy usr/bin/mysqlhotcopy
+usr/bin/mariadb-plugin usr/bin/mysql_plugin
+usr/bin/mariadb-secure-installation usr/bin/mysql_secure_installation
+usr/bin/mariadb-setpermission usr/bin/mysql_setpermission
+usr/bin/mariadb-tzinfo-to-sql usr/bin/mysql_tzinfo_to_sql
+usr/bin/mariadbd-multi usr/bin/mysqld_multi
+usr/bin/mariadbd-safe usr/bin/mysqld_safe
+usr/bin/mariadbd-safe-helper usr/bin/mysqld_safe_helper
diff --git a/mariadb-server.lintian-overrides b/mariadb-server.lintian-overrides
new file mode 100644 (file)
index 0000000..587b983
--- /dev/null
@@ -0,0 +1,24 @@
+# False positive in Lintian, template is actually used
+unused-debconf-template mariadb-server/old_data_directory_saved [templates:2]
+# MyISAM stopwords that cannot be changed and spelling errors remain
+spelling-error-in-binary noone no one [usr/bin/*]
+spelling-error-in-binary thats that's [usr/bin/*]
+spelling-error-in-binary theres there's [usr/bin/*]
+# False positive from Lintian, these strings are nowhere in test in source code
+spelling-error-in-binary AfE Safe [usr/bin/*]
+# Intentional in-context documentation
+package-contains-documentation-outside-usr-share-doc [usr/share/mysql/errmsg-utf8.txt]
+# Man syntax needs to be fixed upstream
+groff-message troff:<standard input>:*: warning: macro 'an-trap' not defined [usr/share/man/*]
+# Most likely false positive
+hardening-no-fortify-functions [usr/lib/mysql/plugin/auth_pam_v1.so]
+hardening-no-fortify-functions [usr/lib/mysql/plugin/auth_pam.so]
+hardening-no-fortify-functions [usr/lib/mysql/plugin/file_key_management.so]
+hardening-no-fortify-functions [usr/lib/mysql/plugin/ha_archive.so]
+hardening-no-fortify-functions [usr/lib/mysql/plugin/ha_blackhole.so]
+hardening-no-fortify-functions [usr/lib/x86_64-linux-gnu/security/pam_user_map.so]
+# Special purpose executable to implement custom system permissions
+executable-in-usr-lib [usr/lib/mysql/plugin/auth_pam_tool_dir/auth_pam_tool]
+# Intentional to handle upgrades from versioned package names to versionless
+# (e.g. mariadb-server-10.5 -> mariadb-server)
+uses-dpkg-database-directly [postinst]
diff --git a/mariadb-server.logcheck.ignore.paranoid b/mariadb-server.logcheck.ignore.paranoid
new file mode 100644 (file)
index 0000000..407d406
--- /dev/null
@@ -0,0 +1,9 @@
+/etc/init.d/mariadb\[[0-9]+\]: Check that mariadbd is running and that the socket: '/run/mysqld/mysqld.sock' exists\!$
+/etc/init.d/mariadb\[[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\.$
+mariadbd\[[0-9]+\]: $
+mariadbd\[[0-9]+\]: Version: .* socket: '/run/mysqld/mysqld.sock'  port: 3306$
+mariadbd\[[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/mariadb-server.logcheck.ignore.server b/mariadb-server.logcheck.ignore.server
new file mode 100644 (file)
index 0000000..7db321a
--- /dev/null
@@ -0,0 +1,30 @@
+/etc/init.d/mariadb\[[0-9]+\]: [0-9]+ processes alive and '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$
+/etc/init.d/mariadb\[[0-9]+\]: Check that mariadbd is running and that the socket: '/run/mysqld/mysqld.sock' exists\!$
+/etc/init.d/mariadb\[[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\.$
+mariadbd\[[0-9]+\]: ?$
+mariadbd\[[0-9]+\]: .*InnoDB: Shutdown completed
+mariadbd\[[0-9]+\]: .*InnoDB: Started;
+mariadbd\[[0-9]+\]: .*InnoDB: Starting shutdown\.\.\.$
+mariadbd\[[0-9]+\]: .*\[Note\] /usr/sbin/mariadbd: Normal shutdown$
+mariadbd\[[0-9]+\]: .*\[Note\] /usr/sbin/mariadbd: ready for connections\.$
+mariadbd\[[0-9]+\]: .*\[Note\] /usr/sbin/mariadbd: Shutdown complete$
+mariadbd\[[0-9]+\]: /usr/sbin/mariadbd: ready for connections\.$
+mariadbd\[[0-9]+\]: .*/usr/sbin/mariadbd: Shutdown Complete$
+mariadbd\[[0-9]+\]: Version: .* socket
+mariadbd\[[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]+\]: 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 at https://jira.mariadb.org$
+mysqld_safe\[[0-9]+\]: See the manual for more instructions.$
+mysqld_safe\[[0-9]+\]: started$
+mysqld_safe\[[0-9]+\]: The latest information about MariaDB is available 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/mariadb-server.logcheck.ignore.workstation b/mariadb-server.logcheck.ignore.workstation
new file mode 100644 (file)
index 0000000..7db321a
--- /dev/null
@@ -0,0 +1,30 @@
+/etc/init.d/mariadb\[[0-9]+\]: [0-9]+ processes alive and '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$
+/etc/init.d/mariadb\[[0-9]+\]: Check that mariadbd is running and that the socket: '/run/mysqld/mysqld.sock' exists\!$
+/etc/init.d/mariadb\[[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\.$
+mariadbd\[[0-9]+\]: ?$
+mariadbd\[[0-9]+\]: .*InnoDB: Shutdown completed
+mariadbd\[[0-9]+\]: .*InnoDB: Started;
+mariadbd\[[0-9]+\]: .*InnoDB: Starting shutdown\.\.\.$
+mariadbd\[[0-9]+\]: .*\[Note\] /usr/sbin/mariadbd: Normal shutdown$
+mariadbd\[[0-9]+\]: .*\[Note\] /usr/sbin/mariadbd: ready for connections\.$
+mariadbd\[[0-9]+\]: .*\[Note\] /usr/sbin/mariadbd: Shutdown complete$
+mariadbd\[[0-9]+\]: /usr/sbin/mariadbd: ready for connections\.$
+mariadbd\[[0-9]+\]: .*/usr/sbin/mariadbd: Shutdown Complete$
+mariadbd\[[0-9]+\]: Version: .* socket
+mariadbd\[[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]+\]: 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 at https://jira.mariadb.org$
+mysqld_safe\[[0-9]+\]: See the manual for more instructions.$
+mysqld_safe\[[0-9]+\]: started$
+mysqld_safe\[[0-9]+\]: The latest information about MariaDB is available 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/mariadb-server.mariadb.init b/mariadb-server.mariadb.init
new file mode 100644 (file)
index 0000000..6f44c7c
--- /dev/null
@@ -0,0 +1,298 @@
+#!/bin/bash
+#
+### BEGIN INIT INFO
+# Provides:          mariadb
+# Required-Start:    $remote_fs $syslog
+# Required-Stop:     $remote_fs $syslog
+# Should-Start:      $network $named $time
+# Should-Stop:       $network $named $time
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start and stop the MariaDB database server daemon
+# Description:       Controls the main MariaDB database server daemon "mariadbd"
+#                    and its wrapper script "mysqld_safe".
+### END INIT INFO
+#
+set -e
+set -u
+${DEBIAN_SCRIPT_DEBUG:+ set -v -x}
+
+test -x /usr/sbin/mariadbd || exit 0
+
+# shellcheck source=/dev/null
+. /lib/lsb/init-functions
+
+SELF="$(cd "$(dirname "$0")"; pwd -P)/$(basename "$0")"
+
+if [ -f /usr/bin/mariadb-admin ]
+then
+  MYADMIN="/usr/bin/mariadb-admin --defaults-file=/etc/mysql/debian.cnf"
+elif [ -f /usr/bin/mysqladmin ]
+then
+  MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
+else
+  log_failure_msg "Command mariadb-admin/mysqladmin not found! This SysV init script depends on it."
+  exit 1
+fi
+
+if [ ! -x /usr/bin/mariadbd-safe ]
+then
+  log_failure_msg "/usr/bin/mariadbd-safe not found or executable! This SysV init script depends on it."
+  exit 1
+fi
+
+# priority can be overridden and "-s" adds output to stderr
+ERR_LOGGER="logger -p daemon.err -t /etc/init.d/mariadb -i"
+
+if [ -f /etc/default/mysql ]
+then
+  # shellcheck source=/dev/null
+  . /etc/default/mysql
+fi
+
+# Also source default/mariadb in case the installation was upgraded from
+# packages originally installed from MariaDB.org repositories, which have
+# had support for reading /etc/default/mariadb since March 2016.
+if [ -f /etc/default/mariadb ]
+then
+  # shellcheck source=/dev/null
+  . /etc/default/mariadb
+fi
+
+# Safeguard (relative paths, core dumps..)
+cd /
+umask 077
+
+# mysqladmin likes to read /root/.my.cnf. This is usually not what I want
+# as many admins e.g. only store a password without a username there and
+# so break my scripts.
+export HOME=/etc/mysql/
+
+## Fetch a particular option from mysql's invocation.
+#
+# Usage: void mariadbd_get_param option
+mariadbd_get_param() {
+  /usr/sbin/mariadbd --print-defaults \
+    | tr " " "\n" \
+    | grep -- "--$1" \
+    | tail -n 1 \
+    | cut -d= -f2
+}
+
+## Do some sanity checks before even trying to start mariadbd.
+sanity_checks() {
+  # check for config file
+  if [ ! -r /etc/mysql/my.cnf ]
+  then
+    log_warning_msg "$0: WARNING: /etc/mysql/my.cnf cannot be read. See README.Debian.gz"
+    echo                "WARNING: /etc/mysql/my.cnf cannot be read. See README.Debian.gz" | $ERR_LOGGER
+  fi
+
+  # check for diskspace shortage
+  datadir="$(mariadbd_get_param datadir)"
+
+  # If datadir location is not customized in configuration
+  # then it's not printed with /usr/sbin/mariadbd --print-defaults
+  # and this should fall backt to a sane default value
+  if [ -z "$datadir" ]
+  then
+    datadir="/var/lib/mysql"
+  fi
+
+  # Verify the datadir location exists
+  if [ ! -d "$datadir" ] && [ ! -L "$datadir" ]
+  then
+    log_failure_msg "$0: ERROR: Can't locate MariaDB data location at $datadir"
+    echo                "ERROR: Can't locate MariaDB data location at $datadir" | $ERR_LOGGER
+    exit 1
+  fi
+
+  # As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
+  # 4096 blocks is then lower than 4 MB
+  df_available_blocks="$(LC_ALL=C BLOCKSIZE='' df --output=avail "$datadir" | tail -n 1)"
+  if [ "$df_available_blocks" -lt "4096" ]
+  then
+    log_failure_msg "$0: ERROR: The partition with $datadir is too full!"
+    echo                "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER
+    exit 1
+  fi
+}
+
+## Checks if there is a server running and if so if it is accessible.
+#
+# check_alive insists on a pingable server
+# check_dead also fails if there is a lost mariadbd in the process list
+#
+# Usage: boolean mariadbd_status [check_alive|check_dead] [warn|nowarn]
+mariadbd_status () {
+  ping_output="$($MYADMIN ping 2>&1)"
+  # The whole mariadbd_status function should be rewritten in clean shell script,
+  # so ignore minor Shellcheck nag for now as fixing it would be half of the
+  # rewrite
+  # shellcheck disable=SC2181
+  ping_alive="$(( ! $? ))"
+
+  ps_alive=0
+  pidfile="$(mariadbd_get_param pid-file)"
+  if [ -f "$pidfile" ] && ps "$(cat "$pidfile")" >/dev/null 2>&1
+  then
+    ps_alive=1
+  fi
+
+  # Using '-a' is unstandard, but it works and might be needed for the grouping
+  # of the if-else, so keep it and just ignore in Shellcheck
+  # shellcheck disable=SC2166
+  if [ "$1" = "check_alive"  -a  $ping_alive = 1 ] ||
+     [ "$1" = "check_dead"   -a  $ping_alive = 0  -a  $ps_alive = 0 ]
+  then
+    return 0 # EXIT_SUCCESS
+  else
+    if [ "$2" = "warn" ]
+    then
+      echo -e "$ps_alive processes alive and '$MYADMIN ping' resulted in\n$ping_output\n" | $ERR_LOGGER -p daemon.debug
+    fi
+  return 1 # EXIT_FAILURE
+  fi
+}
+
+#
+# main()
+#
+
+case "${1:-''}" in
+
+  'start')
+  sanity_checks;
+  # Start daemon
+  log_daemon_msg "Starting MariaDB database server" "mariadbd"
+  if mariadbd_status check_alive nowarn
+  then
+   log_progress_msg "already running"
+   log_end_msg 0
+  else
+    # Could be removed during boot
+    test -e /run/mysqld || install -m 755 -o mysql -g root -d /run/mysqld
+
+    # Start MariaDB!
+    /usr/bin/mariadbd-safe "${@:2}" 2>&1 >/dev/null | $ERR_LOGGER &
+
+    for _ in $(seq 1 "${MYSQLD_STARTUP_TIMEOUT:-30}")
+    do
+      sleep 1
+      if mariadbd_status check_alive nowarn
+      then
+        break
+      fi
+      log_progress_msg "."
+    done
+    if mariadbd_status check_alive warn
+    then
+      log_end_msg 0
+      # Now start mysqlcheck or whatever the admin wants.
+      output=$(/etc/mysql/debian-start)
+      if [ -n "$output" ]
+      then
+        log_action_msg "$output"
+      fi
+    else
+      # Try one more time but save error log separately, then spit it out
+      # before logging ends and init script execution ends.
+      if pgrep -ax mariadbd > /dev/null
+      then
+        echo "ERROR: The mariadbd process is running but not responding:"
+        # shellcheck disable=SC2009
+        # Show the mariadbd process and it's parent and next line (if there is a child process)
+        ps faxu | grep mariadbd -C 1
+      else
+        ERROR_LOG_FILE="$(mktemp).err"
+        echo # ensure newline
+        timeout --kill-after=20 10 /usr/bin/mysqld_safe "${@:2}" --log-error="$ERROR_LOG_FILE"
+        echo "Running '/etc/init.d/mariadb start' failed with error log:"
+        cat "$ERROR_LOG_FILE"
+      fi
+
+      log_end_msg 1
+      log_failure_msg "Please take a look at the syslog"
+    fi
+  fi
+  ;;
+
+  'stop')
+  # * As a passwordless mysqladmin (e.g. via ~/.my.cnf) must be possible
+  # at least for cron, we can rely on it here, too. (although we have
+  # to specify it explicit as e.g. sudo environments points to the normal
+  # users home and not /root)
+  log_daemon_msg "Stopping MariaDB database server" "mariadbd"
+  if ! mariadbd_status check_dead nowarn
+  then
+    set +e
+    shutdown_out="$($MYADMIN shutdown 2>&1)"
+    r=$?
+    set -e
+    if [ "$r" -ne 0 ]
+    then
+      log_end_msg 1
+      [ "$VERBOSE" != "no" ] && log_failure_msg "Error: $shutdown_out"
+      log_daemon_msg "Killing MariaDB database server by signal" "mariadbd"
+      killall -15 mariadbd
+      server_down=
+      for _ in {1..600}
+      do
+        sleep 1
+        if mariadbd_status check_dead nowarn
+        then
+          server_down=1
+          break
+        fi
+      done
+      if test -z "$server_down"
+      then
+        killall -9 mariadbd
+      fi
+    fi
+  fi
+
+  if ! mariadbd_status check_dead warn
+  then
+    log_end_msg 1
+    log_failure_msg "Please stop MariaDB manually and read /usr/share/doc/mariadb-server/README.Debian.gz!"
+    exit 1
+  else
+    log_end_msg 0
+  fi
+  ;;
+
+  'restart')
+  set +e; $SELF stop; set -e
+  shift
+  $SELF start "${@}"
+  ;;
+
+  'reload'|'force-reload')
+  log_daemon_msg "Reloading MariaDB database server" "mariadbd"
+  $MYADMIN reload
+  log_end_msg 0
+  ;;
+
+  'status')
+  if mariadbd_status check_alive nowarn
+  then
+    log_action_msg "$($MYADMIN version)"
+  else
+    log_action_msg "MariaDB is stopped."
+    exit 3
+  fi
+  ;;
+
+  'bootstrap')
+  # Bootstrap the cluster, start the first node
+  # that initiates the cluster
+  log_daemon_msg "Bootstrapping the cluster" "mariadbd"
+  $SELF start "${@:2}" --wsrep-new-cluster
+  ;;
+
+  *)
+  echo "Usage: $SELF start|stop|restart|reload|force-reload|status"
+  exit 1
+  ;;
+esac
diff --git a/mariadb-server.mysql.default b/mariadb-server.mysql.default
new file mode 100644 (file)
index 0000000..36079ed
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# NOTE: This file is read only by the traditional SysV init script.
+# Debian 9 and Ubuntu 17.04 onward do not normally read this file as they use
+# systemd by default.
+#
+# For similar behavior, systemd users should override ExecStart by dropping
+# files into /etc/systemd/system/mariadb.service.d/
+#
+# See also:
+# https://wiki.debian.org/Teams/pkg-systemd/Packaging#overriding_options_and_.2Fetc.2Fdefault_handling
+# https://mariadb.com/kb/en/mariadb/systemd/
+#
+# Note also that MariaDB systemd does _not_ utilize mysqld_safe.
+
+# The delay in seconds the init script waits for the server to be up and running after having started "mysqld_safe" to run the "/etc/mysql/debian-start" script.
+# If the server is still not responding after the delay, the script won't be executed and an error will be thrown on the syslog.
+# Default: 30
+#MYSQLD_STARTUP_TIMEOUT=30
+
+# The email recipient(s) of the output of the check for crashed and improperly closed MyISAM and Aria tables done at each server start by the "/etc/mysql/debian-start" script.
+# Default: root
+#MYCHECK_RCPT="root"
diff --git a/mariadb-server.postinst b/mariadb-server.postinst
new file mode 100644 (file)
index 0000000..8273292
--- /dev/null
@@ -0,0 +1,304 @@
+#!/bin/bash
+set -e
+
+# shellcheck source=/dev/null
+. /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 mariadb-server.postinst -i"
+# Specify syslog tag name so it is clear the entry came from this postinst script.
+# This will make an error in a logged command immediately apparent by aborting
+# the install, rather than failing silently and leaving a broken install.
+set -o pipefail
+
+case "$1" in
+  configure)
+    # This is needed because mariadb-install-db removes the pid file in /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 /run.
+    set +e
+    invoke-rc.d mariadb stop
+    set -e
+
+    # An existing /etc/init.d/mysql might be on the system if there was a
+    # previous MySQL or MariaDB installation, since /etc/init.d files are
+    # considered config files and stay around even after the package is removed.
+    #
+    # The install step of this package adds a new /etc/init.d/mariadb file. As
+    # we also want to ensure that there are no old (and potentially outdated)
+    # versions of /etc/init.d/mysql we simply replace it using a copy of the
+    # latest 'mariadb' file. This has also the added benefit that anything that
+    # invokes traditional sysv init with either 'mysql' or 'mariadb' will end up
+    # controlling this newly installed MariaDB, and thus we maintain better
+    # backwards compatibility.
+    #
+    # Note that the 'Provides' line is also updated to avoid 'insserv' exiting
+    # on failure (when it is run by update-rc.d) because of duplicate service
+    # names.
+    if [ -f "/etc/init.d/mysql" ] && [ -f "/etc/init.d/mariadb" ]
+    then
+      # Copy init file and rename the service name and filename on the fly
+      sed 's/Provides:          mariadb/Provides:          mysql/g' /etc/init.d/mariadb > /etc/init.d/mysql
+      # NOTE: Number of spaces/tabs is important here!
+      # Confirm if the sed worked
+      if ! grep --quiet "Provides:          mysql" /etc/init.d/mysql
+      then
+        # If not, then delete the file to avoid failures later on
+        rm -f /etc/init.d/mysql
+        echo "Warning! Failed creating a mysql named copy of mariadb init.d file"
+      fi
+    fi
+
+    mysql_statedir=/usr/share/mysql
+    mysql_datadir=/var/lib/mysql
+    mysql_logdir=/var/log/mysql
+    mysql_cfgdir=/etc/mysql
+    mysql_upgradedir=/var/lib/mysql-upgrade
+
+    # If the following symlink exists, it is a preserved copy the old data dir
+    # created by the preinst script during a upgrade that would have otherwise
+    # been replaced by an empty mysql dir.  This should restore it.
+    for dir in DATADIR LOGDIR
+    do
+
+      if [ "$dir" = "DATADIR" ]
+      then
+        targetdir=$mysql_datadir
+      else
+        targetdir=$mysql_logdir
+      fi
+
+      savelink="$mysql_upgradedir/$dir.link"
+      if [ -L "$savelink" ]
+      then
+        # If the targetdir was a symlink before we upgraded it is supposed
+        # to be either still be present or not existing anymore now.
+        if [ -L "$targetdir" ]
+        then
+          rm "$savelink"
+        elif [ ! -d "$targetdir" ]
+        then
+          mv "$savelink" "$targetdir"
+        else
+          # this should never even happen, but just in case...
+          mysql_tmp=$(mktemp -d -t mysql-symlink-restore-XXXXXX)
+          echo "this is very strange!  see $mysql_tmp/README..." >&2
+          mv "$targetdir" "$mysql_tmp"
+          cat << EOF > "$mysql_tmp/README"
+
+If you're reading this, it's most likely because you had replaced /var/lib/mysql
+with a symlink, then upgraded to a new version of mysql, and then dpkg
+removed your symlink (see #182747 and others). The mysql packages noticed
+that this happened, and as a workaround have restored it. However, because
+/var/lib/mysql seems to have been re-created in the meantime, and because
+we don't want to rm -rf something we don't know as much about, we are going
+to leave this unexpected directory here. If your database looks normal,
+and this is not a symlink to your database, you should be able to blow
+this all away.
+
+EOF
+        fi
+      fi
+      rmdir $mysql_upgradedir 2>/dev/null || true
+
+    done # end 'for dir' loop
+
+    # Upgrading from mysql.com needs might have the root user as auth_socket.
+    # auto.cnf is a sign of a mysql install, that doesn't exist in mariadb.
+    # We use lsof to protect against concurrent access by mysqld (mariadb has
+    # its own projection). We make sure we're not doing this on a MySQL-8.0
+    # directory.
+    # This direct update is needed to enable an authentication mechanism to
+    # perform mariadb-upgrade, (MDEV-22678).  To keep the impact minimal, we
+    # skip innodb and set key-buffer-size to 0 as it isn't reused.
+    if [ -f "$mysql_datadir/auto.cnf" ] &&
+       [ -f "$mysql_datadir/mysql/user.MYD" ] &&
+       ! lsof -nt "$mysql_datadir"/mysql/user.MYD > /dev/null &&
+       [ ! -f "$mysql_datadir/undo_001" ]
+    then
+      echo "UPDATE mysql.user SET plugin='unix_socket' WHERE plugin='auth_socket';" |
+        mariadbd --skip-innodb --key_buffer_size=0  --default-storage-engine=MyISAM --bootstrap 2> /dev/null
+    fi
+
+    # Ensure the existence and right permissions for the database and
+    # log files. Use mkdir option 'Z' to create with correct SELinux context.
+    if [ ! -d "$mysql_statedir" ] && [ ! -L "$mysql_statedir" ]
+    then
+      mkdir -Z "$mysql_statedir"
+    fi
+    if [ ! -d "$mysql_datadir"  ] && [ ! -L "$mysql_datadir" ]
+    then
+      mkdir -Z "$mysql_datadir"
+    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 modifiable by chown.
+    # The mysql_statedir must not be writable by the mysql user under any
+    # circumstances as it contains scripts that are executed by root.
+    set +e
+    find $mysql_statedir ! -uid 0 -print0 -or ! -gid 0 -print0 | xargs -0 -r sudo chown 0:0
+    find $mysql_datadir ! -uid "$(id -u mysql)" -print0 | xargs -0 -r chown mysql
+    set -e
+
+    ## Set the correct filesystem ownership for the PAM v2 plugin
+    # eg. /usr/lib/x86_64-linux-gnu/mysql/plugin/auth_pam_tool_dir/
+    # NOTE! This is security sensitive, don't allow for a race condition.
+    #
+    # 1. Drop privileges of directory
+    # -> At this point only root can see and execute auth_pam_tool
+    chmod 0700 /usr/lib/mysql/plugin/auth_pam_tool_dir
+    #
+    # 2. Make binary setuid
+    # -> At this point only root can run the setuid binary so no escalation here yet
+    chmod 04755 /usr/lib/mysql/plugin/auth_pam_tool_dir/auth_pam_tool
+    #
+    # 3. Allow user 'mysql' to see and execute auth_pam_tool
+    # -> Now user mysql owns the directory and can see and execute the binary inside
+    # -> Since the binary is setuid, user mysql gets limited root powers here to
+    #    run the PAM authetications, which need root (e.g. to validate passwords
+    #    against /etc/shadow)
+    chown mysql /usr/lib/mysql/plugin/auth_pam_tool_dir
+
+    # 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 somehow gets purged by the admin.
+    db_set mariadb-server/postrm_remove_database false || true
+
+    # Clean up old flags before setting new one
+    rm -f $mysql_datadir/debian-*.flag
+    # Flag data dir to avoid downgrades
+    # @TODO: Rewrite this to use the new upstream /var/lib/mysql_upgrade_info file
+    # instead of the legacy /var/lib/debian-XX.X.flag file
+    touch "$mysql_datadir/debian-__MARIADB_MAJOR_VER__.flag"
+
+    # initiate databases. Output is not allowed by debconf :-(
+    # This will fail if we are upgrading an existing database; in this case
+    # mariadb-upgrade, called from the /etc/mysql/debian-start script, will
+    # handle things.
+    # Debian: beware of the bashisms...
+    # Debian: can safely run on upgrades with existing databases
+    # Workaround for Debian Bug #1022994: failure to create database when
+    # working with libpam-tmpdir (by setting TMPDIR to empty value).
+    set +e
+    TMPDIR='' bash /usr/bin/mariadb-install-db \
+      --rpm --cross-bootstrap \
+      --user=mysql --disable-log-bin \
+      --skip-test-db 2>&1 |
+      $ERR_LOGGER
+    set -e
+
+    # On new installations root user can connect via unix_socket.
+    # But on upgrades, scripts rely on debian-sys-maint user and
+    # credentials in /etc/mysql/debian.cnf
+    # All tools use --defaults-file=/etc/mysql/debian.cnf
+    # And while it's not needed for new installations, we keep using
+    # --defaults-file option for tools (for the sake of upgrades)
+    # and thus need /etc/mysql/debian.cnf to exist, even if it's empty.
+    # In the long run the goal is to obsolete this file.
+    dc="$mysql_cfgdir/debian.cnf"
+    if [ ! -d "$mysql_cfgdir" ]
+    then
+      install -o 0 -g 0 -m 0755 -d $mysql_cfgdir
+    fi
+
+    if [ ! -e "$dc" ]
+    then
+      cat /dev/null > $dc
+      {
+        echo "# THIS FILE IS OBSOLETE. STOP USING IT IF POSSIBLE.";
+        echo "# This file exists only for backwards compatibility for";
+        echo "# tools that run '--defaults-file=/etc/mysql/debian.cnf'";
+        echo "# and have root level access to the local filesystem.";
+        echo "# With those permissions one can run 'mariadb' directly";
+        echo "# anyway thanks to unix socket authentication and hence";
+        echo "# this file is useless. See package README for more info.";
+        echo "[client]";
+        echo "host     = localhost";
+        echo "user     = root";
+        echo "[mysql_upgrade]";
+        echo "host     = localhost";
+        echo "user     = root";
+        echo "# THIS FILE WILL BE REMOVED IN A FUTURE DEBIAN RELEASE.";
+      } >> $dc
+    fi
+    # Keep it only root-readable, as it always was
+    chown 0:0 $dc
+    chmod 0600 $dc
+
+    # If there is a real AppArmor profile, we reload it.
+    # If the default empty profile is installed, then we remove any old
+    # profile that may be loaded.
+    # This allows upgrade from old versions (that have an apparmor profile
+    # on by default) to work both to disable a default profile, and to keep
+    # any profile installed and maintained by users themselves.
+    profile="/etc/apparmor.d/usr.sbin.mariadbd"
+    if [ -f "$profile" ] && aa-status --enabled 2> /dev/null
+    then
+      if grep -q /usr/sbin/mariadbd "$profile" 2> /dev/null
+      then
+        apparmor_parser -r "$profile" || true
+      else
+        echo "/usr/sbin/mariadbd { }" | apparmor_parser --remove 2> /dev/null || true
+      fi
+    fi
+
+    # The introduction of /etc/logrotate.d/mariadb has made the old config
+    # obsolete and it needs to be disabled to prevent logrotate running twice.
+    if [ -f /etc/logrotate.d/mysql-server ]
+    then
+      mv -vf /etc/logrotate.d/mysql-server /etc/logrotate.d/mysql-server.dpkg-bak
+    fi
+
+    # The introduction of versionless server package is not fully backwards
+    # compatible as the purge of an old mariadb-server-x.y package would
+    # commands such as 'deb-systemd-helper purge mariadb.service' and
+    # 'update-rc.d mariadb remove'. Fix it by simly deleting any existing postrm
+    # stanzas opportunistically.
+    for old_postrm_file in /var/lib/dpkg/info/mariadb-server-10.?.postrm
+    do
+      # For loop will always run, but the globbing pattern will be expanded into
+      # something only if there are files that match the pattern, so we need to
+      # not act on it if the result is just the globbing pattern itself.
+      if [ "$old_postrm_file" != "/var/lib/dpkg/info/mariadb-server-10.?.postrm" ]
+      then
+        sed '/Automatically added by dh_installinit/,/End automatically added section/d' \
+          -i "$old_postrm_file" || true
+        sed '/Automatically added by dh_systemd_enable/,/End automatically added section/d' \
+          -i "$old_postrm_file" || true
+      fi
+    done
+    ;;
+
+  abort-upgrade|abort-remove|abort-configure)
+    ;;
+
+  triggered)
+    if [ -d /run/systemd/system ]
+    then
+      systemctl --system daemon-reload
+    elif [ -x /etc/init.d/mariadb ]
+    then
+      invoke-rc.d mariadb restart
+    fi
+    ;;
+
+  *)
+    echo "postinst called with unknown argument '$1'" 1>&2
+    exit 1
+    ;;
+esac
+
+db_stop # in case invoke fails
+
+#DEBHELPER#
diff --git a/mariadb-server.postrm b/mariadb-server.postrm
new file mode 100644 (file)
index 0000000..fc8401b
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/bash
+set -e
+
+# shellcheck source=/dev/null
+. /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 }
+
+#
+# - Purge logs and data only if they are ours (#307473)
+# - Remove the mysql user only after all his owned files are purged.
+# - Cleanup the initscripts only if this was the last provider of them
+#
+if [ "$1" = "purge" ] && [ -f "/var/lib/mysql/debian-__MARIADB_MAJOR_VER__.flag" ]
+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 "mariadb-server/postrm_remove_databases" || true
+  db_go || true
+  db_get "mariadb-server/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
+    # Remove all contents from /var/lib/mysql except if it's a
+    # directory with file system data. See #829491 for details and
+    # #608938 for potential mysql-server leftovers which erroneously
+    # had been renamed.
+    # Attempt removal only if the directory hasn't already been removed
+    # by dpkg to avoid failing on "No such file or directory" errors.
+    if [ -d /var/lib/mysql ]
+    then
+      find /var/lib/mysql -mindepth 1 \
+        -not -path '*/lost+found/*'     -not -name 'lost+found' \
+        -not -path '*/lost@002bfound/*' -not -name 'lost@002bfound' \
+        -delete
+
+      # "|| true" still needed as rmdir still exits with non-zero if
+      # /var/lib/mysql is a mount point
+      rmdir --ignore-fail-on-non-empty /var/lib/mysql || true
+    fi
+    rm -rf /run/mysqld # this directory is created by the init script, don't leave behind
+    userdel mysql || true
+  fi
+
+fi
+
+#DEBHELPER#
diff --git a/mariadb-server.preinst b/mariadb-server.preinst
new file mode 100644 (file)
index 0000000..392fa4f
--- /dev/null
@@ -0,0 +1,288 @@
+#!/bin/bash -e
+#
+# 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>
+#
+
+# shellcheck source=/dev/null
+. /usr/share/debconf/confmodule
+
+# Just kill the invalid insserv.conf.d directory without fallback
+if [ -d "/etc/insserv.conf.d/mariadb/" ]
+then
+  rm -rf "/etc/insserv.conf.d/mariadb/"
+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 }
+
+export PATH=$PATH:/sbin:/usr/sbin:/bin:/usr/bin
+mysql_datadir=/var/lib/mysql
+mysql_upgradedir=/var/lib/mysql-upgrade
+
+MARIADBD_USERS="root"
+
+# Check if user 'mysql' exists before referring to it in pgrep
+# to avoid pgrep erroring on 'invalid user name'
+if id mysql >/dev/null 2>&1
+then
+  MARIADBD_USERS="$MARIADBD_USERS,mysql"
+fi
+
+# 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 mariadbd in e.g. a different chroot is fine for us.
+stop_server() {
+  # Return immediately if there are no mysqld processes running on a host
+  # (leave containerized processes with the same name in other namespaces)
+  # as there is no point in trying to shutdown in that case.
+  if ! pgrep -x -u "$MARIADBD_USERS" --nslist pid --ns $$ "mysqld|mariadbd" > /dev/null
+  then
+    return
+  fi
+
+  set +e
+  invoke-rc.d mariadb stop
+  invoke-rc.d mysql stop # Backwards compatibility
+  errno=$?
+  set -e
+
+  # systemctl could emit exit code 100=no init script (fresh install)
+  if [ "$errno" != 0 ] && [ "$errno" != 100 ]
+  then
+    echo "Attempt to stop MariaDB/MySQL server returned exitcode $errno" 1>&2
+    echo "There is a MariaDB/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() ##########################
+
+# @TODO: Rewrite this to use the new upstream /var/lib/mysql_upgrade_info file
+# instead of the legacy /var/lib/debian-XX.X.flag file
+this_version=__MARIADB_MAJOR_VER__
+max_upgradeable_version=5.7
+
+# Check if a flag file is found that indicates a previous MariaDB or MySQL
+# version was installed. If multiple flags are found, check which one was
+# the biggest version number.
+for flag in "$mysql_datadir"/debian-*.flag
+do
+
+  # The for loop leaves $flag as the query string if there are no results,
+  # so the check below is needed to stop further processing when there are
+  # no real results.
+  if [ "$flag" = "$mysql_datadir/debian-*.flag" ]
+  then
+    break
+  fi
+
+  # The whole flag_version thing should be rewritten, so ignore minor Shellcheck
+  # nag for now
+  # shellcheck disable=SC2001
+  flag_version=$(echo "$flag" | sed 's/.*debian-\([0-9\.]\+\).flag/\1/')
+
+  # Initialize value if empty
+  if [ -z "$found_version" ]
+  then
+    found_version=$flag_version
+  fi
+
+  # Update value if now bigger then before
+  if dpkg --compare-versions "$flag_version" '>>' "$found_version"
+  then
+    found_version=$flag_version
+  fi
+
+done
+
+
+# If an upgrade is detected, proceed with it automatically without
+# requiring any user interaction.
+#
+# However, if the user attempts to downgrade, warn about the incompatibility.
+# Downgrade is detected if the flag version is bigger than $this_version
+# (e.g. 10.1 > 10.0) or the flag version is smaller than 10.0 but bigger
+# than $max_upgradeable_version.
+if [ -n "$found_version" ]
+then
+
+  # MySQL 8.0 in Ubuntu has a bug in packaging and the file is name wrongly
+  # 'debian-5.7.flag', so in case '5.7' was encountered an extra check needs to
+  # be done to see is there is a file called undo_001, which is a sign of 8.0.
+  if [ "$found_version" == "5.7" ] && [ -f "$mysql_datadir/undo_001" ]
+  then
+    # Seems to be a 8.0, flag has wrongly 5.7 (know bug)
+    found_version=8.0
+  fi
+
+  echo "$mysql_datadir: found previous version $found_version"
+
+  if dpkg --compare-versions "$found_version" '>>' "$this_version"
+  then
+    downgrade_detected=true
+  fi
+
+  if dpkg --compare-versions "$found_version" '>>' "$max_upgradeable_version" \
+    && dpkg --compare-versions "$found_version" '<<' "10.0"
+  then
+    downgrade_detected=true
+  fi
+
+fi
+
+# If there is no debian-*.flag, and no version was detected, but a file that
+# indicated MySQL 8.0 is found (undo_001 is created by default in MySQL 8.0+
+# installs), then that file is enough of additional indication to trigger the
+# move of the data directory.
+if [ -z "$found_version" ] &&
+   [ -z "$(find $mysql_datadir/debian-*.flag 2> /dev/null)" ] &&
+   [ -f "$mysql_datadir/undo_001" ]
+then
+  echo "$mysql_datadir: no server version flag found, assuming MySQL 8.0 data encountered" 1>&2
+  downgrade_detected=true
+  found_version="previous" # Just use dummy name as we don't know real version
+fi
+
+# Don't abort dpkg if downgrade is detected (as was done previously).
+# Instead simply move the old datadir and create a new for this_version.
+if [ -n "$downgrade_detected" ]
+then
+  db_input critical "mariadb-server/old_data_directory_saved" || true
+  db_go
+  echo "The contents of $mysql_datadir/ indicates a" 1>&2
+  echo "version that cannot automatically be upgraded. Therefore the" 1>&2
+  echo "previous data directory will be renamed to $mysql_datadir-$found_version and" 1>&2
+  echo "a new data directory will be initialized at $mysql_datadir." 1>&2
+  echo "Please manually export/import your data (e.g. with mysqldump) if needed." 1>&2
+  mv -f "$mysql_datadir" "$mysql_datadir-$found_version"
+  # Also move away the old debian.cnf file that included credentials that are
+  # no longer valid. If none existed, ignore error and let dpkg continue.
+  mv -f /etc/mysql/debian.cnf "/etc/mysql/debian.cnf-$found_version" || true
+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 "$(command -v 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:MariaDB 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 "MariaDB Server" \
+    --shell /bin/false \
+    mysql >/dev/null 2>&1
+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
+    # Use mkdir option 'Z' to create with correct SELinux context.
+    mkdir -pZ "$mysql_upgradedir"
+    cp -dT "$checkdir" "$mysql_upgradedir/$dir.link"
+  fi
+done
+
+# creating mysql home directory
+if [ ! -d $mysql_datadir ] && [ ! -L $mysql_datadir ]
+then
+  # Use mkdir option 'Z' to create with correct SELinux context.
+  mkdir -Z $mysql_datadir
+fi
+
+# As preset blocksize of GNU df is 1024 then available bytes is $df_available_blocks * 1024
+# 4096 blocks is then lower than 4 MB
+df_available_blocks="$(LC_ALL=C BLOCKSIZE='' df --output=avail "$mysql_datadir" | tail -n 1)"
+if [ "$df_available_blocks" -lt "4096" ]
+then
+  echo "ERROR: There's not enough space in $mysql_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
+find $mysql_datadir ! -uid "$(id -u mysql)" -print0 | xargs -0 -r chown mysql
+find $mysql_datadir -follow -not -group mysql -print0 2>/dev/null \
+  | xargs -0 --no-run-if-empty chgrp mysql
+set -e
+
+db_stop
+
+#DEBHELPER#
+
+# dh_installinit/13.11.3 adds this check but only with 'install', so we need to
+# have and extra one to check 'upgrade'. This ensures that upgrades from
+# mariadb-server-x.y to mariadb-server (without version suffix) ends up with
+# the executable bit set on /etc/init.d/mariadb, which otherwise would end up
+# disabled due to the mariadb-server-x.y.postrm being triggered.
+#   $1 = upgrade
+#   $2 = 1:10.6.11-2
+if [ "$1" = "upgrade" ] && [ -n "$2" ] && [ -e "/etc/init.d/mariadb" ]
+then
+  chmod +x "/etc/init.d/mariadb" >/dev/null || true
+fi
+
+# dh_installinit/13.11.3 adds this check but with extra condition that there
+# must be a version passed as '$2', but that will always be empty when install
+# runs after the unpack that is retriggered for package 'mariadb-server' when
+# the old 'mariadb-server-10.6' is purged, so we need to repeat the same check
+# here without any expectation for '$2'. This ensures that upgrades from
+# mariadb-server-x.y to mariadb-server (without version suffix) ends up with the
+# executable bit set on /etc/init.d/mariadb.
+if [ "$1" = "install" ] && [ -e "/etc/init.d/mariadb" ]
+then
+  chmod +x "/etc/init.d/mariadb" >/dev/null || true
+fi
diff --git a/mariadb-server.templates b/mariadb-server.templates
new file mode 100644 (file)
index 0000000..3f790bc
--- /dev/null
@@ -0,0 +1,45 @@
+# 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: mariadb-server/old_data_directory_saved
+Type: note
+_Description: The old data directory will be saved at new location
+ A file named /var/lib/mysql/debian-*.flag exists on this system.
+ The number indicates a database binary format version that cannot automatically
+ be upgraded (or downgraded).
+ .
+ Therefore the previous data directory will be renamed to /var/lib/mysql-* and
+ a new data directory will be initialized at /var/lib/mysql.
+ .
+ Please manually export/import your data (e.g. with mysqldump) if needed.
+
+Template: mariadb-server/nis_warning
+Type: note
+#flag:translate!:3,5
+_Description: Important note for NIS/YP users
+ Using MariaDB 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: mariadb-server/postrm_remove_databases
+Type: boolean
+Default: false
+_Description: Remove all MariaDB databases?
+ The /var/lib/mysql directory which contains the MariaDB databases is about
+ to be removed.
+ .
+ If you're removing the MariaDB package in order to later install a more
+ recent version or if a different mariadb-server package is already
+ using it, the data should be kept.
diff --git a/mariadb-server.triggers b/mariadb-server.triggers
new file mode 100644 (file)
index 0000000..d1f5f5e
--- /dev/null
@@ -0,0 +1,2 @@
+interest-noawait /etc/mysql
+interest-noawait /etc/systemd/system/mariadb.service.d
diff --git a/mariadb-test-data.install b/mariadb-test-data.install
new file mode 100644 (file)
index 0000000..0f2f5f0
--- /dev/null
@@ -0,0 +1,7 @@
+debian/unstable-tests.* usr/share/mysql/mysql-test/
+usr/share/mysql/mysql-test/collections
+usr/share/mysql/mysql-test/include
+usr/share/mysql/mysql-test/main
+usr/share/mysql/mysql-test/plugin
+usr/share/mysql/mysql-test/std_data
+usr/share/mysql/mysql-test/suite
diff --git a/mariadb-test-data.lintian-overrides b/mariadb-test-data.lintian-overrides
new file mode 100644 (file)
index 0000000..9557c03
--- /dev/null
@@ -0,0 +1,24 @@
+# Intentional for test files
+national-encoding [usr/share/mysql/mysql-test/*]
+# Extra test documentation files that really need to be kept in context in test directory
+package-contains-documentation-outside-usr-share-doc [usr/share/mysql/mysql-test/*]
+# Intentional directory structure
+repeated-path-segment auth_gssapi [usr/share/mysql/mysql-test/plugin/auth_gssapi/auth_gssapi/]
+repeated-path-segment connect [usr/share/mysql/mysql-test/plugin/connect/connect/]
+repeated-path-segment disks [usr/share/mysql/mysql-test/plugin/disks/disks/]
+repeated-path-segment func_test [usr/share/mysql/mysql-test/plugin/func_test/func_test/]
+repeated-path-segment metadata_lock_info [usr/share/mysql/mysql-test/plugin/metadata_lock_info/metadata_lock_info/]
+repeated-path-segment mroonga [usr/share/mysql/mysql-test/plugin/mroonga/mroonga/]
+repeated-path-segment mroonga [usr/share/mysql/mysql-test/plugin/mroonga/mroonga/include/mroonga/]
+repeated-path-segment oqgraph [usr/share/mysql/mysql-test/plugin/oqgraph/oqgraph/]
+repeated-path-segment query_response_time [usr/share/mysql/mysql-test/plugin/query_response_time/query_response_time/]
+repeated-path-segment rocksdb [usr/share/mysql/mysql-test/plugin/rocksdb/rocksdb/]
+repeated-path-segment sequence [usr/share/mysql/mysql-test/plugin/sequence/sequence/]
+repeated-path-segment sphinx [usr/share/mysql/mysql-test/plugin/sphinx/sphinx/]
+repeated-path-segment spider [usr/share/mysql/mysql-test/plugin/spider/spider/]
+repeated-path-segment type_inet [usr/share/mysql/mysql-test/plugin/type_inet/type_inet/]
+repeated-path-segment type_mysql_timestamp [usr/share/mysql/mysql-test/plugin/type_mysql_timestamp/type_mysql_timestamp/]
+repeated-path-segment type_test [usr/share/mysql/mysql-test/plugin/type_test/type_test/]
+repeated-path-segment type_uuid [usr/share/mysql/mysql-test/plugin/type_uuid/type_uuid/]
+repeated-path-segment user_variables [usr/share/mysql/mysql-test/plugin/user_variables/user_variables/]
+repeated-path-segment wsrep_info [usr/share/mysql/mysql-test/plugin/wsrep_info/wsrep_info/]
diff --git a/mariadb-test.install b/mariadb-test.install
new file mode 100644 (file)
index 0000000..b43e782
--- /dev/null
@@ -0,0 +1,54 @@
+usr/bin/mariadb-client-test
+usr/bin/mariadb-client-test-embedded
+usr/bin/mariadb-test
+usr/bin/mariadb-test-embedded
+usr/bin/mysql_client_test
+usr/bin/mysql_client_test_embedded
+usr/bin/mysqltest
+usr/bin/mysqltest_embedded
+usr/bin/test-connect-t
+usr/lib/*/libmariadb3/plugin/auth_test_plugin.so
+usr/lib/*/libmariadb3/plugin/qa_auth_client.so
+usr/lib/*/libmariadb3/plugin/qa_auth_interface.so
+usr/lib/*/libmariadb3/plugin/test_sql_service.so
+usr/lib/mysql/plugin/adt_null.so
+usr/lib/mysql/plugin/auth_0x0100.so
+usr/lib/mysql/plugin/auth_test_plugin.so
+usr/lib/mysql/plugin/daemon_example.ini
+usr/lib/mysql/plugin/debug_key_management.so
+usr/lib/mysql/plugin/dialog_examples.so
+usr/lib/mysql/plugin/example_key_management.so
+usr/lib/mysql/plugin/func_test.so
+usr/lib/mysql/plugin/ha_example.so
+usr/lib/mysql/plugin/ha_test_sql_discovery.so
+usr/lib/mysql/plugin/libdaemon_example.so
+usr/lib/mysql/plugin/mypluglib.so
+usr/lib/mysql/plugin/qa_auth_interface.so
+usr/lib/mysql/plugin/qa_auth_server.so
+usr/lib/mysql/plugin/test_sql_service.so
+usr/lib/mysql/plugin/test_versioning.so
+usr/lib/mysql/plugin/type_mysql_timestamp.so
+usr/lib/mysql/plugin/type_test.so
+usr/share/man/man1/mariadb-client-test-embedded.1
+usr/share/man/man1/mariadb-client-test.1
+usr/share/man/man1/mariadb-test-embedded.1
+usr/share/man/man1/mariadb-test.1
+usr/share/man/man1/mysql-test-run.pl.1
+usr/share/man/man1/mysql_client_test.1
+usr/share/man/man1/mysql_client_test_embedded.1
+usr/share/man/man1/mysqltest.1
+usr/share/man/man1/mysqltest_embedded.1
+usr/share/mysql/mysql-test/README
+usr/share/mysql/mysql-test/README-gcov
+usr/share/mysql/mysql-test/README.stress
+usr/share/mysql/mysql-test/dgcov.pl
+usr/share/mysql/mysql-test/lib
+usr/share/mysql/mysql-test/mariadb-stress-test.pl
+usr/share/mysql/mysql-test/mariadb-test-run
+usr/share/mysql/mysql-test/mariadb-test-run.pl
+usr/share/mysql/mysql-test/mtr
+usr/share/mysql/mysql-test/mysql-test-run
+usr/share/mysql/mysql-test/mysql-test-run.pl
+usr/share/mysql/mysql-test/purify.supp
+usr/share/mysql/mysql-test/suite.pm
+usr/share/mysql/mysql-test/valgrind.supp
diff --git a/mariadb-test.lintian-overrides b/mariadb-test.lintian-overrides
new file mode 100644 (file)
index 0000000..372f8d9
--- /dev/null
@@ -0,0 +1,20 @@
+# These should be moved, see https://jira.mariadb.org/browse/MDEV-21653
+arch-dependent-file-in-usr-share [usr/share/mysql/mysql-test/lib/My/SafeProcess/my_safe_process]
+arch-dependent-file-in-usr-share [usr/share/mysql/mysql-test/lib/My/SafeProcess/wsrep_check_version]
+# MyISAM stopwords that cannot be changed and spelling errors remain
+spelling-error-in-binary noone no one [usr/bin/*]
+spelling-error-in-binary thats that's [usr/bin/*]
+spelling-error-in-binary theres there's [usr/bin/*]
+# False positive from Lintian, these strings are nowhere in test in source code
+spelling-error-in-binary AfE Safe [usr/bin/*]
+# Valid reason for documentation in context in directory
+package-contains-documentation-outside-usr-share-doc [usr/share/mysql/mysql-test/README*]
+# Test plugins intentionally not fully featured
+shared-library-lacks-prerequisites [usr/lib/mysql/plugin/auth_0x0100.so]
+shared-library-lacks-prerequisites [usr/lib/mysql/plugin/debug_key_management.so]
+shared-library-lacks-prerequisites [usr/lib/mysql/plugin/test_sql_service.so]
+# The file mysql-test-run.pl is a symlink for mariadb-test-run.pl, which does
+# not have a man page, so the man page is indeed used and not a spare one
+spare-manual-page [usr/share/man/man1/mysql-test-run.pl.1.gz]
+# Text script, should be moved to another path
+no-manual-page [usr/bin/test-connect-t]
diff --git a/not-installed b/not-installed
new file mode 100644 (file)
index 0000000..50ac78f
--- /dev/null
@@ -0,0 +1,58 @@
+etc/columnstore/storagemanager.cnf.example # Copy of etc/columnstore/storagemanager.cnf that is installed
+etc/logrotate.d/mysql # Debian packaging uses mariadb-server.mysql-server.logrotate
+etc/my.cnf # Debian packaging has /etc/mysql/my.cnf, which is a symlink to mariadb.cnf
+etc/mysql/mariadb.conf.d/client.cnf # Debian packaging uses files from debian/additions/mariadb.cnf.d/
+etc/mysql/mariadb.conf.d/enable_encryption.preset # Debian packaging uses files from debian/additions/mariadb.cnf.d/
+etc/mysql/mariadb.conf.d/mysql-clients.cnf # Debian packaging uses files from debian/additions/mariadb.cnf.d/
+etc/mysql/mariadb.conf.d/server.cnf # Debian packaging uses files from debian/additions/mariadb.cnf.d/
+usr/bin/mariadb-embedded # Shipping the embedded server in distro packaging does not make sense
+usr/bin/mysql_config # Debian packaging has mysql_config as symlink to mariadb_config
+usr/bin/mysql_embedded # Symlink to mariadb-embedded which is intentionally not included
+usr/bin/sst_dump # Use the one from rocksdb-tools package
+usr/lib/*/libdbbc.a # ColumnStore header file
+usr/lib/*/libidbboot.a # ColumnStore header file
+usr/lib/*/libprocessor.a # ColumnStore header file
+usr/lib/*/libwe_xml.a # ColumnStore header file
+usr/lib/sysusers.d/mariadb.conf # Not used (yet) in Debian systemd
+usr/lib/tmpfiles.d/mariadb.conf # Not used (yet) in Debian systemd
+usr/sbin/rcmysql
+usr/share/doc/mariadb-server/COPYING (related file: "debian/tmp/usr/share/mysql/mroonga/COPYING")
+usr/share/doc/mariadb-server/CREDITS
+usr/share/doc/mariadb-server/INSTALL-BINARY
+usr/share/doc/mariadb-server/README.md
+usr/share/doc/mariadb-server/README-wsrep
+usr/share/doc/mariadb-server/THIRDPARTY
+usr/share/groonga/COPYING
+usr/share/groonga-normalizer-mysql/lgpl-2.0.txt
+usr/share/groonga-normalizer-mysql/README.md
+usr/share/groonga/README.md
+usr/share/man/man1/mariadb-embedded.1 # Shipping the embedded server in distro packaging does not make sense
+usr/share/man/man1/my_safe_process.1
+usr/share/man/man1/mysql-test-run.pl.1 # Spare manual page, should be deleted upstream
+usr/share/man/man1/mysql_embedded.1 # Symlink to mariadb-embedded.1 which is intentionally not included
+usr/share/man/man1/mysql.server.1
+usr/share/man/man1/mysql-stress-test.pl.1
+usr/share/mysql/binary-configure
+usr/share/mysql/JavaWrappers.jar # These are only built if JNI/libjawt.so is installed from e.g. openjdk-8-jre-headless
+usr/share/mysql/JdbcInterface.jar # These are only built if JNI/libjawt.so is installed from e.g. openjdk-8-jre-headless
+usr/share/mysql/mariadb.logrotate
+usr/share/mysql/magic
+usr/share/mysql/maria_add_gis_sp.sql # mariadb-server-core.install has *_bootstrap.sql
+usr/share/mysql/mysqld_multi.server
+usr/share/mysql/mysql.server # Debian packaging uses mariadb-server.mariadb.init
+usr/share/mysql/mysql-test/asan.supp
+usr/share/mysql/mysql-test/lsan.supp
+usr/share/mysql/policy/apparmor/README # In MariaDB we don't want to use AppArmor at the moment
+usr/share/mysql/policy/apparmor/usr.sbin.mysqld # In MariaDB we don't want to use AppArmor at the moment
+usr/share/mysql/policy/apparmor/usr.sbin.mysqld.local # In MariaDB we don't want to use AppArmor at the moment
+usr/share/mysql/policy/selinux/mariadb-server.fc # In MariaDB we don't want to use SELinux at the moment
+usr/share/mysql/policy/selinux/mariadb-server.te # In MariaDB we don't want to use SELinux at the moment
+usr/share/mysql/policy/selinux/mariadb.te # In MariaDB we don't want to use SELinux at the moment
+usr/share/mysql/policy/selinux/README # In MariaDB we don't want to use SELinux at the moment
+usr/share/mysql/systemd/mariadb-extra@.socket # Installed by rules file
+usr/share/mysql/systemd/mariadb.service # Installed by rules file
+usr/share/mysql/systemd/mariadb@.service # Installed by rules file
+usr/share/mysql/systemd/mariadb@.socket # Installed by rules file
+usr/share/mysql/systemd/mysqld.service  # Installed by rules file
+usr/share/mysql/systemd/mysql.service  # Installed by rules file
+usr/share/mysql/systemd/use_galera_new_cluster.conf
diff --git a/patches/0025-Change-the-default-optimization-from-O3-to-O2-in-mys.patch b/patches/0025-Change-the-default-optimization-from-O3-to-O2-in-mys.patch
new file mode 100644 (file)
index 0000000..538dc6b
--- /dev/null
@@ -0,0 +1,55 @@
+From: Ondrej Sury <ondrej@debian.org>
+Date: Wed, 22 Nov 2017 20:32:51 +0000
+Subject: Change the default optimization from -O3 to -O2 in
+ mysql_release.cmake BUILD_CONFIG profile
+Forwarded: no
+Bug: https://jira.mariadb.org/browse/MDEV-19734?focusedCommentId=156606&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-156606
+
+---
+ cmake/build_configurations/mysql_release.cmake           | 12 ++++++------
+ .../PerconaFT/cmake_modules/TokuSetupCompiler.cmake      | 16 ++++++++--------
+ 2 files changed, 14 insertions(+), 14 deletions(-)
+
+--- a/cmake/build_configurations/mysql_release.cmake
++++ b/cmake/build_configurations/mysql_release.cmake
+@@ -174,12 +174,12 @@ IF(UNIX)
+   IF(CMAKE_COMPILER_IS_GNUCC)
+     SET(COMMON_C_FLAGS               "-g -static-libgcc -fno-omit-frame-pointer -fno-strict-aliasing  -Wno-uninitialized")
+     SET(CMAKE_C_FLAGS_DEBUG          "-O ${COMMON_C_FLAGS}")
+-    SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 ${COMMON_C_FLAGS}")
++    SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 ${COMMON_C_FLAGS}")
+   ENDIF()
+   IF(CMAKE_COMPILER_IS_GNUCXX)
+     SET(COMMON_CXX_FLAGS               "-g -static-libgcc -fno-omit-frame-pointer -fno-strict-aliasing -Wno-uninitialized")
+     SET(CMAKE_CXX_FLAGS_DEBUG          "-O ${COMMON_CXX_FLAGS}")
+-    SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 ${COMMON_CXX_FLAGS}")
++    SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 ${COMMON_CXX_FLAGS}")
+   ENDIF()
+   # IBM Z flags
+@@ -228,8 +228,8 @@ IF(UNIX)
+       ENDIF()
+       SET(CMAKE_C_FLAGS_DEBUG            "${COMMON_C_FLAGS}")
+       SET(CMAKE_CXX_FLAGS_DEBUG          "${COMMON_CXX_FLAGS}")
+-      SET(CMAKE_C_FLAGS_RELWITHDEBINFO   "-O3 -unroll2 -ip ${COMMON_C_FLAGS}")
+-      SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -unroll2 -ip ${COMMON_CXX_FLAGS}")
++      SET(CMAKE_C_FLAGS_RELWITHDEBINFO   "-O2 -unroll2 -ip ${COMMON_C_FLAGS}")
++      SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -unroll2 -ip ${COMMON_CXX_FLAGS}")
+       SET(WITH_SSL no)
+     ENDIF()
+   ENDIF()
+@@ -238,12 +238,12 @@ IF(UNIX)
+   IF(CMAKE_C_COMPILER_ID MATCHES "Clang")
+     SET(COMMON_C_FLAGS               "-g -fno-omit-frame-pointer -fno-strict-aliasing -Wno-parentheses-equality -Wno-string-plus-int")
+     SET(CMAKE_C_FLAGS_DEBUG          "${COMMON_C_FLAGS}")
+-    SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 ${COMMON_C_FLAGS}")
++    SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O2 ${COMMON_C_FLAGS}")
+   ENDIF()
+   IF(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+     SET(COMMON_CXX_FLAGS               "-g -fno-omit-frame-pointer -fno-strict-aliasing -Wno-parentheses-equality -Wno-string-plus-int")
+     SET(CMAKE_CXX_FLAGS_DEBUG          "${COMMON_CXX_FLAGS}")
+-    SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 ${COMMON_CXX_FLAGS}")
++    SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 ${COMMON_CXX_FLAGS}")
+   ENDIF()
+   # Solaris flags
diff --git a/patches/1006531-hurd-no-auth-socket.patch b/patches/1006531-hurd-no-auth-socket.patch
new file mode 100644 (file)
index 0000000..d6ae82f
--- /dev/null
@@ -0,0 +1,28 @@
+Forwarded: no
+Origin: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1006531
+From: Daniel Black <daniel@mariadb.org>
+Subject: mariadb: FTBFS on hurd-i386: undefined reference to misc functions and files
+
+requires https://github.com/MariaDB/server/pull/2893 as debian
+explicit architectures aren't needed since dh_auto_configure handles
+this.
+
+If it works, upstream welcome.
+
+Hurd string from uname -m, "SYSTEM processor: i686-AT386" in mariadb
+output. And wiki reference https://en.wikipedia.org/wiki/Uname
+
+--- a/cmake/build_configurations/mysql_release.cmake
++++ b/cmake/build_configurations/mysql_release.cmake
+@@ -118,7 +118,10 @@ ELSEIF(DEB)
+   SET(WITH_ZLIB system CACHE STRING "")
+   SET(WITH_LIBWRAP ON)
+   SET(HAVE_EMBEDDED_PRIVILEGE_CONTROL ON)
+-  SET(PLUGIN_AUTH_SOCKET YES CACHE STRING "")
++  # No hurd implementation
++  IF(NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "i686-AT386")
++    SET(PLUGIN_AUTH_SOCKET YES CACHE STRING "")
++  ENDIF()
+   SET(WITH_EMBEDDED_SERVER ON CACHE BOOL "")
+   SET(WITH_PCRE system CACHE STRING "")
+   SET(CLIENT_PLUGIN_ZSTD OFF)
diff --git a/patches/2541-fix-stack-overflow-in-pinbox-allocator.patch b/patches/2541-fix-stack-overflow-in-pinbox-allocator.patch
new file mode 100644 (file)
index 0000000..b6dd97e
--- /dev/null
@@ -0,0 +1,282 @@
+From fd83a9431cd16e6c61b8cdbb89810c554a315338 Mon Sep 17 00:00:00 2001
+From: Hugo Wen <wenhug@amazon.com>
+Date: Sat, 11 Mar 2023 00:27:42 +0000
+Subject: [PATCH] Fix a stack overflow in pinbox allocator
+
+MariaDB supports a "wait-free concurrent allocator based on pinning addresses".
+In `lf_pinbox_real_free()` it tries to sort the pinned addresses for better
+performance to use binary search during "real free". `alloca()` was used to
+allocate stack memory and copy addresses.
+
+To prevent a stack overflow when allocating the stack memory the function checks
+if there's enough stack space. However, the available stack size was calculated
+inaccurately which eventually caused database crash due to stack overflow.
+
+The crash was seen on MariaDB 10.6.11 but the same code defect exists on all
+MariaDB versions.
+
+A similar issue happened previously and the fix in fc2c1e43 was to add a
+`ALLOCA_SAFETY_MARGIN` which is 8192 bytes. However, that safety margin is not
+enough during high connection workloads.
+
+MySQL also had a similar issue and the fix
+https://github.com/mysql/mysql-server/commit/b086fda was to remove the use of
+`alloca` and replace qsort approach by a linear scan through all pointers (pins)
+owned by each thread.
+
+This commit is mostly the same as it is the only way to solve this issue as:
+1. Frame sizes in different architecture can be different.
+2. Number of active (non-null) pinned addresses varies, so the frame
+   size for the recursive sorting function `msort_with_tmp` is also hard
+   to predict.
+3. Allocating big memory blocks in stack doesn't seem to be a very good
+   practice.
+
+For further details see the mentioned commit in MySQL and the inline comments.
+
+All new code of the whole pull request, including one or several files
+that are either new files or modified ones, are contributed under the
+BSD-new license. I am contributing on behalf of my employer Amazon Web
+Services, Inc.
+---
+ mysys/lf_alloc-pin.c | 180 ++++++++++++++-----------------------------
+ 1 file changed, 59 insertions(+), 121 deletions(-)
+
+--- a/mysys/lf_alloc-pin.c
++++ b/mysys/lf_alloc-pin.c
+@@ -103,12 +103,6 @@
+ #include <lf.h>
+ #include "my_cpu.h"
+-/*
+-  when using alloca() leave at least that many bytes of the stack -
+-  for functions we might be calling from within this stack frame
+-*/
+-#define ALLOCA_SAFETY_MARGIN 8192
+-
+ #define LF_PINBOX_MAX_PINS 65536
+ static void lf_pinbox_real_free(LF_PINS *pins);
+@@ -239,24 +233,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                                                                    \
+-  {                                                                     \
+-    my_atomic_storeptr_explicit(                                        \
+-      (void **)((char *)(ADDR)+(PINS)->pinbox->free_ptr_offset),        \
+-      (PINS)->purgatory, MY_MEMORY_ORDER_RELEASE);                      \
+-    (PINS)->purgatory= (ADDR);                                          \
+-    (PINS)->purgatory_count++;                                          \
+-  } while (0)
+-
+ /*
+   Free an object allocated via pinbox allocator
+@@ -274,138 +265,85 @@ void lf_pinbox_free(LF_PINS *pins, void
+                       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 forlf_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= my_atomic_loadptr((void **)&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 forlf_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 (my_atomic_loadptr((void **)&el->pin[i]) == addr)
+-        return 1;
+-  return 0;
+-}
+-
+-#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;
+-  struct st_my_thread_var *var= my_thread_var;
+-  void *stack_ends_here= var ? var->stack_ends_here : 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 (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, stack_ends_here) >
+-        alloca_size + ALLOCA_SAFETY_MARGIN)
+-    {
+-      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= (int)(hv.granary-addr);
+-      /* and sort them */
+-      if (npins)
+-        qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp);
+-    }
+-  }
+-#endif
+-  list= pins->purgatory;
+-  pins->purgatory= 0;
+-  pins->purgatory_count= 0;
+-  while (list)
++  lf_dynarray_iterate(&pinbox->pinarray,
++                      (lf_dynarray_func)match_and_save, &arg);
++
++  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 */
+ /*
diff --git a/patches/env-perl-usr-bin-perl.patch b/patches/env-perl-usr-bin-perl.patch
new file mode 100644 (file)
index 0000000..9637624
--- /dev/null
@@ -0,0 +1,99 @@
+Forwarded: https://github.com/MariaDB/server/pull/1718 (rejected, will never be merged)
+Origin: https://patch-diff.githubusercontent.com/raw/MariaDB/server/pull/1718.patch
+From: Otto Kekäläinen <otto@debian.org>
+Date: Sun, 20 Dec 2020 20:58:42 +0200
+Subject: Fix perl path in scripts
+ Fix Lintian issue
+ https://lintian.debian.org/tags/incorrect-path-for-interpreter.html
+ .
+ Upstream will never accept this patch, see
+ https://github.com/MariaDB/server/pull/1718
+
+--- a/mysql-test/lib/process-purecov-annotations.pl
++++ b/mysql-test/lib/process-purecov-annotations.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ # -*- cperl -*-
+ # This script processes a .gcov coverage report to honor purecov 
+--- a/mysql-test/lib/v1/mysql-test-run.pl
++++ b/mysql-test/lib/v1/mysql-test-run.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ # -*- cperl -*-
+ # Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+--- a/mysql-test/mariadb-stress-test.pl
++++ b/mysql-test/mariadb-stress-test.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ # Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
+ #
+--- a/mysql-test/mariadb-test-run.pl
++++ b/mysql-test/mariadb-test-run.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ # -*- cperl -*-
+ # Copyright (c) 2004, 2014, Oracle and/or its affiliates.
+--- a/mysql-test/std_data/checkDBI_DBD-MariaDB.pl
++++ b/mysql-test/std_data/checkDBI_DBD-MariaDB.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ # Copyright (c) 2011, Oracle and/or its affiliates
+ #
+--- a/mysql-test/suite/engines/rr_trx/run_stress_tx_rr.pl
++++ b/mysql-test/suite/engines/rr_trx/run_stress_tx_rr.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ ################################################################################
+ #
+ # This script runs the transactional stress test "stress_tx_rr" against the
+--- a/mysql-test/suite/funcs_1/lib/DataGen_local.pl
++++ b/mysql-test/suite/funcs_1/lib/DataGen_local.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ if ( (scalar(@ARGV) != 1 ) || ($ARGV[0] =~ /[^0-9]/i ) )
+--- a/mysql-test/suite/funcs_1/lib/DataGen_modify.pl
++++ b/mysql-test/suite/funcs_1/lib/DataGen_modify.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ if ( (scalar(@ARGV) != 2 ) || ($ARGV[0] =~ /[^0-9]/i ) )
+--- a/mysql-test/suite/funcs_2/lib/gen_charset_utf8.pl
++++ b/mysql-test/suite/funcs_2/lib/gen_charset_utf8.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #################################################################################
+ # Author:  Serge Kozlov                                                               #       
+--- a/mysql-test/suite/rpl/extension/checksum.pl
++++ b/mysql-test/suite/rpl/extension/checksum.pl
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ #
+--- a/scripts/mytop.sh
++++ b/scripts/mytop.sh
+@@ -1,4 +1,4 @@
+-#!/usr/bin/env perl
++#!/usr/bin/perl
+ #
+ # $Id: mytop,v 1.99-maria6 2019/10/22 14:53:51 jweisbuch Exp $
diff --git a/patches/fix-reproducible-builds-rocksdb.patch b/patches/fix-reproducible-builds-rocksdb.patch
new file mode 100644 (file)
index 0000000..1bc0125
--- /dev/null
@@ -0,0 +1,26 @@
+Origin: https://github.com/facebook/rocksdb/commit/0a9a05ae12943b1529ef1eabbca5ce5a71c986bf
+# Merged in RocksDB 6.19.3, but not updated into MariaDB yet
+Bug: https://github.com/facebook/rocksdb/issues/7035
+Author: Otto Kekäläinen <otto@kekalainen.net>
+Subject: Make RocksDB build reproducible
+
+The RocksDB binary included a string with the build timestamp:
+> rocksdb_build_git_date:@2021-05-23·16:04:38@
+
+As this changes from build to build, it makes the builds unreproducible.
+Simply removing it solves the issue.
+
+This temporary fix can be removed when a proper fix already done in upstream
+lands in MariaDB when the RocksDB submodule is updated to a newer release.
+
+--- a/storage/rocksdb/rocksdb/util/build_version.cc.in
++++ b/storage/rocksdb/rocksdb/util/build_version.cc.in
+@@ -1,5 +1,5 @@
+ // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
+ #include "build_version.h"
+-const char* rocksdb_build_git_sha = "rocksdb_build_git_sha:@@GIT_SHA@@";
+-const char* rocksdb_build_git_date = "rocksdb_build_git_date:@@GIT_DATE_TIME@@";
+-const char* rocksdb_build_compile_date = __DATE__;
++const char* rocksdb_build_git_sha = "rocksdb_build_git_sha:REDACTED";
++const char* rocksdb_build_git_date = "rocksdb_build_git_date:REDACTED";
++const char* rocksdb_build_compile_date = "REDACTED";
diff --git a/patches/fix-spelling-libmariadb.patch b/patches/fix-spelling-libmariadb.patch
new file mode 100644 (file)
index 0000000..57cdaec
--- /dev/null
@@ -0,0 +1,155 @@
+Forwarded: https://github.com/mariadb-corporation/mariadb-connector-c/pull/220
+Origin: https://patch-diff.githubusercontent.com/raw/mariadb-corporation/mariadb-connector-c/pull/220.patch
+Author: Otto Kekäläinen <otto@kekalainen.net>
+Date: Sat, 11 Mar 2023 11:22:24 -0800
+Subject: [PATCH] Fix trivial spelling errors
+
+- handshak -> handshake
+- occured -> occurred
+- releated -> related
+- reponse -> response
+- seperated -> separated
+- sucess -> success
+- use use -> use
+
+All new code of the whole pull request, including one or several files
+that are either new files or modified ones, are contributed under the
+BSD-new license. I am contributing on behalf of my employer Amazon Web
+Services, Inc.
+---
+ man/mariadb_get_infov.3       | 4 ++--
+ man/mariadb_reconnect.3       | 2 +-
+ man/mysql_ping.3              | 2 +-
+ man/mysql_real_connect.3      | 4 ++--
+ man/mysql_send_query.3        | 2 +-
+ man/mysql_set_character_set.3 | 2 +-
+ man/mysql_stmt_error.3        | 2 +-
+ man/mysql_stmt_reset.3        | 2 +-
+ man/mysql_store_result.3      | 2 +-
+ unittest/libmariadb/result.c  | 2 +-
+ 10 files changed, 12 insertions(+), 12 deletions(-)
+
+--- a/libmariadb/man/mariadb_get_infov.3
++++ b/libmariadb/man/mariadb_get_infov.3
+@@ -5,7 +5,7 @@
+ .hy
+ .SS Name
+ .PP
+-mariadb_get_infov \- retrieves generic or connection releated
++mariadb_get_infov \- retrieves generic or connection related
+ information
+ .SS Synopsis
+ .IP
+@@ -170,7 +170,7 @@ Retrieves character set information for
+ .PD 0
+ .P
+ .PD
+-Returns the handshak capability flags] of the client.
++Returns the handshake capability flags] of the client.
+ .IP \[bu] 2
+ \f[C]MARIADB_CONNECTION_ERROR\f[R]
+ .PD 0
+--- a/libmariadb/man/mariadb_reconnect.3
++++ b/libmariadb/man/mariadb_reconnect.3
+@@ -22,7 +22,7 @@ It uses the same credentials which were
+ \f[B]mysql_real_connect(3)\f[R].
+ .SS Return value
+ .PP
+-The function will return 0 on sucess, a non zero value on error
++The function will return 0 on success, a non zero value on error
+ .PP
+ \f[B]Note\f[R]: The function will return an error, if the option
+ \f[C]MYSQL_OPT_RECONNECT\f[R] wasn\[cq]t set before.
+--- a/libmariadb/man/mysql_ping.3
++++ b/libmariadb/man/mysql_ping.3
+@@ -36,7 +36,7 @@ Also resources bundled to the connection
+ temporary tables, \&...) will be released.
+ .SS Return value
+ .PP
+-Returns zero on success, nonzero if an error occured.
++Returns zero on success, nonzero if an error occurred.
+ .SS See also
+ .IP \[bu] 2
+ \f[B]mysql_optionsv(3)\f[R]
+--- a/libmariadb/man/mysql_real_connect.3
++++ b/libmariadb/man/mysql_real_connect.3
+@@ -141,11 +141,11 @@ since version 3.3.0).
+ The following syntax is required:
+ .RS 2
+ .IP \[bu] 2
+-hostname and port must be seperated by a colon (:)
++hostname and port must be separated by a colon (:)
+ .IP \[bu] 2
+ IPv6 addresses must be enclosed within square brackets
+ .IP \[bu] 2
+-hostname:port pairs must be be seperated by a comma (,)
++hostname:port pairs must be be separated by a comma (,)
+ .IP \[bu] 2
+ if only one host:port was specified, the host string needs to end with a
+ comma.
+--- a/libmariadb/man/mysql_send_query.3
++++ b/libmariadb/man/mysql_send_query.3
+@@ -5,7 +5,7 @@
+ .SS Name
+ .PP
+ mysql_send_query \- sends a SQL statement without waiting for server
+-reponse
++response
+ .SS Synopsis
+ .IP
+ .nf
+--- a/libmariadb/man/mysql_set_character_set.3
++++ b/libmariadb/man/mysql_set_character_set.3
+@@ -34,7 +34,7 @@ of \f[C]SET NAMES ...\f[R] since \f[B]my
+ might fail or deliver unexpected results.
+ .SS Return value
+ .PP
+-Zero on success, non zero if an error occured
++Zero on success, non zero if an error occurred
+ .SS Supported character sets
+ .PP
+ The client library supports the following character sets:
+--- a/libmariadb/man/mysql_stmt_error.3
++++ b/libmariadb/man/mysql_stmt_error.3
+@@ -27,7 +27,7 @@ The string will be empty if no error occ
+ .SS Return value
+ .IP \[bu] 2
+ A string describing the last error or an empty string if no error
+-occured.
++occurred.
+ .SS Notes
+ .IP \[bu] 2
+ Client error messages are listed in the \f[C]errmsg.h\f[R] header file,
+--- a/libmariadb/man/mysql_stmt_reset.3
++++ b/libmariadb/man/mysql_stmt_reset.3
+@@ -24,7 +24,7 @@ Resets a prepared statement on client an
+ Returns zero on success, nonzero if an error occurred.
+ .SS Return value
+ .PP
+-Returns zero on succes, 1 if an error occured.
++Returns zero on succes, 1 if an error occurred.
+ .SS Notes
+ .IP \[bu] 2
+ \f[C]mysql_stmt_reset()\f[R] resets the statement on the server,
+--- a/libmariadb/man/mysql_store_result.3
++++ b/libmariadb/man/mysql_store_result.3
+@@ -31,7 +31,7 @@ allocated by \f[B]mysql_init(3)\f[R] and
+ \f[B]mysql_real_connect(3)\f[R].
+ .SS Return value
+ .PP
+-Returns a buffered result set or NULL in case an error occured or if the
++Returns a buffered result set or NULL in case an error occurred or if the
+ query didn\[cq]t return data (e.g.\ when executing an INSERT, UPDATE,
+ DELETE or REPLACE statement).
+ ## See also * \f[B]mysql_free_result(3)\f[R] *
+--- a/libmariadb/unittest/libmariadb/result.c
++++ b/libmariadb/unittest/libmariadb/result.c
+@@ -65,7 +65,7 @@ static int client_use_result(MYSQL *mysq
+   result= mysql_use_result(mysql);
+   FAIL_IF(!result, "Invalid result set");
+-  /* since we use use result, we shouldn't be able execute other api calls */
++  /* since we use result, we shouldn't be able execute other api calls */
+   rc= mysql_ping(mysql);
+   FAIL_IF(!rc, "Error expected");
diff --git a/patches/fix-spelling-mariadb.patch b/patches/fix-spelling-mariadb.patch
new file mode 100644 (file)
index 0000000..5d5265c
--- /dev/null
@@ -0,0 +1,90 @@
+Forwarded: no
+Author: Otto Kekäläinen <otto@debian.org>
+Date: Sun, 10 Mar 2024 16:56:13 +0000
+Subject: [PATCH] Fix misc spelling in MariaDB Server repository
+
+--- a/storage/connect/odbconn.cpp
++++ b/storage/connect/odbconn.cpp
+@@ -281,7 +281,7 @@ static CATPARM *AllocCatInfo(PGLOBAL g,
+               cap->Status = (UWORD *)PlugSubAlloc(g, NULL, m * sizeof(UWORD));
+       } catch (int n) {
+-              htrc("Exeption %d: %s\n", n, g->Message);
++              htrc("Exception %d: %s\n", n, g->Message);
+               cap = NULL;
+       } catch (const char *msg) {
+               htrc(g->Message, msg);
+--- a/extra/mariabackup/innobackupex.cc
++++ b/extra/mariabackup/innobackupex.cc
+@@ -188,7 +188,7 @@ enum innobackupex_options
+       OPT_DATABASES,
+       OPT_DECOMPRESS,
+-      /* options wich are passed directly to xtrabackup */
++      /* options which are passed directly to xtrabackup */
+       OPT_CLOSE_FILES,
+       OPT_COMPACT,
+       OPT_COMPRESS,
+@@ -447,7 +447,7 @@ static struct my_option ibx_long_options
+       {"startup-wait-timeout", OPT_LOCK_WAIT_TIMEOUT,
+          "This option specifies time in seconds that mariadb-backup should wait for "
+          "BACKUP STAGE START to complete. BACKUP STAGE START has to wait until all "
+-         "currently running queries using explicite LOCK TABLES has ended. "
++         "currently running queries using explicit LOCK TABLES has ended. "
+          "If there are still such queries when the timeout expires, mariadb-backup "
+          "terminates with an error. Default is 0, in which case mariadb-backup waits "
+          "indefinitely for BACKUP STAGE START to finish",
+--- a/extra/mariabackup/xtrabackup.cc
++++ b/extra/mariabackup/xtrabackup.cc
+@@ -217,7 +217,7 @@ uint xtrabackup_compress = FALSE;
+ uint xtrabackup_compress_threads;
+ ulonglong xtrabackup_compress_chunk_size = 0;
+-/* sleep interval beetween log copy iterations in log copying thread
++/* sleep interval between log copy iterations in log copying thread
+ in milliseconds (default is 1 second) */
+ ulint xtrabackup_log_copy_interval = 1000;
+ static ulong max_buf_pool_modified_pct;
+@@ -1597,11 +1597,11 @@ struct my_option xb_client_options[]= {
+      GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+     {"rsync", OPT_RSYNC,
+-     "Obsolete depricated option",
++     "Obsolete deprecated option",
+      &ignored_option, &ignored_option,  0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+     {"no-backup-locks", OPT_NO_BACKUP_LOCKS,
+-     "Obsolete depricated option",
++     "Obsolete deprecated option",
+      &ignored_option, &ignored_option,  0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+     {"force-non-empty-directories", OPT_FORCE_NON_EMPTY_DIRS,
+@@ -1729,7 +1729,7 @@ struct my_option xb_client_options[]= {
+     {"startup-wait-timeout", OPT_LOCK_WAIT_TIMEOUT,
+      "This option specifies time in seconds that mariadb-backup should wait for "
+      "BACKUP STAGE START to complete. BACKUP STAGE START has to wait until all "
+-     "currently running queries using explicite LOCK TABLES has ended. "
++     "currently running queries using explicit LOCK TABLES has ended. "
+      "If there are still such queries when the timeout expires, mariadb-backup "
+      "terminates with an error. Default is 0, in which case mariadb-backup waits "
+      "indefinitely for BACKUP STAGE START to finish",
+@@ -5622,7 +5622,7 @@ void CorruptedPages::backup_fix_ddl(ds_c
+       }
+       /* Mariabackup doesn't detect any FILE_OP for the deferred
+-      tablespace. There is a possiblity that page0 could've
++      tablespace. There is a possibility that page0 could've
+       been corrupted persistently in the disk */
+       for (auto space_name: defer_space_names) {
+               if (!check_if_skip_table(space_name.c_str())) {
+--- a/support-files/mysql.server.sh
++++ b/support-files/mysql.server.sh
+@@ -194,7 +194,7 @@ su_kill() {
+ #
+ # Read defaults file from 'basedir'.   If there is no defaults file there
+-# check if it's in the old (depricated) place (datadir) and read it from there
++# check if it's in the old (deprecated) place (datadir) and read it from there
+ #
+ extra_args=""
diff --git a/patches/fix-spelling-rocksdb.patch b/patches/fix-spelling-rocksdb.patch
new file mode 100644 (file)
index 0000000..6e68109
--- /dev/null
@@ -0,0 +1,39 @@
+Forwarded: https://github.com/facebook/rocksdb/pull/9653
+Origin: https://patch-diff.githubusercontent.com/raw/facebook/rocksdb/pull/9653.patch
+# Merged in RocksDB 7.3.1, but not updated into MariaDB yet
+From: Otto Kekäläinen <otto@debian.org>
+Date: Wed, 2 Mar 2022 18:13:18 -0800
+Subject: Fix various spelling errors still found in code
+  Two upstream PRs remain that have been merged, but not imported on MariaDB yet.
+
+--- a/storage/rocksdb/rocksdb/db/external_sst_file_ingestion_job.cc
++++ b/storage/rocksdb/rocksdb/db/external_sst_file_ingestion_job.cc
+@@ -46,7 +46,7 @@ Status ExternalSstFileIngestionJob::Prep
+             TablePropertiesCollectorFactory::Context::kUnknownColumnFamily &&
+         f.cf_id != cfd_->GetID()) {
+       return Status::InvalidArgument(
+-          "External file column family id dont match");
++          "External file column family id don't match");
+     }
+   }
+@@ -646,7 +646,7 @@ Status ExternalSstFileIngestionJob::Assi
+     return Status::InvalidArgument("Global seqno is required, but disabled");
+   } else if (file_to_ingest->global_seqno_offset == 0) {
+     return Status::InvalidArgument(
+-        "Trying to set global seqno for a file that dont have a global seqno "
++        "Trying to set global seqno for a file that don't have a global seqno "
+         "field");
+   }
+--- a/storage/rocksdb/rocksdb/include/rocksdb/cache.h
++++ b/storage/rocksdb/rocksdb/include/rocksdb/cache.h
+@@ -60,7 +60,7 @@ struct LRUCacheOptions {
+   // If greater than zero, the LRU list will be split into a high-pri
+   // list and a low-pri list. High-pri entries will be insert to the
+   // tail of high-pri list, while low-pri entries will be first inserted to
+-  // the low-pri list (the midpoint). This is refered to as
++  // the low-pri list (the midpoint). This is referred to as
+   // midpoint insertion strategy to make entries never get hit in cache
+   // age out faster.
+   //
diff --git a/patches/hurd-i386-plugin_disks_information_schema_disks.cc.patch b/patches/hurd-i386-plugin_disks_information_schema_disks.cc.patch
new file mode 100644 (file)
index 0000000..ca5b669
--- /dev/null
@@ -0,0 +1,19 @@
+Forwarded: no
+Origin: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1069094
+Author: Svante Signell <svante.signell@gmail.com>
+Subject: Bug#1069094: mariadb: FTBFS on hurd-i386
+
+Define PATH_MAX if not defined.
+
+--- a/plugin/disks/information_schema_disks.cc
++++ b/plugin/disks/information_schema_disks.cc
+@@ -32,6 +32,9 @@
+ #include <sys/mntent.h>
+ #endif
+ #endif
++#ifndef PATH_MAX
++#define PATH_MAX 4096
++#endif
+ #include <sql_class.h>
+ #include <sql_i_s.h>
+ #include <sql_acl.h>                            /* check_global_access() */
diff --git a/patches/hurd-i386-storage_connect_ioapi.h.patch b/patches/hurd-i386-storage_connect_ioapi.h.patch
new file mode 100644 (file)
index 0000000..75cd7df
--- /dev/null
@@ -0,0 +1,22 @@
+Forwarded: no
+Origin: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1069094
+Author: Svante Signell <svante.signell@gmail.com>
+Subject: Bug#1069094: mariadb: FTBFS on hurd-i386
+
+Add Hurd to define __USE_FILE_OFFSET64 et al.
+
+--- a/storage/connect/ioapi.h
++++ b/storage/connect/ioapi.h
+@@ -21,9 +21,10 @@
+ #ifndef _ZLIBIOAPI64_H
+ #define _ZLIBIOAPI64_H
+-#if defined(__linux__)
++#if defined(__linux__) || defined (__GNU__)
+-  // Linux needs this to support file operation on files larger then 4+GB
++  // Linux and Hurd needs this to support file operation on files larger
++  // than 4+GB.
+   // But might need better if/def to select just the platforms that needs them.
+         #ifndef __USE_FILE_OFFSET64
diff --git a/patches/install-files-into-usr.patch b/patches/install-files-into-usr.patch
new file mode 100644 (file)
index 0000000..3788477
--- /dev/null
@@ -0,0 +1,27 @@
+Forwarded: no
+Origin: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1061348
+From: Michael Biebl <biebl@debian.org>
+Date: Mon, 22 Jan 2024 22:52:25 +0100
+Subject: [PATCH] Install PAM modules and systemd units into /usr
+
+Since Debian trixie all files need to be installed into their canonical
+location under /usr.
+---
+ cmake/install_layout.cmake | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/cmake/install_layout.cmake
++++ b/cmake/install_layout.cmake
+@@ -194,10 +194,10 @@ SET(INSTALL_SUPPORTFILESDIR_DEB
+ SET(INSTALL_MYSQLDATADIR_DEB            "/var/lib/mysql")
+ SET(INSTALL_UNIX_ADDRDIR_DEB            "/run/mysqld/mysqld.sock")
+-SET(INSTALL_SYSTEMD_UNITDIR_DEB         "/lib/systemd/system")
++SET(INSTALL_SYSTEMD_UNITDIR_DEB         "/usr/lib/systemd/system")
+ SET(INSTALL_SYSTEMD_SYSUSERSDIR_DEB     "/usr/lib/sysusers.d")
+ SET(INSTALL_SYSTEMD_TMPFILESDIR_DEB     "/usr/lib/tmpfiles.d")
+-SET(INSTALL_PAMDIR_DEB                  "/lib/${CMAKE_CXX_LIBRARY_ARCHITECTURE}/security")
++SET(INSTALL_PAMDIR_DEB                  "/usr/lib/${CMAKE_CXX_LIBRARY_ARCHITECTURE}/security")
+ SET(INSTALL_PAMDATADIR_DEB              "/etc/security")
+ #
diff --git a/patches/mroonga-mrn-lib-dirs-path-reproducible-build.patch b/patches/mroonga-mrn-lib-dirs-path-reproducible-build.patch
new file mode 100644 (file)
index 0000000..eeb91cc
--- /dev/null
@@ -0,0 +1,39 @@
+Forwarded: not-needed
+Origin: https://github.com/mroonga/mroonga/issues/298#issuecomment-1030815927
+Bug: https://github.com/mroonga/mroonga/issues/298
+From: Sutou Kouhei <kou@clear-code.com>
+Date: Sat, 5 Feb 2022 11:05:39 +0900
+Subject: [PATCH] cmake: add support for reproducible buildS
+ .
+ We should use relative path not absolute path.
+ We can use target without breaking reproducibility.
+--- a/storage/mroonga/CMakeLists.txt
++++ b/storage/mroonga/CMakeLists.txt
+@@ -214,7 +214,7 @@ set(MYSQL_INCLUDE_DIRS
+ if(MRN_BUNDLED)
+   set(MYSQL_PLUGIN_DIR "${INSTALL_PLUGINDIR}")
+-  set(MYSQL_SERVICES_LIB_DIR "${MYSQL_BUILD_DIR}/libservices")
++  set(MYSQL_SERVICES_LIB_DIR)
+   set(MYSQL_CFLAGS "${CMAKE_C_FLAGS}")
+   set(MYSQL_VERSION "${MYSQL_BASE_VERSION}")
+ else()
+@@ -253,15 +253,11 @@ endif()
+ if(MRN_GROONGA_BUNDLED)
+   set(GROONGA_INCLUDE_DIRS "${MRN_BUNDLED_GROONGA_DIR}/include")
+-  set(GROONGA_LIBRARY_DIRS "${MRN_BUNDLED_GROONGA_DIR}/lib")
+-  set(GROONGA_LIBRARIES "libgroonga")
++  set(GROONGA_LIBRARY "libgroonga")
+-  set(MRN_LIBRARY_DIRS ${GROONGA_LIBRARY_DIRS})
+-  set(MRN_LIBRARIES ${GROONGA_LIBRARIES})
++  set(MRN_LIBRARY_DIRS)
++  set(MRN_LIBRARIES ${GROONGA_LIBRARY})
+   if(MRN_GROONGA_NORMALIZER_MYSQL_EMBED)
+-    set(MRN_LIBRARY_DIRS
+-      ${MRN_LIBRARY_DIRS}
+-      "${MRN_BUNDLED_GROONGA_NORMALIZER_MYSQL_DIR}/normalizers")
+     set(MRN_LIBRARIES ${MRN_LIBRARIES} mysql_normalizer)
+   endif()
+ else()
diff --git a/patches/rocksdb-kfreebsd.patch b/patches/rocksdb-kfreebsd.patch
new file mode 100644 (file)
index 0000000..2b7f2d9
--- /dev/null
@@ -0,0 +1,151 @@
+Forwarded: https://github.com/facebook/rocksdb/pull/6992
+# Merged in RocksDB 6.12.6 but not updated into MariaDB yet
+From: Andrew Kryczka <andrewkr@fb.com>
+Date: Tue, 16 Jun 2020 19:34:21 -0700
+# Merged in RocksDB 6.13.fb, but not updated into MariaDB yet
+Bug: https://jira.mariadb.org/browse/MDEV-19251
+Description:
+ Upstream has merged this but we still need to wait for it to be included
+ in a RocksDB release and imported into MariaDB and then into Debian.
+--- a/storage/rocksdb/build_rocksdb.cmake
++++ b/storage/rocksdb/build_rocksdb.cmake
+@@ -90,6 +90,8 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Linux"
+   add_definitions(-DOS_LINUX)
+ elseif(CMAKE_SYSTEM_NAME MATCHES "SunOS")
+   add_definitions(-DOS_SOLARIS)
++elseif(CMAKE_SYSTEM_NAME MATCHES "kFreeBSD")
++  add_definitions(-DOS_GNU_KFREEBSD)
+ elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+   add_definitions(-DOS_FREEBSD)
+ elseif(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
+--- a/storage/rocksdb/rocksdb/CMakeLists.txt
++++ b/storage/rocksdb/rocksdb/CMakeLists.txt
+@@ -91,7 +91,7 @@ if(MSVC)
+   option(WITH_XPRESS "build with windows built in compression" OFF)
+   include(${CMAKE_CURRENT_SOURCE_DIR}/thirdparty.inc)
+ else()
+-  if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
++  if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD" AND NOT CMAKE_SYSTEM_NAME MATCHES "kFreeBSD")
+     # FreeBSD has jemalloc as default malloc
+     # but it does not have all the jemalloc files in include/...
+     set(WITH_JEMALLOC ON)
+@@ -413,6 +413,8 @@ elseif(CMAKE_SYSTEM_NAME MATCHES "Linux"
+   add_definitions(-DOS_LINUX)
+ elseif(CMAKE_SYSTEM_NAME MATCHES "SunOS")
+   add_definitions(-DOS_SOLARIS)
++elseif(CMAKE_SYSTEM_NAME MATCHES "kFreeBSD")
++  add_definitions(-DOS_GNU_KFREEBSD)
+ elseif(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
+   add_definitions(-DOS_FREEBSD)
+ elseif(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
+--- a/storage/rocksdb/rocksdb/build_tools/build_detect_platform
++++ b/storage/rocksdb/rocksdb/build_tools/build_detect_platform
+@@ -190,6 +190,17 @@ EOF
+         PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lpthread"
+         # PORT_FILES=port/freebsd/freebsd_specific.cc
+         ;;
++    GNU/kFreeBSD)
++        PLATFORM=OS_GNU_KFREEBSD
++        COMMON_FLAGS="$COMMON_FLAGS -DOS_GNU_KFREEBSD"
++        if [ -z "$USE_CLANG" ]; then
++            COMMON_FLAGS="$COMMON_FLAGS -fno-builtin-memcmp"
++        else
++            PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -latomic"
++        fi
++        PLATFORM_LDFLAGS="$PLATFORM_LDFLAGS -lpthread -lrt"
++        # PORT_FILES=port/gnu_kfreebsd/gnu_kfreebsd_specific.cc
++        ;;
+     NetBSD)
+         PLATFORM=OS_NETBSD
+         COMMON_FLAGS="$COMMON_FLAGS -fno-builtin-memcmp -D_REENTRANT -DOS_NETBSD"
+--- a/storage/rocksdb/rocksdb/env/env_posix.cc
++++ b/storage/rocksdb/rocksdb/env/env_posix.cc
+@@ -41,7 +41,7 @@
+ #include <time.h>
+ #include <algorithm>
+ // Get nano time includes
+-#if defined(OS_LINUX) || defined(OS_FREEBSD)
++#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD)
+ #elif defined(__MACH__)
+ #include <Availability.h>
+ #include <mach/clock.h>
+@@ -287,7 +287,8 @@ class PosixEnv : public CompositeEnvWrap
+   }
+   uint64_t NowNanos() override {
+-#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_AIX)
++#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD) || \
++    defined(OS_AIX)
+     struct timespec ts;
+     clock_gettime(CLOCK_MONOTONIC, &ts);
+     return static_cast<uint64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
+@@ -307,8 +308,8 @@ class PosixEnv : public CompositeEnvWrap
+   }
+   uint64_t NowCPUNanos() override {
+-#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_AIX) || \
+-    (defined(__MACH__) && defined(__MAC_10_12))
++#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD) || \
++    defined(OS_AIX) || (defined(__MACH__) && defined(__MAC_10_12))
+     struct timespec ts;
+     clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
+     return static_cast<uint64_t>(ts.tv_sec) * 1000000000 + ts.tv_nsec;
+--- a/storage/rocksdb/rocksdb/port/stack_trace.cc
++++ b/storage/rocksdb/rocksdb/port/stack_trace.cc
+@@ -32,7 +32,7 @@ namespace port {
+ namespace {
+-#if defined(OS_LINUX) || defined(OS_FREEBSD)
++#if defined(OS_LINUX) || defined(OS_FREEBSD) || defined(OS_GNU_KFREEBSD)
+ const char* GetExecutableName() {
+   static char name[1024];
+--- a/storage/rocksdb/rdb_io_watchdog.h
++++ b/storage/rocksdb/rdb_io_watchdog.h
+@@ -56,19 +56,19 @@ class Rdb_io_watchdog {
+   int stop_timers() {
+     int ret = 0;
+-    if (m_io_check_watchdog_timer) {
++    if (m_io_check_watchdog_timer != reinterpret_cast<timer_t>(-1)) {
+       ret = timer_delete(m_io_check_watchdog_timer);
+       if (!ret) {
+-        m_io_check_watchdog_timer = nullptr;
++        m_io_check_watchdog_timer = reinterpret_cast<timer_t>(-1);
+       }
+     }
+-    if (m_io_check_timer && !ret) {
++    if (m_io_check_timer != reinterpret_cast<timer_t>(-1) && !ret) {
+       ret = timer_delete(m_io_check_timer);
+       if (!ret) {
+-        m_io_check_timer = nullptr;
++        m_io_check_timer = reinterpret_cast<timer_t>(-1);
+       }
+     }
+@@ -93,8 +93,8 @@ class Rdb_io_watchdog {
+  public:
+   explicit Rdb_io_watchdog(std::vector<std::string> &&directories)
+-      : m_io_check_timer(nullptr),
+-        m_io_check_watchdog_timer(nullptr),
++      : m_io_check_timer(reinterpret_cast<timer_t>(-1)),
++        m_io_check_watchdog_timer(reinterpret_cast<timer_t>(-1)),
+         m_io_in_progress(false),
+         m_dirs_to_check(std::move(directories)),
+         m_buf(nullptr) {
+--- a/storage/rocksdb/rdb_io_watchdog.cc
++++ b/storage/rocksdb/rdb_io_watchdog.cc
+@@ -111,7 +111,7 @@ void Rdb_io_watchdog::io_check_callback(
+     sql_print_warning("Deleting the watchdog I/O timer failed with %d.", errno);
+   }
+-  m_io_check_watchdog_timer = nullptr;
++  m_io_check_watchdog_timer = reinterpret_cast<timer_t>(-1);
+   RDB_MUTEX_UNLOCK_CHECK(m_reset_mutex);
+ }
diff --git a/patches/series b/patches/series
new file mode 100644 (file)
index 0000000..d1a6925
--- /dev/null
@@ -0,0 +1,14 @@
+0025-Change-the-default-optimization-from-O3-to-O2-in-mys.patch
+rocksdb-kfreebsd.patch
+env-perl-usr-bin-perl.patch
+fix-spelling-rocksdb.patch
+fix-reproducible-builds-rocksdb.patch
+mroonga-mrn-lib-dirs-path-reproducible-build.patch
+2541-fix-stack-overflow-in-pinbox-allocator.patch
+fix-spelling-libmariadb.patch
+install-files-into-usr.patch
+1006531-hurd-no-auth-socket.patch
+startup-message.patch
+fix-spelling-mariadb.patch
+hurd-i386-plugin_disks_information_schema_disks.cc.patch
+hurd-i386-storage_connect_ioapi.h.patch
diff --git a/patches/startup-message.patch b/patches/startup-message.patch
new file mode 100644 (file)
index 0000000..6b8bbce
--- /dev/null
@@ -0,0 +1,68 @@
+Forwarded: no
+Author: Otto Kekäläinen <otto@debian.org>
+Date: Sun, 10 Mar 2024 16:56:13 +0000
+Subject: [PATCH] Show banner in server and client startup to drive community engagement
+
+Suggest to users that they can support MariaDB development by simply giving a
+star on GitHub. This patch experiments with how well such a banner works, and
+may later change the contents to drive some other kind of engagement.
+
+Client output:
+    Welcome to the MariaDB monitor.  Commands end with ; or \g.
+    Your MariaDB connection id is 34
+    Server version: 10.11.7-MariaDB-3 Debian n/a
+
+    Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
+    Support MariaDB developers by giving a star at https://github.com/MariaDB/server
+
+    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
+
+    MariaDB [(none)]>
+
+Server output:
+    [Note] Support MariaDB developers by giving a star at https://github.com/MariaDB/server
+
+Server output if build in git directory:
+    [Note] Starting MariaDB 10.11.7-MariaDB-3 source revision 219efb0a6ab0ee8ce2ec831c715783586c4db2ef as process 5426
+
+--- a/client/mysql.cc
++++ b/client/mysql.cc
+@@ -1328,6 +1328,9 @@ int main(int argc,char *argv[])
+             mysql_thread_id(&mysql), server_version_string(&mysql));
+     put_info((char*) glob_buffer.ptr(),INFO_INFO);
+     put_info(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000"), INFO_INFO);
++    put_info("Support MariaDB developers by giving a star at "
++             "https://github.com/MariaDB/server",
++             INFO_INFO);
+   }
+ #ifdef HAVE_READLINE
+--- a/sql/mysqld.cc
++++ b/sql/mysqld.cc
+@@ -4985,12 +4985,21 @@ static int init_server_components()
+   my_sleep_for_space= mariadb_sleep_for_space;
+   /*
+-    Print source revision hash, as one of the first lines, if not the
+-    first in error log, for troubleshooting and debugging purposes
++    Print source revision hash, if set, for troubleshooting and debugging
++    purposes. If not, suggest database adming to help project by giving a
++    star on GitHub.
+   */
+-  if (!opt_help)
+-    sql_print_information("Starting MariaDB %s source revision %s as process %lu",
+-                          server_version, SOURCE_REVISION, (ulong) getpid());
++  if (!opt_help) {
++    if (SOURCE_REVISION) {
++      sql_print_information("Starting MariaDB %s source revision %s as process %lu",
++                            server_version, SOURCE_REVISION, (ulong) getpid());
++    } else {
++      sql_print_information("Starting MariaDB %s as process %lu",
++                            server_version, (ulong) getpid());
++      sql_print_information("Support MariaDB developers by giving a star at "
++                            "https://github.com/MariaDB/server");
++    }
++  }
+ #ifdef WITH_PERFSCHEMA_STORAGE_ENGINE
+   /*
diff --git a/po/POTFILES.in b/po/POTFILES.in
new file mode 100644 (file)
index 0000000..460c8f7
--- /dev/null
@@ -0,0 +1 @@
+[type: gettext/rfc822deb] mariadb-server.templates
diff --git a/po/ar.po b/po/ar.po
new file mode 100644 (file)
index 0000000..3737c75
--- /dev/null
+++ b/po/ar.po
@@ -0,0 +1,107 @@
+# 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: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\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: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "ملاحظة هامة لمستخدمي NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.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
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "إزالة جميع قواعد بيانات MariaDB؟"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr "الدليل /var/lib/mysql الذي يحتوي قواعد بيانات MariaDB ستتم إزالته."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"إن كنت تقوم بإزالة حزمة MariaDB كي تقوم لاحقاً بتثبيت نسخة أحدث أو إن كانت "
+"حزمة mariadb-server مختلفة تستخدمها، فيجب إبقاء البيانات."
diff --git a/po/ca.po b/po/ca.po
new file mode 100644 (file)
index 0000000..cf41099
--- /dev/null
+++ b/po/ca.po
@@ -0,0 +1,109 @@
+# mariadb (debconf) translation to Catalan.
+# his file is distributed under the same license as the mariadb package.
+# Aleix Badia i Bosch <abadia@ica.es> 2004
+# Innocent De Marchi <tangram.peces@gmail.com> 2017
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2017-03-20 17:55+0100\n"
+"Last-Translator: Innocent De Marchi <tangram.peces@gmail.com>\n"
+"Language-Team: Debian l10n Catalan <debian-l10n-catalan@lists.debian.org>\n"
+"Language: ca\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.11\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "El directori de dades antigues es desarà a una nova localització"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Ja hi ha un fitxer amb el nom «/var/lib/mysql/debian-*.flag» en aquests "
+"sistema. El número indica la versió de format binari de la base de dades que "
+"no és possible actualitzar (o tornar a una versió anterior) automàticament."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"En conseqüència, el directori de dades anterior serà renomenat a «/var/lib/"
+"mysql-*» i s'iniciarà un nou directori de dades a «/var/lib/mysql»."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Si us plau, importau o exportau manualment les vostres dades (p. ex. amb "
+"«mysqldump») si és necessari."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Nota important pels usuaris de «NIS/YP»"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Fer servir MariaDB sota «NIS/YP» requereix afegir un compte d'usuari MySQL "
+"al sistema local fent servir:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"També heu de comprovar els permisos i els propietaris del directori «/var/"
+"lib/mysql»"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Eliminar totes les bases de dades MariaDB?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"El directori «/var/lib/mysql» que conté totes les bases de dades MariaDB "
+"està a punt d'ésser eliminat."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Si estau des-instal·lant el paquet MariaDB amb la intenció d'instal·lar a "
+"continuació una versió més recent o hi ha una versió diferent del paquet "
+"«mariadb-server» que l'està fent servir, cal mantenir les dades."
diff --git a/po/cs.po b/po/cs.po
new file mode 100644 (file)
index 0000000..d55024a
--- /dev/null
+++ b/po/cs.po
@@ -0,0 +1,115 @@
+#
+#    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: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2020-10-18 17:13+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: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "Starý adresář s daty bude uložen na novém místě."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"V systému existuje soubor /var/lib/mysql/debian-*.flag. Číslo znamená verzi "
+"binárního formátu databáze, kterou nelze automaticky aktualizovat (ani "
+"degradovat)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Z tohoto důvodu bude původní adresář přejmenován na /var/lib/mysql-* a ve /"
+"var/lib/mysql se inicializuje nové datové úložiště."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Pokud je to potřeba, vyexportujte/naimportujte data ručně (např. pomocí "
+"mysqldump)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Důležitá poznámka pro uživatele NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Používání MariaDB pod NIS/YP vyžaduje, aby byl účet mysql uživatele přidán "
+"na lokálním systému příkazem:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+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
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Odstranit všechny MariaDB databáze?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"Adresář /var/lib/mysql, ve kterém se nachází MariaDB databáze, bude "
+"odstraněn."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Jestliže odstraňujete balík MariaDB za účelem instalace novější verze "
+"MariaDB, nebo pokud tato data souběžně využívá jiný balík mariadb-server, "
+"měli byste data ponechat."
diff --git a/po/da.po b/po/da.po
new file mode 100644 (file)
index 0000000..4a82051
--- /dev/null
+++ b/po/da.po
@@ -0,0 +1,109 @@
+# Danish translation mariadb.
+# Copyright (C) 2014 mariadb og nedenstående oversættere.
+# This file is distributed under the same license as the mariadb package.
+# Claus Hindsgaul <claus.hindsgaul@gmail.com>, 2005, 2006, 2007.
+# Joe Hansen <joedalton2@yahoo.dk>, 2014, 2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2016-07-09 22:41+0200\n"
+"Last-Translator: Joe Hansen <joedalton2@yahoo.dk>\n"
+"Language-Team: Danish <debian-l10n-danish@lists.debian.org>\n"
+"Language: da\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "Den gamle datamappe vil blive gemt på en ny placering"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"En fil navngivet /var/lib/msyql/debian-*.flag findes på dette system. "
+"Nummeret antyder en databaseversion i binært format, som ikke automatisk kan "
+"opgraderes (eller nedgraderes)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Derfor vil den tidligere datamappe blive omdøbt til /var/lib/mysql-* og en "
+"ny datamappe vil blive initialiseret i /var/lib/msyql."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Eksporter/importer venligst manuelt dine data (f.eks. med mysqldump) hvis "
+"krævet."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Vigtig oplysning til NIS/YP-brugere"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Brug af MariaDB under NIS/YP kræver, at en mysql-brugerkonto tilføjes på det "
+"lokale system med:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Du bør også kontrollere filrettighederne og ejerskabet af mappen /var/lib/"
+"mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Fjern alle MariaDB-databaser?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"Mappen /var/lib/mysql, der indeholder MariaDB-databaserne, er ved at blive "
+"fjernet."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Hvis du fjerner MariaDB-pakken for senere at installere en nyere version, "
+"eller hvis en anden mariadb-server-pakke allerede benytter den, bør dataene "
+"bevares."
diff --git a/po/de.po b/po/de.po
new file mode 100644 (file)
index 0000000..2292e3b
--- /dev/null
+++ b/po/de.po
@@ -0,0 +1,109 @@
+# German translation of mariadb
+# Alwin Meschede <ameschede@gmx.de>, 2006, 2007.
+# Thomas Mueller <thomas.mueller@tmit.eu>, 2009.
+# Chris Leick <c.leick@vollbio.de>, 2014-2016.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2016-05-12 22:39+0100\n"
+"Last-Translator: Chris Leick <c.leick@vollbio.de>\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"
+"Plural-Forms:  nplurals=2; plural=(n != 1);\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "Das alte Datenverzeichnis wird an einer neuen Stelle gespeichert"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Auf diesem System gibt es bereits eine Datei namens /var/lib/mysql/debian-*."
+"flag. Die Zahl gibt eine Binärformatversion der Datenbank an, von der nicht "
+"automatisch ein Upgrade (oder Downgrade) durchgeführt werden kann."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Daher wird das vorherige Datenverzeichnis in /var/lib/mysql-* umbenannt und "
+"unter /var/lib/mysql wird ein neues Datenverzeichnis initialisiert."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Bitte exportieren/importieren Sie im Bedarfsfall Ihre Daten (z.B. mit "
+"Mysqldump)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Wichtige Anmerkung für NIS/YP-Benutzer!"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Falls MariaDB mit NIS/YP genutzt wird, muss ein »mysql«-Benutzerkonto auf "
+"dem lokalen System hinzugefügt werden mit:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.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
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Alle MariaDB-Datenbanken entfernen?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"Das Verzeichnis /var/lib/mysql mit den MariaDB-Datenbanken soll entfernt "
+"werden."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Falls geplant ist, das MariaDB-Paket zu entfernen, um lediglich eine höhere "
+"Version zu installieren oder ein anderes mariadb-server-Paket die Daten "
+"benutzt, sollten diese beibehalten werden."
diff --git a/po/es.po b/po/es.po
new file mode 100644 (file)
index 0000000..4a383b1
--- /dev/null
+++ b/po/es.po
@@ -0,0 +1,144 @@
+# MariaDB translation to Spanish
+# Copyright (C) 2005-2016 Software in the Public Interest, SPI Inc.
+# This file is distributed under the same license as the mariadb package.
+#
+# Changes:
+# - Initial translation
+#       Jesus Aneiros, 2006
+# - Updated
+#       Javier Fernandez-Sanguino, 2006-2007, 2012, 2016
+# - Revision
+#       Nacho Barrientos Arias
+#       Fernando Cerezal
+#       David Martínez Moreno
+#       Ricardo Mones
+#       Carlos Galisteo
+#       Javier Fernandez-Sanguino
+#
+#
+#  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: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2016-04-30 21:26+0200\n"
+"Last-Translator: Javier Fernández-Sanguino <jfs@debian.org>\n"
+"Language-Team: Debian l10 Spanish <debian-l10n-spanish@lists.debian.org>\n"
+"Language: Spanish\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-POFile-SpellExtra: YP mariadb lib ej server flag mysqldump mysql var NIS\n"
+"X-POFile-SpellExtra: MariaDB\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "Se guardará el directorio antiguo de datos a la nueva ubicación"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Se ha encontrado un archivo «/var/lib/mysql/debian-*.flag» en el sistema. "
+"Este número indica una versión de base de datos en formato binario que no "
+"puede ser subirse (o bajarse) de versión automáticamente."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Por tanto, el archivo de datos anterior se renombrará a «/var/lib/mysql-*» y "
+"se inicializará un nuevo directorio de datos en «/var/lib/mysql»."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Si lo necesita, tendrá que exportar e importar sus datos manualmente (p.ej. "
+"con mysqldump)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Nota importante para los usuarios de NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Para utilizar MariaDB bajo NIS/YP es necesario añadir una cuenta de usuario "
+"mysql en el sistema local con:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.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
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "¿Desea eliminar todas las bases de datos MariaDB?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"El directorio /var/lib/mysql contiene bases de datos MariaDB que van a "
+"eliminarse."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-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 "
+"MariaDB más reciente o si hay un paquete «mariadb-server» distinto que los "
+"está utilizando."
diff --git a/po/eu.po b/po/eu.po
new file mode 100644 (file)
index 0000000..cf9826f
--- /dev/null
+++ b/po/eu.po
@@ -0,0 +1,104 @@
+# 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: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\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: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "NIS/YP erabiltzaileentzat ohar garrantzitsua"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.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
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Ezabatu MariaDB datubase guztiak?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"MariaDB datubaseak dituen /var/lib/mysql direktorioa ezabatua izango da."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"MariaDB paketea beranduago bertsio berriago bat instalatzeko kentzen ari "
+"bazara, edo beste mariadb-server pakete bat berau erabiltzen ari bada, "
+"datuak mantendu egin beharko lirateke."
diff --git a/po/fi.po b/po/fi.po
new file mode 100644 (file)
index 0000000..a58a516
--- /dev/null
+++ b/po/fi.po
@@ -0,0 +1,105 @@
+# Finnish translations for mariadb package
+# This file is distributed under the same license as the mariadb package.
+# Antti Järvinen <antti.jarvinen@katiska.org>, 2017.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2017-03-15 22:36+0200\n"
+"Last-Translator: antti.jarvinen@katiska.org\n"
+"Language-Team: \n"
+"Language: fi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.11\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "Vanha datahakemisto tullaan tallentamaan uuteen paikkaan"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Järjestelmässä on tiedosto /var/lib/mysql/debian-*.flag. Numero osoittaa "
+"tietokantatiedoston binääriformaatin version, josta/johon päivittäminen ei "
+"automaattisesti onnistu. "
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Siksipä vanha datahakemisto tullaan siirtämään nimelle /var/lib/mysql-* ja "
+"uudet tiedostot luodaan hakemistoon /var/lib/mysql."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Tarpeittesi mukaan tuo tai vie tietokannan sisältö käsipelillä, esim. "
+"käyttäen mysqldump-ohjelmaa."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Merkittävä huomio NIS/YP -käyttäjille"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"MariaDB:n käyttäminen NIS/YP:n kanssa edellyttää, että järjestelmään luodaan "
+"käyttäjätunnus mysql:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr "Tarkista myös hakemiston /var/lib/mysql omistaja ja oikeudet:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Poistetaanko kaikki MariaDB-tietokannat?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"MariaDB-tietokannat sisältävä hakemisto /var/lib/mysql ollaan poistamassa."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Jos poistat MariaDB-paketin asentaaksesi uudemman version tai jos joku muu "
+"mariadb-server -paketti jo käyttää tietoja, tiedot tulisi säästää. "
diff --git a/po/fr.po b/po/fr.po
new file mode 100644 (file)
index 0000000..d18cc71
--- /dev/null
+++ b/po/fr.po
@@ -0,0 +1,112 @@
+# Copyright (C) 2004-2016 Debian French l10n team <debian-l10n-french@lists.debian.org>
+# French translation of mariadb
+# This file is distributed under the same license as the mariadb package.
+# Translators:
+# Baptiste Jammet <baptiste@mailoo.org>, 2016.
+# Christian Perrier <bubulle@debian.org>, 2004-2013
+# bubu <bubub@no-log.org>, 2023.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2023-01-30 18:38+0100\n"
+"Last-Translator: bubu <bubub@no-log.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"
+"X-Generator: Poedit 2.4.2\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "L'ancien répertoire de données sera sauvegardé à un nouvel emplacement"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Un fichier nommé /var/lib/mysql/debian-*.flag existe sur ce système. Le "
+"numéro indique une version de base de données au format binaire qui ne peut "
+"être mise à niveau automatiquement (ni rétrogradée)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Par conséquent, le répertoire de données précédent sera renommé /var/lib/"
+"mysql.* et un nouveau répertoire sera initialisé à /var/lib/mysql."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Veuillez importer et exporter vos données manuellement (par exemple avec "
+"mysqldump) si nécessaire."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Remarque importante pour les utilisateurs de NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"L'utilisation de MariaDB sous NIS/YP nécessite qu'un compte utilisateur "
+"« mysql » soit ajouté au système local avec :"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Vous devriez aussi vérifier les permissions et propriétaire du répertoire /"
+"var/lib/mysql :"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Faut-il supprimer toutes les bases de données MariaDB ?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"Le répertoire /var/lib/mysql qui contient les bases de données MariaDB est "
+"sur le point d'être supprimé."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Si vous supprimez le paquet MariaDB pour installer ultérieurement une "
+"version plus récente ou si un autre paquet mariadb-server l'utilise déjà, "
+"les données devraient être conservées."
diff --git a/po/gl.po b/po/gl.po
new file mode 100644 (file)
index 0000000..cda277c
--- /dev/null
+++ b/po/gl.po
@@ -0,0 +1,106 @@
+# Galician translation of mariadb debconf templates
+# This file is distributed under the same license as the mariadb package.
+# Jacobo Tarrio <jtarrio@debian.org>, 2007.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2023-01-30 10:35+0100\n"
+"Last-Translator: Pablo <parodper@gmail.com>\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"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Poedit 3.2.2\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "O antigo directorio con datos gardarase noutro sitio."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Xa existe un ficheiro chamado /var/lib/mysql/debian-*.flag. O número indica "
+"unha versión do formato binario da base de datos que non se pode actualizar "
+"(ou desactualizar) de forma automática."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Por mor disto, o directorio de datos antigo moverase a /var/lib/mysql-* e "
+"crearase un novo directorio de datos en /var/lib/mysql."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Se o precisa, exporte e importe os datos de forma manual (v.g. con "
+"mysqldump)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Aviso importante se usa NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Para usar MariaDB con NIS/YP precisa engadir a conta de usuario mysql ao "
+"sistema local facendo:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr "Tamén comprobe os permisos e propietario do directorio /var/lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Eliminar todas as bases de datos MariaDB?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"Vaise eliminar o directorio /var/lib/mysql con todas as base de datos MariaDB"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Recomendamos que non elimine os datos se vai eliminar o paquete MariaDB para "
+"instalar unha versión máis nova, ou se inda os usa algún paquete mariadb-"
+"server."
diff --git a/po/it.po b/po/it.po
new file mode 100644 (file)
index 0000000..6afcd35
--- /dev/null
+++ b/po/it.po
@@ -0,0 +1,107 @@
+# Italian (it) translation of debconf templates for mariadb
+# This file is distributed under the same license as the mariadb package.
+# Luca Monducci <luca.mo@tiscali.it>, 2006-2017.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2017-083-20 20:29+0100\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: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "La vecchia directory data verrà salvata in una nuova posizione"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Su questo sistema esiste già un file con nome /var/lib/mysql/debian-*.flag. "
+"Il numero indica una versione del database in formato binario che non è "
+"possibile promuovere (o retrocedere) a una nuova versione automaticamente."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Di conseguenza la precedene directory data verrà rinominata in /var/lib/"
+"mysql-* e verrà preparata una nuova directory data in /var/lib/mysql."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Se necessario eseguire manualmente l'export/import (per esempio con "
+"mysqldump) dei propri dati."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Nota importante per gli utenti NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Per usare MariaDB con NIS/YP è necessario aggiungere al sistema un account "
+"utente locale con nome mysql con:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Inoltre è opportuno verificare i permessi e la proprietà della directory /"
+"var/lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Eliminare tutti i database MariaDB?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"La directory /var/lib/mysql che contiene i database di MariaDB sta per "
+"essere eliminata."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Se si rimuove il pacchetto MariaDB per poi installare una versione più "
+"recente oppure se sono già in uso da un altro pacchetto mariadb-server, i "
+"dati non devono essere eliminati."
diff --git a/po/ja.po b/po/ja.po
new file mode 100644 (file)
index 0000000..556a3ea
--- /dev/null
+++ b/po/ja.po
@@ -0,0 +1,118 @@
+#
+#    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.
+# Hideki Yamane (Debian-JP) <henrich@debian.or.jp>, 2013.
+# Takuma Yamada <tyamada@takumayamada.com>, 2016-2017.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2016-05-01 11:27+0900\n"
+"Last-Translator: Takuma Yamada <tyamada@takumayamada.com>\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"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"X-Generator: Gtranslator 2.91.6\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "古いデータディレクトリは、新しい場所に保存されます"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"/var/lib/mysql/debian-*.flag という名前のファイルがこのシステム上に存在しま"
+"す。番号は、自動的にアップグレード (またはダウングレード) することができない"
+"データベースバイナリフォーマットのバージョンを示します。"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"そのため、以前のデータディレクトリは /var/lib/mysql-* にリネームされ、新しい"
+"データディレクトリは /var/lib/mysql に初期化されます。"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"必要に応じて、(例えば mysqldump で) データを手動でエクスポート/インポートして"
+"ください。"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "NIS/YP ユーザへの重要な注意"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"NIS/YP 配下で MariaDB を使うにはローカルのシステムに mysql のユーザアカウント"
+"を追加するのが必要です。"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr "/var/lib/mysql の所有者権限をチェックする必要もあります。"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "すべての MariaDB データベースを削除しますか?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"MariaDB データベースを含んでいるディレクトリ /var/lib/mysql を削除しようとし"
+"ています。"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"後でより新しいバージョンのものをインストールしようとするために MariaDB パッ"
+"ケージを削除しようとしている、あるいは別の mariadb-server パッケージを既に"
+"使っている場合、データは保持する必要があります。"
diff --git a/po/ka.po b/po/ka.po
new file mode 100644 (file)
index 0000000..b0e8058
--- /dev/null
+++ b/po/ka.po
@@ -0,0 +1,108 @@
+# Translation of ka.po to Georgian
+# Copyright (C) 2023, MariaDB authors.
+# This file is distributed under the same license as the mariadb package.
+# Ekaterine Papava <papava.e@gtu.ge>, 2023.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2019-07-23 19:16-0300\n"
+"PO-Revision-Date: 2023-03-04 05:18+0100\n"
+"Last-Translator: Ekaterine Papava <papava.e@gtu.ge>\n"
+"Language-Team: Georgian <(nothing)>\n"
+"Language: ka\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: Poedit 3.2.2\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "ძველი მონაცემების საქაღალდე ახალ მდებარეობაზე იქნება შენახული"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"ამ სისტემაში არსებობს ფაილი სახელით /var/lib/mysql/debian-*.flag. რიცხვი "
+"მიუთითებს ბაზის ბინარული ფორმატის ვერსიაზე, რომლის განახლება (ან ვერსიის "
+"ჩამოწევა) შეუძლებელია."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"ამიტომ წინა მონაცემების საქაღალდეს სახელი /var/lib/mysql-*-ზე გადაერქმევა "
+"და /var/lib/mysql მონაცემების საქაღალდე თავიდან შეიქმნება."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"საჭიროების შემთხვევაში თქვენი მონაცემები ხელით გაიტანეთ/შემოიტანეთ (მაგ: "
+"mysqldump-ით)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "მნიშვნელოვანი შენიშვნა NIS/YP მომხმარებლებისთვის"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"MariaDB-ის გამოყენება NIS/YP-ის ქვეშ გასაშვებად მოითხოვს ლოკალურ სისტემაში "
+"mysql-ის მომხმარებლის დამატებას შემდეგი პარამეტრებით:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr "ასევე შეამოწმეთ /var/lib/mysql საქაღალდის წვდომები და მფლობელი:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "წავშალო MariaDB-ის ყველა ბაზა?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"საქაღალდე /var/lib/mysql, რომელიც MariaDB-ის მონაცემთა ბაზებს შეიცავს, "
+"წაიშლება."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"თუ შლით MariaDB-ის პაკეტს იმისთვის, რომ მოგვიანებით უფრო ახალი ვერსია "
+"დააყენოთ ან mariadb-server-ის სხვა პაკეტი უკვე იყენებს მას, მონაცემები უნდა "
+"შენარჩუნდეს."
diff --git a/po/nb.po b/po/nb.po
new file mode 100644 (file)
index 0000000..c0efb32
--- /dev/null
+++ b/po/nb.po
@@ -0,0 +1,103 @@
+# 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: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\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: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.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
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.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 MariaDB package in order to later install a more "
+"recent version or if a different mariadb-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 MariaDB-versjon, eller "
+"hvis en annen mariadb-server-pakke allerede bruker den."
diff --git a/po/nl.po b/po/nl.po
new file mode 100644 (file)
index 0000000..58f0a61
--- /dev/null
+++ b/po/nl.po
@@ -0,0 +1,111 @@
+# Dutch mariadb po-debconf translation,
+# Copyright (C) 2006 THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the mariadb package.
+# Vincent Zweije <zweije@xs4all.nl>, 2006.
+# Frans Spiesschaert <Frans.Spiesschaert@yucom.be>, 2014, 2016, 2018.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2018-03-29 21:25+0200\n"
+"Last-Translator: Frans Spiesschaert <Frans.Spiesschaert@yucom.be>\n"
+"Language-Team: Debian Dutch l10n Team <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"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Generator: Gtranslator 2.91.7\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "De oude data-map zal op een nieuwe locatie bewaard worden"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Er bestaat op dit systeem een bestand met als naam /var/lib/mysql/debian-*."
+"flag. Het nummer duidt op een versie van het binair database-bestandsformaat "
+"dat niet automatisch opgewaardeerd (of gedegradeerd) kan worden."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Daarom zal de vroegere data-map hernoemd worden naar /var/lib/mysql-* en zal "
+"er een nieuwe data-map geïnitialiseerd worden op /var/lib/mysql."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Gelieve uw data zo nodig handmatig te exporteren/importeren (bijv. met "
+"mysqldump)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Belangrijke opmerking voor gebruikers van NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Het gebruik van MariaDB onder NIS/YP vereist dat een mysql gebruikersaccount "
+"wordt toegevoegd aan het lokale systeem met:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"U moet ook controleren wie eigenaar is en wat de gebruikersrechten zijn van "
+"de map /var/lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Wilt u alle MariaDB-databases verwijderen?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"De map /var/lib/mysql die de MariaDB-databases bevat staat op het punt om "
+"verwijderd te worden."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Als u het MariaDB-pakket verwijdert om later een meer recente versie te "
+"installeren of als een ander mariadb-serverpakket het al gebruikt, zou de "
+"data behouden moeten worden."
diff --git a/po/pt.po b/po/pt.po
new file mode 100644 (file)
index 0000000..2f3149d
--- /dev/null
+++ b/po/pt.po
@@ -0,0 +1,109 @@
+# Portuguese translation for mariadb debconf messages
+# Copyright (C) 2006 Miguel Figueiredo <elmig@debianpt.org>
+# This file is distributed under the same license as the mariadb package.
+# Miguel Figueiredo <elmig@debianpt.org>, 2014
+# Rui Branco <ruipb@debianpt.org>, 2017.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2017-08-06 10:00+0100\n"
+"Last-Translator: Rui Branco <ruipb@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"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "O antigo directório de data será guardado num novo local"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Já existe um ficheiro /var/lib/mysql/debian-*.flag no sistema. O número "
+"indica uma base de dados de formato binário que não pode ser actualizada "
+"automaticamente (ou baixar de versão)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Assim o directório de dados anterior será renomeado para /var/lib/mysql-* e "
+"um novo directório de dados será inicializado em /var/lib/mysql."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Por favor, se necessário, exporte/importe manualmente os seus dados (p.ex. "
+"com mysqldump)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Nota importante para os utilizadores de NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Utilizar MariaDB com NIS/YP necessita de uma conta de utilizador de mysql "
+"para ser acrescentada ao sistema local com:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.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
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Remover todas as bases de dados MariaDB?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"O directório /var/lib/mysql que contém as bases de dados MariaDB está "
+"prestes a ser removido."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Se está a remover o pacote MariaDB de forma a posteriormente instalar uma "
+"versão mais recente ou se um pacote mariadb-server já o está a utilizar, "
+"então os dados devem ser mantidos."
diff --git a/po/pt_BR.po b/po/pt_BR.po
new file mode 100644 (file)
index 0000000..faba8c9
--- /dev/null
@@ -0,0 +1,109 @@
+# Debconf translations for mariadb.
+# This file is distributed under the same license as the mariadb package.
+# André Luís Lopes, <andrelop@debian.org>, 2005-2007.
+# Adriano Rafael Gomes <adrianorg@debian.org>, 2015-2023.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2023-02-04 15:43-0300\n"
+"Last-Translator: Adriano Rafael Gomes <adrianorg@debian.org>\n"
+"Language-Team: Brazilian Portuguese <debian-l10n-portuguese@lists.debian."
+"org>\n"
+"Language: pt_BR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "O diretório de dados antigo será salvo em novo local"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Um arquivo chamado /var/lib/mysql/debian-*.flag já existe nesse sistema. O "
+"número indica uma versão de formato binário de banco de dados que não pode "
+"ser atualizada (ou rebaixada) automaticamente."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Portanto, o diretório de dados anterior será renomeado para /var/lib/mysql-* "
+"e um novo diretório de dados será inicializado em /var/lib/mysql."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Por favor, exporte/importe manualmente seus dados (por exemplo, com "
+"mysqldump) se necessário."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Aviso importante para usuários NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Usar o MariaDB sob NIS/YP requer que uma conta de usuário mysql seja "
+"adicionada ao sistema local com:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Você deverá também verificar as permissões e o dono do diretório /var/lib/"
+"mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Remover todas as bases de dados do MariaDB?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"O diretório /var/lib/mysql, o qual contém as bases de dados do MariaDB, está "
+"prestes a ser removido."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Caso você esteja removendo o pacote MariaDB para posteriormente instalar uma "
+"versão mais recente ou, caso uma versão diferente do pacote mariadb-server "
+"esteja sendo utilizada, os dados deverão ser mantidos."
diff --git a/po/ro.po b/po/ro.po
new file mode 100644 (file)
index 0000000..c2851f0
--- /dev/null
+++ b/po/ro.po
@@ -0,0 +1,110 @@
+# Romanian translation of mariadb.
+# Copyright © 2006, 2023 THE mariadb COPYRIGHT HOLDER
+# This file is distributed under the same license as the mariadb package.
+#
+# Stan Ioan-Eugen <stan.ieugen@gmail.com>, 2006.
+# Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>, 2023.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2023-01-29 23:56+0100\n"
+"Last-Translator: Remus-Gabriel Chelu <remusgabriel.chelu@disroot.org>\n"
+"Language-Team: romanian <debian-l10n-romanian@lists.debian.org>\n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.2.2\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "Vechiul director de date va fi salvat în noua locație"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Un fișier numit „/var/lib/mysql/debian-*.flag” există în acest sistem. Numărul "
+"indică o versiune în format binar al bazei de date care nu poate fi actualizată "
+"(sau retrogradată) automat."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* and a "
+"new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Prin urmare, directorul de date anterior va fi redenumit în „/var/lib/mysql-*” "
+"și un nou director de date va fi inițializat la „/var/lib/mysql”."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Exportați/importați manual datele dumneavoastră (de exemplu, cu «mysqldump»), "
+"dacă este necesar."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Notă importantă pentru utilizatorii NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Dacă MariaDB se utilizează sub NIS/YP, se necesită adăugarea unui cont de "
+"utilizator „mysql” în sistemul local cu:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Ar trebui să verificați, de asemenea, permisiunile și dreptul de proprietate "
+"asupra directorului „/var/lib/mysql”:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Eliminați toate bazele de date MariaDB?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about to "
+"be removed."
+msgstr ""
+"Directorul „/var/lib/mysql” care conține bazele de date MariaDB este pe cale să "
+"fie eliminat."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more recent "
+"version or if a different mariadb-server package is already using it, the data "
+"should be kept."
+msgstr ""
+"Dacă eliminați pachetul MariaDB pentru a instala ulterior o versiune mai "
+"recentă sau dacă un alt pachet mariadb-server îl folosește deja, datele ar "
+"trebui păstrate."
diff --git a/po/ru.po b/po/ru.po
new file mode 100644 (file)
index 0000000..5271c56
--- /dev/null
+++ b/po/ru.po
@@ -0,0 +1,110 @@
+# translation of ru.po to Russian
+#
+# 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, 2014, 2016.
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2016-05-04 18:56+0300\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.5\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: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "Каталог со старыми данными будет сохранён в новом месте"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"В системе найден файл /var/lib/mysql/debian-*.flag. Число представляет "
+"версию двоичного формата базы данных, которую невозможно обновить "
+"автоматически (или откатить к старой версии)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"В следствии этого, предыдущий каталог с данными будет переименован в /var/"
+"lib/mysql-*, а в /var/lib/mysql будет инициализирован каталог для новых "
+"данных."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Если нужно, выполните экспорт/импорт данных вручную (например, с помощью "
+"mysqldump)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Важное замечание для пользователей NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Использование MariaDB в NIS/YP требует добавления учётной записи mysql в "
+"локальную систему с:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr "Также проверьте права доступа и владельца каталога /var/lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Удалить все базы данных MariaDB?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"Запрос на удаление каталога /var/lib/mysql, содержащий базы данных MariaDB."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Если вы удаляете пакет MariaDB для установки более новой версии MariaDB, или "
+"есть другие пакеты mariadb-server, использующие этот каталог, то данные "
+"лучше сохранить."
diff --git a/po/sv.po b/po/sv.po
new file mode 100644 (file)
index 0000000..806ebba
--- /dev/null
+++ b/po/sv.po
@@ -0,0 +1,110 @@
+# Translation of mariadb debconf template to Swedish
+# Copyright (C) 2017 Martin Bagge <brother@bsnet.se>
+# This file is distributed under the same license as the mariadb package.
+#
+# Andreas Henriksson <andreas@fatal.se>, 2007
+# Martin Bagge <brother@bsnet.se>, 2009, 2015, 2017
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2017-03-23 09:20+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-Generator: Poedit 1.8.11\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "Den gamla data-katalogen kommer att sparas till en ny plats"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"En fil med namn på formatet /var/lib/mysql/debian-*.flag hittades i "
+"systemet. Siffran indikerar ett binärformat på databasen som inte kan "
+"uppgraderas (eller nedgraderas)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Därför kommer den gamla data-katalogen att byta namn till /var/lib/mysql-* "
+"och en ny katalog kommer att initieras på /var/lib/mysql."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Exportera/importera din data manuellt (exempelvis med mysqldump) om detta är "
+"nödvändigt."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Viktig information för NIS/YP-användare"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"För att kunna använda MariaDB under NIS/YP måste ett användarkonto för mysql "
+"läggas till i systemet."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.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
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Ta bort alla MariaDB-databaser?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"Katalogen /var/lib/mysql som innehåller MariaDB-databaser kommer att tas "
+"bort."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Om avinstallationen av MariaDB-paketet görs för att senare kunna installera "
+"en nyare version eller om en annan mariadb-server redan använder filerna ska "
+"de inte raderas."
diff --git a/po/sw.po b/po/sw.po
new file mode 100644 (file)
index 0000000..ec5d48e
--- /dev/null
+++ b/po/sw.po
@@ -0,0 +1,110 @@
+# Translation of mariadb debconf templates to Swahili
+# Copyright (C) 2023, MariaDB authors.
+# This file is distributed under the same license as the mariadb packages.
+#
+# Translators:
+# Nicholas Othieno <nothieno@amazon.com>, 2023.
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2019-07-23 19:16-0300\n"
+"PO-Revision-Date: 2023-06-16 18:32-0400\n"
+"Last-Translator: Nicholas Othieno <nothieno@amazon.com>\n"
+"Language-Team: Swahili <(nothing)>\n"
+"Language: sw\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"debian.org>\n"
+"X-Generator: Poedit 3.2.2\n"
+"Plural-Forms: Plural-Forms: nplurals=2; plural=n>1;\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "Saraka la zamani la data itahifadhiwa kwenye eneo jipya"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Faili linaloitwa /var/lib/mysql/debian-*.flag lipo katika mfumo huu. Namba "
+"inaonyesha toleo la umbizo wa mfumo wa jozi la hifadhidata ambalo haliwezi "
+"kuboreshwa (au kushushwa) kiotomatiki."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Hivyo basi saraka la zamani la data litapewa jina jipya kuwa /var/lib/mysql-* "
+"na saraka jipya la data litaanzishwa kwenye /var/lib/mysql."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Tafadhali peleka/ingiza data yako kwa mkono (kwa mfano kwa kutumia mysqldump) ikiwa inahitajika."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Ujumbe muhimu kwa watumiaji wa NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Kutumia MariaDB chini ya NIS/YP inahitaji akaunti ya mtumiaji wa mysql kuongezwa "
+"katika mfumo wa ndani na:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Unapaswa pia kukagua ruhusa na umiliki wa saraka la /var/lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Ondoa hifadhidata zote za MariaDB?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"Eneo la /var/lib/mysql ambalo lina hifadhidata za MariaDB linakaribia "
+"kuondolewa."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Ikiwa unatoa kifurushi cha MariaDB ili kusakinisha toleo jipya zaidi baadaye "
+"au ikiwa kifurushi tofauti cha mariadb-server tayari inaitumia data, data "
+"inapaswa kuwekwa."
\ No newline at end of file
diff --git a/po/templates.pot b/po/templates.pot
new file mode 100644 (file)
index 0000000..49daaa3
--- /dev/null
@@ -0,0 +1,93 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the mariadb package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\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: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
diff --git a/po/tr.po b/po/tr.po
new file mode 100644 (file)
index 0000000..b8ec2a7
--- /dev/null
+++ b/po/tr.po
@@ -0,0 +1,107 @@
+# Turkish translation of mariadb-server.
+# This file is distributed under the same license as the mariadb-server package.
+# Gürkan Aslan <gurkan@iaslan.com>, 2004
+# Atila KOÇ <koc@artielektronik.com.tr>, 2015, 2017
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2017-03-16 13:16+0300\n"
+"Last-Translator: Atila KOÇ <koc@artielektronik.com.tr>\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"
+"X-Generator: Poedit 1.8.7.1\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "Eski veritabanı dizini yeni konumuna kaydedilecektir"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Bu sistemde /var/lib/mysql/debian-*.flag adlı bir dosya bulunmaktadır. "
+"Belirtilen numara kendiliğinden yükseltilemeyecek ya da alçaltılamayacak bir "
+"ikilik veritabanı biçimini işaret etmektedir."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Önceki veri dizini /var/lib/mysql-* olarak yeniden adlandırılacak ve yeni "
+"veri dizini /var/lib/mysql konumunda hazırlanacaktır."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr "Gerektiğinde verinizi elle (ör. mysqldump ile) içe/dışa aktarın."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "NIS/YP kullanıcıları için önemli not"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"MariaDB'nin NIS/YP ile kullanılması için yerel sisteme aşağıdaki komut "
+"çalıştırılarak mysql kullanıcı hesabının eklenmesi gereklidir:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"/var/lib/mysql dizininin sahiplik ve izin ayarlarını da gözden "
+"geçirmelisiniz:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Tüm MariaDB veritabanları kaldırılsın mı?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"MariaDB veritabanlarını barındıran /var/lib/mysql dizini kaldırılmak üzere"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Eğer MariaDB paketini daha sonra güncel bir sürümünü kurmak üzere "
+"kaldırıyorsanız ya da veritabanlarınıza başka bir mariadb-server paketi ile "
+"erişiyorsanız, veritabanlarınızı kaldırmamalısınız."
diff --git a/po/vi.po b/po/vi.po
new file mode 100644 (file)
index 0000000..3600ec3
--- /dev/null
+++ b/po/vi.po
@@ -0,0 +1,109 @@
+# Vietnamese translations for mariadb package
+# Bản dịch Tiếng Việt dành cho gói mariadb.
+# This file is distributed under the same license as the mariadb package.
+# Trần Ngọc Quân <vnwildman@gmail.com>, 2017.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2017-03-18 13:32+0700\n"
+"Last-Translator: Trần Ngọc Quân <vnwildman@gmail.com>\n"
+"Language-Team: Vietnamese <debian-l10n-vietnamese@lists.debian.org>\n"
+"Language: vi\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"
+"X-Generator: Gtranslator 2.91.7\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "Thư mục dữ liệu cũ sẽ được lưu tại vị trí mới"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"Một tập tin có tên /var/lib/mysql/debian-*.flag đã sẵn có trên hệ thống này. "
+"Con số chỉ ra rằng một phiên bản định dạng cơ sở dữ liệu không thể tự động "
+"nâng cấp (hoặc hạ cấp)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"Do đó thư mục dữ liệu trước đây sẽ được đổi tên thành /var/lib/mysql-* và "
+"thư mục dữ liệu mới sẽ được khởi tạo tại /var/lib/mysql."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr ""
+"Vui lòng xuất/nhập dữ liệu của bạn bằng tay nếu thấy cần (ví dụ bằng "
+"mysqldump)."
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "Chú ý quan trọng cho người dùng NIS/YP"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr ""
+"Dùng MariaDB dưới NIS/YP cần một tài khoản người dùng được thêm vào một hệ "
+"thống nội bộ với:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr ""
+"Bạn cũng nên kiểm tra phân quyền và chủ sở hữu của thư mục /var/lib/mysql:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "Xóa bỏ mọi cơ sở dữ liệu MariaDB chứ?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr ""
+"Thư mục /var/lib/mysql nơi mà chứa các cơ sở dữ liệu MariaDB chuẩn bị bị xóa "
+"bỏ."
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"Nếu bạn gỡ bỏ gói cốt để mà sau này cài đặt gói máy phục vụ phiên bản gần "
+"đây hoặc là một gói mariadb-server khác đang được dùng, dữ liệu nên được giữ "
+"lại."
diff --git a/po/zh_CN.po b/po/zh_CN.po
new file mode 100644 (file)
index 0000000..7a62179
--- /dev/null
@@ -0,0 +1,99 @@
+# Simplified Chinese translation of mariadb-server
+# This file is distributed under the same license as the mariadb package.
+# Tianyu Chen <billchenchina2001@gmail.com>, 2023.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: mariadb\n"
+"Report-Msgid-Bugs-To: mariadb@packages.debian.org\n"
+"POT-Creation-Date: 2022-12-31 18:55-0800\n"
+"PO-Revision-Date: 2023-02-02 03:08+0800\n"
+"Last-Translator: Tianyu Chen <billchenchina2001@gmail.com>\n"
+"Language-Team: \n"
+"Language: zh_CN\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"
+"X-Generator: Poedit 3.2.2\n"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid "The old data directory will be saved at new location"
+msgstr "旧的数据目录将被保存在新位置"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"A file named /var/lib/mysql/debian-*.flag exists on this system. The number "
+"indicates a database binary format version that cannot automatically be "
+"upgraded (or downgraded)."
+msgstr ""
+"系统中存在名为 /var/lib/mysql/debian-*.flag 的文件。这个数字说明系统中存在一"
+"个对应版本的数据库无法自动升级(或降级)。"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Therefore the previous data directory will be renamed to /var/lib/mysql-* "
+"and a new data directory will be initialized at /var/lib/mysql."
+msgstr ""
+"因此之前的数据目录将被重命名至 /var/lib/mysql-*,新的数据目录将被初始化为 /"
+"var/lib/mysql。"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:2001
+msgid ""
+"Please manually export/import your data (e.g. with mysqldump) if needed."
+msgstr "如必要,请手动导出/导入你的数据。(如,使用 mysqldump)"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid "Important note for NIS/YP users"
+msgstr "对 NIS/YP 用户的重要提示"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"Using MariaDB under NIS/YP requires a mysql user account to be added on the "
+"local system with:"
+msgstr "在 NIS/YP 下使用 MariaDB 需要使用以下命令在系统中添加一个 mysql 用户:"
+
+#. Type: note
+#. Description
+#: ../mariadb-server.templates:3001
+msgid ""
+"You should also check the permissions and ownership of the /var/lib/mysql "
+"directory:"
+msgstr "你还需要检查 /var/lib/mysql 目录的权限和所有权:"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid "Remove all MariaDB databases?"
+msgstr "移除全部 MariaDB 数据库?"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"The /var/lib/mysql directory which contains the MariaDB databases is about "
+"to be removed."
+msgstr "包含 MariaDB 数据库的目录 /var/lib/mysql 将被删除。"
+
+#. Type: boolean
+#. Description
+#: ../mariadb-server.templates:4001
+msgid ""
+"If you're removing the MariaDB package in order to later install a more "
+"recent version or if a different mariadb-server package is already using it, "
+"the data should be kept."
+msgstr ""
+"如果您是为了安装新版本而卸载 MariaDB 包,或正在使用另一个 mariadb-server 包,"
+"您应该保留数据。"
diff --git a/rules b/rules
new file mode 100755 (executable)
index 0000000..94eb814
--- /dev/null
+++ b/rules
@@ -0,0 +1,234 @@
+#!/usr/bin/make -f
+
+# Enable Debian Hardening
+# https://wiki.debian.org/Hardening
+export DEB_BUILD_MAINT_OPTIONS = hardening=+all
+
+# Disable LTO on Ubuntu, see LP: #1970634 and https://jira.mariadb.org/browse/MDEV-25633
+ifeq ($(shell dpkg-vendor --derives-from Ubuntu && echo yes), yes)
+    export DEB_BUILD_MAINT_OPTIONS += optimize=-lto
+endif
+
+DPKG_EXPORT_BUILDFLAGS = 1
+# Include all defaults, including buildflags.mk
+include /usr/share/dpkg/default.mk
+# CPPFLAGS are nor read by CMake, so copy them to CXXFLAGS
+# See why at https://cmake.org/Bug/view.php?id=12928
+# This is needed for e.g. all automatic Debian hardening flags to apply on all cmake builds.
+CFLAGS+=$(CPPFLAGS)
+CXXFLAGS+=$(CPPFLAGS)
+
+# Only do a strict symbol checking on Linux
+# https://manpages.debian.org/testing/dpkg-dev/dpkg-gensymbols.1.en.html
+# Level 4: Fails if some libraries have been introduced.
+ifneq (,$(filter linux,$(DEB_HOST_ARCH_OS)))
+    export DPKG_GENSYMBOLS_CHECK_LEVEL = 4
+endif
+
+BUILDDIR := builddir
+DEB_VERSION_REVISION := $(shell echo $(DEB_VERSION) | sed -e 's/^.*-//')
+DEB_VERSION_VERSION := $(shell echo $(DEB_VERSION) | sed -e 's/^.*:\(.*\)\(-\|+\).*/\1/')
+DEB_VERSION_MAJOR := $(shell echo $(DEB_VERSION_VERSION) | sed -e 's/^\(.*\)\..*$$/\1/')
+RELEASE := $(shell lsb_release -r -s) # Use changelog based DEB_DISTRIBUTION instead?
+TMP := $(CURDIR)/debian/tmp
+MTR_SKIP_TEST_LIST := $(shell mktemp)
+
+# According to Debian Policy version 4.2.0 builds should be as verbose as
+# possible unless 'terse' is specifically passed.
+ifeq (,$(filter terse,$(DEB_BUILD_OPTIONS)))
+    export DH_VERBOSE=1
+endif
+
+# Parallel build support as advised
+# at https://www.debian.org/doc/debian-policy/ch-source.html#s-debianrules-options
+ifneq (,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+    NUMJOBS = $(patsubst parallel=%,%,$(filter parallel=%,$(DEB_BUILD_OPTIONS)))
+    MAKEFLAGS += -j$(NUMJOBS)
+else
+    # NUMJOBS cannot be empty as it is used as a parameter to mtr, default to 'auto'.
+    NUMJOBS = auto
+endif
+
+# RocksDB cannot build on 32-bit platforms
+ifeq (32,$(DEB_HOST_ARCH_BITS))
+    CMAKEFLAGS += -DPLUGIN_ROCKSDB=NO
+endif
+
+# Only attempt to build with PMEM on archs that have package libpmem-dev available
+# See https://packages.debian.org/search?searchon=names&keywords=libpmem-dev
+ifneq (,$(filter $(DEB_HOST_ARCH),amd64 arm64 ppc64el riscv64))
+    CMAKEFLAGS += -DWITH_PMEM=ON
+endif
+
+# Fix compilation errors like "relocation truncated to fit: GPREL16 against symbol `wsrep_debug'"
+ifeq ($(DEB_HOST_ARCH),alpha)
+    export DEB_LDFLAGS_MAINT_APPEND += -Wl,--no-relax
+endif
+
+# Add support for verbose builds
+MAKEFLAGS += VERBOSE=1
+
+override_dh_auto_clean:
+       @echo "RULES.$@"
+       dh_testdir
+       # Delete obsolete/unstable components and embedded source code copies
+       # to ensure they are not used in Debian and in general to keep MariaDB binaries
+       # secure and using only system libraries that can be updated quickly and easily
+       # in case security vulnerabilities are found in any of the libraries
+       rm -rf $(BUILDDIR) builddir-native extra/readline extra/wolfssl zlib libmariadb/external/zlib
+       # Remove columnstore as the source code is dirty and software not mature enough for Debian anyway
+       rm -rf storage/columnstore
+       # Delete precompiled binaries in upstream sources to ensure they are not used in Debian
+       rm -rf storage/connect/JavaWrappers.jar storage/columnstore/columnstore/utils/jemalloc/libjemalloc.so.2
+
+       # Update po-files when clean runs before each build
+       debconf-updatepo
+
+       # Clean up files created by custom sections in build that 'dh clean' does not see automatically
+       rm -rf debian/mariadb-server.*.socket debian/substvars
+
+override_dh_auto_configure:
+       @echo "RULES.$@"
+       dh_testdir
+
+ifneq ($(DEB_BUILD_ARCH),$(DEB_HOST_ARCH))
+       dpkg-architecture -a$(DEB_BUILD_ARCH) -f -c dh_auto_configure --builddirectory=builddir-native --reload-all-buildenv-variables
+       dh_auto_build --builddirectory=builddir-native -- import_executables
+endif
+
+       echo "server:Version=$(DEB_VERSION)" >> debian/substvars
+
+       # As packages does not have major version any more in package name there is no
+       # way as it not set by dpkg to use this on postinst script. Use sed to
+       # determine major version instead.
+       # @TODO: Rewrite this to use the new upstream /var/lib/mysql_upgrade_info file
+       # instead of the legacy /var/lib/debian-XX.X.flag file
+       sed -i 's/__MARIADB_MAJOR_VER__/$(DEB_VERSION_MAJOR)/g' debian/mariadb-server.post* debian/mariadb-server.preinst
+
+       # Don't build ColumnStore, not mature enough for Debian yet.
+       PATH=$${MYSQL_BUILD_PATH:-"/usr/lib/ccache:/usr/local/bin:/usr/bin:/bin"} \
+           dh_auto_configure --builddirectory=$(BUILDDIR) -- \
+           -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+           $(CMAKEFLAGS) \
+           $(if $(filter $(DEB_BUILD_ARCH),$(DEB_HOST_ARCH)),,-DIMPORT_EXECUTABLES=$(CURDIR)/builddir-native/import_executables.cmake) \
+           -DCOMPILATION_COMMENT="$(DEB_VENDOR) $(RELEASE)" \
+           -DMYSQL_SERVER_SUFFIX="-$(DEB_VERSION_REVISION)" \
+           -DSYSTEM_TYPE="debian-$(DEB_HOST_GNU_SYSTEM)" \
+           -DBUILD_CONFIG=mysql_release \
+           -DCONC_DEFAULT_CHARSET=utf8mb4 \
+           -DPLUGIN_AWS_KEY_MANAGEMENT=NO \
+           -DPLUGIN_COLUMNSTORE=NO \
+           -DWITH_NUMA=AUTO \
+           -DIGNORE_AIO_CHECK=ON \
+           -DWITH_URING=ON \
+           -DWITH_INNODB_SNAPPY=ON \
+           -DHAVE_SYSTEM_LIBFMT_EXITCODE=0 \
+           -DDEB=$(DEB_VENDOR)
+
+# This is needed, otherwise 'make test' will run before binaries have been built
+override_dh_auto_build:
+       @echo "RULES.$@"
+       # Print build env info to help debug builds on different platforms
+       dpkg-architecture
+       cd $(BUILDDIR) && $(MAKE)
+
+override_dh_auto_test:
+       @echo "RULES.$@"
+       dh_testdir
+       # Skip running test suite after build if DEB_BUILD_OPTIONS contains 'nocheck'
+       @echo "DEB_BUILD_OPTIONS: $(DEB_BUILD_OPTIONS)"
+ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
+       # Skip unstable tests if such are defined for arch
+       [ ! -f debian/unstable-tests.$(DEB_HOST_ARCH) ] || cat debian/unstable-tests.$(DEB_HOST_ARCH) >> $(MTR_SKIP_TEST_LIST)
+       # Show contents of skip list on this architecture
+       @echo "On architecture $(DEB_HOST_ARCH) skip tests:"
+       cat $(MTR_SKIP_TEST_LIST)
+       # Run testsuite
+       cd $(BUILDDIR)/mysql-test && \
+       export MTR_PRINT_CORE=detailed && \
+       ./mtr --force --testcase-timeout=120 --suite-timeout=540 --retry=3 \
+             --verbose-restart --max-save-core=1 --max-save-datadir=1 \
+             --parallel=$(NUMJOBS) --skip-rpl --suite=main \
+             --skip-test-list=$(MTR_SKIP_TEST_LIST) \
+             $(MTR_ARGUMENTS_APPEND)
+       # Don't use --mem here as official Debian builders and most Docker systems don't have a large mem device available and
+       # would fail with errors on lack of disk space.
+endif
+
+override_dh_auto_install:
+       @echo "RULES.$@"
+       dh_testdir
+       dh_testroot
+
+       # Run 'make install' without output since it is uninteresting and
+       # silencing it helps to make overall build log shorter and more readable
+       @echo "Running $(MAKE) install DESTDIR=$(TMP) ..."
+       cd $(BUILDDIR) && $(MAKE) install DESTDIR=$(TMP) > /dev/null
+
+       # If mariadb-test package is removed, also remove most of it's files
+       grep --quiet "Package: mariadb-test" debian/control || rm -rf $(TMP)/usr/share/mysql/mysql-test
+
+       # Delete lone compiled binary that that does not belong in the
+       # mariadb-test-data package and which seems hard to move
+       # https://jira.mariadb.org/browse/MDEV-21654
+       rm -rf $(TMP)/usr/share/mysql/mysql-test/suite/plugins/pam/pam_mariadb_mtr.so
+
+       # Delete private files from libraries so they don't get shipped in the -dev packages
+       rm -r $(TMP)/usr/include/mariadb/server/private
+
+       # Don't ship sql-bench at all, just delete it completely even though it builds
+       rm -r $(TMP)/usr/sql-bench
+
+       # nm numeric soft is not enough, therefore extra sort in command
+       # to satisfy Debian reproducible build requirements
+       mkdir -p $(TMP)/usr/share/doc/mariadb-server
+       nm --defined-only $(BUILDDIR)/sql/mariadbd | LC_ALL=C sort | gzip -n -9 > $(TMP)/usr/share/doc/mariadb-server/mariadbd.sym.gz
+
+       # Rename and install AppArmor profile
+       install -D -m 644 debian/apparmor-profile $(TMP)/etc/apparmor.d/usr.sbin.mariadbd
+
+       # Install mariadb.pc as a symlink for the client library,
+       # use -f to override the existing server mariadb.pc file
+       ln -sf libmariadb.pc $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/pkgconfig/mariadb.pc
+
+       # Install libmariadbclient18 compatibility links
+       ln -s libmariadb.so.3 $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadbclient.so
+
+       # Install libmariadbclient.a compatibility link
+       ln -s libmariadb.a $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadbclient.a
+
+       # Symlink plugins that are used by both server and client and thus need to
+       # load from the libmariadb path as well
+       ln -s ../../../mysql/plugin/auth_test_plugin.so $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadb3/plugin/auth_test_plugin.so
+       ln -s ../../../mysql/plugin/qa_auth_interface.so $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadb3/plugin/qa_auth_interface.so
+       ln -s ../../../mysql/plugin/test_sql_service.so $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadb3/plugin/test_sql_service.so
+       # Move test plugins that are only needed by the client to the libmariadb path
+       mv -v $(TMP)/usr/lib/mysql/plugin/qa_auth_client.so $(TMP)/usr/lib/$(DEB_HOST_MULTIARCH)/libmariadb3/plugin/
+
+# Define name used for service, and install mariadb.service on Linux only
+override_dh_installsystemd:
+ifneq (,$(filter linux,$(DEB_HOST_ARCH_OS)))
+       dh_installsystemd -pmariadb-server mariadb.service
+endif
+
+# Change dh_missing from fail to list on non-Linux
+override_dh_missing:
+ifneq (,$(filter linux,$(DEB_HOST_ARCH_OS)))
+       dh_missing --list-missing
+endif
+
+override_dh_installinit-arch:
+       dh_installinit --name=mariadb
+
+# Use custom server version string variable
+override_dh_gencontrol:
+       dh_gencontrol -- -Tdebian/substvars
+
+# If a file is not supposed to be included anywhere, add it to the not-installed
+# file and document the reason. Note that dh_install supports the above mentioned
+# white list file only starting from Debian Stretch and Ubuntu Xenial.
+# To find more, grep build logs for 'but is not installed to anywhere'.
+%:
+       dh $@
+
+# vim: ts=8
diff --git a/salsa-ci.yml b/salsa-ci.yml
new file mode 100644 (file)
index 0000000..2395692
--- /dev/null
@@ -0,0 +1,1065 @@
+---
+# Include Salsa-CI as a base
+include:
+  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml
+  - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml
+
+# Override Salsa-CI with MariaDB specific variations
+variables:
+  BUILT_PACKAGES: "libmariadb-dev libmariadb-dev-compat libmariadb3
+    libmariadbd19t64 libmariadbd-dev mariadb-common mariadb-client-core
+    mariadb-client mariadb-server-core mariadb-server mariadb-backup
+    mariadb-plugin-connect mariadb-plugin-s3 mariadb-plugin-rocksdb
+    mariadb-plugin-oqgraph mariadb-plugin-mroonga mariadb-plugin-spider
+    mariadb-plugin-gssapi-server mariadb-plugin-gssapi-client
+    mariadb-plugin-cracklib-password-check mariadb-plugin-hashicorp-key-management
+    mariadb-plugin-provider-bzip2 mariadb-plugin-provider-lz4
+    mariadb-plugin-provider-lzma mariadb-plugin-provider-lzo
+    mariadb-plugin-provider-snappy mariadb-test mariadb-test-data"
+  DEB_BUILD_OPTIONS: "nocheck noautodbgsym"
+  RELEASE: sid
+  # Reprotest works, but takes very long time and often fails due to timeouts.
+  # Thus is best kept disabled and only occasionally manually enabled to
+  # test that reproducibility works, along with atomic reprotest to directly
+  # pinpoint what aspect of the build is broken if not reproducible.
+  SALSA_CI_DISABLE_REPROTEST: 1
+  SALSA_CI_ENABLE_ATOMIC_REPROTEST: 0
+  SALSA_CI_DISABLE_MISSING_BREAKS: 0
+  SALSA_CI_DISABLE_RC_BUGS: 0
+
+# Extend Salsa-CI build jobs to have longer timeout as the default GitLab
+# timeout (1h) is often not enough
+.build-package:
+  timeout: 3h
+
+stages:
+  - provisioning
+  - build
+  - test
+  - upgrade MariaDB
+  - upgrade MariaDB and distro
+  - upgrade MariaDB variant
+  - test extras
+  - publish # Stage referenced by Salsa-CI template aptly stanza, so must exist even though not used
+
+gnitpick:
+  stage: provisioning
+  image: debian:sid-slim
+  script: |
+    # Bare minimal (<4MB) for apt-key and gnitpick to work
+    apt-get update -qq && apt-get -qq install --no-install-recommends --yes ca-certificates curl python3-minimal git
+    curl -sS https://raw.githubusercontent.com/Seravo/gnitpick/master/gnitpick.py -o /usr/bin/gnitpick; chmod +x /usr/bin/gnitpick
+    # Actual Gnitpick part
+    gnitpick --target-repository https://salsa.debian.org/mariadb-team/mariadb-server.git --target-branch debian/latest
+  except:
+    variables:
+      - $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/
+  allow_failure: true  # Gnitpick does not fully support this branch naming scheme so ignore it for now
+
+packaging-fix-checks:
+  stage: provisioning
+  image: debian:sid-slim
+  script:
+    - apt-get update -qq && apt-get -qq install --no-install-recommends --yes git devscripts python3-debian shellcheck make lsb-release dh-debputy python3-pygls
+    # Check debian/* for typical errors. Don't check spelling as there are too
+    # many false positives and anyway spelling issues are level 'pedantic' in
+    # Debputy and do not emit an exit code, so wouldn't show up as failure in CI
+    # anyway.
+    - debputy lint
+    - |
+      if [ "$(find debian/patches/ -type f -not -name series | wc -l)" -eq "$(cat debian/patches/series | wc -l)" ]
+      then
+        echo "The directory debian/patches/ contents and debian/patches/series file match by count."
+      else
+        find debian/patches -type f -not -name series -printf "%P\n" | sort > /tmp/patches-directory-sorted
+        sort debian/patches/series > /tmp/patches-series-sorted
+        diff -y /tmp/patches-series-sorted /tmp/patches-directory-sorted
+        echo
+        echo "The directory debian/patches/ file count does not match that in debian/series. Check that there are no unaccounted patches!"
+        exit 1
+      fi
+    - |
+      wrap-and-sort -ast
+      git checkout debian/tests/control # Revert touching this file, wrap-and-sort shouldn't do it
+      if [ "$(git diff --name-only | wc -l)" -eq 0 ]
+      then
+        echo "No uncommitted changes after 'wrap-and-sort -ast', maintainer has done good job keeping files in order."
+      else
+        git diff
+        echo
+        echo "Debian packaging files are unordered! Please run 'wrap-and-sort -vast'."
+        exit 1
+      fi
+    # Print syntax errors if found, otherwise continue silently
+    - make --dry-run --makefile=debian/rules > /dev/null
+    - |
+      shellcheck -x --shell=sh $(grep -Irnw debian/ -e '^#!.*/sh' | sort -u |cut -d ':' -f 1 | xargs)
+      shellcheck -x --shell=bash $(grep -Irnw debian/ -e '^#!.*/bash' | sort -u |cut -d ':' -f 1 | xargs)
+  except:
+    variables:
+      - $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/
+
+# Buster only has libfmt 6.1 but 7.0 is required, so backport build for Buster
+# is not possible unless somebody packages libfmt7-dev for Buster.
+
+test-crossbuild-arm64:
+  stage: build
+  # Cross-builds allowed to fail by default in Salsa-CI
+
+test-crossbuild-armhf:
+  stage: build
+  extends: .test-crossbuild-package-arm64
+  variables:
+    HOST_ARCH: armhf
+  allow_failure: true  # Cross-builds seem to fail frequently due to unclear reasons
+
+test-crossbuild-armel:
+  stage: build
+  extends: .test-crossbuild-package-arm64
+  variables:
+    HOST_ARCH: armel
+  allow_failure: true  # Cross-builds seem to fail frequently due to unclear reasons
+
+autopkgtest:
+  extends: .test-autopkgtest
+  artifacts:
+    reports:
+      junit: ${WORKING_DIR}/debci/artifacts/mysql-test-run-junit.xml
+
+piuparts:
+  stage: test extras
+
+blhc:
+  stage: test extras
+
+# In addition to Salsa-CI, also run these fully MariaDB specific build jobs
+
+# Define snippets used to construct jobs
+
+.test-prepare-container: &test-prepare-container |
+  cd ${WORKING_DIR} # Don't repeat this step, it's just cd ./debian/output
+  # Enable automatic restarts from maint scripts
+  sed -i "s/101/0/g" -i /usr/sbin/policy-rc.d
+  # Fake /sbin/runlevel to avoid warnings of "invoke-rc.d: could not determine current runlevel"
+  echo -e '#!/bin/sh\necho "N 5"' > /sbin/runlevel; chmod +x /sbin/runlevel
+  # Avoid the warnings of "debconf: unable to initialize frontend: Dialog"
+  echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections
+  # Emit non-zero exit code also on warnings
+  echo 'APT::Update::Error-Mode "any";' > /etc/apt/apt.conf.d/non-zero-exit-on-warnings
+  # Prime the apt cache so later apt commands can run
+  apt-get update -qq
+
+# Readline was removed from Debian Sid (and Bullseye) in Feb 2021. To be able to install older
+# versions of MariaDB that depend on it, fetch and install it from Buster.
+.test-install-readline-in-sid-for-backwards-compat: &test-install-readline-in-sid-for-backwards-compat |
+  curl -sS -O https://snapshot.debian.org/archive/debian/20190316T031117Z/pool/main/r/readline5/libreadline5_5.2%2Bdfsg-3%2Bb13_amd64.deb
+  apt-get -qq install --no-install-recommends --yes ./libreadline5_5.2%2Bdfsg-3%2Bb13_amd64.deb
+
+# OpenSSL 1.1 was Debian Sid in Dec 2022 (as Bookworm will ship with OpenSSL 3.0
+# only). To be able to install versions of MariaDB that depend on OpenSSL 1.1,
+# fetch and install it manually.
+.test-install-openssl1-in-sid-for-backwards-compat: &test-install-openssl1-in-sid-for-backwards-compat |
+  curl -sS -O https://snapshot.debian.org/archive/debian/20220507T034236Z/pool/main/o/openssl/libssl1.1_1.1.1o-1_amd64.deb
+  apt-get -qq install --no-install-recommends --yes ./libssl1.1_1.1.1o-1_amd64.deb
+
+# Package libaio1 was replaced by libaio1t64 in Debian Sid in April 2024. To
+# continue installing old MariaDB versions that depend on libaio1, use libaio1
+# from snapshots.
+.test-install-libaio-in-sid-for-backwards-compat: &test-install-libaio-in-sid-for-backwards-compat |
+  curl -sS -O https://snapshot.debian.org/archive/debian/20240331T210805Z/pool/main/liba/libaio/libaio1_0.3.113-5_amd64.deb
+  apt-get -qq install --no-install-recommends --yes ./libaio1_0.3.113-5_amd64.deb
+
+.test-verify-initial: &test-verify-initial |
+  dpkg -l | grep -iE 'maria|mysql|galera' || true # List installed
+  # MariaDB until 10.5 only had 'mysql', and since only 'mariadb', so try both
+  service mysql status || service mariadb status
+  mysql --skip-column-names -e "select @@version, @@version_comment" # Show version
+  mysql --table -e "SHOW DATABASES;" # List databases before upgrade
+  mysql --table -e "SELECT host,user,plugin,authentication_string FROM user;" mysql
+  mysql --table -e "SELECT * FROM plugin;" mysql
+  mysql --table -e "SHOW PLUGINS;" mysql
+
+.test-enable-sid-repos: &test-enable-sid-repos
+  # Replace any old repos with just Sid
+  - echo 'deb http://deb.debian.org/debian sid main' > /etc/apt/sources.list
+  # Upgrade minimal stack first
+  - apt-get update -qq
+  # Complete upgrade of minimal stack
+  - apt-get install -qq --yes apt || export APT_STATUS="failed"
+  # Due to https://bugs.debian.org/993755 and #975077 upgrades from Buster or
+  # older to Bookworm or newer fails on:
+  #   /usr/bin/perl: error while loading shared libraries: libcrypt.so.1: cannot
+  #     open shared object file: No such file or directory
+  #   dpkg: error processing package libc6:amd64 (--configure):
+  # Therefore, run this extra workaround if first run of apt-get install failed:
+  - |
+    if [ "$APT_STATUS" = "failed" ]
+    then
+      cd $(mktemp -d) # Use temp dir where apt can download and unpack files
+      apt-get -y download libcrypt1
+      dpkg-deb -x libcrypt1_*.deb .
+      cp -ra usr/lib/* /lib/ || true # libcrypt 1:4.4.36-3+
+      cd - # Back to /builds/$USER/mariadb-server/debian/output
+      find /lib/*/libcrypt.* -ls # Show that new libcrypt is there
+      apt-get -qq --yes --fix-broken install
+      apt-get install -qq --yes apt
+    fi
+
+.test-enable-artifacts-repo: &test-enable-artifacts-repo |
+  apt-get install -qq --yes apt-utils
+  apt-ftparchive packages . > Packages
+  echo "deb [trusted=yes] file:$(pwd) ./" > /etc/apt/sources.list.d/mariadb-local.list
+  apt-get update -qq
+
+.test-install-all: &test-install-all
+  - *test-enable-artifacts-repo
+  - apt-get install -qq --simulate ${BUILT_PACKAGES}
+  - apt-get install -qq --yes ${BUILT_PACKAGES}
+  # Verify installation of MariaDB built in this commit
+  - mariadb --version
+  - dpkg -l | grep -iE 'maria|mysql|galera'
+  - find /etc -name '*mariadb*' -ls -or -name '*mysql*' -ls | sort -k 11
+  # Purge old versions if they exist
+  - apt-get purge --yes mariadb*10.?
+  - find /etc -name '*mariadb*' -ls -or -name '*mysql*' -ls | sort -k 11
+
+.test-full-upgrade: &test-full-upgrade
+  - *test-enable-artifacts-repo
+  - apt-get full-upgrade -qq --simulate
+  - apt-get full-upgrade -qq --yes
+  # Verify installation of MariaDB built in this commit
+  - mariadb --version
+  - dpkg -l | grep -iE 'maria|mysql|galera'
+  - find /etc -name '*mariadb*' -ls -or -name '*mysql*' -ls | sort -k 11
+  # Purge old versions if they exist
+  - apt-get purge --yes mariadb*10.?
+  - find /etc -name '*mariadb*' -ls -or -name '*mysql*' -ls | sort -k 11
+  # Purging the old server might stop the running server, so restart it just in case
+  - service mariadb restart
+
+.test-install-all-libs: &test-install-all-libs
+  - *test-enable-artifacts-repo
+  - apt-get install -yq --no-install-recommends libmariadb-dev-compat libmariadbd-dev
+  # Installs 31 packages, including:
+  # libmariadb3 libmariadb-dev libmariadb-dev-compat libmariadbd19t64 libmariadbd-dev
+
+.test-full-upgrade-libs: &test-full-upgrade-libs
+  - *test-enable-artifacts-repo
+  - apt-get full-upgrade -y
+  - dpkg -l | grep -iE 'maria|mysql|galera'
+  # library tests don't have the mariadb client nor server, so don't check them
+
+.test-verify-final: &test-verify-final |
+  dpkg -l | grep -e "mariadb-server.*10\.11"
+  mkdir -p debug # Ensure dir exists before using it
+  find /var/lib/mysql -ls > debug/var-lib-mysql.list || true # Ignore errors about "no such file or directory"
+  cp -ra /etc/mysql debug/etc-mysql
+  mariadb --skip-column-names -e "select @@version, @@version_comment" # Show version
+  mariadb --table -e "SHOW DATABASES;" # List databases
+  mariadb --table -e "SELECT host,user,plugin,authentication_string FROM user;" mysql
+  mariadb --table -e "SELECT * FROM plugin;" mysql
+  mariadb --table -e "SHOW PLUGINS;" mysql
+  # Test that InnoDB works and that command 'mysql' is also still usable
+  mysql -e "CREATE DATABASE test; USE test; CREATE TABLE t(a INT PRIMARY KEY) ENGINE=INNODB; INSERT INTO t VALUEs (1); SELECT * FROM t; DROP TABLE t; DROP DATABASE test;"
+
+.test-verify-libs: &test-verify-libs
+  # Don't use a collapsed command as Gitlab-CI would hide each command from the output
+  - ldconfig -p | grep -e mariadb -e mysql
+  - pkg-config --list-all
+  - pkg-config --cflags --libs mysqlclient
+  - pkg-config --cflags --libs libmariadb
+  - pkg-config --cflags --libs mariadb
+  - apt-get install -qq --yes --no-install-recommends g++
+  - |
+    # Build a test binary that depends on libmysqlclient
+    cat > b933063.cpp <<EOF
+    #include <iostream>
+    #include <mysql/mysql.h>
+    #include <stdexcept>
+    int main()
+    {
+      MYSQL h;
+      if (!mysql_init(&h)
+        || mysql_options(&h, MYSQL_READ_DEFAULT_GROUP, "")
+        // || mysql_options(&h, MYSQL_SET_CHARSET_NAME, "utf8mb4")
+        || !mysql_real_connect(&h, "", "", NULL, "", 0, NULL, 0))
+        throw std::runtime_error(mysql_error(&h));
+      std::string q = "show variables like '%char%'";
+      if (mysql_real_query(&h, q.data(), q.size()))
+        throw std::runtime_error(mysql_error(&h));
+      MYSQL_RES* result = mysql_store_result(&h);
+      if (!result && mysql_errno(&h))
+        throw std::runtime_error(mysql_error(&h));
+      while (MYSQL_ROW row = mysql_fetch_row(result))
+      {
+        std::cout << row[0] << ": " << row[1] << "\n";
+      }
+      return 0;
+    }
+    EOF
+    apt-get install -qq --yes ./*.deb # Server must be installed for client to connect
+    echo "Testing -l mysqlclient"
+    g++ b933063.cpp -l mysqlclient && ./a.out | tee result
+    if grep --quiet latin result; then echo "ERROR: Charset latin found!"; exit 1; fi
+    echo "Testing -l mariadbclient"
+    g++ b933063.cpp -l mariadbclient && ./a.out | tee result
+    if grep --quiet latin result; then echo "ERROR: Charset latin found!"; exit 1; fi
+  - |
+    # Build a test binary to verify API version strings
+    cat > b1031863.cpp <<EOF
+    #include <cstring>
+    #include <iostream>
+    #include <mysql/mysql.h>
+    using namespace std;
+
+    void test_if_starts_with(const string expected, const string tested, const string name) {
+      int r = strncmp(tested.c_str(), expected.c_str(), expected.size());
+      if (r == 0) {
+        cout << name << ": " << tested << "\n";
+      } else {
+        cout << "ERROR: " << name << " started with " << tested << " instead of the expected " << expected << "!\n";
+        exit(1);
+      }
+    }
+
+    int main()
+    {
+      MYSQL h;
+      // Constants refer to server version
+      test_if_starts_with("1011", to_string(MARIADB_VERSION_ID), "MARIADB_VERSION_ID");
+      test_if_starts_with("1011", to_string(MYSQL_VERSION_ID), "MYSQL_VERSION_ID");
+      // Client ABI returns connector version
+      test_if_starts_with("303", to_string(mysql_get_client_version()), "mysql_get_client_version()");
+      test_if_starts_with("3.3", mysql_get_client_info(), "mysql_get_client_info()");
+      return 0;
+    }
+    EOF
+    g++ b1031863.cpp -l mysqlclient && ./a.out
+
+
+.salsa-ci-template-for-mariadb:
+  stage: test
+  needs:
+    - job: build
+  image: debian:${RELEASE}
+  artifacts:
+    when: always
+    name: "$CI_BUILD_NAME"
+    paths:
+      - ${WORKING_DIR}/debug
+  script:
+    - echo "This script section must be overridden in each test" && exit 1
+  variables:
+    GIT_STRATEGY: none
+  except:
+    variables:
+      - $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/
+
+.salsa-ci-template-for-mariadb-upgrade:
+  stage: test
+  needs:
+    - job: build
+  image: debian:${RELEASE}
+  artifacts:
+    when: always
+    name: "$CI_BUILD_NAME"
+    paths:
+      - ${WORKING_DIR}/debug
+  before_script:
+    - *test-prepare-container
+    - apt-get install -qq --yes --no-install-recommends ca-certificates curl
+    - |
+      [[ -d /etc/apt/keyrings ]] || mkdir /etc/apt/keyrings
+      curl -sS https://mariadb.org/mariadb_release_signing_key.pgp -o /etc/apt/keyrings/mariadb-keyring.pgp
+      cat >/etc/apt/sources.list.d/mariadb.sources <<EOF
+      X-Repolib-Name: MariaDB
+      Types: deb
+      URIs: https://archive.mariadb.org/mariadb-${MARIADB_VERSION}/repo/debian
+      Suites: ${RELEASE}
+      Components: main
+      Signed-By: /etc/apt/keyrings/mariadb-keyring.pgp
+      EOF
+    - apt-get update -qq
+  script:
+    - echo "This script section must be overridden in each test" && exit 1
+  variables:
+    GIT_STRATEGY: none
+    MARIADB_VERSION: "10.0"
+  except:
+    variables:
+      - $CI_COMMIT_TAG != null && $SALSA_CI_ENABLE_PIPELINE_ON_TAGS !~ /^(1|yes|true)$/
+
+fresh install:
+  extends: .salsa-ci-template-for-mariadb
+  script:
+    - *test-prepare-container
+    - *test-install-all
+    - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+
+simple upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB
+  script:
+    - *test-prepare-container
+    - apt-get install -qq --yes 'default-mysql*' ${BUILT_PACKAGES}
+    - *test-full-upgrade
+    - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+
+mariadb and Bookworm upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB and distro
+  image: debian:bookworm
+  script:
+    - *test-prepare-container
+    # Install everything MariaDB currently in Debian Bookworm
+    - apt-get install -qq --yes 'default-mysql*' 'mariadb-*' 'libmariadb*'
+    # Verify installation of MariaDB from Bookworm
+    - dpkg -l | grep -e "mariadb-server.*10\.11"
+    - *test-verify-initial
+    - *test-enable-sid-repos
+    # Ensure mariadbd will not crash on next shutdown for any reason
+    - service mariadb restart
+    - *test-full-upgrade
+    - service mariadb status  # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+
+mariadb-10.6 and Bookworm-20230208 upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB and distro
+  image: debian:bookworm-20230208
+  script:
+    - *test-prepare-container
+    - |
+      echo 'deb [check-valid-until=no] http://snapshot.debian.org/archive/debian/20230208T130000Z bookworm main' > /etc/apt/sources.list.d/bookworm.list
+      rm /etc/apt/sources.list.d/debian.sources
+      apt-get update -qq
+    # In February 2023 Bookworm snapshot this will install MariaDB 10.6
+    - apt-get install -qq --yes mariadb-server
+    # Verify installation of MariaDB from (February 2023) Bookworm
+    - dpkg -l | grep -e "mariadb-server.*10\.6"
+    - *test-verify-initial
+    - *test-enable-sid-repos
+    # Ensure mariadbd will not crash on next shutdown for any reason
+    - service mariadb restart
+    - *test-full-upgrade
+    - service mariadb status  # There is no init.d/mysql in MariaDB 10.5+
+    - apt-get purge --yes mariadb*10.?
+    - *test-verify-final
+
+mariadb-10.6 and Jammy upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB and distro
+  image: ubuntu:jammy
+  script:
+    - *test-prepare-container
+    # Install everything MariaDB currently in Ubuntu Jammy
+    - apt-get install -qq --yes 'mariadb-*' 'libmariadb*'
+    # Verify installation of MariaDB from Jammy
+    - dpkg -l | grep -e "mariadb-server.*10\.6"
+    - *test-verify-initial
+    # Install Debian Sid signing keys as Ubuntu does not have them by default
+    - apt-get install -qq --yes --no-install-recommends curl
+    - curl -sSLO http://deb.debian.org/debian/pool/main/d/debian-archive-keyring/debian-archive-keyring_2023.4_all.deb
+    - apt-get install -qq --yes ./debian-archive-keyring_*
+    - *test-enable-sid-repos
+    # Ensure mariadbd will not crash on next shutdown for any reason
+    - service mariadb restart
+    - *test-enable-artifacts-repo
+    - apt-get install -qq --simulate mariadb-server
+    - apt-get install -qq --yes mariadb-server
+    # Due to usrmerge, full-upgrade from Jammy to Trixie or newer cannot work
+    - service mariadb status  # There is no init.d/mysql in MariaDB 10.5+
+    - apt-get purge --yes mariadb*10.?
+    - *test-verify-final
+
+mariadb-10.5 and Bullseye upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB and distro
+  image: debian:bullseye
+  script:
+    - *test-prepare-container
+    # Install everything MariaDB currently in Debian Bullseye
+    - apt-get install -qq --yes 'default-mysql*' 'mariadb-*' 'libmariadb*'
+    # Verify installation of MariaDB from Bullseye
+    - dpkg -l | grep -e "mariadb-server.*10\.5"
+    - *test-verify-initial
+    - *test-enable-sid-repos
+    # Ensure mariadbd will not crash on next shutdown for any reason
+    - service mariadb restart
+    - *test-enable-artifacts-repo
+    - apt-get install -qq --simulate mariadb-server
+    - apt-get install -qq --yes mariadb-server
+    # Due to usrmerge, full-upgrade from Bullseye to Trixie or newer cannot work
+    - service mariadb status  # There is no init.d/mysql in MariaDB 10.5+
+    - apt-get purge --yes mariadb*10.?
+    - *test-verify-final
+
+mariadb-10.3 and Buster upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB and distro
+  image: debian:buster
+  script:
+    - *test-prepare-container
+    # Install everything MariaDB currently in Debian Buster
+    - apt-get install -qq --yes 'default-mysql*' 'mariadb-*' 'libmariadb*'
+    # Verify installation of MariaDB from Buster
+    - dpkg -l | grep -e "mariadb-server.*10\.3"
+    - *test-verify-initial
+    - *test-enable-sid-repos
+    # Ensure mariadbd will not crash on next shutdown for any reason
+    - service mysql restart # in 10.3 service name is still 'mysql'
+    - *test-enable-artifacts-repo
+    - apt-get install -qq --simulate mariadb-server
+    - apt-get install -qq --yes mariadb-server
+    # Due to usrmerge, full-upgrade from Bullseye to Trixie or newer cannot work
+    - service mysql status
+    # mariadb-10.3 in Buster ships a /etc/init.d/mysql and it continues to exist
+    # after upgrade, and is removed only on purge
+    - apt-get purge --yes mariadb*10.?
+    - service mariadb status
+    # Give the mariadb-upgrade plenty of time to complete, otherwise next commands
+    # fail on non-existing mariadb.sys user
+    - sleep 15
+    - *test-verify-final
+
+mariadb-10.3 and Focal upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB and distro
+  image: ubuntu:focal
+  script:
+    - *test-prepare-container
+    # Install everything MariaDB currently in Ubuntu Focal
+    - apt-get install -qq --yes 'mariadb-*' 'libmariadb*'
+    # Verify installation of MariaDB from Focal
+    - dpkg -l | grep -e "mariadb-server.*10\.3"
+    - *test-verify-initial
+    # Install Debian Sid signing keys as Ubuntu does not have them by default
+    - apt-get install -qq --yes --no-install-recommends curl
+    - curl -sSLO http://deb.debian.org/debian/pool/main/d/debian-archive-keyring/debian-archive-keyring_2023.4_all.deb
+    - apt-get install -qq --yes ./debian-archive-keyring_*
+    - *test-enable-sid-repos
+    # Ensure mariadbd will not crash on next shutdown for any reason
+    - service mysql restart # in 10.3 service name is still 'mysql'
+    - *test-enable-artifacts-repo
+    - apt-get install -qq --simulate mariadb-server
+    - apt-get install -qq --yes mariadb-server
+    # Due to usrmerge, full-upgrade from Focal to Trixie or newer cannot work
+    - service mysql status
+    # mariadb-10.3 in Focal ships a /etc/init.d/mysql and it continues to exist
+    # after upgrade, and is removed only on purge
+    - apt-get purge --yes mariadb*10.?
+    # Give the mariadb-upgrade plenty of time to complete, otherwise next commands
+    # fail on non-existing mariadb.sys user
+    - sleep 15
+    - *test-verify-final
+
+# Similar to the Cacti install test, check that MariaDB consumer Zoph upgrades
+default-mysql-server and Bookworm upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB and distro
+  image: debian:bookworm
+  script:
+    - *test-prepare-container
+    # Install everything MariaDB currently in Debian Bookworm
+    - apt-get install -qq --yes default-mysql-server zoph
+    # Verify installation of MariaDB from Bookworm
+    - dpkg -l | grep -e "mariadb-server.*10\.11"
+    - *test-verify-initial
+    - *test-enable-sid-repos
+    - *test-enable-artifacts-repo
+    - apt-get install -qq --simulate default-mysql-server
+    - apt-get install -qq --yes default-mysql-server
+    - *test-full-upgrade
+    - service mariadb status  # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+
+# Similar to the Cacti install test, check that MariaDB consumer Zoph upgrades
+default-mysql-server and Bullseye upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB and distro
+  image: debian:bullseye
+  script:
+    - *test-prepare-container
+    # Install everything MariaDB currently in Debian Bullseye
+    - apt-get install -qq --yes default-mysql-server zoph
+    # Verify installation of MariaDB from Bullseye
+    - dpkg -l | grep -e "mariadb-server.*10\.5"
+    - *test-verify-initial
+    - *test-enable-sid-repos
+    - *test-enable-artifacts-repo
+    - apt-get install -qq --simulate default-mysql-server
+    - apt-get install -qq --yes default-mysql-server
+    # Due to usrmerge, full-upgrade from Bullseye to Trixie or newer cannot work
+    - service mariadb status  # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+
+test basic features:
+  extends: .salsa-ci-template-for-mariadb
+  script:
+    - *test-prepare-container
+    - *test-install-all
+    - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+    - |
+      # Print info about server
+      mariadb --skip-column-names -e "select @@version, @@version_comment"
+      mariadb --skip-column-names -e "select engine, support, transactions, savepoints from information_schema.engines order by engine" | sort
+      mariadb --skip-column-names -e "select plugin_name, plugin_status, plugin_type, plugin_library, plugin_license from information_schema.all_plugins order by plugin_name, plugin_library"
+      # Test various features
+      mariadb -e "CREATE DATABASE db"
+      mariadb -e "CREATE TABLE db.t_innodb(a1 SERIAL, c1 CHAR(8)) ENGINE=InnoDB; INSERT INTO db.t_innodb VALUES (1,'"'"'foo'"'"'),(2,'"'"'bar'"'"')"
+      mariadb -e "CREATE TABLE db.t_myisam(a2 SERIAL, c2 CHAR(8)) ENGINE=MyISAM; INSERT INTO db.t_myisam VALUES (1,'"'"'foo'"'"'),(2,'"'"'bar'"'"')"
+      mariadb -e "CREATE TABLE db.t_aria(a3 SERIAL, c3 CHAR(8)) ENGINE=Aria; INSERT INTO db.t_aria VALUES (1,'"'"'foo'"'"'),(2,'"'"'bar'"'"')"
+      mariadb -e "CREATE TABLE db.t_memory(a4 SERIAL, c4 CHAR(8)) ENGINE=MEMORY; INSERT INTO db.t_memory VALUES (1,'"'"'foo'"'"'),(2,'"'"'bar'"'"')"
+      mariadb -e "CREATE ALGORITHM=MERGE VIEW db.v_merge AS SELECT * FROM db.t_innodb, db.t_myisam, db.t_aria"
+      mariadb -e "CREATE ALGORITHM=TEMPTABLE VIEW db.v_temptable AS SELECT * FROM db.t_innodb, db.t_myisam, db.t_aria"
+      mariadb -e "CREATE PROCEDURE db.p() SELECT * FROM db.v_merge"
+      mariadb -e "CREATE FUNCTION db.f() RETURNS INT DETERMINISTIC RETURN 1"
+      # Test that the features still work (this step can be done e.g. after an upgrade)
+      mariadb -e "SHOW TABLES IN db"
+      mariadb -e "SELECT * FROM db.t_innodb; INSERT INTO db.t_innodb VALUES (3,'"'"'foo'"'"'),(4,'"'"'bar'"'"')"
+      mariadb -e "SELECT * FROM db.t_myisam; INSERT INTO db.t_myisam VALUES (3,'"'"'foo'"'"'),(4,'"'"'bar'"'"')"
+      mariadb -e "SELECT * FROM db.t_aria; INSERT INTO db.t_aria VALUES (3,'"'"'foo'"'"'),(4,'"'"'bar'"'"')"
+      mariadb -e "SELECT * FROM db.t_memory; INSERT INTO db.t_memory VALUES (3,'"'"'foo'"'"'),(4,'"'"'bar'"'"')"
+      mariadb -e "SELECT COUNT(*) FROM db.v_merge"
+      mariadb -e "SELECT COUNT(*) FROM db.v_temptable"
+      mariadb -e "CALL db.p()"
+      mariadb -e "SELECT db.f()"
+    - |
+      # Test TLS connections
+      dpkg -l | grep -i -e tls -e ssl
+      # Create user for TCP connection, must have password
+      mariadb -e "SET PASSWORD FOR 'mysql'@'localhost' = PASSWORD('asdf234');"
+      cat <<EOF > /root/.my.cnf
+      [client]
+      user=mysql
+      password=asdf234
+      protocol=tcp
+      EOF
+      export CERT_PATH=/usr/share/mysql/mysql-test/std_data
+      openssl verify -CAfile $CERT_PATH/cacert.pem $CERT_PATH/server-cert.pem
+      openssl x509 -subject -issuer -noout -in $CERT_PATH/cacert.pem
+      openssl x509 -subject -issuer -noout -in $CERT_PATH/server-cert.pem
+      cat <<EOF > /etc/mysql/mariadb.conf.d/tls.cnf
+      [client-server]
+      ssl = on
+      ssl-ca = $CERT_PATH/cacert.pem
+      ssl-cert = $CERT_PATH/server-cert.pem
+      ssl-key = $CERT_PATH/server-key.pem
+      [server]
+      require-secure-transport = on
+      [client]
+      ssl-verify-server-cert = on
+      EOF
+      service mariadb restart
+      mariadb -Bse 'STATUS' | tee result
+      # Ensure important values present, otherwise fail job
+      grep --quiet "localhost via TCP/IP" result
+      mariadb -Bse 'SHOW VARIABLES' | grep -e tls -e ssl | tee result
+      grep --quiet "have_ssl   YES" result
+      grep --quiet TLSv1.3 result
+      mariadb -Bse 'SHOW SESSION STATUS' | grep -i -e tls -e ssl | tee result
+      grep --quiet TLSv1.3 result
+
+# Install Cacti, which in uses dbconfig-common to configure the MariaDB user and
+# connection automatically in order to validate that at least one downstream
+# server consumer continues to work.
+test consumer cacti:
+  extends: .salsa-ci-template-for-mariadb
+  script:
+    - *test-prepare-container
+    - *test-enable-artifacts-repo
+    - apt-get install -qq --yes cacti
+    - mariadb -E -e "SHOW CREATE TABLE version;" cacti
+
+# Build a piece of software that was designed for libmysqlclient-dev but using the
+# libmariadb-dev-compat layer. Should always end up using libmariadb.so.3 run-time.
+build mariadbclient consumer Python-MySQLdb:
+  extends: .salsa-ci-template-for-mariadb
+  script:
+    - *test-prepare-container
+    - *test-install-all-libs
+    - apt-get install -qq --yes pkg-config python3-pip
+    # See what MySQLdb will build with
+    - pkg-config --cflags --libs mysqlclient
+    # MySQLdb is also available in Debian as package python3-mysqldb, but
+    # install it from pip to force that the client is compiled with
+    # libmariadb-dev-compat on-the-fly.
+    # Python 3.11 needs `--break-system-packages` to proceed with this.
+    - pip3 install --break-system-packages mysqlclient # Compiles module against libmysqlclient
+    - apt-get purge --yes libmariadb-dev # Not needed for run-time
+    - python3 -c "import MySQLdb; print(MySQLdb.get_client_info())"
+
+libmysql* to libmariadb* upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB
+  script:
+    - *test-prepare-container
+    # Install all libmysql* available in Debian unstable
+    - apt-get install -qq --yes pkg-config libmysqlclient-dev
+    - pkg-config --list-all
+    - pkg-config --cflags mysqlclient # mysqlclient.pc from original package
+    - *test-enable-artifacts-repo
+    - apt-get install -qq --yes libmariadb3
+    - pkg-config --list-all
+    - apt-get install -qq --yes libmariadb-dev
+    - pkg-config --list-all
+    - apt-get install -qq --yes libmariadb-dev-compat
+    - pkg-config --cflags mysqlclient # mysqlclient.pc from compat package
+    - pkg-config --list-all
+    - apt-get install -qq --yes libmariadbd19t64
+    - pkg-config --list-all
+    - apt-get install -qq --yes libmariadbd-dev
+    - pkg-config --list-all
+    - apt-get install -qq --yes default-libmysqlclient-dev default-libmysqld-dev
+    - *test-verify-libs
+
+default-libmysqlclient-dev upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB
+  script:
+    - *test-prepare-container
+    - apt-get install -qq --yes pkg-config default-libmysqlclient-dev default-libmysqld-dev
+    - pkg-config --list-all
+    - *test-full-upgrade-libs
+    - *test-verify-libs
+
+default-libmysqlclient-dev and Bookworm upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB and distro
+  image: debian:bookworm
+  script:
+    - *test-prepare-container
+    - apt-get install -qq --yes pkg-config default-libmysqlclient-dev
+    - pkg-config --list-all
+    - *test-enable-sid-repos
+    - *test-full-upgrade-libs
+    - *test-verify-libs
+
+default-libmysqlclient-dev and Bullseye upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB and distro
+  image: debian:bullseye
+  script:
+    - *test-prepare-container
+    - apt-get install -qq --yes pkg-config default-libmysqlclient-dev
+    - pkg-config --list-all
+    - *test-enable-sid-repos
+    # Due to usrmerge, full-upgrade from Bullseye to Trixie or newer cannot work
+    - *test-install-all-libs
+    - *test-verify-libs
+
+# No longer possible since as it pulls as dependencies packages that trigger
+# usrmerge, which cannot run in a container
+#default-libmysqlclient-dev and Buster upgrade:
+
+# Upgrading from MySQL 8.0 with datadir in place is not possible. Users need to do a data dump.
+# The Debian maintainer scripts detect this situation and simply moves old datadir aside and start fresh.
+mysql-8.0 in Sid upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB variant
+  image: debian:sid
+  script:
+    - *test-prepare-container
+    # The postinst fails often if 'ps' is missing from system, so install procps
+    - apt-get install -qq --yes 'mysql*' libmysqlcppconn7t64
+    # Ensure MySQL 8.0 package actually got installed
+    - dpkg -l | grep -e "mysql-server.*8\.0"
+    - *test-verify-initial
+    - *test-install-all
+    # Due to some (currently unknown) changes in MySQL 8.0 packaging or apt
+    # behaviour changes, a system with a previous installation of MySQL 8.0 will
+    # on upgrades to MariaDB first fully remove MySQL, including the
+    # /etc/init.d/mysql file, so previous techniques in
+    # mariadb-server-10.6.postinst to maintain backwards compatibility with
+    # 'service mysql status' after installing MariaDB on top MySQL no longer
+    # works. Thus the step to test it now intentionally has a fallback to use
+    # the service name 'mariadb' instead, and the fallback is always used.
+    - sleep 5 # Give the mysql_upgrade a bit of time to complete before querying the server
+    - service mysql status || service mariadb status
+    - *test-verify-final
+
+# Upgrading from MySQL 8.0 with datadir in place is not possible. Users need to do a data dump.
+# The Debian maintainer scripts detect this situation and simply moves old datadir aside and start fresh.
+mysql-8.0 in Ubuntu 23.10 upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB variant
+  image: ubuntu:mantic
+  script:
+    - *test-prepare-container
+    - apt-get install -qq --yes procps mysql-server 'libmysqlc*'
+    # Ensure MySQL 8.0 package actually got installed
+    - dpkg -l | grep mysql
+    - service mysql status
+    - *test-verify-initial
+    # Install Debian Sid signing keys as Ubuntu does not have them by default
+    - apt-get install -qq --yes --no-install-recommends curl
+    - curl -sSLO http://deb.debian.org/debian/pool/main/d/debian-archive-keyring/debian-archive-keyring_2023.4_all.deb
+    - apt-get install -qq --yes ./debian-archive-keyring_*
+    - *test-enable-sid-repos
+    # Ensure mysqld will not crash on next shutdown for any reason
+    - service mysql restart
+    - *test-enable-artifacts-repo
+    - apt-get install -qq --simulate mariadb-server
+    - apt-get install -qq --yes mariadb-server
+    # Due to usrmerge, full-upgrade from Mantic to Trixie or newer may not work
+    - service mariadb status  # There is no init.d/mysql in MariaDB 10.5+
+    # Remove everything MySQL except mysql-common which also MariaDB depends on
+    - apt-get purge --yes mysql-s* mysql-cl* libmysql*
+    - *test-verify-final
+
+# Upgrading from MySQL 8.0 with datadir in place is not possible. Users need to do a data dump.
+# The Debian maintainer scripts detect this situation and simply moves old datadir aside and start fresh.
+mysql-community-cluster-8.0 from MySQL.com with Bookworm upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB variant
+  image: debian:bookworm
+  script:
+    - *test-prepare-container
+    - |
+      apt-get install -qq --yes --no-install-recommends ca-certificates curl systemctl
+      curl -sS "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0xbca43417c3b485dd128ec6d4b7b3b788a8d3785c" -o /etc/apt/trusted.gpg.d/mysql.asc
+      echo "deb https://repo.mysql.com/apt/debian/ bookworm mysql-cluster-8.0" > /etc/apt/sources.list.d/mysql.list
+      apt-get update -qq
+    - apt-get install -qq --yes mysql-cluster-community-server
+    - sed 's/ExecStartPre=+/ExecStartPre=/' -i /lib/systemd/system/mysql.service # Hack to make file compatible with systemctl shim
+    - systemctl start mysql
+    - dpkg -l | grep -iE 'maria|mysql|galera'
+    - systemctl status mysql; mysql -e 'SELECT VERSION()'
+    - systemctl stop mysql # Stop manually as maintainer scripts don't handle this with systemctl shim
+    - *test-enable-sid-repos
+    - *test-enable-artifacts-repo
+    - apt-get install -qq --simulate mariadb-server
+    - apt-get install -qq --yes mariadb-server
+    # Ignore systemctl shim result as MariaDB systemd file is incompatible with it and yields:
+    #   ERROR:systemctl:the ExecStartPre control process exited with error code
+    - systemctl status mysql || true
+    - mysql -e 'SELECT VERSION()' || true
+    - sleep 5 # Give the mysql_upgrade a bit of time to complete before querying the server
+    - *test-verify-final
+
+mariadb.org-10.11 upgrade:
+  extends: .salsa-ci-template-for-mariadb-upgrade
+  stage: upgrade MariaDB variant
+  variables:
+    MARIADB_VERSION: "10.11"
+  script:
+    - apt-get install -qq --yes mariadb-server
+    - *test-verify-initial
+    # Install MariaDB built in this commit
+    # Force downgrades so our version installs on top of upstream revision, e.g. 1:11.10.1-1 vs 1:11.10.1+mariadb~sid
+    - apt-get install -qq --yes --allow-downgrades ./*.deb
+    # Verify installation of MariaDB built in this commit
+    - dpkg -l | grep -iE 'maria|mysql|galera' || true # List installed
+    - mariadb --version # Client version
+    - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+
+mariadb.org-10.10 upgrade:
+  extends: .salsa-ci-template-for-mariadb-upgrade
+  stage: upgrade MariaDB variant
+  variables:
+    MARIADB_VERSION: "10.10"
+  script:
+    # this should not use Sid to begin with
+    - apt-get install -qq --yes mariadb-server=1:10.10.2+maria~debunstable mariadb-client=1:10.10.2+maria~debunstable
+    - *test-verify-initial
+    - *test-full-upgrade
+    - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+
+mariadb.org-10.9 upgrade:
+  extends: .salsa-ci-template-for-mariadb-upgrade
+  stage: upgrade MariaDB variant
+  variables:
+    MARIADB_VERSION: "10.9"
+  script:
+    # this should not use Sid to begin with
+    - apt-get install -qq --yes mariadb-server=1:10.9.4+maria~debunstable mariadb-client=1:10.9.4+maria~debunstable
+    - *test-verify-initial
+    - *test-full-upgrade
+    - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+
+mariadb.org-10.8 upgrade:
+  extends: .salsa-ci-template-for-mariadb-upgrade
+  stage: upgrade MariaDB variant
+  variables:
+    MARIADB_VERSION: "10.8"
+  script:
+    - apt-get install -qq --yes mariadb-server-10.8
+    - *test-verify-initial
+    - *test-install-all
+    - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+
+mariadb.org-10.7 upgrade:
+  extends: .salsa-ci-template-for-mariadb-upgrade
+  stage: upgrade MariaDB variant
+  variables:
+    MARIADB_VERSION: "10.7"
+  script:
+    - apt-get install -qq --yes mariadb-server-10.7
+    - *test-verify-initial
+    - *test-install-all
+    - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+
+mariadb.org-10.6 upgrade:
+  extends: .salsa-ci-template-for-mariadb-upgrade
+  stage: upgrade MariaDB variant
+  variables:
+    MARIADB_VERSION: "10.6"
+  script:
+    # Package libmariadbclient-dev from mariadb.org conflicts with libmariadb-dev in Sid, so cannot use wildcard that would include it
+    # Enable this line when there is a way to install them only from the mariadb.org repo
+    # - apt-get install -qq --yes 'mariadb*' libmariadb3 'libmariadb-*' 'libmariadbd*'
+    - apt-get install -qq --yes mariadb-server-10.6
+    - *test-verify-initial
+    - *test-install-all
+    - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+
+# archive.mariadb.org for Debian Sid latest is 10.5.13
+mariadb.org-10.5 upgrade:
+  extends: .salsa-ci-template-for-mariadb-upgrade
+  stage: upgrade MariaDB variant
+  variables:
+    MARIADB_VERSION: "10.5"
+  script:
+    - *test-install-openssl1-in-sid-for-backwards-compat
+    - apt-get install -qq --yes mariadb-server-10.5
+    - *test-verify-initial
+    - *test-install-all
+    - service mariadb status # There is no init.d/mysql in MariaDB 10.5+
+    - *test-verify-final
+
+# archive.mariadb.org for Debian Sid latest is 10.4.17
+mariadb.org-10.4 upgrade:
+  extends: .salsa-ci-template-for-mariadb-upgrade
+  stage: upgrade MariaDB variant
+  variables:
+    MARIADB_VERSION: "10.4"
+  script:
+    - *test-install-readline-in-sid-for-backwards-compat
+    - *test-install-openssl1-in-sid-for-backwards-compat
+    - *test-install-libaio-in-sid-for-backwards-compat
+    - apt-get install -qq --yes mariadb-server-10.4
+    # MariaDB.org version of 10.4 and early 10.5 do not install an init file, so
+    # it must be installed here manually
+    - cp /usr/share/mysql/mysql.init /etc/init.d/mysql; chmod +x /etc/init.d/mysql; service mysql start; sleep 5
+    - *test-verify-initial
+    - *test-install-all
+    - sleep 5 # Give the mysql_upgrade a bit of time to complete before querying the server
+    - service mysql status
+    - service mariadb status
+    - *test-verify-final
+
+# archive.mariadb.org for Debian Sid latest is 10.3.27
+mariadb.org-10.3 upgrade:
+  extends: .salsa-ci-template-for-mariadb-upgrade
+  stage: upgrade MariaDB variant
+  variables:
+    MARIADB_VERSION: "10.3"
+  script:
+    - *test-install-readline-in-sid-for-backwards-compat
+    - *test-install-openssl1-in-sid-for-backwards-compat
+    - *test-install-libaio-in-sid-for-backwards-compat
+    - apt-get install -qq --yes mariadb-server-10.3
+    - *test-verify-initial
+    - *test-install-all
+    # mariadb-10.3 in Buster ships a /etc/init.d/mysql and it continues to exist
+    # after upgrade, and is removed only on purge
+    - service mysql status || service mariadb status
+    # Give the mariadb-upgrade plenty of time to complete, otherwise next commands
+    # fail on non-existing mariadb.sys user
+    - sleep 15
+    - *test-verify-final
+
+# archive.mariadb.org for Debian Sid latest is 10.2.21
+mariadb.org-10.2 upgrade:
+  extends: .salsa-ci-template-for-mariadb-upgrade
+  stage: upgrade MariaDB variant
+  variables:
+    MARIADB_VERSION: "10.2"
+  script:
+    - *test-install-readline-in-sid-for-backwards-compat
+    - *test-install-openssl1-in-sid-for-backwards-compat
+    - *test-install-libaio-in-sid-for-backwards-compat
+    - apt-get install -qq --yes mariadb-server-10.2
+    # Verify initial state before upgrade
+    - dpkg -l | grep -iE 'maria|mysql|galera' || true # List installed
+    - service mysql status
+    # prepending with --defaults-file=/etc/mysql/debian.cnf is needed in upstream 5.5–10.3
+    - |
+      mysql --defaults-file=/etc/mysql/debian.cnf --skip-column-names -e "SELECT @@version, @@version_comment"
+      mysql --defaults-file=/etc/mysql/debian.cnf --table -e "SHOW DATABASES;"
+      mysql --defaults-file=/etc/mysql/debian.cnf --table -e "SELECT * FROM mysql.user; SHOW CREATE USER root@localhost;"
+      mysql --defaults-file=/etc/mysql/debian.cnf --table -e "SELECT * FROM mysql.plugin; SHOW PLUGINS;"
+    - *test-install-all
+    # mariadb-10.2 in ships a /etc/init.d/mysql and it continues to exist
+    # after upgrade, and is removed only on purge
+    - service mysql status || service mariadb status
+    # Give the mariadb-upgrade plenty of time to complete, otherwise next commands
+    # fail on non-existing mariadb.sys user
+    - sleep 15
+    - *test-verify-final
+
+# Buster is the last Debian release Oracle MySQL 5.7 offers binaries for
+mysql.com-5.7 with Buster upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB variant
+  needs:
+    - job: build
+  image: debian:buster
+  script:
+    - *test-prepare-container
+    - |
+      apt-get install -qq --yes --no-install-recommends gpg gpg-agent dirmngr ca-certificates # Bare minimal (<4MB) for apt-key to work
+      apt-key adv --recv-keys --keyserver hkps://keyserver.ubuntu.com:443 B7B3B788A8D3785C
+      echo "deb https://repo.mysql.com/apt/debian/ buster mysql-5.7" > /etc/apt/sources.list.d/mysql.list
+      apt-get update -qq
+    - apt-get install -qq --yes mysql-server 'libmysqlc*'
+    # Ensure MySQL 5.7 package actually got installed
+    - dpkg -l | grep -e "mysql-server.*5.7"
+    - *test-verify-initial
+    - *test-enable-sid-repos
+    - *test-install-all
+    # Due to some (currently unknown) changes in MySQL 5.7 packaging or apt
+    # behaviour changes, a system with a previous installation of MySQL will
+    # on upgrades to MariaDB first fully remove MySQL, including the
+    # /etc/init.d/mysql file, so previous techniques in
+    # mariadb-server-10.6.postinst to maintain backwards compatibility with
+    # 'service mysql status' after installing MariaDB on top MySQL no longer
+    # works. Thus the step to test it now intentionally has a fallback to use
+    # the service name 'mariadb' instead, and the fallback is always used.
+    - sleep 5 # Give the mysql_upgrade a bit of time to complete before querying the server
+    - service mysql status || service mariadb status
+    - sleep 15 # Give the mysql_upgrade a bit of extra time to complete with MySQL 5.7 before querying the server
+    - *test-verify-final
+
+# Note: pmm2-client does not exist in the Bookworm repository anymore
+percona-xtradb-5.7 with Bookworm upgrade:
+  extends: .salsa-ci-template-for-mariadb
+  stage: upgrade MariaDB variant
+  image: debian:bookworm
+  script:
+    - *test-prepare-container
+    - |
+      apt-get install -qq --yes --no-install-recommends ca-certificates curl systemctl
+      curl -sS "https://keyserver.ubuntu.com/pks/lookup?op=get&search=0x9334A25F8507EFA5" -o /etc/apt/trusted.gpg.d/percona.asc
+      echo "deb https://repo.percona.com/apt/ bookworm main" > /etc/apt/sources.list.d/percona.list
+      apt-get update -qq
+    - apt-get install -qq --yes percona-xtradb-cluster-full-57 percona-xtrabackup-24 percona-toolkit
+    # Ensure Percona 5.7 package actually got installed
+    - dpkg -l | grep -e "percona.*5\.7"
+    - service mysql status
+    - *test-verify-initial
+    - *test-enable-sid-repos
+    - *test-install-all
+    # Percona package owned /etc/init.d/mysql, so on removal and upgrade to MariaDB old service name can't be referenced anymore
+    - service mariadb status
+    - sleep 15 # Give the mysql_upgrade a bit of extra time to complete with MySQL 5.7 before querying the server
+    - *test-verify-final
diff --git a/source/format b/source/format
new file mode 100644 (file)
index 0000000..163aaf8
--- /dev/null
@@ -0,0 +1 @@
+3.0 (quilt)
diff --git a/source/lintian-overrides b/source/lintian-overrides
new file mode 100644 (file)
index 0000000..edf48eb
--- /dev/null
@@ -0,0 +1,96 @@
+# Intentional control relationships
+version-substvar-for-external-package Replaces ${source:Version} libmariadb-dev -> libmysqld-dev *
+# Do not alert for documentation in html
+source-is-missing [sql/share/charsets/languages.html]
+source-is-missing [storage/rocksdb/rocksdb/docs/_includes/footer.html]
+# Data or test files where long lines are justified
+very-long-line-length-in-source-file * [*.dfm:*]
+very-long-line-length-in-source-file * [*.expected:*]
+very-long-line-length-in-source-file * [*.frm:*]
+very-long-line-length-in-source-file * [*.MYD:*]
+very-long-line-length-in-source-file * [*.MYI:*]
+very-long-line-length-in-source-file * [*.p7b:*]
+very-long-line-length-in-source-file * [*.pcap:*]
+very-long-line-length-in-source-file * [*.result:*]
+very-long-line-length-in-source-file * [*.test:*]
+very-long-line-length-in-source-file * [*COPYING.rtf:*]
+very-long-line-length-in-source-file * [BUILD/compile-*]
+# These are mainly found under extra/wolfssl
+very-long-line-length-in-source-file * [*.cproject:*]
+very-long-line-length-in-source-file * [*.launch:*]
+very-long-line-length-in-source-file * [*.md:*]
+very-long-line-length-in-source-file * [*.scfg:*]
+very-long-line-length-in-source-file * [extra/wolfssl/wolfssl/doc/dox_comments/header_files-ja/ssl.h:*]
+very-long-line-length-in-source-file * [extra/wolfssl/wolfssl/doc/dox_comments/header_files-ja/types.h:*]
+very-long-line-length-in-source-file * [extra/wolfssl/wolfssl/doc/dox_comments/header_files-ja/wolfio.h:*]
+very-long-line-length-in-source-file * [extra/wolfssl/wolfssl/doc/formats/html/html_changes/tabs.css:*]
+very-long-line-length-in-source-file * [extra/wolfssl/wolfssl/IDE/Espressif/ESP-IDF/test/test_wolfssl.c:*]
+very-long-line-length-in-source-file * [extra/wolfssl/wolfssl/IDE/IAR-MSP430/main.c:*]
+# Preprocessed C files which have long lines
+very-long-line-length-in-source-file * [extra/wolfssl/wolfssl/wolfcrypt/src/*.i:*]
+# These are all results for test cases and similar so they can be
+# especially formatted to be too long
+very-long-line-length-in-source-file * [mysql-test/*.000*:*]
+very-long-line-length-in-source-file * [mysql-test/*.ARZ:*]
+very-long-line-length-in-source-file * [mysql-test/*.dump:*]
+very-long-line-length-in-source-file * [mysql-test/*.ibd:*]
+very-long-line-length-in-source-file * [mysql-test/*.inc:*]
+very-long-line-length-in-source-file * [mysql-test/*.MAD:*]
+very-long-line-length-in-source-file * [mysql-test/*.MAI:*]
+very-long-line-length-in-source-file * [mysql-test/*.rdiff:*]
+very-long-line-length-in-source-file * [mysql-test/*.txt:*]
+very-long-line-length-in-source-file * [mysql-test/*.weekly:*]
+very-long-line-length-in-source-file * [mysql-test/*001:*]
+very-long-line-length-in-source-file * [mysql-test/*ibdata*:*]
+very-long-line-length-in-source-file * [mysql-test/std_data/Moscow_leap:*]
+very-long-line-length-in-source-file * [mysql-test/suite/parts/r/*.out:*]
+# SQL source file that has very long inserts/selects
+very-long-line-length-in-source-file * [scripts/fill_help_tables.sql:*]
+very-long-line-length-in-source-file * [scripts/mysql_system_tables.sql:*]
+# Machine formatted HTML
+very-long-line-length-in-source-file * [sql/share/charsets/languages.html:*]
+very-long-line-length-in-source-file * [sql/share/errmsg-utf8.txt:*]
+# Very long test string
+very-long-line-length-in-source-file * [storage/archive/archive_test.c:*]
+# ColumnStore ignores
+# In Directory mysql-test are some long test includes
+very-long-line-length-in-source-file * [storage/columnstore/columnstore/.drone.jsonnet:*]
+very-long-line-length-in-source-file * [storage/columnstore/columnstore/*.xmi:*]
+very-long-line-length-in-source-file * [storage/columnstore/columnstore/CMakeLists.txt:*]
+very-long-line-length-in-source-file * [storage/columnstore/columnstore/dbcon/doc/q19_plan.txt:*]
+very-long-line-length-in-source-file * [storage/columnstore/columnstore/mysql-test/columnstore/csinternal/include/autopilot_create_datatypetestm_tables.inc:*]
+very-long-line-length-in-source-file * [storage/columnstore/columnstore/mysql-test/columnstore/csinternal/include/autopilot_create_datatypeupdate_table.inc:*]
+very-long-line-length-in-source-file * [storage/columnstore/columnstore/primitives/linux-port/dictblock.cdf:*]
+very-long-line-length-in-source-file * [storage/columnstore/columnstore/storage-manager/test_data/*:*]
+very-long-line-length-in-source-file * [storage/columnstore/columnstore/utils/udfsdk/docs/source/reference/mcsv1Context.rst:*]
+very-long-line-length-in-source-file * [storage/columnstore/columnstore/utils/winport/win_setup_mysql_part1.sql:*]
+# Minified CSS files. These appear in several places
+very-long-line-length-in-source-file * [*badge_only.css:*]
+very-long-line-length-in-source-file * [*theme.css:*]
+# Font files
+very-long-line-length-in-source-file * [*.eot:*]
+# General storage ignores
+very-long-line-length-in-source-file * [storage/rocksdb/mysql-test/rocksdb/t/bypass_select_basic_bloom-master.opt:*]
+very-long-line-length-in-source-file * [storage/rocksdb/mysql-test/rocksdb/t/type_enum.inc:*]
+very-long-line-length-in-source-file * [storage/rocksdb/mysql-test/rocksdb/t/type_set.inc:*]
+very-long-line-length-in-source-file * [storage/rocksdb/rocksdb/docs/_includes/footer.html:*]
+very-long-line-length-in-source-file * [storage/rocksdb/rocksdb/docs/_posts/*.markdown:*]
+very-long-line-length-in-source-file * [storage/spider/mysql-test/spider/bugfix/include/sql_mode_init.inc:*]
+# These are generated files which should not make any harm
+source-contains-autogenerated-visual-c++-file [extra/wolfssl/wolfssl/IDE/WIN10/resource.h]
+source-contains-autogenerated-visual-c++-file [extra/wolfssl/wolfssl/IDE/WIN10/wolfssl-fips.rc]
+source-contains-autogenerated-visual-c++-file [extra/wolfssl/wolfssl/resource.h]
+source-contains-autogenerated-visual-c++-file [storage/columnstore/columnstore/*.h]
+source-contains-autogenerated-visual-c++-file [storage/columnstore/columnstore/*.rc]
+source-contains-autogenerated-visual-c++-file [win/upgrade_wizard/resource.h]
+source-contains-autogenerated-visual-c++-file [win/upgrade_wizard/upgrade.rc]
+# Known cases, pending to be fixed upstream
+very-long-line-length-in-source-file * [libmariadb/benchmark/main-benchmark.cc:*]
+very-long-line-length-in-source-file * [man/mysql.1:*]
+very-long-line-length-in-source-file * [scripts/msql2mysql.sh:*]
+very-long-line-length-in-source-file * [scripts/wsrep_sst_mysqldump.sh:*]
+very-long-line-length-in-source-file * [sql-bench/bench-init.pl.sh:*]
+very-long-line-length-in-source-file * [sql-bench/test-ATIS.sh:*]
+very-long-line-length-in-source-file * [sql-bench/test-wisconsin.sh:*]
+very-long-line-length-in-source-file * [storage/columnstore/columnstore/utils/windowfunction/windowfunctiontype.cpp:*]
+very-long-line-length-in-source-file * [strings/ctype-czech.c:*]
diff --git a/tests/configuration-tracing b/tests/configuration-tracing
new file mode 100755 (executable)
index 0000000..fc6dbbd
--- /dev/null
@@ -0,0 +1,111 @@
+#!/bin/sh
+# dep8 smoke test for mariadbd
+# Author: Otto Kekäläinen <otto@debian.org>
+#
+# This test should be declared in debian/tests/control with a dependency
+# on the package that provides a configured MariaDB server (eg.
+# mariadb-server).
+#
+# This test should be declared in debian/tests/control with the
+# following restrictions:
+# - needs-root (binaries in /usr/sbin need root to run)
+# - allow-stderr (set -x always outputs to stderr, also if mariadbd was not
+#   launched as a service it will complain that mysql.plugin table is empty)
+#
+# This test prints out various configuration information from mariadbd and
+# compares the result to expected values in original binary/build.
+#
+
+normalize_value() {
+  VARIABLE="$1"
+  VALUE="$2"
+  # In sed the '\s.*' will match whitespace followed by any other chars until end of line
+  sed "s/^$VARIABLE\(\s\s*\).*$/$VARIABLE\1$VALUE/" -i "$TEMPFILE"
+}
+
+trace() {
+  TRACE_NAME="$(echo "$*" | sed -E 's|/usr/(s?)bin/||' | sed 's/ //g' | sed 's/--/-/g')"
+
+  # Show in test what was run
+  echo
+  echo "Tracing: $*"
+
+  # shellcheck disable=SC2068
+  $@ > "$TRACE_NAME.actual"
+
+  # Normalize contents for know special case
+  if echo "$*" | grep -q verbose
+  then
+    TEMPFILE="$(mktemp)"
+    # Use 'tail' to skip first line that has version and architecture strings which
+    # we intentionally do not want to include in the trace file.
+    tail -n +2 "$TRACE_NAME.actual" > "$TEMPFILE"
+
+    # Hostname varies one very machine
+    sed "s/$(hostname)/HOSTNAME/g" -i "$TEMPFILE"
+
+    # Version/revision increases on every release
+    VERSION=$(mariadbd --help --verbose | grep -e "^version " | rev | cut -d ' ' -f 1 | rev)
+    sed "s/$VERSION/VERSION/g" -i "$TEMPFILE"
+
+    # SSL library version inherited form dependency, not relevant for tracing
+    # the correctness of the MariaDB build itself
+    sed 's/OpenSSL 3.*/SSL-VERSION/' -i "$TEMPFILE"
+
+    # Normalize values that depend on build environment
+    normalize_value system-time-zone UTC    # depends on OS environment
+    normalize_value open-files-limit 32000  # depends on OS environment
+    normalize_value thread-pool-size 2      # depends on CPU cores available
+    normalize_value version-compile-machine ARCH # x86_64, aarch64, armv7l ..
+
+    # armhf/armel might have: debian-linux-gnueabi, debian-linux-gnueabihf
+    normalize_value version-compile-os debian-linux-gnu
+
+    # In Sid 'Debian n/a', in Bookworm 'Debian 12'
+    normalize_value version-comment "Debian RELEASE"
+
+    # Inherits git commit id from latest upstream release and thus not constant
+    normalize_value version-source-revision -
+
+    # 32-bit systems (i386, armel, armhf) have lower values
+    normalize_value innodb-io-capacity-max 18446744073709551615 # 32-bit: 4294967295
+    normalize_value max-binlog-cache-size 18446744073709547520 # 32-bit: 4294963200
+    normalize_value max-binlog-stmt-cache-size 18446744073709547520 # 32-bit: 4294963200
+    normalize_value myisam-max-sort-file-size 18446744073709551615 # 32-bit: 2146435072
+    normalize_value myisam-mmap-size 9223372036853727232 # 32-bit: 4294967295
+    normalize_value tmp-disk-table-size 18446744073709551615 # 32-bit: 4294967295
+
+    # ppc64el has larger default value: 393216
+    normalize_value log-tc-size 24576
+
+    mv "$TEMPFILE" "$TRACE_NAME.actual"
+  fi
+
+  echo "diff --ignore-space-change -u $TRACE_NAME.expected $TRACE_NAME.actual"
+  # Validate that trace file in source code matches tested
+  if ! diff --ignore-space-change -u "$TRACE_NAME.expected" "$TRACE_NAME.actual"
+  then
+    echo "Error: Output from '$*' did NOT match what was expected"
+    echo
+    echo "If the change is intentional, update the debian/tests/traces to match"
+    echo "the new values and document change to users in mariadb-server.NEWS"
+    exit 1
+  fi
+}
+
+echo "Running test 'configuration-tracing'"
+cd debian/tests/traces || exit 1
+
+set -e
+
+# Dump out what parameters mariadb would be called with by default
+trace /usr/bin/mariadb --print-defaults
+
+# Dump out all help texts, client variables and their default values
+trace /usr/bin/mariadb --verbose --help
+
+# Dump out what parameters mariadbd would be called with by default on system
+trace /usr/sbin/mariadbd --print-defaults
+
+# Dump out all help texts, server variables and their default values
+trace /usr/sbin/mariadbd --verbose --help
diff --git a/tests/control b/tests/control
new file mode 100644 (file)
index 0000000..2a8c23a
--- /dev/null
@@ -0,0 +1,21 @@
+Tests: configuration-tracing
+Depends:
+ diffutils,
+ mariadb-server,
+Restrictions: allow-stderr needs-root
+
+Tests: smoke
+Depends:
+ mariadb-plugin-provider-bzip2,
+ mariadb-plugin-provider-lz4,
+ mariadb-plugin-provider-lzma,
+ mariadb-plugin-provider-lzo,
+ mariadb-plugin-provider-snappy,
+ mariadb-plugin-rocksdb [amd64 arm64 mips64el ppc64el riscv64],
+Restrictions: allow-stderr needs-root isolation-container
+
+Tests: upstream
+Depends:
+ eatmydata,
+ mariadb-test,
+Restrictions: allow-stderr breaks-testbed
diff --git a/tests/smoke b/tests/smoke
new file mode 100644 (file)
index 0000000..5c4facb
--- /dev/null
@@ -0,0 +1,123 @@
+#!/bin/sh
+# 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 MariaDB server (eg.
+# mariadb-server).
+#
+# This test should be declared in debian/tests/control with the
+# following restrictions:
+# - allow-stderr (set -x always outputs to stderr)
+# - needs-root (to be able to log into the database)
+# - isolation-container (to be able to start service)
+#
+# This test:
+#
+# 1) Creates a test database and test user as the root user.
+#
+# 2) Creates a test table and checks it appears to operate normally
+# using the test user and test database.
+#
+# 3) Checks compression support for InnoDB & RocksDB engine.
+
+echo "Running test 'smoke'"
+set -ex
+
+# Start the daemon if it was not running. For example in Docker testing
+# environments there might not be any systemd et al and the service needs to
+# be started manually.
+if ! command -v systemctl
+then
+  if ! /etc/init.d/mariadb status
+  then
+    echo "Did not find systemctl and daemon was not running, starting it.."
+    /etc/init.d/mariadb start
+  fi
+else
+  # If systemd (and systemctl) is available, but the service did not start, then
+  # this smoke test is supposed to fail if next commands don't work.
+  echo "Found systemctl, continuing smoke test.."
+  # Compression plugins are separated from main server package
+  # to own packages (for example LZ4 package mariadb-plugin-provider-lz4)
+  # and they are installed after mariadb-server.
+  # which means that they don't exist if MariaDB is not restarted
+  systemctl restart mariadb
+fi
+
+mysql <<EOT
+CREATE DATABASE testdatabase;
+CREATE USER 'testuser'@'localhost' identified by 'testpassword';
+GRANT ALL ON testdatabase.* TO 'testuser'@'localhost';
+EOT
+
+mysql 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 <<EOT
+DROP DATABASE testdatabase;
+DROP USER 'testuser'@'localhost';
+EOT
+
+# This will never fail but exists purely for debugging purposes in case a later
+# step would fail
+mariadb <<EOT
+SHOW GLOBAL STATUS WHERE Variable_name LIKE 'Innodb_have_%';
+EOT
+
+mariadb <<EOT
+SET GLOBAL innodb_compression_algorithm=lz4;
+SET GLOBAL innodb_compression_algorithm=lzo;
+SET GLOBAL innodb_compression_algorithm=lzma;
+SET GLOBAL innodb_compression_algorithm=bzip2;
+SET GLOBAL innodb_compression_algorithm=snappy;
+SET GLOBAL innodb_compression_algorithm=zlib;
+SET GLOBAL innodb_compression_algorithm=none;
+EOT
+
+# Check whether RocksDB should be installed or not
+plugin=mariadb-plugin-rocksdb
+if [ "$(dpkg-architecture -qDEB_HOST_ARCH_BITS)" != 32 ] &&
+   [ "$(dpkg-architecture -qDEB_HOST_ARCH_ENDIAN)" = little ]
+then
+  dpkg-query -W $plugin
+
+  LOG=/var/lib/mysql/#rocksdb/LOG
+  # XXX: The server may only be started during the install of
+  #      mariadb-server, which happens before that of the plugin.
+  [ -e $LOG ] || mariadb -e "INSTALL PLUGIN RocksDB SONAME 'ha_rocksdb';"
+  # XXX: rocksdb_supported_compression_types variable does not report ZSTD.
+
+  # Print RocksDB supported items so test log is easier to debug
+  grep -F " supported:" $LOG
+
+  # Check that the expected compression methods are supported
+  for a in LZ4 Snappy Zlib ZSTD
+  do
+    if ! grep -qE "k$a(Compression)? supported: 1" $LOG
+    then
+      # Fail with explicit error message
+      echo "Error: Compression method $a not supported by RocksDB!" >&2
+      exit 1
+    fi
+  done
+else
+  if dpkg-query -W $plugin
+  then
+    echo "Error: Plugin $plugin was found even though it should not exist on a 32-bit and little-endian system"
+    exit 1
+  fi
+fi
diff --git a/tests/traces/mariadb-print-defaults.expected b/tests/traces/mariadb-print-defaults.expected
new file mode 100644 (file)
index 0000000..acb5795
--- /dev/null
@@ -0,0 +1,2 @@
+/usr/bin/mariadb would have been started with the following arguments:
+--socket=/run/mysqld/mysqld.sock 
diff --git a/tests/traces/mariadb-verbose-help.expected b/tests/traces/mariadb-verbose-help.expected
new file mode 100644 (file)
index 0000000..2c81bd3
--- /dev/null
@@ -0,0 +1,229 @@
+Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
+
+Usage: /usr/bin/mariadb [OPTIONS] [database]
+
+Default options are read from the following files in the given order:
+/etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf 
+The following groups are read: mysql mariadb-client client client-server client-mariadb
+The following options may be given as the first argument:
+--print-defaults          Print the program argument list and exit.
+--no-defaults             Don't read default options from any option file.
+The following specify which files/extra groups are read (specified before remaining options):
+--defaults-file=#         Only read default options from the given file #.
+--defaults-extra-file=#   Read this file after the global files are read.
+--defaults-group-suffix=# Additionally read default groups with # appended as a suffix.
+
+  -?, --help          Display this help and exit.
+  -I, --help          Synonym for -?
+  --abort-source-on-error 
+                      Abort 'source filename' operations in case of errors
+  --auto-rehash       Enable automatic rehashing. One doesn't need to use
+                      'rehash' to get table and field completion, but startup
+                      and reconnecting may take a longer time.
+                      (Defaults to on; use --skip-auto-rehash to disable.)
+  -A, --no-auto-rehash 
+                      No automatic rehashing. One has to use 'rehash' to get
+                      table and field completion. This gives a quicker start of
+                      mysql and disables rehashing on reconnect.
+  --auto-vertical-output 
+                      Automatically switch to vertical output mode if the
+                      result is wider than the terminal width.
+  -B, --batch         Don't use history file. Disable interactive behavior.
+                      (Enables --silent.)
+  --binary-as-hex     Print binary data as hex
+  --binary-mode       Binary mode allows certain character sequences to be
+                      processed as data that would otherwise be treated with a
+                      special meaning by the parser. Specifically, this switch
+                      turns off parsing of all client commands except \C and
+                      DELIMITER in non-interactive mode (i.e., when binary mode
+                      is combined with either 1) piped input, 2) the --batch
+                      mysql option, or 3) the 'source' command). Also, in
+                      binary mode, occurrences of '\r\n' and ASCII '\0' are
+                      preserved within strings, whereas by default, '\r\n' is
+                      translated to '\n' and '\0' is disallowed in user input.
+  --character-sets-dir=name 
+                      Directory for character set files.
+  --column-names      Write column names in results.
+                      (Defaults to on; use --skip-column-names to disable.)
+  -N, --skip-column-names 
+                      Don't write column names in results.
+  --column-type-info  Display column type information.
+  -c, --comments      Preserve comments. Send comments to the server. The
+                      default is --skip-comments (discard comments), enable
+                      with --comments.
+  -C, --compress      Use compression in server/client protocol.
+  --connect-expired-password 
+                      Notify the server that this client is prepared to handle
+                      expired password sandbox mode even if --batch was
+                      specified.
+  --connect-timeout=# Number of seconds before connection timeout.
+  -D, --database=name Database to use.
+  -#, --debug[=#]     This is a non-debug version. Catch this and exit.
+  --debug-check       Check memory and open file usage at exit.
+  -T, --debug-info    Print some debug info at exit.
+  --default-auth=name Default authentication client-side plugin to use.
+  --default-character-set=name 
+                      Set the default character set.
+  --delimiter=name    Delimiter to be used.
+  --enable-cleartext-plugin 
+                      Obsolete option. Exists only for MySQL compatibility.
+  -e, --execute=name  Execute command and quit. (Disables --force and history
+                      file.)
+  -f, --force         Continue even if we get an SQL error. Sets
+                      abort-source-on-error to 0
+  -h, --host=name     Connect to host.
+  -H, --html          Produce HTML output.
+  -i, --ignore-spaces Ignore space after function names.
+  --init-command=name SQL Command to execute when connecting to MariaDB server.
+                      Will automatically be re-executed when reconnecting.
+  --line-numbers      Write line numbers for errors.
+                      (Defaults to on; use --skip-line-numbers to disable.)
+  -L, --skip-line-numbers 
+                      Don't write line number for errors.
+  --local-infile      Enable LOAD DATA LOCAL INFILE.
+  --max-allowed-packet=# 
+                      The maximum packet length to send to or receive from
+                      server.
+  --max-join-size=#   Automatic limit for rows in a join when using
+                      --safe-updates.
+  -G, --named-commands 
+                      Enable named commands. Named commands mean this program's
+                      internal commands; see mysql> help . When enabled, the
+                      named commands can be used from any line of the query,
+                      otherwise only from the first line, before an enter.
+                      Disable with --disable-named-commands. This option is
+                      disabled by default.
+  --net-buffer-length=# 
+                      The buffer size for TCP/IP and socket communication.
+  -b, --no-beep       Turn off beep on error.
+  -o, --one-database  Ignore statements except those that occur while the
+                      default database is the one named at the command line.
+  --pager[=name]      Pager to use to display results. If you don't supply an
+                      option, the default pager is taken from your ENV variable
+                      PAGER. Valid pagers are less, more, cat [> filename],
+                      etc. See interactive help (\h) also. This option does not
+                      work in batch mode. Disable with --disable-pager. This
+                      option is disabled by default.
+  -p, --password[=name] 
+                      Password to use when connecting to server. If password is
+                      not given it's asked from the tty.
+  --plugin-dir=name   Directory for client-side plugins.
+  -P, --port=#        Port number to use for connection or 0 for default to, in
+                      order of preference, my.cnf, $MYSQL_TCP_PORT,
+                      /etc/services, built-in default (3306).
+  --progress-reports  Get progress reports for long running commands (like
+                      ALTER TABLE)
+                      (Defaults to on; use --skip-progress-reports to disable.)
+  --prompt=name       Set the command line prompt to this value.
+  --protocol=name     The protocol to use for connection (tcp, socket, pipe).
+  -q, --quick         Don't cache result, print it row by row. This may slow
+                      down the server if the output is suspended. Doesn't use
+                      history file.
+  -r, --raw           Write fields without conversion. Used with --batch.
+  --reconnect         Reconnect if the connection is lost.
+                      (Defaults to on; use --skip-reconnect to disable.)
+  -U, --safe-updates  Only allow UPDATE and DELETE that uses keys.
+  -U, --i-am-a-dummy  Synonym for option --safe-updates, -U.
+  --sandbox           Disallow commands that access the file system (except \P
+                      without an argument and \e).
+  --secure-auth       Refuse client connecting to server if it uses old
+                      (pre-4.1.1) protocol.
+  --select-limit=#    Automatic limit for SELECT when using --safe-updates.
+  --server-arg=name   Send embedded server this as a parameter.
+  --show-warnings     Show warnings after every statement.
+  --sigint-ignore     Ignore SIGINT (CTRL-C).
+  -s, --silent        Be more silent. Print results with a tab as separator,
+                      each row on new line.
+  -S, --socket=name   The socket file to use for connection.
+  --ssl               Enable SSL for connection (automatically enabled with
+                      other flags).
+                      (Defaults to on; use --skip-ssl to disable.)
+  --ssl-ca=name       CA file in PEM format (check OpenSSL docs, implies
+                      --ssl).
+  --ssl-capath=name   CA directory (check OpenSSL docs, implies --ssl).
+  --ssl-cert=name     X509 cert in PEM format (implies --ssl).
+  --ssl-cipher=name   SSL cipher to use (implies --ssl).
+  --ssl-key=name      X509 key in PEM format (implies --ssl).
+  --ssl-crl=name      Certificate revocation list (implies --ssl).
+  --ssl-crlpath=name  Certificate revocation list path (implies --ssl).
+  --tls-version=name  TLS protocol version for secure connection.
+  --ssl-verify-server-cert 
+                      Verify server's "Common Name" in its cert against
+                      hostname used when connecting. This option is disabled by
+                      default.
+  -t, --table         Output in table format.
+  --tee=name          Append everything into outfile. See interactive help (\h)
+                      also. Does not work in batch mode. Disable with
+                      --disable-tee. This option is disabled by default.
+  -n, --unbuffered    Flush buffer after each query.
+  -u, --user=name     User for login if not current user.
+  -v, --verbose       Write more. (-v -v -v gives the table output format).
+  -V, --version       Output version information and exit.
+  -E, --vertical      Print the output of a query (rows) vertically.
+  -w, --wait          Wait and retry if connection is down.
+  -X, --xml           Produce XML output.
+
+Variables (--variable-name=value)
+and boolean options {FALSE|TRUE}  Value (after reading options)
+--------------------------------- ----------------------------------------
+abort-source-on-error             FALSE
+auto-rehash                       TRUE
+auto-vertical-output              FALSE
+binary-as-hex                     FALSE
+binary-mode                       FALSE
+character-sets-dir                (No default value)
+column-names                      TRUE
+column-type-info                  FALSE
+comments                          FALSE
+compress                          FALSE
+connect-expired-password          FALSE
+connect-timeout                   0
+database                          (No default value)
+debug-check                       FALSE
+debug-info                        FALSE
+default-auth                      (No default value)
+default-character-set             auto
+delimiter                         ;
+force                             FALSE
+host                              (No default value)
+html                              FALSE
+ignore-spaces                     FALSE
+init-command                      (No default value)
+line-numbers                      TRUE
+local-infile                      FALSE
+max-allowed-packet                16777216
+max-join-size                     1000000
+named-commands                    FALSE
+net-buffer-length                 16384
+no-beep                           FALSE
+plugin-dir                        (No default value)
+port                              0
+progress-reports                  TRUE
+prompt                            \N [\d]> 
+protocol                          
+quick                             FALSE
+raw                               FALSE
+reconnect                         TRUE
+safe-updates                      FALSE
+i-am-a-dummy                      FALSE
+sandbox                           FALSE
+secure-auth                       FALSE
+select-limit                      1000
+show-warnings                     FALSE
+sigint-ignore                     FALSE
+socket                            /run/mysqld/mysqld.sock
+ssl                               TRUE
+ssl-ca                            (No default value)
+ssl-capath                        (No default value)
+ssl-cert                          (No default value)
+ssl-cipher                        (No default value)
+ssl-key                           (No default value)
+ssl-crl                           (No default value)
+ssl-crlpath                       (No default value)
+tls-version                       (No default value)
+ssl-verify-server-cert            FALSE
+table                             FALSE
+unbuffered                        FALSE
+user                              (No default value)
+vertical                          FALSE
+xml                               FALSE
diff --git a/tests/traces/mariadbd-print-defaults.expected b/tests/traces/mariadbd-print-defaults.expected
new file mode 100644 (file)
index 0000000..b03f257
--- /dev/null
@@ -0,0 +1,2 @@
+/usr/sbin/mariadbd would have been started with the following arguments:
+--socket=/run/mysqld/mysqld.sock --pid-file=/run/mysqld/mysqld.pid --basedir=/usr --bind-address=127.0.0.1 --expire_logs_days=10 --character-set-server=utf8mb4 --collation-server=utf8mb4_general_ci 
diff --git a/tests/traces/mariadbd-verbose-help.expected b/tests/traces/mariadbd-verbose-help.expected
new file mode 100644 (file)
index 0000000..1c0f4be
--- /dev/null
@@ -0,0 +1,3129 @@
+Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
+
+Starts the MariaDB database server.
+
+Usage: /usr/sbin/mariadbd [OPTIONS]
+
+Default options are read from the following files in the given order:
+/etc/my.cnf /etc/mysql/my.cnf ~/.my.cnf 
+The following groups are read: mysqld server mysqld-10.11 mariadb mariadb-10.11 mariadbd mariadbd-10.11 client-server galera
+The following options may be given as the first argument:
+--print-defaults          Print the program argument list and exit.
+--no-defaults             Don't read default options from any option file.
+The following specify which files/extra groups are read (specified before remaining options):
+--defaults-file=#         Only read default options from the given file #.
+--defaults-extra-file=#   Read this file after the global files are read.
+--defaults-group-suffix=# Additionally read default groups with # appended as a suffix.
+
+  --allow-suspicious-udfs 
+                      Allows use of user-defined functions (UDFs) consisting of
+                      only one symbol xxx() without corresponding xxx_init() or
+                      xxx_deinit(). That also means that one can load any
+                      function from any library, for example exit() from
+                      libc.so
+  --alter-algorithm[=name] 
+                      Specify the alter table algorithm. One of: DEFAULT, COPY,
+                      INPLACE, NOCOPY, INSTANT
+  --analyze-sample-percentage=# 
+                      Percentage of rows from the table ANALYZE TABLE will
+                      sample to collect table statistics. Set to 0 to let
+                      MariaDB decide what percentage of rows to sample.
+  -a, --ansi          Use ANSI SQL syntax instead of MySQL syntax. This mode
+                      will also set transaction isolation level 'serializable'.
+  --aria-block-size=# Block size to be used for Aria index pages.
+  --aria-checkpoint-interval=# 
+                      Interval between tries to do an automatic checkpoints. In
+                      seconds; 0 means 'no automatic checkpoints' which makes
+                      sense only for testing.
+  --aria-checkpoint-log-activity=# 
+                      Number of bytes that the transaction log has to grow
+                      between checkpoints before a new checkpoint is written to
+                      the log.
+  --aria-encrypt-tables 
+                      Encrypt tables (only for tables with ROW_FORMAT=PAGE
+                      (default) and not FIXED/DYNAMIC)
+  --aria-force-start-after-recovery-failures=# 
+                      Number of consecutive log recovery failures after which
+                      logs will be automatically deleted to cure the problem; 0
+                      (the default) disables the feature.
+  --aria-group-commit=name 
+                      Specifies Aria group commit mode. Possible values are
+                      "none" (no group commit), "hard" (with waiting to actual
+                      commit), "soft" (no wait for commit (DANGEROUS!!!))
+  --aria-group-commit-interval=# 
+                      Interval between commits in microseconds (1/1000000 sec).
+                      0 stands for no waiting for other threads to come and do
+                      a commit in "hard" mode and no sync()/commit at all in
+                      "soft" mode.  Option has only an effect if
+                      aria_group_commit is used
+  --aria-log-dir-path=name 
+                      Path to the directory where to store transactional log
+  --aria-log-file-size=# 
+                      Limit for transaction log size
+  --aria-log-purge-type=name 
+                      Specifies how Aria transactional log will be purged. One
+                      of: immediate, external, at_flush
+  --aria-max-sort-file-size=# 
+                      Don't use the fast sort index method to created index if
+                      the temporary file would get bigger than this.
+  --aria-page-checksum 
+                      Maintain page checksums (can be overridden per table with
+                      PAGE_CHECKSUM clause in CREATE TABLE)
+                      (Defaults to on; use --skip-aria-page-checksum to disable.)
+  --aria-pagecache-age-threshold=# 
+                      This characterizes the number of hits a hot block has to
+                      be untouched until it is considered aged enough to be
+                      downgraded to a warm block. This specifies the percentage
+                      ratio of that number of hits to the total number of
+                      blocks in the page cache.
+  --aria-pagecache-buffer-size=# 
+                      The size of the buffer used for index blocks for Aria
+                      tables. Increase this to get better index handling (for
+                      all reads and multiple writes) to as much as you can
+                      afford.
+  --aria-pagecache-division-limit=# 
+                      The minimum percentage of warm blocks in key cache
+  --aria-pagecache-file-hash-size=# 
+                      Number of hash buckets for open and changed files.  If
+                      you have a lot of Aria files open you should increase
+                      this for faster flush of changes. A good value is
+                      probably 1/10 of number of possible open Aria files.
+  --aria-recover-options[=name] 
+                      Specifies how corrupted tables should be automatically
+                      repaired. Any combination of: NORMAL, BACKUP, FORCE, 
+                      QUICK, OFF
+  Use 'ALL' to set all combinations.
+  --aria-repair-threads=# 
+                      Number of threads to use when repairing Aria tables. The
+                      value of 1 disables parallel repair.
+  --aria-sort-buffer-size=# 
+                      The buffer that is allocated when sorting the index when
+                      doing a REPAIR or when creating indexes with CREATE INDEX
+                      or ALTER TABLE.
+  --aria-stats-method=name 
+                      Specifies how Aria index statistics collection code
+                      should treat NULLs. One of: nulls_unequal, nulls_equal, 
+                      nulls_ignored
+  --aria-sync-log-dir=name 
+                      Controls syncing directory after log file growth and new
+                      file creation. One of: NEVER, NEWFILE, ALWAYS
+  --auto-increment-increment[=#] 
+                      Auto-increment columns are incremented by this
+  --auto-increment-offset[=#] 
+                      Offset added to Auto-increment columns. Used when
+                      auto-increment-increment != 1
+  --autocommit        Set default value for autocommit (0 or 1)
+                      (Defaults to on; use --skip-autocommit to disable.)
+  --automatic-sp-privileges 
+                      Creating and dropping stored procedures alters ACLs
+                      (Defaults to on; use --skip-automatic-sp-privileges to disable.)
+  --back-log=#        The number of outstanding connection requests MariaDB can
+                      have. This comes into play when the main MariaDB thread
+                      gets very many connection requests in a very short time
+                      (Automatically configured unless set explicitly)
+  -b, --basedir=name  Path to installation directory. All paths are usually
+                      resolved relative to this
+  --big-tables        Old variable, which if set to 1, allows large result sets
+                      by saving all temporary sets to disk, avoiding 'table
+                      full' errors. No longer needed, as the server now handles
+                      this automatically.
+  --bind-address=name IP address to bind to. Several addresses may be
+                      specified, separated by a comma (,).
+  --binlog-alter-two-phase 
+                      When set, split ALTER at binary logging into 2
+                      statements: START ALTER and COMMIT/ROLLBACK ALTER
+  --binlog-annotate-row-events 
+                      Tells the master to annotate RBR events with the
+                      statement that caused these events
+                      (Defaults to on; use --skip-binlog-annotate-row-events to disable.)
+  --binlog-cache-size=# 
+                      The size of the transactional cache for updates to
+                      transactional engines for the binary log. If you often
+                      use transactions containing many statements, you can
+                      increase this to get more performance
+  --binlog-checksum=name 
+                      Type of BINLOG_CHECKSUM_ALG. Include checksum for log
+                      events in the binary log. One of: NONE, CRC32
+  --binlog-commit-wait-count=# 
+                      If non-zero, binlog write will wait at most
+                      binlog_commit_wait_usec microseconds for at least this
+                      many commits to queue up for group commit to the binlog.
+                      This can reduce I/O on the binlog and provide increased
+                      opportunity for parallel apply on the slave, but too high
+                      a value will decrease commit throughput.
+  --binlog-commit-wait-usec=# 
+                      Maximum time, in microseconds, to wait for more commits
+                      to queue up for binlog group commit. Only takes effect if
+                      the value of binlog_commit_wait_count is non-zero.
+  --binlog-direct-non-transactional-updates 
+                      Causes updates to non-transactional engines using
+                      statement format to be written directly to binary log.
+                      Before using this option make sure that there are no
+                      dependencies between transactional and non-transactional
+                      tables such as in the statement INSERT INTO t_myisam
+                      SELECT * FROM t_innodb; otherwise, slaves may diverge
+                      from the master.
+  --binlog-do-db=name Tells the master it should log updates for the specified
+                      database, and exclude all others not explicitly
+                      mentioned.
+  --binlog-expire-logs-seconds=# 
+                      If non-zero, binary logs will be purged after
+                      binlog_expire_logs_seconds seconds; It and
+                      expire_logs_days are linked, such that changes in one are
+                      converted into the other. Possible purges happen at
+                      startup and at binary log rotation.
+  --binlog-file-cache-size=# 
+                      The size of file cache for the binary log
+  --binlog-format=name 
+                      What form of binary logging the master will use: either
+                      ROW for row-based binary logging, STATEMENT for
+                      statement-based binary logging, or MIXED. MIXED is
+                      statement-based binary logging except for those
+                      statements where only row-based is correct: those which
+                      involve user-defined functions (i.e. UDFs) or the UUID()
+                      function; for those, row-based binary logging is
+                      automatically used.
+  --binlog-ignore-db=name 
+                      Tells the master that updates to the given database
+                      should not be logged to the binary log.
+  --binlog-optimize-thread-scheduling 
+                      Run fast part of group commit in a single thread, to
+                      optimize kernel thread scheduling. On by default. Disable
+                      to run each transaction in group commit in its own
+                      thread, which can be slower at very high concurrency.
+                      This option is mostly for testing one algorithm versus
+                      the other, and it should not normally be necessary to
+                      change it.
+                      (Defaults to on; use --skip-binlog-optimize-thread-scheduling to disable.)
+  --binlog-row-event-max-size=# 
+                      The maximum size of a row-based binary log event in
+                      bytes. Rows will be grouped into events smaller than this
+                      size if possible. The value has to be a multiple of 256.
+  --binlog-row-image=name 
+                      Controls whether rows should be logged in 'FULL',
+                      'NOBLOB' or 'MINIMAL' formats. 'FULL', means that all
+                      columns in the before and after image are logged.
+                      'NOBLOB', means that mysqld avoids logging blob columns
+                      whenever possible (eg, blob column was not changed or is
+                      not part of primary key). 'MINIMAL', means that a PK
+                      equivalent (PK columns or full row if there is no PK in
+                      the table) is logged in the before image, and only
+                      changed columns are logged in the after image. (Default:
+                      FULL).
+  --binlog-row-metadata=name 
+                      Controls whether metadata is logged using FULL , MINIMAL
+                      format and NO_LOG.FULL causes all metadata to be logged;
+                      MINIMAL means that only metadata actually required by
+                      slave is logged; NO_LOG NO metadata will be
+                      logged.Default: NO_LOG.
+  --binlog-stmt-cache-size=# 
+                      The size of the statement cache for updates to
+                      non-transactional engines for the binary log. If you
+                      often use statements updating a great number of rows, you
+                      can increase this to get more performance.
+  --bootstrap         Used by mysql installation scripts.
+  --bulk-insert-buffer-size=# 
+                      Size of tree cache used in bulk insert optimisation. Note
+                      that this is a limit per thread!
+  --character-set-client-handshake 
+                      Don't ignore client side character set value sent during
+                      handshake.
+                      (Defaults to on; use --skip-character-set-client-handshake to disable.)
+  --character-set-filesystem=name 
+                      Set the filesystem character set.
+  -C, --character-set-server=name 
+                      Set the default character set.
+  --character-sets-dir=name 
+                      Directory where character sets are
+  -r, --chroot=name   Chroot mysqld daemon during startup.
+  --collation-server=name 
+                      Set the default collation.
+  --column-compression-threshold=# 
+                      Minimum column data length eligible for compression
+  --column-compression-zlib-level=# 
+                      zlib compression level (1 gives best speed, 9 gives best
+                      compression)
+  --column-compression-zlib-strategy=name 
+                      The strategy parameter is used to tune the compression
+                      algorithm. Use the value DEFAULT_STRATEGY for normal
+                      data, FILTERED for data produced by a filter (or
+                      predictor), HUFFMAN_ONLY to force Huffman encoding only
+                      (no string match), or RLE to limit match distances to one
+                      (run-length encoding). Filtered data consists mostly of
+                      small values with a somewhat random distribution. In this
+                      case, the compression algorithm is tuned to compress them
+                      better. The effect of FILTERED is to force more Huffman
+                      coding and less string matching; it is somewhat
+                      intermediate between DEFAULT_STRATEGY and HUFFMAN_ONLY.
+                      RLE is designed to be almost as fast as HUFFMAN_ONLY, but
+                      give better compression for PNG image data. The strategy
+                      parameter only affects the compression ratio but not the
+                      correctness of the compressed output even if it is not
+                      set appropriately. FIXED prevents the use of dynamic
+                      Huffman codes, allowing for a simpler decoder for special
+                      applications.
+  --column-compression-zlib-wrap 
+                      Generate zlib header and trailer and compute adler32
+                      check value. It can be used with storage engines that
+                      don't provide data integrity verification to detect data
+                      corruption.
+  --completion-type=name 
+                      The transaction completion type. One of: NO_CHAIN, CHAIN,
+                      RELEASE
+  --concurrent-insert[=name] 
+                      Use concurrent insert with MyISAM. One of: NEVER, AUTO, 
+                      ALWAYS
+  --connect-timeout=# The number of seconds the mysqld server is waiting for a
+                      connect packet before responding with 'Bad handshake'
+  --console           Write error output on screen; don't remove the console
+                      window on windows.
+  --core-file         Write core on crashes
+  -h, --datadir=name  Path to the database root directory
+  --date-format=name  The DATE format (ignored)
+  --datetime-format=name 
+                      The DATETIME format (ignored)
+  --deadlock-search-depth-long=# 
+                      Long search depth for the two-step deadlock detection
+  --deadlock-search-depth-short=# 
+                      Short search depth for the two-step deadlock detection
+  --deadlock-timeout-long=# 
+                      Long timeout for the two-step deadlock detection (in
+                      microseconds)
+  --deadlock-timeout-short=# 
+                      Short timeout for the two-step deadlock detection (in
+                      microseconds)
+  -#, --debug[=name]  Built in DBUG debugger. Disabled in this build.
+  --debug-abort-slave-event-count=# 
+                      Option used by mysql-test for debugging and testing of
+                      replication.
+  --debug-disconnect-slave-event-count=# 
+                      Option used by mysql-test for debugging and testing of
+                      replication.
+  -T, --debug-exit-info[=#] 
+                      Used for debugging. Use at your own risk.
+  --debug-gdb         Set up signals usable for debugging.
+  --debug-max-binlog-dump-events=# 
+                      Option used by mysql-test for debugging and testing of
+                      replication.
+  --debug-no-sync     Disables system sync calls. Only for running tests or
+                      debugging!
+  --debug-no-thread-alarm 
+                      Disable system thread alarm calls. Disabling it may be
+                      useful in debugging or testing, never do it in production
+  --debug-sporadic-binlog-dump-fail 
+                      Option used by mysql-test for debugging and testing of
+                      replication.
+  --default-password-lifetime=# 
+                      This defines the global password expiration policy. 0
+                      means automatic password expiration is disabled. If the
+                      value is a positive integer N, the passwords must be
+                      changed every N days. This behavior can be overridden
+                      using the password expiration options in ALTER USER.
+  --default-regex-flags=name 
+                      Default flags for the regex library. Any combination of: 
+                      DOTALL, DUPNAMES, EXTENDED, EXTENDED_MORE, EXTRA, 
+                      MULTILINE, UNGREEDY
+  Use 'ALL' to set all combinations.
+  --default-storage-engine=name 
+                      The default storage engine for new tables
+  --default-time-zone=name 
+                      Set the default time zone.
+  --default-tmp-storage-engine=name 
+                      The default storage engine for user-created temporary
+                      tables
+  --default-week-format=# 
+                      The default week format used by WEEK() functions
+  --delay-key-write[=name] 
+                      Specifies how MyISAM tables handles CREATE TABLE
+                      DELAY_KEY_WRITE. If set to ON, the default, any DELAY KEY
+                      WRITEs are honored. The key buffer is then flushed only
+                      when the table closes, speeding up writes. MyISAM tables
+                      should be automatically checked upon startup in this
+                      case, and --external locking should not be used, as it
+                      can lead to index corruption. If set to OFF, DELAY KEY
+                      WRITEs are ignored, while if set to ALL, all new opened
+                      tables are treated as if created with DELAY KEY WRITEs
+                      enabled.
+  --delayed-insert-limit=# 
+                      After inserting delayed_insert_limit rows, the INSERT
+                      DELAYED handler will check if there are any SELECT
+                      statements pending. If so, it allows these to execute
+                      before continuing.
+  --delayed-insert-timeout=# 
+                      How long a INSERT DELAYED thread should wait for INSERT
+                      statements before terminating
+  --delayed-queue-size=# 
+                      What size queue (in rows) should be allocated for
+                      handling INSERT DELAYED. If the queue becomes full, any
+                      client that does INSERT DELAYED will wait until there is
+                      room in the queue again
+  --des-key-file=name Load keys for des_encrypt() and des_encrypt from given
+                      file.
+  --disconnect-on-expired-password 
+                      This variable controls how the server handles clients
+                      that are not aware of the sandbox mode. If enabled, the
+                      server disconnects the client, otherwise the server puts
+                      the client in a sandbox mode.
+  --div-precision-increment=# 
+                      Precision of the result of '/' operator will be increased
+                      on that value
+  --encrypt-binlog    Encrypt binary logs (including relay logs)
+  --encrypt-tmp-disk-tables 
+                      Encrypt temporary on-disk tables (created as part of
+                      query execution)
+  --encrypt-tmp-files Encrypt temporary files (created for filesort, binary log
+                      cache, etc)
+  --enforce-storage-engine=name 
+                      Force the use of a storage engine for new tables
+  --eq-range-index-dive-limit=# 
+                      The optimizer will use existing index statistics instead
+                      of doing index dives for equality ranges if the number of
+                      equality ranges for the index is larger than or equal to
+                      this number. If set to 0, index dives are always used.
+  --event-scheduler[=name] 
+                      Enable the event scheduler. Possible values are ON, OFF,
+                      and DISABLED (keep the event scheduler completely
+                      deactivated, it cannot be activated run-time)
+  --expensive-subquery-limit=# 
+                      The maximum number of rows a subquery may examine in
+                      order to be executed during optimization and used for
+                      constant optimization
+  --expire-logs-days=# 
+                      If non-zero, binary logs will be purged after
+                      expire_logs_days days; It and binlog_expire_logs_seconds
+                      are linked, such that changes in one are converted into
+                      the other, presentable as a decimal value with 1/1000000
+                      of the day precision; possible purges happen at startup
+                      and at binary log rotation
+  --explicit-defaults-for-timestamp 
+                      This option causes CREATE TABLE to create all TIMESTAMP
+                      columns as NULL with DEFAULT NULL attribute, Without this
+                      option, TIMESTAMP columns are NOT NULL and have implicit
+                      DEFAULT clauses.
+                      (Defaults to on; use --skip-explicit-defaults-for-timestamp to disable.)
+  --external-locking  Use system (external) locking (disabled by default). 
+                      With this option enabled you can run myisamchk to test
+                      (not repair) tables while the MySQL server is running.
+                      Disable with --skip-external-locking.
+  --extra-max-connections=# 
+                      The number of connections on extra-port
+  --extra-port=#      Extra port number to use for tcp connections in a
+                      one-thread-per-connection manner. 0 means don't use
+                      another port
+  --feedback[=name]   Enable or disable FEEDBACK plugin. One of: ON, OFF, FORCE
+                      (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --feedback-http-proxy=name 
+                      Proxy server host:port.
+  --feedback-send-retry-wait=# 
+                      Wait this many seconds before retrying a failed send.
+  --feedback-send-timeout=# 
+                      Timeout (in seconds) for the sending the report.
+  --feedback-url=name Space separated URLs to send the feedback report to.
+  --feedback-user-info=name 
+                      User specified string that will be included in the
+                      feedback report.
+  --flashback         Setup the server to use flashback. This enables binary
+                      log in row mode and will enable extra logging for DDL's
+                      needed by flashback feature
+  --flush             Flush MyISAM tables to disk between SQL commands
+  --flush-time=#      A dedicated thread is created to flush all tables at the
+                      given interval
+  --ft-boolean-syntax=name 
+                      List of operators for MATCH ... AGAINST ( ... IN BOOLEAN
+                      MODE)
+  --ft-max-word-len=# The maximum length of the word to be included in a
+                      FULLTEXT index. Note: FULLTEXT indexes must be rebuilt
+                      after changing this variable
+  --ft-min-word-len=# The minimum length of the word to be included in a
+                      FULLTEXT index. Note: FULLTEXT indexes must be rebuilt
+                      after changing this variable
+  --ft-query-expansion-limit=# 
+                      Number of best matches to use for query expansion
+  --ft-stopword-file=name 
+                      Use stopwords from this file instead of built-in list
+  --gdb               Set up signals usable for debugging. Deprecated, use
+                      --debug-gdb instead.
+  --general-log       Log connections and queries to a table or log file.
+                      Defaults logging to a file 'hostname'.log or a table
+                      mysql.general_logif --log-output=TABLE is used.
+  --general-log-file=name 
+                      Log connections and queries to given file
+  --getopt-prefix-matching 
+                      Recognize command-line options by their unambiguos
+                      prefixes.
+                      (Defaults to on; use --skip-getopt-prefix-matching to disable.)
+  --group-concat-max-len=# 
+                      The maximum length of the result of function
+                      GROUP_CONCAT()
+  --gtid-cleanup-batch-size=# 
+                      Normally does not need tuning. How many old rows must
+                      accumulate in the mysql.gtid_slave_pos table before a
+                      background job will be run to delete them. Can be
+                      increased to reduce number of commits if using many
+                      different engines with --gtid_pos_auto_engines, or to
+                      reduce CPU overhead if using a huge number of different
+                      gtid_domain_ids. Can be decreased to reduce number of old
+                      rows in the table.
+  --gtid-domain-id=#  Used with global transaction ID to identify logically
+                      independent replication streams. When events can
+                      propagate through multiple parallel paths (for example
+                      multiple masters), each independent source server must
+                      use a distinct domain_id. For simple tree-shaped
+                      replication topologies, it can be left at its default, 0.
+  --gtid-ignore-duplicates 
+                      When set, different master connections in multi-source
+                      replication are allowed to receive and process event
+                      groups with the same GTID (when using GTID mode). Only
+                      one will be applied, any others will be ignored. Within a
+                      given replication domain, just the sequence number will
+                      be used to decide whether a given GTID has been already
+                      applied; this means it is the responsibility of the user
+                      to ensure that GTID sequence numbers are strictly
+                      increasing.
+  --gtid-pos-auto-engines=name 
+                      List of engines for which to automatically create a
+                      mysql.gtid_slave_pos_ENGINE table, if a transaction using
+                      that engine is replicated. This can be used to avoid
+                      introducing cross-engine transactions, if engines are
+                      used different from that used by table
+                      mysql.gtid_slave_pos
+  --gtid-strict-mode  Enforce strict seq_no ordering of events in the binary
+                      log. Slave stops with an error if it encounters an event
+                      that would cause it to generate an out-of-order binlog if
+                      executed. When ON the same server-id semisync-replicated
+                      transactions that duplicate existing ones in binlog are
+                      ignored without error and slave interruption.
+  -?, --help          Display this help and exit.
+  --histogram-size=#  Number of bytes used for a histogram. If set to 0, no
+                      histograms are created by ANALYZE.
+  --histogram-type=name 
+                      Specifies type of the histograms created by ANALYZE.
+                      Possible values are: SINGLE_PREC_HB - single precision
+                      height-balanced, DOUBLE_PREC_HB - double precision
+                      height-balanced, JSON_HB - height-balanced, stored as
+                      JSON.
+  --host-cache-size=# How many host names should be cached to avoid resolving.
+                      (Automatically configured unless set explicitly)
+  --idle-readonly-transaction-timeout=# 
+                      The number of seconds the server waits for read-only idle
+                      transaction
+  --idle-transaction-timeout=# 
+                      The number of seconds the server waits for idle
+                      transaction
+  --idle-write-transaction-timeout=# 
+                      The number of seconds the server waits for write idle
+                      transaction
+  --ignore-builtin-innodb 
+                      Disable initialization of builtin InnoDB plugin
+  --ignore-db-dirs=name 
+                      Specifies a directory to add to the ignore list when
+                      collecting database names from the datadir. Put a blank
+                      argument to reset the list accumulated so far.
+  --in-predicate-conversion-threshold=# 
+                      The minimum number of scalar elements in the value list
+                      of IN predicate that triggers its conversion to IN
+                      subquery. Set to 0 to disable the conversion.
+  --init-connect=name Command(s) that are executed for each new connection
+                      (unless the user has SUPER privilege)
+  --init-file=name    Read SQL commands from this file at startup
+  --init-rpl-role=name 
+                      Set the replication role. One of: MASTER, SLAVE
+  --init-slave=name   Command(s) that are executed by a slave server each time
+                      the SQL thread starts
+  --innodb[=name]     Enable or disable InnoDB plugin. One of: ON, OFF, FORCE
+                      (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-adaptive-flushing 
+                      Attempt flushing dirty pages to avoid IO bursts at
+                      checkpoints.
+                      (Defaults to on; use --skip-innodb-adaptive-flushing to disable.)
+  --innodb-adaptive-flushing-lwm=# 
+                      Percentage of log capacity below which no adaptive
+                      flushing happens.
+  --innodb-adaptive-hash-index 
+                      Enable InnoDB adaptive hash index (disabled by default).
+  --innodb-adaptive-hash-index-parts[=#] 
+                      Number of InnoDB Adaptive Hash Index Partitions (default
+                      8)
+  --innodb-autoextend-increment=# 
+                      Data file autoextend increment in megabytes
+  --innodb-autoinc-lock-mode=# 
+                      The AUTOINC lock modes supported by InnoDB: 0 => Old
+                      style AUTOINC locking (for backward compatibility); 1 =>
+                      New style AUTOINC locking; 2 => No AUTOINC locking
+                      (unsafe for SBR)
+  --innodb-buf-dump-status-frequency=# 
+                      A number between [0, 100] that tells how oftern buffer
+                      pool dump status in percentages should be printed. E.g.
+                      10 means that buffer pool dump status is printed when
+                      every 10% of number of buffer pool pages are dumped.
+                      Default is 0 (only start and end status is printed).
+  --innodb-buffer-page[=name] 
+                      Enable or disable INNODB_BUFFER_PAGE plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-buffer-page-lru[=name] 
+                      Enable or disable INNODB_BUFFER_PAGE_LRU plugin. One of:
+                      ON, OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-buffer-pool-chunk-size=# 
+                      Size of a single memory chunk for resizing buffer pool.
+                      Online buffer pool resizing happens at this granularity.
+                      0 means autosize this variable based on buffer pool size.
+  --innodb-buffer-pool-dump-at-shutdown 
+                      Dump the buffer pool into a file named
+                      @@innodb_buffer_pool_filename
+                      (Defaults to on; use --skip-innodb-buffer-pool-dump-at-shutdown to disable.)
+  --innodb-buffer-pool-dump-now 
+                      Trigger an immediate dump of the buffer pool into a file
+                      named @@innodb_buffer_pool_filename
+  --innodb-buffer-pool-dump-pct=# 
+                      Dump only the hottest N% of each buffer pool, defaults to
+                      25
+  --innodb-buffer-pool-filename=name 
+                      Filename to/from which to dump/load the InnoDB buffer
+                      pool
+  --innodb-buffer-pool-load-abort 
+                      Abort a currently running load of the buffer pool
+  --innodb-buffer-pool-load-at-startup 
+                      Load the buffer pool from a file named
+                      @@innodb_buffer_pool_filename
+                      (Defaults to on; use --skip-innodb-buffer-pool-load-at-startup to disable.)
+  --innodb-buffer-pool-load-now 
+                      Trigger an immediate load of the buffer pool from a file
+                      named @@innodb_buffer_pool_filename
+  --innodb-buffer-pool-size=# 
+                      The size of the memory buffer InnoDB uses to cache data
+                      and indexes of its tables.
+  --innodb-buffer-pool-stats[=name] 
+                      Enable or disable INNODB_BUFFER_POOL_STATS plugin. One
+                      of: ON, OFF, FORCE (don't start if the plugin fails to
+                      load), FORCE_PLUS_PERMANENT (like FORCE, but the plugin
+                      can not be uninstalled).
+  --innodb-change-buffer-max-size=# 
+                      Maximum on-disk size of change buffer in terms of
+                      percentage of the buffer pool.
+  --innodb-change-buffering=name 
+                      Buffer changes to secondary indexes.. One of: none, 
+                      inserts, deletes, changes, purges, all
+  --innodb-checksum-algorithm=name 
+                      The algorithm InnoDB uses for page checksumming. Possible
+                      values are FULL_CRC32 for new files, always use CRC-32C;
+                      for old, see CRC32 below; STRICT_FULL_CRC32 for new
+                      files, always use CRC-32C; for old, see STRICT_CRC32
+                      below; CRC32 write crc32, allow previously used
+                      algorithms to match when reading; STRICT_CRC32 write
+                      crc32, do not allow other algorithms to match when
+                      reading; New files created with full_crc32 are readable
+                      by MariaDB 10.4.3+
+  --innodb-cmp[=name] Enable or disable INNODB_CMP plugin. One of: ON, OFF,
+                      FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-cmp-per-index[=name] 
+                      Enable or disable INNODB_CMP_PER_INDEX plugin. One of:
+                      ON, OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-cmp-per-index-enabled 
+                      Enable INFORMATION_SCHEMA.innodb_cmp_per_index, may have
+                      negative impact on performance (off by default)
+  --innodb-cmp-per-index-reset[=name] 
+                      Enable or disable INNODB_CMP_PER_INDEX_RESET plugin. One
+                      of: ON, OFF, FORCE (don't start if the plugin fails to
+                      load), FORCE_PLUS_PERMANENT (like FORCE, but the plugin
+                      can not be uninstalled).
+  --innodb-cmp-reset[=name] 
+                      Enable or disable INNODB_CMP_RESET plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-cmpmem[=name] 
+                      Enable or disable INNODB_CMPMEM plugin. One of: ON, OFF,
+                      FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-cmpmem-reset[=name] 
+                      Enable or disable INNODB_CMPMEM_RESET plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-compression-algorithm[=name] 
+                      Compression algorithm used on page compression. One of:
+                      none, zlib, lz4, lzo, lzma, bzip2, or snappy
+  --innodb-compression-default 
+                      Is compression the default for new tables
+  --innodb-compression-failure-threshold-pct[=#] 
+                      If the compression failure rate of a table is greater
+                      than this number more padding is added to the pages to
+                      reduce the failures. A value of zero implies no padding
+  --innodb-compression-level=# 
+                      Compression level used for zlib compression.  0 is no
+                      compression, 1 is fastest, 9 is best compression and
+                      default is 6.
+  --innodb-compression-pad-pct-max[=#] 
+                      Percentage of empty space on a data page that can be
+                      reserved to make the page compressible.
+  --innodb-data-file-path=name 
+                      Path to individual files and their sizes.
+  --innodb-data-home-dir=name 
+                      The common part for InnoDB table spaces.
+  --innodb-deadlock-detect 
+                      Enable/disable InnoDB deadlock detector (default ON). if
+                      set to OFF, deadlock detection is skipped, and we rely on
+                      innodb_lock_wait_timeout in case of deadlock.
+                      (Defaults to on; use --skip-innodb-deadlock-detect to disable.)
+  --innodb-deadlock-report=name 
+                      How to report deadlocks (if innodb_deadlock_detect=ON)..
+                      One of: off, basic, full
+  --innodb-default-encryption-key-id=# 
+                      Default encryption key id used for table encryption.
+  --innodb-default-row-format=name 
+                      The default ROW FORMAT for all innodb tables created
+                      without explicit ROW_FORMAT. Possible values are
+                      REDUNDANT, COMPACT, and DYNAMIC. The ROW_FORMAT value
+                      COMPRESSED is not allowed. One of: redundant, compact, 
+                      dynamic
+  --innodb-defragment Enable/disable InnoDB defragmentation (default FALSE).
+                      When set to FALSE, all existing defragmentation will be
+                      paused. And new defragmentation command will fail.Paused
+                      defragmentation commands will resume when this variable
+                      is set to true again.
+  --innodb-defragment-fill-factor=# 
+                      A number between [0.7, 1] that tells defragmentation how
+                      full it should fill a page. Default is 0.9. Number below
+                      0.7 won't make much sense.This variable, together with
+                      innodb_defragment_fill_factor_n_recs, is introduced so
+                      defragmentation won't pack the page too full and cause
+                      page split on the next insert on every page. The variable
+                      indicating more defragmentation gain is the one
+                      effective.
+  --innodb-defragment-fill-factor-n-recs=# 
+                      How many records of space defragmentation should leave on
+                      the page. This variable, together with
+                      innodb_defragment_fill_factor, is introduced so
+                      defragmentation won't pack the page too full and cause
+                      page split on the next insert on every page. The variable
+                      indicating more defragmentation gain is the one
+                      effective.
+  --innodb-defragment-frequency=# 
+                      Do not defragment a single index more than this number of
+                      time per second.This controls the number of time
+                      defragmentation thread can request X_LOCK on an index.
+                      Defragmentation thread will check whether
+                      1/defragment_frequency (s) has passed since it worked on
+                      this index last time, and put the index back to the queue
+                      if not enough time has passed. The actual frequency can
+                      only be lower than this given number.
+  --innodb-defragment-n-pages=# 
+                      Number of pages considered at once when merging multiple
+                      pages to defragment
+  --innodb-defragment-stats-accuracy=# 
+                      How many defragment stats changes there are before the
+                      stats are written to persistent storage. Set to 0 meaning
+                      disable defragment stats tracking.
+  --innodb-disable-sort-file-cache 
+                      Whether to disable OS system file cache for sort I/O
+  --innodb-doublewrite 
+                      Enable InnoDB doublewrite buffer (enabled by default).
+                      Disable with --skip-innodb-doublewrite.
+                      (Defaults to on; use --skip-innodb-doublewrite to disable.)
+  --innodb-encrypt-log 
+                      Enable redo log encryption
+  --innodb-encrypt-tables[=name] 
+                      Enable encryption for tables. Don't forget to enable
+                      --innodb-encrypt-log too. One of: OFF, ON, FORCE
+  --innodb-encrypt-temporary-tables 
+                      Enrypt the temporary table data.
+  --innodb-encryption-rotate-key-age=# 
+                      Key rotation - re-encrypt in background all pages that
+                      were encrypted with a key that many (or more) versions
+                      behind. Value 0 indicates that key rotation is disabled.
+  --innodb-encryption-rotation-iops=# 
+                      Use this many iops for background key rotation
+  --innodb-encryption-threads=# 
+                      Number of threads performing background key rotation 
+  --innodb-fast-shutdown[=#] 
+                      Speeds up the shutdown process of the InnoDB storage
+                      engine. Possible values are 0, 1 (faster), 2
+                      (crash-like), 3 (fastest clean).
+  --innodb-fatal-semaphore-wait-threshold=# 
+                      Maximum number of seconds that semaphore times out in
+                      InnoDB.
+  --innodb-file-per-table 
+                      Stores each InnoDB table to an .ibd file in the database
+                      dir.
+                      (Defaults to on; use --skip-innodb-file-per-table to disable.)
+  --innodb-fill-factor=# 
+                      Percentage of B-tree page filled during bulk insert
+  --innodb-flush-log-at-timeout[=#] 
+                      Write and flush logs every (n) second.
+  --innodb-flush-log-at-trx-commit[=#] 
+                      Controls the durability/speed trade-off for commits. Set
+                      to 0 (write and flush redo log to disk only once per
+                      second), 1 (flush to disk at each commit), 2 (write to
+                      log at commit but flush to disk only once per second) or
+                      3 (flush to disk at prepare and at commit, slower and
+                      usually redundant). 1 and 3 guarantees that after a
+                      crash, committed transactions will not be lost and will
+                      be consistent with the binlog and other transactional
+                      engines. 2 can get inconsistent and lose transactions if
+                      there is a power failure or kernel crash but not if
+                      mysqld crashes. 0 has no guarantees in case of crash. 0
+                      and 2 can be faster than 1 or 3.
+  --innodb-flush-method=name 
+                      With which method to flush data.. One of: fsync, O_DSYNC,
+                      littlesync, nosync, O_DIRECT, O_DIRECT_NO_FSYNC
+  --innodb-flush-neighbors[=#] 
+                      Set to 0 (don't flush neighbors from buffer pool), 1
+                      (flush contiguous neighbors from buffer pool) or 2 (flush
+                      neighbors from buffer pool), when flushing a block
+  --innodb-flush-sync Allow IO bursts at the checkpoints ignoring io_capacity
+                      setting.
+                      (Defaults to on; use --skip-innodb-flush-sync to disable.)
+  --innodb-flushing-avg-loops=# 
+                      Number of iterations over which the background flushing
+                      is averaged.
+  --innodb-force-primary-key 
+                      Do not allow creating a table without primary key (off by
+                      default)
+  --innodb-force-recovery=# 
+                      Helps to save your data in case the disk image of the
+                      database becomes corrupt. Value 5 can return bogus data,
+                      and 6 can permanently corrupt data.
+  --innodb-ft-aux-table=name 
+                      FTS internal auxiliary table to be checked
+  --innodb-ft-being-deleted[=name] 
+                      Enable or disable INNODB_FT_BEING_DELETED plugin. One of:
+                      ON, OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-ft-cache-size=# 
+                      InnoDB Fulltext search cache size in bytes
+  --innodb-ft-config[=name] 
+                      Enable or disable INNODB_FT_CONFIG plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-ft-default-stopword[=name] 
+                      Enable or disable INNODB_FT_DEFAULT_STOPWORD plugin. One
+                      of: ON, OFF, FORCE (don't start if the plugin fails to
+                      load), FORCE_PLUS_PERMANENT (like FORCE, but the plugin
+                      can not be uninstalled).
+  --innodb-ft-deleted[=name] 
+                      Enable or disable INNODB_FT_DELETED plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-ft-enable-diag-print 
+                      Whether to enable additional FTS diagnostic printout 
+  --innodb-ft-enable-stopword 
+                      Create FTS index with stopword.
+                      (Defaults to on; use --skip-innodb-ft-enable-stopword to disable.)
+  --innodb-ft-index-cache[=name] 
+                      Enable or disable INNODB_FT_INDEX_CACHE plugin. One of:
+                      ON, OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-ft-index-table[=name] 
+                      Enable or disable INNODB_FT_INDEX_TABLE plugin. One of:
+                      ON, OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-ft-max-token-size=# 
+                      InnoDB Fulltext search maximum token size in characters
+  --innodb-ft-min-token-size=# 
+                      InnoDB Fulltext search minimum token size in characters
+  --innodb-ft-num-word-optimize[=#] 
+                      InnoDB Fulltext search number of words to optimize for
+                      each optimize table call 
+  --innodb-ft-result-cache-limit=# 
+                      InnoDB Fulltext search query result cache limit in bytes
+  --innodb-ft-server-stopword-table[=name] 
+                      The user supplied stopword table name.
+  --innodb-ft-sort-pll-degree=# 
+                      InnoDB Fulltext search parallel sort degree, will round
+                      up to nearest power of 2 number
+  --innodb-ft-total-cache-size=# 
+                      Total memory allocated for InnoDB Fulltext Search cache
+  --innodb-ft-user-stopword-table[=name] 
+                      User supplied stopword table name, effective in the
+                      session level.
+  --innodb-immediate-scrub-data-uncompressed 
+                      Enable scrubbing of data
+  --innodb-instant-alter-column-allowed=name 
+                      File format constraint for ALTER TABLE. One of: never, 
+                      add_last, add_drop_reorder
+  --innodb-io-capacity=# 
+                      Number of IOPs the server can do. Tunes the background IO
+                      rate
+  --innodb-io-capacity-max=# 
+                      Limit to which innodb_io_capacity can be inflated.
+  --innodb-lock-wait-timeout=# 
+                      Timeout in seconds an InnoDB transaction may wait for a
+                      lock before being rolled back. The value 100000000 is
+                      infinite timeout.
+  --innodb-lock-waits[=name] 
+                      Enable or disable INNODB_LOCK_WAITS plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-locks[=name] 
+                      Enable or disable INNODB_LOCKS plugin. One of: ON, OFF,
+                      FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-log-buffer-size=# 
+                      Redo log buffer size in bytes.
+  --innodb-log-file-buffering 
+                      Whether the file system cache for ib_logfile0 is enabled
+  --innodb-log-file-size=# 
+                      Redo log size in bytes.
+  --innodb-log-group-home-dir=name 
+                      Path to ib_logfile0
+  --innodb-log-spin-wait-delay[=#] 
+                      Delay between log buffer spin lock polls (0 to use a
+                      blocking latch)
+  --innodb-lru-flush-size=# 
+                      How many pages to flush on LRU eviction
+  --innodb-lru-scan-depth=# 
+                      How deep to scan LRU to keep it clean
+  --innodb-max-dirty-pages-pct=# 
+                      Percentage of dirty pages allowed in bufferpool.
+  --innodb-max-dirty-pages-pct-lwm=# 
+                      Percentage of dirty pages at which flushing kicks in. The
+                      value 0 (default) means 'refer to
+                      innodb_max_dirty_pages_pct'.
+  --innodb-max-purge-lag=# 
+                      Desired maximum length of the purge queue (0 = no limit)
+  --innodb-max-purge-lag-delay=# 
+                      Maximum delay of user threads in micro-seconds
+  --innodb-max-purge-lag-wait=# 
+                      Wait until History list length is below the specified
+                      limit
+  --innodb-max-undo-log-size[=#] 
+                      Desired maximum UNDO tablespace size in bytes
+  --innodb-metrics[=name] 
+                      Enable or disable INNODB_METRICS plugin. One of: ON, OFF,
+                      FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-monitor-disable=name 
+                      Turn off a monitor counter
+  --innodb-monitor-enable=name 
+                      Turn on a monitor counter
+  --innodb-monitor-reset=name 
+                      Reset a monitor counter
+  --innodb-monitor-reset-all=name 
+                      Reset all values for a monitor counter
+  --innodb-numa-interleave 
+                      Use NUMA interleave memory policy to allocate InnoDB
+                      buffer pool.
+  --innodb-old-blocks-pct=# 
+                      Percentage of the buffer pool to reserve for 'old'
+                      blocks.
+  --innodb-old-blocks-time=# 
+                      Move blocks to the 'new' end of the buffer pool if the
+                      first access was at least this many milliseconds ago. The
+                      timeout is disabled if 0.
+  --innodb-online-alter-log-max-size=# 
+                      Maximum modification log file size for online index
+                      creation
+  --innodb-open-files=# 
+                      How many files at the maximum InnoDB keeps open at the
+                      same time.
+  --innodb-optimize-fulltext-only 
+                      Only optimize the Fulltext index of the table
+  --innodb-page-size[=#] 
+                      Page size to use for all InnoDB tablespaces.
+  --innodb-prefix-index-cluster-optimization 
+                      Deprecated parameter with no effect
+                      (Defaults to on; use --skip-innodb-prefix-index-cluster-optimization to disable.)
+  --innodb-print-all-deadlocks 
+                      Print all deadlocks to MariaDB error log (off by default)
+  --innodb-purge-batch-size[=#] 
+                      Number of UNDO log pages to purge in one batch from the
+                      history list.
+  --innodb-purge-rseg-truncate-frequency[=#] 
+                      Deprecated parameter with no effect
+  --innodb-purge-threads[=#] 
+                      Number of tasks for purging transaction history
+  --innodb-random-read-ahead 
+                      Whether to use read ahead for random access within an
+                      extent.
+  --innodb-read-ahead-threshold=# 
+                      Number of pages that must be accessed sequentially for
+                      InnoDB to trigger a readahead.
+  --innodb-read-io-threads=# 
+                      Number of background read I/O threads in InnoDB.
+  --innodb-read-only  Start InnoDB in read only mode (off by default)
+  --innodb-read-only-compressed 
+                      Make ROW_FORMAT=COMPRESSED tables read-only
+  --innodb-rollback-on-timeout 
+                      Roll back the complete transaction on lock wait timeout,
+                      for 4.x compatibility (disabled by default)
+  --innodb-snapshot-isolation 
+                      Use snapshot isolation (write-write conflict detection).
+  --innodb-sort-buffer-size=# 
+                      Memory buffer size for index creation
+  --innodb-spin-wait-delay[=#] 
+                      Maximum delay between polling for a spin lock (4 by
+                      default)
+  --innodb-stats-auto-recalc 
+                      InnoDB automatic recalculation of persistent statistics
+                      enabled for all tables unless overridden at table level
+                      (automatic recalculation is only done when InnoDB decides
+                      that the table has changed too much and needs a new
+                      statistics)
+                      (Defaults to on; use --skip-innodb-stats-auto-recalc to disable.)
+  --innodb-stats-include-delete-marked 
+                      Include delete marked records when calculating persistent
+                      statistics
+  --innodb-stats-method=name 
+                      Specifies how InnoDB index statistics collection code
+                      should treat NULLs. Possible values are NULLS_EQUAL
+                      (default), NULLS_UNEQUAL and NULLS_IGNORED. One of: 
+                      nulls_equal, nulls_unequal, nulls_ignored
+  --innodb-stats-modified-counter=# 
+                      The number of rows modified before we calculate new
+                      statistics (default 0 = current limits)
+  --innodb-stats-on-metadata 
+                      Enable statistics gathering for metadata commands such as
+                      SHOW TABLE STATUS for tables that use transient
+                      statistics (off by default)
+  --innodb-stats-persistent 
+                      InnoDB persistent statistics enabled for all tables
+                      unless overridden at table level
+                      (Defaults to on; use --skip-innodb-stats-persistent to disable.)
+  --innodb-stats-persistent-sample-pages=# 
+                      The number of leaf index pages to sample when calculating
+                      persistent statistics (by ANALYZE, default 20)
+  --innodb-stats-traditional 
+                      Enable traditional statistic calculation based on number
+                      of configured pages (default true)
+                      (Defaults to on; use --skip-innodb-stats-traditional to disable.)
+  --innodb-stats-transient-sample-pages=# 
+                      The number of leaf index pages to sample when calculating
+                      transient statistics (if persistent statistics are not
+                      used, default 8)
+  --innodb-status-file 
+                      Enable SHOW ENGINE INNODB STATUS output in the
+                      innodb_status.<pid> file
+  --innodb-status-output 
+                      Enable InnoDB monitor output to the error log.
+  --innodb-status-output-locks 
+                      Enable InnoDB lock monitor output to the error log.
+                      Requires innodb_status_output=ON.
+  --innodb-strict-mode 
+                      Use strict mode when evaluating create options.
+                      (Defaults to on; use --skip-innodb-strict-mode to disable.)
+  --innodb-sync-spin-loops=# 
+                      Count of spin-loop rounds in InnoDB mutexes (30 by
+                      default)
+  --innodb-sys-columns[=name] 
+                      Enable or disable INNODB_SYS_COLUMNS plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-sys-fields[=name] 
+                      Enable or disable INNODB_SYS_FIELDS plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-sys-foreign[=name] 
+                      Enable or disable INNODB_SYS_FOREIGN plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-sys-foreign-cols[=name] 
+                      Enable or disable INNODB_SYS_FOREIGN_COLS plugin. One of:
+                      ON, OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-sys-indexes[=name] 
+                      Enable or disable INNODB_SYS_INDEXES plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-sys-tables[=name] 
+                      Enable or disable INNODB_SYS_TABLES plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-sys-tablespaces[=name] 
+                      Enable or disable INNODB_SYS_TABLESPACES plugin. One of:
+                      ON, OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-sys-tablestats[=name] 
+                      Enable or disable INNODB_SYS_TABLESTATS plugin. One of:
+                      ON, OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-sys-virtual[=name] 
+                      Enable or disable INNODB_SYS_VIRTUAL plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-table-locks 
+                      Enable InnoDB locking in LOCK TABLES
+                      (Defaults to on; use --skip-innodb-table-locks to disable.)
+  --innodb-tablespaces-encryption[=name] 
+                      Enable or disable INNODB_TABLESPACES_ENCRYPTION plugin.
+                      One of: ON, OFF, FORCE (don't start if the plugin fails
+                      to load), FORCE_PLUS_PERMANENT (like FORCE, but the
+                      plugin can not be uninstalled).
+  --innodb-temp-data-file-path=name 
+                      Path to files and their sizes making temp-tablespace.
+  --innodb-tmpdir[=name] 
+                      Directory for temporary non-tablespace files.
+  --innodb-trx[=name] Enable or disable INNODB_TRX plugin. One of: ON, OFF,
+                      FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --innodb-undo-directory=name 
+                      Directory where undo tablespace files live, this path can
+                      be absolute.
+  --innodb-undo-log-truncate 
+                      Enable or Disable Truncate of UNDO tablespace.
+  --innodb-undo-tablespaces=# 
+                      Number of undo tablespaces to use.
+  --innodb-use-atomic-writes 
+                      Enable atomic writes, instead of using the doublewrite
+                      buffer, for files on devices that supports atomic writes.
+                      (Defaults to on; use --skip-innodb-use-atomic-writes to disable.)
+  --innodb-use-native-aio 
+                      Use native AIO if supported on this platform.
+                      (Defaults to on; use --skip-innodb-use-native-aio to disable.)
+  --innodb-write-io-threads=# 
+                      Number of background write I/O threads in InnoDB.
+  --interactive-timeout=# 
+                      The number of seconds the server waits for activity on an
+                      interactive connection before closing it
+  --join-buffer-size=# 
+                      The size of the buffer that is used for joins
+  --join-buffer-space-limit=# 
+                      The limit of the space for all join buffers used by a
+                      query
+  --join-cache-level=# 
+                      Controls what join operations can be executed with join
+                      buffers. Odd numbers are used for plain join buffers
+                      while even numbers are used for linked buffers
+  --keep-files-on-create 
+                      Don't overwrite stale .MYD and .MYI even if no directory
+                      is specified
+  --key-buffer-size=# The size of the buffer used for index blocks for MyISAM
+                      tables. Increase this to get better index handling (for
+                      all reads and multiple writes) to as much as you can
+                      afford
+  --key-cache-age-threshold=# 
+                      This characterizes the number of hits a hot block has to
+                      be untouched until it is considered aged enough to be
+                      downgraded to a warm block. This specifies the percentage
+                      ratio of that number of hits to the total number of
+                      blocks in key cache
+  --key-cache-block-size=# 
+                      The default size of key cache blocks
+  --key-cache-division-limit=# 
+                      The minimum percentage of warm blocks in key cache
+  --key-cache-file-hash-size=# 
+                      Number of hash buckets for open and changed files.  If
+                      you have a lot of MyISAM files open you should increase
+                      this for faster flush of changes. A good value is
+                      probably 1/10 of number of possible open MyISAM files.
+  --key-cache-segments=# 
+                      The number of segments in a key cache
+  -L, --language=name Client error messages in given language. May be given as
+                      a full path. Deprecated. Use --lc-messages-dir instead.
+  --large-pages       Enable support for large pages
+  --lc-messages=name  Set the language used for the error messages.
+  -L, --lc-messages-dir=name 
+                      Directory where error messages are
+  --lc-time-names=name 
+                      Set the language used for the month names and the days of
+                      the week.
+  --local-infile      Enable LOAD DATA LOCAL INFILE
+                      (Defaults to on; use --skip-local-infile to disable.)
+  --lock-wait-timeout=# 
+                      Timeout in seconds to wait for a lock before returning an
+                      error.
+  --log-basename=name Basename for all log files and the .pid file. This sets
+                      all log file names at once (in 'datadir') and is normally
+                      the only option you need for specifying log files. Sets
+                      names for --log-bin, --log-bin-index, --relay-log,
+                      --relay-log-index, --general-log-file,
+                      --log-slow-query-file, --log-error-file, and --pid-file
+  --log-bin[=name]    Log update queries in binary format. Optional argument
+                      should be name for binary log. If not given
+                      'datadir'/'log-basename'-bin or 'datadir'/mysql-bin will
+                      be used (the later if --log-basename is not specified).
+                      We strongly recommend to use either --log-basename or
+                      specify a filename to ensure that replication doesn't
+                      stop if the real hostname of the computer changes.
+  --log-bin-compress  Whether the binary log can be compressed
+  --log-bin-compress-min-len[=#] 
+                      Minimum length of sql statement(in statement mode) or
+                      record(in row mode)that can be compressed.
+  --log-bin-index=name 
+                      File that holds the names for last binary log files.
+  --log-bin-trust-function-creators 
+                      If set to FALSE (the default), then when --log-bin is
+                      used, creation of a stored function (or trigger) is
+                      allowed only to users having the SUPER privilege and only
+                      if this stored function (trigger) may not break binary
+                      logging. Note that if ALL connections to this server
+                      ALWAYS use row-based binary logging, the security issues
+                      do not exist and the binary logging cannot break, so you
+                      can safely set this to TRUE
+  --log-ddl-recovery=name 
+                      Path to file used for recovery of DDL statements after a
+                      crash
+  --log-disabled-statements=name 
+                      Don't log certain types of statements to general log. Any
+                      combination of: slave, sp
+  Use 'ALL' to set all combinations.
+  --log-error[=name]  Log errors to file (instead of stdout).  If file name is
+                      not specified then 'datadir'/'log-basename'.err or the
+                      'pid-file' path with extension .err is used
+  --log-isam[=name]   Log all MyISAM changes to file.
+  --log-output=name   How logs should be written. Any combination of: NONE, 
+                      FILE, TABLE
+  Use 'ALL' to set all combinations.
+  --log-queries-not-using-indexes 
+                      Log queries that are executed without benefit of any
+                      index to the slow log if it is open. Same as
+                      log_slow_filter='not_using_index'
+  --log-short-format  Don't log extra information to update and slow-query
+                      logs.
+  --log-slave-updates Tells the slave to log the updates from the slave thread
+                      to the binary log. You will need to turn it on if you
+                      plan to daisy-chain the slaves.
+  --log-slow-admin-statements 
+                      Log slow OPTIMIZE, ANALYZE, ALTER and other
+                      administrative statements to the slow log if it is open. 
+                      Resets or sets the option 'admin' in
+                      log_slow_disabled_statements
+                      (Defaults to on; use --skip-log-slow-admin-statements to disable.)
+  --log-slow-disabled-statements=name 
+                      Don't log certain types of statements to slow log. Any
+                      combination of: admin, call, slave, sp
+  Use 'ALL' to set all combinations.
+  --log-slow-filter=name 
+                      Log only certain types of queries to the slow log. If
+                      variable empty all kind of queries are logged.  All types
+                      are bound by slow_query_time, except 'not_using_index'
+                      which is always logged if enabled. Any combination of: 
+                      admin, filesort, filesort_on_disk, 
+                      filesort_priority_queue, full_join, full_scan, 
+                      not_using_index, query_cache, query_cache_miss, tmp_table,
+                      tmp_table_on_disk
+  Use 'ALL' to set all combinations.
+  --log-slow-max-warnings=# 
+                      Max numbers of warnings printed to slow query log per
+                      statement
+  --log-slow-min-examined-row-limit=# 
+                      Don't write queries to slow log that examine fewer rows
+                      than that
+  --log-slow-query    Log slow queries to a table or log file. Defaults logging
+                      to a file 'hostname'-slow.log or a table mysql.slow_log
+                      if --log-output=TABLE is used. Must be enabled to
+                      activate other slow log options.
+  --log-slow-query-file=name 
+                      Log slow queries to given log file. Defaults logging to
+                      'hostname'-slow.log. Must be enabled to activate other
+                      slow log options
+  --log-slow-query-time=# 
+                      Log all queries that have taken more than
+                      log_slow_query_time seconds to execute to the slow query
+                      log file. The argument will be treated as a decimal value
+                      with microsecond precision
+  --log-slow-rate-limit=# 
+                      Write to slow log every #th slow query. Set to 1 to log
+                      everything. Increase it to reduce the size of the slow or
+                      the performance impact of slow logging
+  --log-slow-slave-statements 
+                      Log slow statements executed by slave thread to the slow
+                      log if it is open. Resets or sets the option 'slave' in
+                      log_slow_disabled_statements
+                      (Defaults to on; use --skip-log-slow-slave-statements to disable.)
+  --log-slow-verbosity=name 
+                      Verbosity level for the slow log. Any combination of: 
+                      innodb, query_plan, explain, engine, warnings, full
+  Use 'ALL' to set all combinations.
+  --log-tc=name       Path to transaction coordinator log (used for
+                      transactions that affect more than one storage engine,
+                      when binary log is disabled).
+  --log-tc-size=#     Size of transaction coordinator log.
+  -W, --log-warnings[=#] 
+                      Log some non critical warnings to the error log.Value can
+                      be between 0 and 11. Higher values mean more verbosity
+  --long-query-time=# Alias for log_slow_query_time. Log all queries that have
+                      taken more than long_query_time seconds to execute to the
+                      slow query log file. The argument will be treated as a
+                      decimal value with microsecond precision
+  --low-priority-updates 
+                      INSERT/DELETE/UPDATE has lower priority than selects
+  --lower-case-table-names[=#] 
+                      If set to 1 table names are stored in lowercase on disk
+                      and table names will be case-insensitive.  Should be set
+                      to 2 if you are using a case insensitive file system
+  --master-info-file=name 
+                      The location and name of the file that remembers the
+                      master and where the I/O replication thread is in the
+                      master's binlogs. Defaults to master.info
+  --master-retry-count=# 
+                      The number of tries the slave will make to connect to the
+                      master before giving up.
+  --master-verify-checksum 
+                      Force checksum verification of logged events in the
+                      binary log before sending them to slaves or printing them
+                      in the output of SHOW BINLOG EVENTS
+  --max-allowed-packet=# 
+                      Max packet length to send to or receive from the server
+  --max-binlog-cache-size=# 
+                      Sets the total size of the transactional cache
+  --max-binlog-size=# Binary log will be rotated automatically when the size
+                      exceeds this value.
+  --max-binlog-stmt-cache-size=# 
+                      Sets the total size of the statement cache
+  --max-connect-errors=# 
+                      If there is more than this number of interrupted
+                      connections from a host this host will be blocked from
+                      further connections
+  --max-connections=# The number of simultaneous clients allowed
+  --max-delayed-threads=# 
+                      Don't start more than this number of threads to handle
+                      INSERT DELAYED statements. If set to zero INSERT DELAYED
+                      will be not used
+  --max-digest-length=# 
+                      Maximum length considered for digest text.
+  --max-error-count=# Max number of errors/warnings to store for a statement
+  --max-heap-table-size=# 
+                      Don't allow creation of heap tables bigger than this
+  --max-join-size=#   Joins that are probably going to read more than
+                      max_join_size records return an error
+  --max-length-for-sort-data=# 
+                      Max number of bytes in sorted records
+  --max-password-errors=# 
+                      If there is more than this number of failed connect
+                      attempts due to invalid password, user will be blocked
+                      from further connections until FLUSH_PRIVILEGES.
+  --max-prepared-stmt-count=# 
+                      Maximum number of prepared statements in the server
+  --max-recursive-iterations[=#] 
+                      Maximum number of iterations when executing recursive
+                      queries
+  --max-relay-log-size=# 
+                      relay log will be rotated automatically when the size
+                      exceeds this value.  If 0 at startup, it's set to
+                      max_binlog_size
+  --max-rowid-filter-size=# 
+                      The maximum size of the container of a rowid filter
+  --max-seeks-for-key=# 
+                      Limit assumed max number of seeks when looking up rows
+                      based on a key
+  --max-session-mem-used=# 
+                      Amount of memory a single user session is allowed to
+                      allocate. This limits the value of the session variable
+                      MEM_USED
+  --max-sort-length=# The number of bytes to use when sorting BLOB or TEXT
+                      values (only the first max_sort_length bytes of each
+                      value are used; the rest are ignored)
+  --max-sp-recursion-depth[=#] 
+                      Maximum stored procedure recursion depth
+  --max-statement-time=# 
+                      A query that has taken more than max_statement_time
+                      seconds will be aborted. The argument will be treated as
+                      a decimal value with microsecond precision. A value of 0
+                      (default) means no timeout
+  --max-tmp-tables=#  Unused, will be removed.
+  --max-user-connections=# 
+                      The maximum number of active connections for a single
+                      user (0 = no limit)
+  --max-write-lock-count=# 
+                      After this many write locks, allow some read locks to run
+                      in between
+  --memlock           Lock mysqld in memory.
+  --metadata-locks-cache-size=# 
+                      Unused
+  --metadata-locks-hash-instances=# 
+                      Unused
+  --min-examined-row-limit=# 
+                      Alias for log_slow_min_examined_row_limit. Don't write
+                      queries to slow log that examine fewer rows than that
+  --mrr-buffer-size=# Size of buffer to use when using MRR with range access
+  --myisam-block-size=# 
+                      Block size to be used for MyISAM index pages
+  --myisam-data-pointer-size=# 
+                      Default pointer size to be used for MyISAM tables
+  --myisam-max-sort-file-size=# 
+                      Don't use the fast sort index method to created index if
+                      the temporary file would get bigger than this
+  --myisam-mmap-size=# 
+                      Restricts the total memory used for memory mapping of
+                      MySQL tables
+  --myisam-recover-options[=name] 
+                      Specifies how corrupted tables should be automatically
+                      repaired. Any combination of: DEFAULT, BACKUP, FORCE, 
+                      QUICK, BACKUP_ALL, OFF
+  Use 'ALL' to set all combinations.
+  --myisam-repair-threads=# 
+                      If larger than 1, when repairing a MyISAM table all
+                      indexes will be created in parallel, with one thread per
+                      index. The value of 1 disables parallel repair
+  --myisam-sort-buffer-size=# 
+                      The buffer that is allocated when sorting the index when
+                      doing a REPAIR or when creating indexes with CREATE INDEX
+                      or ALTER TABLE
+  --myisam-stats-method=name 
+                      Specifies how MyISAM index statistics collection code
+                      should treat NULLs. Possible values of name are
+                      NULLS_UNEQUAL (default behavior for 4.1 and later),
+                      NULLS_EQUAL (emulate 4.0 behavior), and NULLS_IGNORED
+  --myisam-use-mmap   Use memory mapping for reading and writing MyISAM tables
+  --mysql56-temporal-format 
+                      Use MySQL-5.6 (instead of MariaDB-5.3) format for TIME,
+                      DATETIME, TIMESTAMP columns.
+                      (Defaults to on; use --skip-mysql56-temporal-format to disable.)
+  --net-buffer-length=# 
+                      Buffer length for TCP/IP and socket communication
+  --net-read-timeout=# 
+                      Number of seconds to wait for more data from a connection
+                      before aborting the read
+  --net-retry-count=# If a read on a communication port is interrupted, retry
+                      this many times before giving up
+  --net-write-timeout=# 
+                      Number of seconds to wait for a block to be written to a
+                      connection before aborting the write
+  --note-verbosity=name 
+                      Verbosity level for note-warnings given to the user. See
+                      also @@sql_notes.. Any combination of: basic, 
+                      unusable_keys, explain
+  Use 'ALL' to set all combinations.
+  --old               Use compatible behavior from previous MariaDB version.
+                      See also --old-mode
+  --old-alter-table[=name] 
+                      Alias for alter_algorithm. Deprecated. Use
+                      --alter-algorithm instead.. One of: DEFAULT, COPY, 
+                      INPLACE, NOCOPY, INSTANT
+  --old-mode=name     Used to emulate old behavior from earlier MariaDB or
+                      MySQL versions. Any combination of: 
+                      NO_DUP_KEY_WARNINGS_WITH_IGNORE, NO_PROGRESS_INFO, 
+                      ZERO_DATE_TIME_CAST, UTF8_IS_UTF8MB3, 
+                      IGNORE_INDEX_ONLY_FOR_JOIN, COMPAT_5_1_CHECKSUM, 
+                      NO_NULL_COLLATION_IDS
+  Use 'ALL' to set all combinations.
+  --old-passwords     Use old password encryption method (needed for 4.0 and
+                      older clients)
+  --old-style-user-limits 
+                      Enable old-style user limits (before 5.0.3, user
+                      resources were counted per each user+host vs. per
+                      account).
+  --open-files-limit=# 
+                      If this is not 0, then mysqld will use this value to
+                      reserve file descriptors to use with setrlimit(). If this
+                      value is 0 or autoset then mysqld will reserve
+                      max_connections*5 or max_connections + table_cache*2
+                      (whichever is larger) number of file descriptors
+                      (Automatically configured unless set explicitly)
+  --optimizer-adjust-secondary-key-costs=name 
+                      A bit field with the following values:
+                      adjust_secondary_key_cost = Update secondary key costs
+                      for ranges to be at least 5x of clustered primary key
+                      costs. disable_max_seek = Disable 'max_seek optimization'
+                      for secondary keys and slight adjustment of filter cost.
+                      disable_forced_index_in_group_by = Disable automatic
+                      forced index in GROUP BY. This variable will be deleted
+                      in MariaDB 11.0 as it is not needed with the new 11.0
+                      optimizer.
+  Use 'ALL' to set all combinations.
+  --optimizer-extra-pruning-depth=# 
+                      If the optimizer needs to enumerate join prefix of this
+                      size or larger, then it will try aggressively prune away
+                      the search space.
+  --optimizer-max-sel-arg-weight=# 
+                      The maximum weight of the SEL_ARG graph. Set to 0 for no
+                      limit
+  --optimizer-max-sel-args=# 
+                      The maximum number of SEL_ARG objects created when
+                      optimizing a range. If more objects would be needed, the
+                      range will not be used by the optimizer.
+  --optimizer-prune-level=# 
+                      Controls the heuristic(s) applied during query
+                      optimization to prune less-promising partial plans from
+                      the optimizer search space. Meaning: 0 - do not apply any
+                      heuristic, thus perform exhaustive search: 1 - prune
+                      plans based on cost and number of retrieved rows eq_ref:
+                      2 - prune also if we find an eq_ref chain
+  --optimizer-search-depth=# 
+                      Maximum depth of search performed by the query optimizer.
+                      Values larger than the number of relations in a query
+                      result in better query plans, but take longer to compile
+                      a query. Values smaller than the number of tables in a
+                      relation result in faster optimization, but may produce
+                      very bad query plans. If set to 0, the system will
+                      automatically pick a reasonable value.
+  --optimizer-selectivity-sampling-limit=# 
+                      Controls number of record samples to check condition
+                      selectivity
+  --optimizer-switch=name 
+                      Fine-tune the optimizer behavior. Takes a comma-separated
+                      list of option=value pairs, where value is on, off, or
+                      default, and options are: index_merge, index_merge_union,
+                      index_merge_sort_union, index_merge_intersection, 
+                      index_merge_sort_intersection, engine_condition_pushdown,
+                      index_condition_pushdown, derived_merge, 
+                      derived_with_keys, firstmatch, loosescan, materialization,
+                      in_to_exists, semijoin, partial_match_rowid_merge, 
+                      partial_match_table_scan, subquery_cache, mrr, 
+                      mrr_cost_based, mrr_sort_keys, outer_join_with_cache, 
+                      semijoin_with_cache, join_cache_incremental, 
+                      join_cache_hashed, join_cache_bka, 
+                      optimize_join_buffer_size, table_elimination, 
+                      extended_keys, exists_to_in, orderby_uses_equalities, 
+                      condition_pushdown_for_derived, split_materialized, 
+                      condition_pushdown_for_subquery, rowid_filter, 
+                      condition_pushdown_from_having, not_null_range_scan, 
+                      hash_join_cardinality, cset_narrowing
+  --optimizer-trace=name 
+                      Controls tracing of the Optimizer:
+                      optimizer_trace=option=val[,option=val...], where option
+                      is one of {enabled} and val is one of {on, off, default}
+  --optimizer-trace-max-mem-size=# 
+                      Maximum allowed size of an optimizer trace
+  --optimizer-use-condition-selectivity=# 
+                      Controls selectivity of which conditions the optimizer
+                      takes into account to calculate cardinality of a partial
+                      join when it searches for the best execution plan
+                      Meaning: 1 - use selectivity of index backed range
+                      conditions to calculate the cardinality of a partial join
+                      if the last joined table is accessed by full table scan
+                      or an index scan, 2 - use selectivity of index backed
+                      range conditions to calculate the cardinality of a
+                      partial join in any case, 3 - additionally always use
+                      selectivity of range conditions that are not backed by
+                      any index to calculate the cardinality of a partial join,
+                      4 - use histograms to calculate selectivity of range
+                      conditions that are not backed by any index to calculate
+                      the cardinality of a partial join.5 - additionally use
+                      selectivity of certain non-range predicates calculated on
+                      record samples
+  --partition[=name]  Enable or disable partition plugin. One of: ON, OFF,
+                      FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --performance-schema 
+                      Enable the performance schema.
+  --performance-schema-accounts-size=# 
+                      Maximum number of instrumented user@host accounts. Use 0
+                      to disable, -1 for automated sizing.
+  --performance-schema-consumer-events-stages-current 
+                      Default startup value for the events_stages_current
+                      consumer.
+  --performance-schema-consumer-events-stages-history 
+                      Default startup value for the events_stages_history
+                      consumer.
+  --performance-schema-consumer-events-stages-history-long 
+                      Default startup value for the events_stages_history_long
+                      consumer.
+  --performance-schema-consumer-events-statements-current 
+                      Default startup value for the events_statements_current
+                      consumer.
+  --performance-schema-consumer-events-statements-history 
+                      Default startup value for the events_statements_history
+                      consumer.
+  --performance-schema-consumer-events-statements-history-long 
+                      Default startup value for the
+                      events_statements_history_long consumer.
+  --performance-schema-consumer-events-transactions-current 
+                      Default startup value for the events_transactions_current
+                      consumer.
+  --performance-schema-consumer-events-transactions-history 
+                      Default startup value for the events_transactions_history
+                      consumer.
+  --performance-schema-consumer-events-transactions-history-long 
+                      Default startup value for the
+                      events_transactions_history_long consumer.
+  --performance-schema-consumer-events-waits-current 
+                      Default startup value for the events_waits_current
+                      consumer.
+  --performance-schema-consumer-events-waits-history 
+                      Default startup value for the events_waits_history
+                      consumer.
+  --performance-schema-consumer-events-waits-history-long 
+                      Default startup value for the events_waits_history_long
+                      consumer.
+  --performance-schema-consumer-global-instrumentation 
+                      Default startup value for the global_instrumentation
+                      consumer.
+                      (Defaults to on; use --skip-performance-schema-consumer-global-instrumentation to disable.)
+  --performance-schema-consumer-statements-digest 
+                      Default startup value for the statements_digest consumer.
+                      (Defaults to on; use --skip-performance-schema-consumer-statements-digest to disable.)
+  --performance-schema-consumer-thread-instrumentation 
+                      Default startup value for the thread_instrumentation
+                      consumer.
+                      (Defaults to on; use --skip-performance-schema-consumer-thread-instrumentation to disable.)
+  --performance-schema-digests-size=# 
+                      Size of the statement digest. Use 0 to disable, -1 for
+                      automated sizing.
+  --performance-schema-events-stages-history-long-size=# 
+                      Number of rows in EVENTS_STAGES_HISTORY_LONG. Use 0 to
+                      disable, -1 for automated sizing.
+  --performance-schema-events-stages-history-size=# 
+                      Number of rows per thread in EVENTS_STAGES_HISTORY. Use 0
+                      to disable, -1 for automated sizing.
+  --performance-schema-events-statements-history-long-size=# 
+                      Number of rows in EVENTS_STATEMENTS_HISTORY_LONG. Use 0
+                      to disable, -1 for automated sizing.
+  --performance-schema-events-statements-history-size=# 
+                      Number of rows per thread in EVENTS_STATEMENTS_HISTORY.
+                      Use 0 to disable, -1 for automated sizing.
+  --performance-schema-events-transactions-history-long-size=# 
+                      Number of rows in EVENTS_TRANSACTIONS_HISTORY_LONG. Use 0
+                      to disable, -1 for automated sizing.
+  --performance-schema-events-transactions-history-size=# 
+                      Number of rows per thread in EVENTS_TRANSACTIONS_HISTORY.
+                      Use 0 to disable, -1 for automated sizing.
+  --performance-schema-events-waits-history-long-size=# 
+                      Number of rows in EVENTS_WAITS_HISTORY_LONG. Use 0 to
+                      disable, -1 for automated sizing.
+  --performance-schema-events-waits-history-size=# 
+                      Number of rows per thread in EVENTS_WAITS_HISTORY. Use 0
+                      to disable, -1 for automated sizing.
+  --performance-schema-hosts-size=# 
+                      Maximum number of instrumented hosts. Use 0 to disable,
+                      -1 for automated sizing.
+  --performance-schema-instrument[=name] 
+                      Default startup value for a performance schema
+                      instrument.
+  --performance-schema-max-cond-classes=# 
+                      Maximum number of condition instruments.
+  --performance-schema-max-cond-instances=# 
+                      Maximum number of instrumented condition objects. Use 0
+                      to disable, -1 for automated sizing.
+  --performance-schema-max-digest-length=# 
+                      Maximum length considered for digest text, when stored in
+                      performance_schema tables.
+  --performance-schema-max-file-classes=# 
+                      Maximum number of file instruments.
+  --performance-schema-max-file-handles=# 
+                      Maximum number of opened instrumented files.
+  --performance-schema-max-file-instances=# 
+                      Maximum number of instrumented files. Use 0 to disable,
+                      -1 for automated sizing.
+  --performance-schema-max-index-stat=# 
+                      Maximum number of index statistics for instrumented
+                      tables. Use 0 to disable, -1 for automated scaling.
+  --performance-schema-max-memory-classes=# 
+                      Maximum number of memory pool instruments.
+  --performance-schema-max-metadata-locks=# 
+                      Maximum number of metadata locks. Use 0 to disable, -1
+                      for automated scaling.
+  --performance-schema-max-mutex-classes=# 
+                      Maximum number of mutex instruments.
+  --performance-schema-max-mutex-instances=# 
+                      Maximum number of instrumented MUTEX objects. Use 0 to
+                      disable, -1 for automated sizing.
+  --performance-schema-max-prepared-statements-instances=# 
+                      Maximum number of instrumented prepared statements. Use 0
+                      to disable, -1 for automated scaling.
+  --performance-schema-max-program-instances=# 
+                      Maximum number of instrumented programs. Use 0 to
+                      disable, -1 for automated scaling.
+  --performance-schema-max-rwlock-classes=# 
+                      Maximum number of rwlock instruments.
+  --performance-schema-max-rwlock-instances=# 
+                      Maximum number of instrumented RWLOCK objects. Use 0 to
+                      disable, -1 for automated sizing.
+  --performance-schema-max-socket-classes=# 
+                      Maximum number of socket instruments.
+  --performance-schema-max-socket-instances=# 
+                      Maximum number of opened instrumented sockets. Use 0 to
+                      disable, -1 for automated sizing.
+  --performance-schema-max-sql-text-length=# 
+                      Maximum length of displayed sql text.
+  --performance-schema-max-stage-classes=# 
+                      Maximum number of stage instruments.
+  --performance-schema-max-statement-classes=# 
+                      Maximum number of statement instruments.
+  --performance-schema-max-statement-stack=# 
+                      Number of rows per thread in EVENTS_STATEMENTS_CURRENT.
+  --performance-schema-max-table-handles=# 
+                      Maximum number of opened instrumented tables. Use 0 to
+                      disable, -1 for automated sizing.
+  --performance-schema-max-table-instances=# 
+                      Maximum number of instrumented tables. Use 0 to disable,
+                      -1 for automated sizing.
+  --performance-schema-max-table-lock-stat=# 
+                      Maximum number of lock statistics for instrumented
+                      tables. Use 0 to disable, -1 for automated scaling.
+  --performance-schema-max-thread-classes=# 
+                      Maximum number of thread instruments.
+  --performance-schema-max-thread-instances=# 
+                      Maximum number of instrumented threads. Use 0 to disable,
+                      -1 for automated sizing.
+  --performance-schema-session-connect-attrs-size=# 
+                      Size of session attribute string buffer per thread. Use 0
+                      to disable, -1 for automated sizing.
+  --performance-schema-setup-actors-size=# 
+                      Maximum number of rows in SETUP_ACTORS.
+  --performance-schema-setup-objects-size=# 
+                      Maximum number of rows in SETUP_OBJECTS.
+  --performance-schema-users-size=# 
+                      Maximum number of instrumented users. Use 0 to disable,
+                      -1 for automated sizing.
+  --pid-file=name     Pid file used by safe_mysqld
+  --plugin-dir=name   Directory for plugins
+  --plugin-load=name  Semicolon-separated list of plugins to load, where each
+                      plugin is specified as ether a plugin_name=library_file
+                      pair or only a library_file. If the latter case, all
+                      plugins from a given library_file will be loaded.
+  --plugin-load-add=name 
+                      Optional semicolon-separated list of plugins to load.
+                      This option adds to the list specified by --plugin-load
+                      in an incremental way. It can be specified many times,
+                      adding more plugins every time.
+  --plugin-maturity=name 
+                      The lowest desirable plugin maturity. Plugins less mature
+                      than that will not be installed or loaded. One of: 
+                      unknown, experimental, alpha, beta, gamma, stable
+  -P, --port=#        Port number to use for connection or 0 to default to,
+                      my.cnf, $MYSQL_TCP_PORT, /etc/services, built-in default
+                      (3306), whatever comes first
+  --port-open-timeout=# 
+                      Maximum time in seconds to wait for the port to become
+                      free. (Default: No wait).
+  --preload-buffer-size=# 
+                      The size of the buffer that is allocated when preloading
+                      indexes
+  --profiling-history-size=# 
+                      Number of statements about which profiling information is
+                      maintained. If set to 0, no profiles are stored. See SHOW
+                      PROFILES.
+  --progress-report-time=# 
+                      Seconds between sending progress reports to the client
+                      for time-consuming statements. Set to 0 to disable
+                      progress reporting.
+  --proxy-protocol-networks=name 
+                      Enable proxy protocol for these source networks. The
+                      syntax is a comma separated list of IPv4 and IPv6
+                      networks. If the network doesn't contain mask, it is
+                      considered to be a single host. "*" represents all
+                      networks and must the only directive on the line. String
+                      "localhost" represents non-TCP local connections (Unix
+                      domain socket, Windows named pipe or shared memory).
+  --query-alloc-block-size=# 
+                      Allocation block size for query parsing and execution
+  --query-cache-limit=# 
+                      Don't cache results that are bigger than this
+  --query-cache-min-res-unit=# 
+                      The minimum size for blocks allocated by the query cache
+  --query-cache-size=# 
+                      The memory allocated to store results from old queries
+  --query-cache-strip-comments 
+                      Strip all comments from a query before storing it in the
+                      query cache
+  --query-cache-type=name 
+                      OFF = Don't cache or retrieve results. ON = Cache all
+                      results except SELECT SQL_NO_CACHE ... queries. DEMAND =
+                      Cache only SELECT SQL_CACHE ... queries
+  --query-cache-wlock-invalidate 
+                      Invalidate queries in query cache on LOCK for write
+  --query-prealloc-size=# 
+                      Persistent buffer for query parsing and execution
+  --range-alloc-block-size=# 
+                      Allocation block size for storing ranges during
+                      optimization
+  --read-binlog-speed-limit=# 
+                      Maximum speed(KB/s) to read binlog from master (0 = no
+                      limit)
+  --read-buffer-size=# 
+                      Each thread that does a sequential scan allocates a
+                      buffer of this size for each table it scans. If you do
+                      many sequential scans, you may want to increase this
+                      value
+  --read-only         Make all non-temporary tables read-only, with the
+                      exception for replication (slave) threads and users with
+                      the 'READ ONLY ADMIN' privilege
+  --read-rnd-buffer-size=# 
+                      When reading rows in sorted order after a sort, the rows
+                      are read through this buffer to avoid a disk seeks
+  --relay-log=name    The location and name to use for relay logs.
+  --relay-log-index=name 
+                      The location and name to use for the file that keeps a
+                      list of the last relay logs
+  --relay-log-info-file=name 
+                      The location and name of the file that remembers where
+                      the SQL replication thread is in the relay logs.
+  --relay-log-purge   if disabled - do not purge relay logs. if enabled - purge
+                      them as soon as they are no more needed.
+                      (Defaults to on; use --skip-relay-log-purge to disable.)
+  --relay-log-recovery 
+                      Enables automatic relay log recovery right after the
+                      database startup, which means that the IO Thread starts
+                      re-fetching from the master right after the last
+                      transaction processed.
+  --relay-log-space-limit=# 
+                      Maximum space to use for all relay logs
+  --replicate-annotate-row-events 
+                      Tells the slave to write annotate rows events received
+                      from the master to its own binary log. Ignored if
+                      log_slave_updates is not set
+                      (Defaults to on; use --skip-replicate-annotate-row-events to disable.)
+  --replicate-do-db=name 
+                      Tells the slave thread to restrict replication to the
+                      specified database. To specify more than one database,
+                      use the directive multiple times, once for each database.
+                      Note that this will only work if you do not use
+                      cross-database queries such as UPDATE some_db.some_table
+                      SET foo='bar' while having selected a different or no
+                      database. If you need cross database updates to work,
+                      make sure you have 3.23.28 or later, and use
+                      replicate-wild-do-table=db_name.%.
+  --replicate-do-table=name 
+                      Tells the slave thread to restrict replication to the
+                      specified table. To specify more than one table, use the
+                      directive multiple times, once for each table. This will
+                      work for cross-database updates, in contrast to
+                      replicate-do-db.
+  --replicate-events-marked-for-skip=name 
+                      Whether the slave should replicate events that were
+                      created with @@skip_replication=1 on the master. Default
+                      REPLICATE (no events are skipped). Other values are
+                      FILTER_ON_SLAVE (events will be sent by the master but
+                      ignored by the slave) and FILTER_ON_MASTER (events marked
+                      with @@skip_replication=1 will be filtered on the master
+                      and never be sent to the slave).
+  --replicate-ignore-db=name 
+                      Tells the slave thread to not replicate to the specified
+                      database. To specify more than one database to ignore,
+                      use the directive multiple times, once for each database.
+                      This option will not work if you use cross database
+                      updates. If you need cross database updates to work, make
+                      sure you have 3.23.28 or later, and use
+                      replicate-wild-ignore-table=db_name.%. 
+  --replicate-ignore-table=name 
+                      Tells the slave thread to not replicate to the specified
+                      table. To specify more than one table to ignore, use the
+                      directive multiple times, once for each table. This will
+                      work for cross-database updates, in contrast to
+                      replicate-ignore-db.
+  --replicate-rewrite-db=name 
+                      Updates to a database with a different name than the
+                      original. Example:
+                      replicate-rewrite-db=master_db_name->slave_db_name.
+  --replicate-same-server-id 
+                      In replication, if set to 1, do not skip events having
+                      our server id. Default value is 0 (to break infinite
+                      loops in circular replication). Can't be set to 1 if
+                      --log-slave-updates is used.
+  --replicate-wild-do-table=name 
+                      Tells the slave thread to restrict replication to the
+                      tables that match the specified wildcard pattern. To
+                      specify more than one table, use the directive multiple
+                      times, once for each table. This will work for
+                      cross-database updates. Example:
+                      replicate-wild-do-table=foo%.bar% will replicate only
+                      updates to tables in all databases that start with foo
+                      and whose table names start with bar.
+  --replicate-wild-ignore-table=name 
+                      Tells the slave thread to not replicate to the tables
+                      that match the given wildcard pattern. To specify more
+                      than one table to ignore, use the directive multiple
+                      times, once for each table. This will work for
+                      cross-database updates. Example:
+                      replicate-wild-ignore-table=foo%.bar% will not do updates
+                      to tables in databases that start with foo and whose
+                      table names start with bar.
+  --report-host=name  Hostname or IP of the slave to be reported to the master
+                      during slave registration. Will appear in the output of
+                      SHOW SLAVE HOSTS. Leave unset if you do not want the
+                      slave to register itself with the master. Note that it is
+                      not sufficient for the master to simply read the IP of
+                      the slave off the socket once the slave connects. Due to
+                      NAT and other routing issues, that IP may not be valid
+                      for connecting to the slave from the master or other
+                      hosts
+  --report-password=name 
+                      The account password of the slave to be reported to the
+                      master during slave registration
+  --report-port=#     Port for connecting to slave reported to the master
+                      during slave registration. Set it only if the slave is
+                      listening on a non-default port or if you have a special
+                      tunnel from the master or other clients to the slave. If
+                      not sure, leave this option unset
+  --report-user=name  The account user name of the slave to be reported to the
+                      master during slave registration
+  --require-secure-transport 
+                      When this option is enabled, connections attempted using
+                      insecure transport will be rejected. Secure transports
+                      are SSL/TLS, Unix sockets or named pipes.
+  --rowid-merge-buff-size=# 
+                      The size of the buffers used [NOT] IN evaluation via
+                      partial matching
+  --rpl-semi-sync-master-enabled 
+                      Enable semi-synchronous replication master (disabled by
+                      default).
+  --rpl-semi-sync-master-timeout=# 
+                      The timeout value (in ms) for semi-synchronous
+                      replication in the master
+  --rpl-semi-sync-master-trace-level=# 
+                      The tracing level for semi-sync replication.
+  --rpl-semi-sync-master-wait-no-slave 
+                      Wait until timeout when no semi-synchronous replication
+                      slave is available.
+                      (Defaults to on; use --skip-rpl-semi-sync-master-wait-no-slave to disable.)
+  --rpl-semi-sync-master-wait-point=name 
+                      Should transaction wait for semi-sync ack after having
+                      synced binlog, or after having committed in storage
+                      engine.. One of: AFTER_SYNC, AFTER_COMMIT
+  --rpl-semi-sync-slave-delay-master 
+                      Only write master info file when ack is needed.
+  --rpl-semi-sync-slave-enabled 
+                      Enable semi-synchronous replication slave (disabled by
+                      default).
+  --rpl-semi-sync-slave-kill-conn-timeout[=#] 
+                      Timeout for the mysql connection used to kill the slave
+                      io_thread's connection on master. This timeout comes into
+                      play when stop slave is executed.
+  --rpl-semi-sync-slave-trace-level=# 
+                      The tracing level for semi-sync replication.
+  --safe-mode         Skip some optimize stages (for testing). Deprecated.
+  --safe-user-create  Don't allow new user creation by the user who has no
+                      write privileges to the mysql.user table.
+  --secure-auth       Disallow authentication for accounts that have old
+                      (pre-4.1) passwords
+                      (Defaults to on; use --skip-secure-auth to disable.)
+  --secure-file-priv=name 
+                      Limit LOAD DATA, SELECT ... OUTFILE, and LOAD_FILE() to
+                      files within specified directory
+  --secure-timestamp=name 
+                      Restricts direct setting of a session timestamp. Possible
+                      levels are: YES - timestamp cannot deviate from the
+                      system clock, REPLICATION - replication thread can adjust
+                      timestamp to match the master's, SUPER - a user with this
+                      privilege and a replication thread can adjust timestamp,
+                      NO - historical behavior, anyone can modify session
+                      timestamp
+  --sequence[=name]   Enable or disable SEQUENCE plugin. One of: ON, OFF, FORCE
+                      (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --server-id=#       Uniquely identifies the server instance in the community
+                      of replication partners
+  --session-track-schema 
+                      Track changes to the default schema.
+                      (Defaults to on; use --skip-session-track-schema to disable.)
+  --session-track-state-change 
+                      Track changes to the session state.
+  --session-track-system-variables=name 
+                      Track changes in registered system variables. 
+  --session-track-transaction-info=name 
+                      Track changes to the transaction attributes. OFF to
+                      disable; STATE to track just transaction state (Is there
+                      an active transaction? Does it have any data? etc.);
+                      CHARACTERISTICS to track transaction state and report all
+                      statements needed to start a transaction with the same
+                      characteristics (isolation level, read only/read
+                      write,snapshot - but not any work done / data modified
+                      within the transaction).
+  --show-slave-auth-info 
+                      Show user and password in SHOW SLAVE HOSTS on this
+                      master.
+  --silent-startup    Don't print [Note] to the error log during startup.
+  --skip-grant-tables Start without grant tables. This gives all users FULL
+                      ACCESS to all tables.
+  --skip-host-cache   Don't cache host names.
+  --skip-name-resolve Don't resolve hostnames. All hostnames are IP's or
+                      'localhost'.
+  --skip-networking   Don't allow connection with TCP/IP
+  --skip-show-database 
+                      Don't allow 'SHOW DATABASE' commands
+  --skip-slave-start  If set, slave is not autostarted.
+  --slave-compressed-protocol 
+                      Use compression on master/slave protocol
+  --slave-ddl-exec-mode=name 
+                      How replication events should be executed. Legal values
+                      are STRICT and IDEMPOTENT (default). In IDEMPOTENT mode,
+                      replication will not stop for DDL operations that are
+                      idempotent. This means that CREATE TABLE is treated as
+                      CREATE TABLE OR REPLACE and DROP TABLE is treated as DROP
+                      TABLE IF EXISTS.
+  --slave-domain-parallel-threads=# 
+                      Maximum number of parallel threads to use on slave for
+                      events in a single replication domain. When using
+                      multiple domains, this can be used to limit a single
+                      domain from grabbing all threads and thus stalling other
+                      domains. The default of 0 means to allow a domain to grab
+                      as many threads as it wants, up to the value of
+                      slave_parallel_threads.
+  --slave-exec-mode=name 
+                      How replication events should be executed. Legal values
+                      are STRICT (default) and IDEMPOTENT. In IDEMPOTENT mode,
+                      replication will not stop for operations that are
+                      idempotent. For example, in row based replication
+                      attempts to delete rows that doesn't exist will be
+                      ignored. In STRICT mode, replication will stop on any
+                      unexpected difference between the master and the slave.
+  --slave-load-tmpdir=name 
+                      The location where the slave should put its temporary
+                      files when replicating a LOAD DATA INFILE command
+  --slave-max-allowed-packet=# 
+                      The maximum packet length to sent successfully from the
+                      master to slave.
+  --slave-max-statement-time=# 
+                      A query that has taken more than slave_max_statement_time
+                      seconds to run on the slave will be aborted. The argument
+                      will be treated as a decimal value with microsecond
+                      precision. A value of 0 (default) means no timeout
+  --slave-net-timeout=# 
+                      Number of seconds to wait for more data from any
+                      master/slave connection before aborting the read
+  --slave-parallel-max-queued=# 
+                      Limit on how much memory SQL threads should use per
+                      parallel replication thread when reading ahead in the
+                      relay log looking for opportunities for parallel
+                      replication. Only used when --slave-parallel-threads > 0.
+  --slave-parallel-mode=name 
+                      Controls what transactions are applied in parallel when
+                      using --slave-parallel-threads. Possible values:
+                      "optimistic" tries to apply most transactional DML in
+                      parallel, and handles any conflicts with rollback and
+                      retry. "conservative" limits parallelism in an effort to
+                      avoid any conflicts. "aggressive" tries to maximise the
+                      parallelism, possibly at the cost of increased conflict
+                      rate. "minimal" only parallelizes the commit steps of
+                      transactions. "none" disables parallel apply completely.
+  --slave-parallel-threads=# 
+                      If non-zero, number of threads to spawn to apply in
+                      parallel events on the slave that were group-committed on
+                      the master or were logged with GTID in different
+                      replication domains. Note that these threads are in
+                      addition to the IO and SQL threads, which are always
+                      created by a replication slave
+  --slave-parallel-workers=# 
+                      Alias for slave_parallel_threads
+  --slave-run-triggers-for-rbr=name 
+                      Modes for how triggers in row-base replication on slave
+                      side will be executed. Legal values are NO (default),
+                      YES, LOGGING and ENFORCE. NO means that trigger for RBR
+                      will not be running on slave. YES and LOGGING means that
+                      triggers will be running on slave, if there was not
+                      triggers running on the master for the statement. LOGGING
+                      also means results of that the executed triggers work
+                      will be written to the binlog. ENFORCE means that
+                      triggers will always be run on the slave, even if there
+                      are triggers on the master. ENFORCE implies LOGGING.
+  --slave-skip-errors=name 
+                      Tells the slave thread to continue replication when a
+                      query event returns an error from the provided list
+  --slave-sql-verify-checksum 
+                      Force checksum verification of replication events after
+                      reading them from relay log. Note: Events are always
+                      checksum-verified by slave on receiving them from the
+                      network before writing them to the relay log
+                      (Defaults to on; use --skip-slave-sql-verify-checksum to disable.)
+  --slave-transaction-retries=# 
+                      Number of times the slave SQL thread will retry a
+                      transaction in case it failed with a deadlock, elapsed
+                      lock wait timeout or listed in
+                      slave_transaction_retry_errors, before giving up and
+                      stopping
+  --slave-transaction-retry-errors=name 
+                      Tells the slave thread to retry transaction for
+                      replication when a query event returns an error from the
+                      provided list. Deadlock error, elapsed lock wait timeout,
+                      net read error, net read timeout, net write error, net
+                      write timeout, connect error and 2 types of lost
+                      connection error are automatically added to this list
+  --slave-transaction-retry-interval=# 
+                      Interval of the slave SQL thread will retry a transaction
+                      in case it failed with a deadlock or elapsed lock wait
+                      timeout or listed in slave_transaction_retry_errors
+  --slave-type-conversions=name 
+                      Set of slave type conversions that are enabled. If the
+                      variable is empty, no conversions are allowed and it is
+                      expected that the types match exactly. Any combination
+                      of: ALL_LOSSY, ALL_NON_LOSSY
+  Use 'ALL' to set all combinations.
+  --slow-launch-time=# 
+                      If creating the thread takes longer than this value (in
+                      seconds), the Slow_launch_threads counter will be
+                      incremented
+  --slow-query-log    Alias for log_slow_query. Log slow queries to a table or
+                      log file. Defaults logging to a file 'hostname'-slow.log
+                      or a table mysql.slow_log if --log-output=TABLE is used.
+                      Must be enabled to activate other slow log options.
+  --slow-query-log-file=name 
+                      Alias for log_slow_query_file. Log slow queries to given
+                      log file. Defaults logging to 'hostname'-slow.log. Must
+                      be enabled to activate other slow log options
+  --socket=name       Socket file to use for connection
+  --sort-buffer-size=# 
+                      Each thread that needs to do a sort allocates a buffer of
+                      this size
+  --sql-mode=name     Sets the sql mode. Any combination of: REAL_AS_FLOAT, 
+                      PIPES_AS_CONCAT, ANSI_QUOTES, IGNORE_SPACE, 
+                      IGNORE_BAD_TABLE_OPTIONS, ONLY_FULL_GROUP_BY, 
+                      NO_UNSIGNED_SUBTRACTION, NO_DIR_IN_CREATE, POSTGRESQL, 
+                      ORACLE, MSSQL, DB2, MAXDB, NO_KEY_OPTIONS, 
+                      NO_TABLE_OPTIONS, NO_FIELD_OPTIONS, MYSQL323, MYSQL40, 
+                      ANSI, NO_AUTO_VALUE_ON_ZERO, NO_BACKSLASH_ESCAPES, 
+                      STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, 
+                      NO_ZERO_DATE, ALLOW_INVALID_DATES, 
+                      ERROR_FOR_DIVISION_BY_ZERO, TRADITIONAL, 
+                      NO_AUTO_CREATE_USER, HIGH_NOT_PRECEDENCE, 
+                      NO_ENGINE_SUBSTITUTION, PAD_CHAR_TO_FULL_LENGTH, 
+                      EMPTY_STRING_IS_NULL, SIMULTANEOUS_ASSIGNMENT, 
+                      TIME_ROUND_FRACTIONAL
+  Use 'ALL' to set all combinations.
+  --sql-safe-updates  If set to 1, UPDATEs and DELETEs need either a key in the
+                      WHERE clause, or a LIMIT clause, or else they will
+                      aborted. Prevents the common mistake of accidentally
+                      deleting or updating every row in a table.
+  --ssl               Enable SSL for connection (automatically enabled if an
+                      ssl option is used).
+  --ssl-ca=name       CA file in PEM format (check OpenSSL docs, implies --ssl)
+  --ssl-capath=name   CA directory (check OpenSSL docs, implies --ssl)
+  --ssl-cert=name     X509 cert in PEM format (implies --ssl)
+  --ssl-cipher=name   SSL cipher to use (implies --ssl)
+  --ssl-crl=name      CRL file in PEM format (check OpenSSL docs, implies
+                      --ssl)
+  --ssl-crlpath=name  CRL directory (check OpenSSL docs, implies --ssl)
+  --ssl-key=name      X509 key in PEM format (implies --ssl)
+  --stack-trace       Print a symbolic stack trace on failure
+                      (Defaults to on; use --skip-stack-trace to disable.)
+  --standard-compliant-cte 
+                      Allow only CTEs compliant to SQL standard
+                      (Defaults to on; use --skip-standard-compliant-cte to disable.)
+  --stored-program-cache=# 
+                      The soft upper limit for number of cached stored routines
+                      for one connection.
+  --strict-password-validation 
+                      When password validation plugins are enabled, reject
+                      passwords that cannot be validated (passwords specified
+                      as a hash)
+                      (Defaults to on; use --skip-strict-password-validation to disable.)
+  -s, --symbolic-links 
+                      Enable symbolic link support.
+                      (Defaults to on; use --skip-symbolic-links to disable.)
+  --sync-binlog=#     Synchronously flush binary log to disk after every #th
+                      event. Use 0 (default) to disable synchronous flushing
+  --sync-frm          Sync .frm files to disk on creation
+                      (Defaults to on; use --skip-sync-frm to disable.)
+  --sync-master-info=# 
+                      Synchronously flush master info to disk after every #th
+                      event. Use 0 to disable synchronous flushing
+  --sync-relay-log=#  Synchronously flush relay log to disk after every #th
+                      event. Use 0 to disable synchronous flushing
+  --sync-relay-log-info=# 
+                      Synchronously flush relay log info to disk after every
+                      #th transaction. Use 0 to disable synchronous flushing
+  --sysdate-is-now    Non-default option to alias SYSDATE() to NOW() to make it
+                      safe-replicable. Since 5.0, SYSDATE() returns a `dynamic'
+                      value different for different invocations, even within
+                      the same statement.
+  --system-versioning-alter-history=name 
+                      Versioning ALTER TABLE mode. ERROR: Fail ALTER with
+                      error; KEEP: Keep historical system rows and subject them
+                      to ALTER
+  --system-versioning-insert-history 
+                      Allows direct inserts into ROW_START and ROW_END columns
+                      if secure_timestamp allows changing @@timestamp
+  --table-cache=#     Deprecated; use --table-open-cache instead.
+  --table-definition-cache=# 
+                      The number of cached table definitions
+  --table-open-cache=# 
+                      The number of cached open tables
+  --table-open-cache-instances=# 
+                      Maximum number of table cache instances
+  --tc-heuristic-recover=name 
+                      Decision to use in heuristic recover process. One of: OFF,
+                      COMMIT, ROLLBACK
+  --tcp-keepalive-interval=# 
+                      The interval, in seconds, between when successive
+                      keep-alive packets are sent if no acknowledgement is
+                      received.If set to 0, system dependent default is used.
+                      (Automatically configured unless set explicitly)
+  --tcp-keepalive-probes=# 
+                      The number of unacknowledged probes to send before
+                      considering the connection dead and notifying the
+                      application layer.If set to 0, system dependent default
+                      is used. (Automatically configured unless set explicitly)
+  --tcp-keepalive-time=# 
+                      Timeout, in seconds, with no activity until the first TCP
+                      keep-alive packet is sent.If set to 0, system dependent
+                      default is used. (Automatically configured unless set
+                      explicitly)
+  --tcp-nodelay       Set option TCP_NODELAY (disable Nagle's algorithm) on
+                      socket
+                      (Defaults to on; use --skip-tcp-nodelay to disable.)
+  --temp-pool         Using this option will cause most temporary files created
+                      to use a small set of names, rather than a unique name
+                      for each new file. Deprecated.
+  --thread-cache-size=# 
+                      How many threads we should keep in a cache for reuse.
+                      These are freed after 5 minutes of idle time
+  --thread-handling=name 
+                      Define threads usage for handling queries. One of: 
+                      one-thread-per-connection, no-threads, pool-of-threads
+  --thread-pool-dedicated-listener 
+                      If set to 1,listener thread will not pick up queries
+  --thread-pool-exact-stats 
+                      If set to 1, provides better statistics in
+                      information_schema threadpool tables
+  --thread-pool-groups[=name] 
+                      Enable or disable THREAD_POOL_GROUPS plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --thread-pool-idle-timeout=# 
+                      Timeout in seconds for an idle thread in the thread
+                      pool.Worker thread will be shut down after timeout
+  --thread-pool-max-threads=# 
+                      Maximum allowed number of worker threads in the thread
+                      pool
+  --thread-pool-oversubscribe=# 
+                      How many additional active worker threads in a group are
+                      allowed.
+  --thread-pool-prio-kickup-timer=# 
+                      The number of milliseconds before a dequeued low-priority
+                      statement is moved to the high-priority queue
+  --thread-pool-priority=name 
+                      Threadpool priority. High priority connections usually
+                      start executing earlier than low priority.If priority set
+                      to 'auto', the the actual priority(low or high) is
+                      determined based on whether or not connection is inside
+                      transaction.
+  --thread-pool-queues[=name] 
+                      Enable or disable THREAD_POOL_QUEUES plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --thread-pool-size=# 
+                      Number of thread groups in the pool. This parameter is
+                      roughly equivalent to maximum number of concurrently
+                      executing threads (threads in a waiting state do not
+                      count as executing).
+  --thread-pool-stall-limit=# 
+                      Maximum query execution time in milliseconds,before an
+                      executing non-yielding thread is considered stalled.If a
+                      worker thread is stalled, additional worker thread may be
+                      created to handle remaining clients.
+  --thread-pool-stats[=name] 
+                      Enable or disable THREAD_POOL_STATS plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --thread-pool-waits[=name] 
+                      Enable or disable THREAD_POOL_WAITS plugin. One of: ON,
+                      OFF, FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --thread-stack=#    The stack size for each thread
+  --time-format=name  The TIME format (ignored)
+  --tls-version=name  TLS protocol version for secure connections.. Any
+                      combination of: TLSv1.0, TLSv1.1, TLSv1.2, TLSv1.3
+  Use 'ALL' to set all combinations.
+  --tmp-disk-table-size=# 
+                      Max size for data for an internal temporary on-disk
+                      MyISAM or Aria table.
+  --tmp-memory-table-size=# 
+                      If an internal in-memory temporary table exceeds this
+                      size, MariaDB will automatically convert it to an on-disk
+                      MyISAM or Aria table. Same as tmp_table_size.
+  --tmp-table-size=#  Alias for tmp_memory_table_size. If an internal in-memory
+                      temporary table exceeds this size, MariaDB will
+                      automatically convert it to an on-disk MyISAM or Aria
+                      table.
+  -t, --tmpdir=name   Path for temporary files. Several paths may be specified,
+                      separated by a colon (:), in this case they are used in a
+                      round-robin fashion
+  --transaction-alloc-block-size=# 
+                      Allocation block size for transactions to be stored in
+                      binary log
+  --transaction-isolation=name 
+                      Default transaction isolation level. One of: 
+                      READ-UNCOMMITTED, READ-COMMITTED, REPEATABLE-READ, 
+                      SERIALIZABLE
+  --transaction-prealloc-size=# 
+                      Persistent buffer for transactions to be stored in binary
+                      log
+  --transaction-read-only 
+                      Default transaction access mode. True if transactions are
+                      read-only.
+  --unix-socket[=name] 
+                      Enable or disable unix_socket plugin. One of: ON, OFF,
+                      FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --updatable-views-with-limit=name 
+                      YES = Don't issue an error message (warning only) if a
+                      VIEW without presence of a key of the underlying table is
+                      used in queries with a LIMIT clause for updating. NO =
+                      Prohibit update of a VIEW, which does not contain a key
+                      of the underlying table and the query uses a LIMIT clause
+                      (usually get from GUI tools)
+  --use-stat-tables=name 
+                      Specifies how to use system statistics tables. One of: 
+                      NEVER, COMPLEMENTARY, PREFERABLY, 
+                      COMPLEMENTARY_FOR_QUERIES, PREFERABLY_FOR_QUERIES
+  -u, --user=name     Run mysqld daemon as user.
+  --user-variables[=name] 
+                      Enable or disable user_variables plugin. One of: ON, OFF,
+                      FORCE (don't start if the plugin fails to load),
+                      FORCE_PLUS_PERMANENT (like FORCE, but the plugin can not
+                      be uninstalled).
+  --userstat          Enables statistics gathering for USER_STATISTICS,
+                      CLIENT_STATISTICS, INDEX_STATISTICS and TABLE_STATISTICS
+                      tables in the INFORMATION_SCHEMA
+  -v, --verbose       Used with --help option for detailed help.
+  -V, --version[=name] 
+                      Output version information and exit.
+  --wait-timeout=#    The number of seconds the server waits for activity on a
+                      connection before closing it
+  --wsrep-OSU-method[=name] 
+                      Method for Online Schema Upgrade. One of: TOI, RSU
+  --wsrep-SR-store=name 
+                      Storage for streaming replication fragments. One of: none,
+                      table
+  --wsrep-allowlist=name 
+                      Allowed IP addresses split by comma delimiter
+  --wsrep-auto-increment-control 
+                      To automatically control the assignment of autoincrement
+                      variables
+                      (Defaults to on; use --skip-wsrep-auto-increment-control to disable.)
+  --wsrep-causal-reads 
+                      Setting this variable is equivalent to setting
+                      wsrep_sync_wait READ flag
+  --wsrep-certification-rules=name 
+                      Certification rules to use in the cluster. Possible
+                      values are: "strict": stricter rules that could result in
+                      more certification failures. "optimized": relaxed rules
+                      that allow more concurrency and cause less certification
+                      failures.
+  --wsrep-certify-nonPK 
+                      Certify tables with no primary key
+                      (Defaults to on; use --skip-wsrep-certify-nonPK to disable.)
+  --wsrep-cluster-address=name 
+                      Address to initially connect to cluster
+  --wsrep-cluster-name=name 
+                      Name for the cluster
+  --wsrep-convert-LOCK-to-trx 
+                      To convert locking sessions into transactions
+  --wsrep-data-home-dir=name 
+                      home directory for wsrep provider
+  --wsrep-dbug-option=name 
+                      DBUG options to provider library
+  --wsrep-debug=name  WSREP debug level logging. One of: NONE, SERVER, 
+                      TRANSACTION, STREAMING, CLIENT
+  --wsrep-desync      To desynchronize the node from the cluster
+  --wsrep-dirty-reads Allow reads even when the node is not in the primary
+                      component.
+  --wsrep-drupal-282555-workaround 
+                      Enable a workaround to handle the cases where inserting a
+                      DEFAULT value into an auto-increment column could fail
+                      with duplicate key error
+  --wsrep-forced-binlog-format=name 
+                      binlog format to take effect over user's choice. One of: 
+                      MIXED, STATEMENT, ROW, NONE
+  --wsrep-gtid-domain-id=# 
+                      When wsrep_gtid_mode is set, this value is used as
+                      gtid_domain_id for galera transactions and also copied to
+                      the joiner nodes during state transfer. It is ignored,
+                      otherwise.
+  --wsrep-gtid-mode   Automatically update the (joiner) node's
+                      wsrep_gtid_domain_id value with that of donor's (received
+                      during state transfer) and use it in place of
+                      gtid_domain_id for all galera transactions. When OFF
+                      (default), wsrep_gtid_domain_id is simply ignored
+                      (backward compatibility).
+  --wsrep-ignore-apply-errors=# 
+                      Ignore replication errors
+  --wsrep-load-data-splitting 
+                      To commit LOAD DATA transaction after every 10K rows
+                      inserted (deprecated)
+  --wsrep-log-conflicts 
+                      To log multi-master conflicts
+  --wsrep-max-ws-rows=# 
+                      Max number of rows in write set
+  --wsrep-max-ws-size=# 
+                      Max write set size (bytes)
+  --wsrep-mode=name   Set of WSREP features that are enabled.. Any combination
+                      of: STRICT_REPLICATION, BINLOG_ROW_FORMAT_ONLY, 
+                      REQUIRED_PRIMARY_KEY, REPLICATE_MYISAM, REPLICATE_ARIA, 
+                      DISALLOW_LOCAL_GTID, BF_ABORT_MARIABACKUP
+  Use 'ALL' to set all combinations.
+  --wsrep-mysql-replication-bundle=# 
+                      mysql replication group commit 
+  --wsrep-new-cluster Bootstrap a cluster. It works by overriding the current
+                      value of wsrep_cluster_address. It is recommended not to
+                      add this option to the config file as this will trigger
+                      bootstrap on every server start.
+  --wsrep-node-address=name 
+                      Specifies the node's network address, in the format ip
+                      address[:port]. Used in situations where autoguessing is
+                      not reliable. As of MariaDB 10.1.8, supports IPv6.
+  --wsrep-node-incoming-address=name 
+                      Client connection address
+  --wsrep-node-name=name 
+                      Name of this node. This name can be used in
+                      wsrep_sst_donor as a preferred donor. Note that multiple
+                      nodes in a cluster can have the same name.
+  --wsrep-notify-cmd=name 
+  --wsrep-on          To enable wsrep replication 
+  --wsrep-provider=name 
+                      Path to replication provider library
+  --wsrep-provider-options=name 
+                      Semicolon (;) separated list of wsrep options (see
+                      wsrep_provider_options documentation).
+  --wsrep-recover     Recover database state after crash and exit
+  --wsrep-reject-queries[=name] 
+                      Variable to set to reject queries. One of: NONE, ALL, 
+                      ALL_KILL
+  --wsrep-restart-slave 
+                      Should MariaDB slave be restarted automatically, when
+                      node joins back to cluster
+  --wsrep-retry-autocommit=# 
+                      Max number of times to retry a failed autocommit
+                      statement
+  --wsrep-slave-FK-checks 
+                      Should slave thread do foreign key constraint checks
+                      (Defaults to on; use --skip-wsrep-slave-FK-checks to disable.)
+  --wsrep-slave-UK-checks 
+                      Should slave thread do secondary index uniqueness checks
+  --wsrep-slave-threads=# 
+                      Number of slave appliers to launch
+  --wsrep-sst-auth=name 
+                      Authentication for SST connection
+  --wsrep-sst-donor=name 
+                      preferred donor node for the SST
+  --wsrep-sst-donor-rejects-queries 
+                      Reject client queries when donating state snapshot
+                      transfer
+  --wsrep-sst-method=name 
+                      State snapshot transfer method
+  --wsrep-sst-receive-address=name 
+                      Address where node is waiting for SST contact
+  --wsrep-start-position=name 
+                      global transaction position to start from 
+  --wsrep-status-file=name 
+                      wsrep status output filename
+  --wsrep-sync-wait[=#] 
+                      Ensure "synchronous" read view before executing an
+                      operation of the type specified by bitmask: 1 -
+                      READ(includes SELECT, SHOW and BEGIN/START TRANSACTION);
+                      2 - UPDATE and DELETE; 4 - INSERT and REPLACE
+  --wsrep-trx-fragment-size=# 
+                      Size of transaction fragments for streaming replication
+                      (measured in units of 'wsrep_trx_fragment_unit')
+  --wsrep-trx-fragment-unit=name 
+                      Unit for streaming replication transaction fragments'
+                      size: bytes, rows, statements
+
+Variables (--variable-name=value)
+and boolean options {FALSE|TRUE}                             Value (after reading options)
+------------------------------------------------------------ -------------
+allow-suspicious-udfs                                        FALSE
+alter-algorithm                                              DEFAULT
+analyze-sample-percentage                                    100
+aria-block-size                                              8192
+aria-checkpoint-interval                                     0
+aria-checkpoint-log-activity                                 1048576
+aria-encrypt-tables                                          FALSE
+aria-force-start-after-recovery-failures                     0
+aria-group-commit                                            none
+aria-group-commit-interval                                   0
+aria-log-dir-path                                            /var/lib/mysql/
+aria-log-file-size                                           1073741824
+aria-log-purge-type                                          immediate
+aria-max-sort-file-size                                      9223372036853727232
+aria-page-checksum                                           TRUE
+aria-pagecache-age-threshold                                 300
+aria-pagecache-buffer-size                                   134217728
+aria-pagecache-division-limit                                100
+aria-pagecache-file-hash-size                                512
+aria-recover-options                                         
+aria-repair-threads                                          1
+aria-sort-buffer-size                                        268434432
+aria-stats-method                                            nulls_unequal
+aria-sync-log-dir                                            NEWFILE
+auto-increment-increment                                     1
+auto-increment-offset                                        1
+autocommit                                                   TRUE
+automatic-sp-privileges                                      TRUE
+back-log                                                     80
+basedir                                                      /usr
+big-tables                                                   FALSE
+bind-address                                                 127.0.0.1
+binlog-alter-two-phase                                       FALSE
+binlog-annotate-row-events                                   TRUE
+binlog-cache-size                                            32768
+binlog-checksum                                              CRC32
+binlog-commit-wait-count                                     0
+binlog-commit-wait-usec                                      100000
+binlog-direct-non-transactional-updates                      FALSE
+binlog-expire-logs-seconds                                   864000
+binlog-file-cache-size                                       16384
+binlog-format                                                MIXED
+binlog-optimize-thread-scheduling                            TRUE
+binlog-row-event-max-size                                    8192
+binlog-row-image                                             FULL
+binlog-row-metadata                                          NO_LOG
+binlog-stmt-cache-size                                       32768
+bulk-insert-buffer-size                                      8388608
+character-set-client-handshake                               TRUE
+character-set-filesystem                                     binary
+character-set-server                                         utf8mb4
+character-sets-dir                                           /usr/share/mysql/charsets/
+chroot                                                       (No default value)
+collation-server                                             utf8mb4_general_ci
+column-compression-threshold                                 100
+column-compression-zlib-level                                6
+column-compression-zlib-strategy                             DEFAULT_STRATEGY
+column-compression-zlib-wrap                                 FALSE
+completion-type                                              NO_CHAIN
+concurrent-insert                                            AUTO
+connect-timeout                                              10
+console                                                      FALSE
+core-file                                                    FALSE
+datadir                                                      /var/lib/mysql/
+date-format                                                  %Y-%m-%d
+datetime-format                                              %Y-%m-%d %H:%i:%s
+deadlock-search-depth-long                                   15
+deadlock-search-depth-short                                  4
+deadlock-timeout-long                                        50000000
+deadlock-timeout-short                                       10000
+debug                                                        
+debug-abort-slave-event-count                                0
+debug-disconnect-slave-event-count                           0
+debug-gdb                                                    FALSE
+debug-max-binlog-dump-events                                 0
+debug-no-sync                                                FALSE
+debug-no-thread-alarm                                        FALSE
+debug-sporadic-binlog-dump-fail                              FALSE
+default-password-lifetime                                    0
+default-regex-flags                                          
+default-storage-engine                                       InnoDB
+default-time-zone                                            (No default value)
+default-tmp-storage-engine                                   (No default value)
+default-week-format                                          0
+delay-key-write                                              ON
+delayed-insert-limit                                         100
+delayed-insert-timeout                                       300
+delayed-queue-size                                           1000
+des-key-file                                                 (No default value)
+disconnect-on-expired-password                               FALSE
+div-precision-increment                                      4
+encrypt-binlog                                               FALSE
+encrypt-tmp-disk-tables                                      FALSE
+encrypt-tmp-files                                            FALSE
+enforce-storage-engine                                       (No default value)
+eq-range-index-dive-limit                                    200
+event-scheduler                                              OFF
+expensive-subquery-limit                                     100
+expire-logs-days                                             10
+explicit-defaults-for-timestamp                              TRUE
+external-locking                                             FALSE
+extra-max-connections                                        1
+extra-port                                                   0
+feedback                                                     ON
+feedback-http-proxy                                          (No default value)
+feedback-send-retry-wait                                     60
+feedback-send-timeout                                        60
+feedback-url                                                 https://feedback.mariadb.org/rest/v1/post
+feedback-user-info                                           
+flashback                                                    FALSE
+flush                                                        FALSE
+flush-time                                                   0
+ft-boolean-syntax                                            + -><()~*:""&|
+ft-max-word-len                                              84
+ft-min-word-len                                              4
+ft-query-expansion-limit                                     20
+ft-stopword-file                                             (No default value)
+gdb                                                          FALSE
+general-log                                                  FALSE
+general-log-file                                             HOSTNAME.log
+getopt-prefix-matching                                       TRUE
+group-concat-max-len                                         1048576
+gtid-cleanup-batch-size                                      64
+gtid-domain-id                                               0
+gtid-ignore-duplicates                                       FALSE
+gtid-pos-auto-engines                                        
+gtid-strict-mode                                             FALSE
+help                                                         TRUE
+histogram-size                                               254
+histogram-type                                               DOUBLE_PREC_HB
+host-cache-size                                              279
+idle-readonly-transaction-timeout                            0
+idle-transaction-timeout                                     0
+idle-write-transaction-timeout                               0
+ignore-builtin-innodb                                        FALSE
+ignore-db-dirs                                               
+in-predicate-conversion-threshold                            1000
+init-connect                                                 
+init-file                                                    (No default value)
+init-rpl-role                                                MASTER
+init-slave                                                   
+innodb                                                       ON
+innodb-adaptive-flushing                                     TRUE
+innodb-adaptive-flushing-lwm                                 10
+innodb-adaptive-hash-index                                   FALSE
+innodb-adaptive-hash-index-parts                             8
+innodb-autoextend-increment                                  64
+innodb-autoinc-lock-mode                                     1
+innodb-buf-dump-status-frequency                             0
+innodb-buffer-page                                           ON
+innodb-buffer-page-lru                                       ON
+innodb-buffer-pool-chunk-size                                0
+innodb-buffer-pool-dump-at-shutdown                          TRUE
+innodb-buffer-pool-dump-now                                  FALSE
+innodb-buffer-pool-dump-pct                                  25
+innodb-buffer-pool-filename                                  ib_buffer_pool
+innodb-buffer-pool-load-abort                                FALSE
+innodb-buffer-pool-load-at-startup                           TRUE
+innodb-buffer-pool-load-now                                  FALSE
+innodb-buffer-pool-size                                      134217728
+innodb-buffer-pool-stats                                     ON
+innodb-change-buffer-max-size                                25
+innodb-change-buffering                                      none
+innodb-checksum-algorithm                                    full_crc32
+innodb-cmp                                                   ON
+innodb-cmp-per-index                                         ON
+innodb-cmp-per-index-enabled                                 FALSE
+innodb-cmp-per-index-reset                                   ON
+innodb-cmp-reset                                             ON
+innodb-cmpmem                                                ON
+innodb-cmpmem-reset                                          ON
+innodb-compression-algorithm                                 zlib
+innodb-compression-default                                   FALSE
+innodb-compression-failure-threshold-pct                     5
+innodb-compression-level                                     6
+innodb-compression-pad-pct-max                               50
+innodb-data-file-path                                        ibdata1:12M:autoextend
+innodb-data-home-dir                                         (No default value)
+innodb-deadlock-detect                                       TRUE
+innodb-deadlock-report                                       full
+innodb-default-encryption-key-id                             1
+innodb-default-row-format                                    dynamic
+innodb-defragment                                            FALSE
+innodb-defragment-fill-factor                                0.9
+innodb-defragment-fill-factor-n-recs                         20
+innodb-defragment-frequency                                  40
+innodb-defragment-n-pages                                    7
+innodb-defragment-stats-accuracy                             0
+innodb-disable-sort-file-cache                               FALSE
+innodb-doublewrite                                           TRUE
+innodb-encrypt-log                                           FALSE
+innodb-encrypt-tables                                        OFF
+innodb-encrypt-temporary-tables                              FALSE
+innodb-encryption-rotate-key-age                             1
+innodb-encryption-rotation-iops                              100
+innodb-encryption-threads                                    0
+innodb-fast-shutdown                                         1
+innodb-fatal-semaphore-wait-threshold                        600
+innodb-file-per-table                                        TRUE
+innodb-fill-factor                                           100
+innodb-flush-log-at-timeout                                  1
+innodb-flush-log-at-trx-commit                               1
+innodb-flush-method                                          O_DIRECT
+innodb-flush-neighbors                                       1
+innodb-flush-sync                                            TRUE
+innodb-flushing-avg-loops                                    30
+innodb-force-primary-key                                     FALSE
+innodb-force-recovery                                        0
+innodb-ft-aux-table                                          (No default value)
+innodb-ft-being-deleted                                      ON
+innodb-ft-cache-size                                         8000000
+innodb-ft-config                                             ON
+innodb-ft-default-stopword                                   ON
+innodb-ft-deleted                                            ON
+innodb-ft-enable-diag-print                                  FALSE
+innodb-ft-enable-stopword                                    TRUE
+innodb-ft-index-cache                                        ON
+innodb-ft-index-table                                        ON
+innodb-ft-max-token-size                                     84
+innodb-ft-min-token-size                                     3
+innodb-ft-num-word-optimize                                  2000
+innodb-ft-result-cache-limit                                 2000000000
+innodb-ft-server-stopword-table                              (No default value)
+innodb-ft-sort-pll-degree                                    2
+innodb-ft-total-cache-size                                   640000000
+innodb-ft-user-stopword-table                                (No default value)
+innodb-immediate-scrub-data-uncompressed                     FALSE
+innodb-instant-alter-column-allowed                          add_drop_reorder
+innodb-io-capacity                                           200
+innodb-io-capacity-max                                       18446744073709551615
+innodb-lock-wait-timeout                                     50
+innodb-lock-waits                                            ON
+innodb-locks                                                 ON
+innodb-log-buffer-size                                       16777216
+innodb-log-file-buffering                                    FALSE
+innodb-log-file-size                                         100663296
+innodb-log-group-home-dir                                    (No default value)
+innodb-log-spin-wait-delay                                   0
+innodb-lru-flush-size                                        32
+innodb-lru-scan-depth                                        1536
+innodb-max-dirty-pages-pct                                   90
+innodb-max-dirty-pages-pct-lwm                               0
+innodb-max-purge-lag                                         0
+innodb-max-purge-lag-delay                                   0
+innodb-max-purge-lag-wait                                    4294967295
+innodb-max-undo-log-size                                     10485760
+innodb-metrics                                               ON
+innodb-monitor-disable                                       (No default value)
+innodb-monitor-enable                                        (No default value)
+innodb-monitor-reset                                         (No default value)
+innodb-monitor-reset-all                                     (No default value)
+innodb-numa-interleave                                       FALSE
+innodb-old-blocks-pct                                        37
+innodb-old-blocks-time                                       1000
+innodb-online-alter-log-max-size                             134217728
+innodb-open-files                                            0
+innodb-optimize-fulltext-only                                FALSE
+innodb-page-size                                             16384
+innodb-prefix-index-cluster-optimization                     TRUE
+innodb-print-all-deadlocks                                   FALSE
+innodb-purge-batch-size                                      1000
+innodb-purge-rseg-truncate-frequency                         128
+innodb-purge-threads                                         4
+innodb-random-read-ahead                                     FALSE
+innodb-read-ahead-threshold                                  56
+innodb-read-io-threads                                       4
+innodb-read-only                                             FALSE
+innodb-read-only-compressed                                  FALSE
+innodb-rollback-on-timeout                                   FALSE
+innodb-snapshot-isolation                                    FALSE
+innodb-sort-buffer-size                                      1048576
+innodb-spin-wait-delay                                       4
+innodb-stats-auto-recalc                                     TRUE
+innodb-stats-include-delete-marked                           FALSE
+innodb-stats-method                                          nulls_equal
+innodb-stats-modified-counter                                0
+innodb-stats-on-metadata                                     FALSE
+innodb-stats-persistent                                      TRUE
+innodb-stats-persistent-sample-pages                         20
+innodb-stats-traditional                                     TRUE
+innodb-stats-transient-sample-pages                          8
+innodb-status-file                                           FALSE
+innodb-status-output                                         FALSE
+innodb-status-output-locks                                   FALSE
+innodb-strict-mode                                           TRUE
+innodb-sync-spin-loops                                       30
+innodb-sys-columns                                           ON
+innodb-sys-fields                                            ON
+innodb-sys-foreign                                           ON
+innodb-sys-foreign-cols                                      ON
+innodb-sys-indexes                                           ON
+innodb-sys-tables                                            ON
+innodb-sys-tablespaces                                       ON
+innodb-sys-tablestats                                        ON
+innodb-sys-virtual                                           ON
+innodb-table-locks                                           TRUE
+innodb-tablespaces-encryption                                ON
+innodb-temp-data-file-path                                   ibtmp1:12M:autoextend
+innodb-tmpdir                                                (No default value)
+innodb-trx                                                   ON
+innodb-undo-directory                                        (No default value)
+innodb-undo-log-truncate                                     FALSE
+innodb-undo-tablespaces                                      0
+innodb-use-atomic-writes                                     TRUE
+innodb-use-native-aio                                        TRUE
+innodb-write-io-threads                                      4
+interactive-timeout                                          28800
+join-buffer-size                                             262144
+join-buffer-space-limit                                      2097152
+join-cache-level                                             2
+keep-files-on-create                                         FALSE
+key-buffer-size                                              134217728
+key-cache-age-threshold                                      300
+key-cache-block-size                                         1024
+key-cache-division-limit                                     100
+key-cache-file-hash-size                                     512
+key-cache-segments                                           0
+large-files-support                                          TRUE
+large-pages                                                  FALSE
+lc-messages                                                  en_US
+lc-messages-dir                                              (No default value)
+lc-time-names                                                en_US
+local-infile                                                 TRUE
+lock-wait-timeout                                            86400
+log-basename                                                 HOSTNAME
+log-bin                                                      (No default value)
+log-bin-compress                                             FALSE
+log-bin-compress-min-len                                     256
+log-bin-index                                                (No default value)
+log-bin-trust-function-creators                              FALSE
+log-ddl-recovery                                             ddl_recovery.log
+log-disabled-statements                                      sp
+log-error                                                    
+log-isam                                                     myisam.log
+log-output                                                   FILE
+log-queries-not-using-indexes                                FALSE
+log-short-format                                             FALSE
+log-slave-updates                                            FALSE
+log-slow-admin-statements                                    TRUE
+log-slow-disabled-statements                                 sp
+log-slow-filter                                              admin,filesort,filesort_on_disk,filesort_priority_queue,full_join,full_scan,query_cache,query_cache_miss,tmp_table,tmp_table_on_disk
+log-slow-max-warnings                                        10
+log-slow-min-examined-row-limit                              0
+log-slow-query                                               FALSE
+log-slow-query-file                                          HOSTNAME-slow.log
+log-slow-query-time                                          10
+log-slow-rate-limit                                          1
+log-slow-slave-statements                                    TRUE
+log-slow-verbosity                                           
+log-tc                                                       tc.log
+log-tc-size                                                  24576
+log-warnings                                                 2
+long-query-time                                              10
+low-priority-updates                                         FALSE
+lower-case-file-system                                       FALSE
+lower-case-table-names                                       0
+master-info-file                                             master.info
+master-retry-count                                           100000
+master-verify-checksum                                       FALSE
+max-allowed-packet                                           16777216
+max-binlog-cache-size                                        18446744073709547520
+max-binlog-size                                              1073741824
+max-binlog-stmt-cache-size                                   18446744073709547520
+max-connect-errors                                           100
+max-connections                                              151
+max-delayed-threads                                          20
+max-digest-length                                            1024
+max-error-count                                              64
+max-heap-table-size                                          16777216
+max-join-size                                                18446744073709551615
+max-length-for-sort-data                                     1024
+max-password-errors                                          4294967295
+max-prepared-stmt-count                                      16382
+max-recursive-iterations                                     1000
+max-relay-log-size                                           1073741824
+max-rowid-filter-size                                        131072
+max-seeks-for-key                                            4294967295
+max-session-mem-used                                         9223372036854775807
+max-sort-length                                              1024
+max-sp-recursion-depth                                       0
+max-statement-time                                           0
+max-tmp-tables                                               32
+max-user-connections                                         0
+max-write-lock-count                                         4294967295
+memlock                                                      FALSE
+metadata-locks-cache-size                                    1024
+metadata-locks-hash-instances                                8
+min-examined-row-limit                                       0
+mrr-buffer-size                                              262144
+myisam-block-size                                            1024
+myisam-data-pointer-size                                     6
+myisam-max-sort-file-size                                    18446744073709551615
+myisam-mmap-size                                             9223372036853727232
+myisam-recover-options                                       BACKUP,QUICK
+myisam-repair-threads                                        1
+myisam-sort-buffer-size                                      134216704
+myisam-stats-method                                          NULLS_UNEQUAL
+myisam-use-mmap                                              FALSE
+mysql56-temporal-format                                      TRUE
+net-buffer-length                                            16384
+net-read-timeout                                             30
+net-retry-count                                              10
+net-write-timeout                                            60
+note-verbosity                                               basic,explain
+old                                                          FALSE
+old-alter-table                                              DEFAULT
+old-mode                                                     UTF8_IS_UTF8MB3
+old-passwords                                                FALSE
+old-style-user-limits                                        FALSE
+open-files-limit                                             32000
+optimizer-adjust-secondary-key-costs                         
+optimizer-extra-pruning-depth                                8
+optimizer-max-sel-arg-weight                                 32000
+optimizer-max-sel-args                                       16000
+optimizer-prune-level                                        2
+optimizer-search-depth                                       62
+optimizer-selectivity-sampling-limit                         100
+optimizer-switch                                             index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on,extended_keys=on,exists_to_in=on,orderby_uses_equalities=on,condition_pushdown_for_derived=on,split_materialized=on,condition_pushdown_for_subquery=on,rowid_filter=on,condition_pushdown_from_having=on
+optimizer-trace                                              
+optimizer-trace-max-mem-size                                 1048576
+optimizer-use-condition-selectivity                          4
+partition                                                    ON
+performance-schema                                           FALSE
+performance-schema-accounts-size                             -1
+performance-schema-consumer-events-stages-current            FALSE
+performance-schema-consumer-events-stages-history            FALSE
+performance-schema-consumer-events-stages-history-long       FALSE
+performance-schema-consumer-events-statements-current        FALSE
+performance-schema-consumer-events-statements-history        FALSE
+performance-schema-consumer-events-statements-history-long   FALSE
+performance-schema-consumer-events-transactions-current      FALSE
+performance-schema-consumer-events-transactions-history      FALSE
+performance-schema-consumer-events-transactions-history-long FALSE
+performance-schema-consumer-events-waits-current             FALSE
+performance-schema-consumer-events-waits-history             FALSE
+performance-schema-consumer-events-waits-history-long        FALSE
+performance-schema-consumer-global-instrumentation           TRUE
+performance-schema-consumer-statements-digest                TRUE
+performance-schema-consumer-thread-instrumentation           TRUE
+performance-schema-digests-size                              -1
+performance-schema-events-stages-history-long-size           -1
+performance-schema-events-stages-history-size                -1
+performance-schema-events-statements-history-long-size       -1
+performance-schema-events-statements-history-size            -1
+performance-schema-events-transactions-history-long-size     -1
+performance-schema-events-transactions-history-size          -1
+performance-schema-events-waits-history-long-size            -1
+performance-schema-events-waits-history-size                 -1
+performance-schema-hosts-size                                -1
+performance-schema-instrument                                
+performance-schema-max-cond-classes                          90
+performance-schema-max-cond-instances                        -1
+performance-schema-max-digest-length                         1024
+performance-schema-max-file-classes                          80
+performance-schema-max-file-handles                          32768
+performance-schema-max-file-instances                        -1
+performance-schema-max-index-stat                            -1
+performance-schema-max-memory-classes                        320
+performance-schema-max-metadata-locks                        -1
+performance-schema-max-mutex-classes                         210
+performance-schema-max-mutex-instances                       -1
+performance-schema-max-prepared-statements-instances         -1
+performance-schema-max-program-instances                     -1
+performance-schema-max-rwlock-classes                        50
+performance-schema-max-rwlock-instances                      -1
+performance-schema-max-socket-classes                        10
+performance-schema-max-socket-instances                      -1
+performance-schema-max-sql-text-length                       1024
+performance-schema-max-stage-classes                         160
+performance-schema-max-statement-classes                     222
+performance-schema-max-statement-stack                       10
+performance-schema-max-table-handles                         -1
+performance-schema-max-table-instances                       -1
+performance-schema-max-table-lock-stat                       -1
+performance-schema-max-thread-classes                        50
+performance-schema-max-thread-instances                      -1
+performance-schema-session-connect-attrs-size                -1
+performance-schema-setup-actors-size                         -1
+performance-schema-setup-objects-size                        -1
+performance-schema-users-size                                -1
+pid-file                                                     /run/mysqld/mysqld.pid
+plugin-dir                                                   /usr/lib/mysql/plugin/
+plugin-maturity                                              gamma
+port                                                         3306
+port-open-timeout                                            0
+preload-buffer-size                                          32768
+profiling-history-size                                       15
+progress-report-time                                         5
+protocol-version                                             10
+proxy-protocol-networks                                      
+query-alloc-block-size                                       16384
+query-cache-limit                                            1048576
+query-cache-min-res-unit                                     4096
+query-cache-size                                             1048576
+query-cache-strip-comments                                   FALSE
+query-cache-type                                             OFF
+query-cache-wlock-invalidate                                 FALSE
+query-prealloc-size                                          24576
+range-alloc-block-size                                       4096
+read-binlog-speed-limit                                      0
+read-buffer-size                                             131072
+read-only                                                    FALSE
+read-rnd-buffer-size                                         262144
+relay-log                                                    (No default value)
+relay-log-index                                              (No default value)
+relay-log-info-file                                          relay-log.info
+relay-log-purge                                              TRUE
+relay-log-recovery                                           FALSE
+relay-log-space-limit                                        0
+replicate-annotate-row-events                                TRUE
+replicate-events-marked-for-skip                             REPLICATE
+replicate-same-server-id                                     FALSE
+report-host                                                  (No default value)
+report-password                                              (No default value)
+report-port                                                  0
+report-user                                                  (No default value)
+require-secure-transport                                     FALSE
+rowid-merge-buff-size                                        8388608
+rpl-semi-sync-master-enabled                                 FALSE
+rpl-semi-sync-master-timeout                                 10000
+rpl-semi-sync-master-trace-level                             32
+rpl-semi-sync-master-wait-no-slave                           TRUE
+rpl-semi-sync-master-wait-point                              AFTER_COMMIT
+rpl-semi-sync-slave-delay-master                             FALSE
+rpl-semi-sync-slave-enabled                                  FALSE
+rpl-semi-sync-slave-kill-conn-timeout                        5
+rpl-semi-sync-slave-trace-level                              32
+safe-user-create                                             FALSE
+secure-auth                                                  TRUE
+secure-file-priv                                             (No default value)
+secure-timestamp                                             NO
+sequence                                                     ON
+server-id                                                    1
+session-track-schema                                         TRUE
+session-track-state-change                                   FALSE
+session-track-system-variables                               autocommit,character_set_client,character_set_connection,character_set_results,time_zone
+session-track-transaction-info                               OFF
+show-slave-auth-info                                         FALSE
+silent-startup                                               FALSE
+skip-grant-tables                                            FALSE
+skip-name-resolve                                            FALSE
+skip-networking                                              FALSE
+skip-show-database                                           FALSE
+skip-slave-start                                             FALSE
+slave-compressed-protocol                                    FALSE
+slave-ddl-exec-mode                                          IDEMPOTENT
+slave-domain-parallel-threads                                0
+slave-exec-mode                                              STRICT
+slave-load-tmpdir                                            /tmp
+slave-max-allowed-packet                                     1073741824
+slave-max-statement-time                                     0
+slave-net-timeout                                            60
+slave-parallel-max-queued                                    131072
+slave-parallel-mode                                          conservative
+slave-parallel-threads                                       0
+slave-parallel-workers                                       0
+slave-run-triggers-for-rbr                                   NO
+slave-skip-errors                                            OFF
+slave-sql-verify-checksum                                    TRUE
+slave-transaction-retries                                    10
+slave-transaction-retry-errors                               1158,1159,1160,1161,1205,1213,1020,1429,2013,12701
+slave-transaction-retry-interval                             0
+slave-type-conversions                                       
+slow-launch-time                                             2
+slow-query-log                                               FALSE
+slow-query-log-file                                          HOSTNAME-slow.log
+socket                                                       /run/mysqld/mysqld.sock
+sort-buffer-size                                             2097152
+sql-mode                                                     STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
+sql-safe-updates                                             FALSE
+ssl                                                          FALSE
+ssl-ca                                                       (No default value)
+ssl-capath                                                   (No default value)
+ssl-cert                                                     (No default value)
+ssl-cipher                                                   (No default value)
+ssl-crl                                                      (No default value)
+ssl-crlpath                                                  (No default value)
+ssl-key                                                      (No default value)
+stack-trace                                                  TRUE
+standard-compliant-cte                                       TRUE
+stored-program-cache                                         256
+strict-password-validation                                   TRUE
+symbolic-links                                               TRUE
+sync-binlog                                                  0
+sync-frm                                                     TRUE
+sync-master-info                                             10000
+sync-relay-log                                               10000
+sync-relay-log-info                                          10000
+sysdate-is-now                                               FALSE
+system-time-zone                                             UTC
+system-versioning-alter-history                              ERROR
+system-versioning-insert-history                             FALSE
+table-cache                                                  2000
+table-definition-cache                                       400
+table-open-cache                                             2000
+table-open-cache-instances                                   8
+tc-heuristic-recover                                         OFF
+tcp-keepalive-interval                                       0
+tcp-keepalive-probes                                         0
+tcp-keepalive-time                                           0
+tcp-nodelay                                                  TRUE
+temp-pool                                                    FALSE
+thread-cache-size                                            151
+thread-handling                                              one-thread-per-connection
+thread-pool-dedicated-listener                               FALSE
+thread-pool-exact-stats                                      FALSE
+thread-pool-groups                                           ON
+thread-pool-idle-timeout                                     60
+thread-pool-max-threads                                      65536
+thread-pool-oversubscribe                                    3
+thread-pool-prio-kickup-timer                                1000
+thread-pool-priority                                         auto
+thread-pool-queues                                           ON
+thread-pool-size                                             2
+thread-pool-stall-limit                                      500
+thread-pool-stats                                            ON
+thread-pool-waits                                            ON
+thread-stack                                                 299008
+time-format                                                  %H:%i:%s
+tls-version                                                  TLSv1.2,TLSv1.3
+tmp-disk-table-size                                          18446744073709551615
+tmp-memory-table-size                                        16777216
+tmp-table-size                                               16777216
+tmpdir                                                       /tmp
+transaction-alloc-block-size                                 8192
+transaction-isolation                                        REPEATABLE-READ
+transaction-prealloc-size                                    4096
+transaction-read-only                                        FALSE
+unix-socket                                                  ON
+updatable-views-with-limit                                   YES
+use-stat-tables                                              PREFERABLY_FOR_QUERIES
+user-variables                                               ON
+userstat                                                     FALSE
+verbose                                                      TRUE
+version                                                      VERSION
+version-comment                                              Debian RELEASE
+version-compile-machine                                      ARCH
+version-compile-os                                           debian-linux-gnu
+version-malloc-library                                       system
+version-source-revision                                      -
+version-ssl-library                                          SSL-VERSION
+wait-timeout                                                 28800
+wsrep-OSU-method                                             TOI
+wsrep-SR-store                                               table
+wsrep-allowlist                                              
+wsrep-auto-increment-control                                 TRUE
+wsrep-causal-reads                                           FALSE
+wsrep-certification-rules                                    strict
+wsrep-certify-nonPK                                          TRUE
+wsrep-cluster-address                                        
+wsrep-cluster-name                                           my_wsrep_cluster
+wsrep-convert-LOCK-to-trx                                    FALSE
+wsrep-data-home-dir                                          /var/lib/mysql/
+wsrep-dbug-option                                            
+wsrep-debug                                                  NONE
+wsrep-desync                                                 FALSE
+wsrep-dirty-reads                                            FALSE
+wsrep-drupal-282555-workaround                               FALSE
+wsrep-forced-binlog-format                                   NONE
+wsrep-gtid-domain-id                                         0
+wsrep-gtid-mode                                              FALSE
+wsrep-ignore-apply-errors                                    7
+wsrep-load-data-splitting                                    FALSE
+wsrep-log-conflicts                                          FALSE
+wsrep-max-ws-rows                                            0
+wsrep-max-ws-size                                            2147483647
+wsrep-mode                                                   
+wsrep-mysql-replication-bundle                               0
+wsrep-new-cluster                                            FALSE
+wsrep-node-address                                           
+wsrep-node-incoming-address                                  AUTO
+wsrep-node-name                                              HOSTNAME
+wsrep-notify-cmd                                             
+wsrep-on                                                     FALSE
+wsrep-patch-version                                          wsrep_26.22
+wsrep-provider                                               none
+wsrep-provider-options                                       
+wsrep-recover                                                FALSE
+wsrep-reject-queries                                         NONE
+wsrep-restart-slave                                          FALSE
+wsrep-retry-autocommit                                       1
+wsrep-slave-FK-checks                                        TRUE
+wsrep-slave-UK-checks                                        FALSE
+wsrep-slave-threads                                          1
+wsrep-sst-auth                                               (No default value)
+wsrep-sst-donor                                              
+wsrep-sst-donor-rejects-queries                              FALSE
+wsrep-sst-method                                             rsync
+wsrep-sst-receive-address                                    AUTO
+wsrep-start-position                                         00000000-0000-0000-0000-000000000000:-1
+wsrep-status-file                                            
+wsrep-sync-wait                                              0
+wsrep-trx-fragment-size                                      0
+wsrep-trx-fragment-unit                                      bytes
+
+To see what variables a running server is using, type
+'SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES' instead of 'mysqld --verbose --help' or 'mariadbd --verbose --help'.
diff --git a/tests/upstream b/tests/upstream
new file mode 100644 (file)
index 0000000..6dc864d
--- /dev/null
@@ -0,0 +1,66 @@
+#!/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
+
+MTR_SKIP_TEST_LIST=$(mktemp)
+ARCH=$(dpkg --print-architecture)
+
+WORKDIR=$(mktemp -d)
+trap 'rm -rf $WORKDIR $MTR_SKIP_TEST_LIST' 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"
+
+# Use the arch specific skiplists if exist, otherwise list is empty
+if [ -f "/usr/share/mysql/mysql-test/unstable-tests.$ARCH" ]
+then
+  cat "/usr/share/mysql/mysql-test/unstable-tests.$ARCH" >> "$MTR_SKIP_TEST_LIST"
+fi
+
+# Skip tests that cannot run properly on ci.debian.net / autopkgtests.ubuntu.com
+cat >> "$MTR_SKIP_TEST_LIST" << EOF
+binlog.binlog_server_start_options : Requires writable /usr
+main.ctype_uca : Requires writable /usr
+rpl.rpl_gtid_mode : Requires starting server as root ref http://bugs.mysql.com/bug.php?id=70517
+EOF
+
+# Skip tests that cannot run properly on Gitlab-CI
+if [ -n "$GITLAB_CI" ]
+then
+  cat >> "$MTR_SKIP_TEST_LIST" << EOF
+main.mysqld--help : For unknown reason table-cache is 4000 instead of default 421
+EOF
+fi
+
+# Store skipped test list in artifacts so it can be viewed while debugging
+# failed autopkgtest runs
+cp -v "$MTR_SKIP_TEST_LIST" "$AUTOPKGTEST_ARTIFACTS"
+
+cd /usr/share/mysql/mysql-test
+echo "starting mysql-test-tun.pl..."
+export MTR_PRINT_CORE=detailed
+# The $MTR_ARGUMENTS_APPEND is intentionally used to pass in extra arguments
+# shellcheck disable=SC2086
+eatmydata perl -I. ./mysql-test-run.pl \
+    --force --testcase-timeout=120 --suite-timeout=540 --retry=3 \
+    --verbose-restart --max-save-core=1 --max-save-datadir=1 \
+    --parallel=auto --skip-rpl --suite=main \
+    --skip-test-list="$MTR_SKIP_TEST_LIST" \
+    --vardir="$WORKDIR/var" --tmpdir="$WORKDIR/tmp" \
+    --xml-report="$AUTOPKGTEST_ARTIFACTS/mysql-test-run-junit.xml" \
+    $MTR_ARGUMENTS_APPEND \
+    "$@" 2>&1
+echo "run: OK"
diff --git a/unstable-tests.alpha b/unstable-tests.alpha
new file mode 100644 (file)
index 0000000..722ed45
--- /dev/null
@@ -0,0 +1,2 @@
+main.alter_table_mdev539_maria : MDEV-23922
+repair_symlink-5543            : MDEV-23920
diff --git a/unstable-tests.amd64 b/unstable-tests.amd64
new file mode 100644 (file)
index 0000000..d28f1eb
--- /dev/null
@@ -0,0 +1,3 @@
+maria.maria-purge : MDEV-31349
+type_test.type_test_double : MDEV-22243, but wasn't actually fixed yet
+unit.conc_connection : CONC-640: unit.conc_connection fails on test_conc21
diff --git a/unstable-tests.arm64 b/unstable-tests.arm64
new file mode 100644 (file)
index 0000000..b6230a8
--- /dev/null
@@ -0,0 +1,4 @@
+binlog.flashback-largebinlog : MDEV-32352
+maria.maria-purge : MDEV-31349
+type_test.type_test_double : MDEV-22243, but wasn't actually fixed yet
+unit.conc_connection : CONC-640: unit.conc_connection fails on test_conc21
diff --git a/unstable-tests.armel b/unstable-tests.armel
new file mode 100644 (file)
index 0000000..88d06b4
--- /dev/null
@@ -0,0 +1,5 @@
+main.partition_key_cache : MDEV-23427
+main.table_value_constr : MDEV-33520
+maria.maria-purge : MDEV-31349
+type_test.type_test_double : MDEV-22243, but wasn't actually fixed yet
+unit.conc_connection : CONC-640: unit.conc_connection fails on test_conc21
diff --git a/unstable-tests.armhf b/unstable-tests.armhf
new file mode 100644 (file)
index 0000000..11bf833
--- /dev/null
@@ -0,0 +1,21 @@
+# MDEV-33381: The full test suite (including --big-test) has numerous failures
+# on armhf and a Raspberry Pi enthusiast is needed to debug them
+federated.federatedx_versioning : MDEV-33381
+index_intersect_innodb : MDEV-23921
+main.index_intersect : MDEV-23921
+main.join_cache_notasan : MDEV-34084
+main.table_value_constr : MDEV-33520
+main.xml : MDEV-21968
+maria.maria-purge : MDEV-31349
+mariabackup.encrypted_page_corruption : Not reported upstream yet
+period.versioning : MDEV-33381
+spider.basic_sql : MDEV-33381
+spider.spider_fixes_part : MDEV-33381
+spider/bg.basic_sql : MDEV-33381
+spider/bg.spider_fixes_part : MDEV-33381
+type_test.type_test_double : MDEV-22243, but wasn't actually fixed yet
+unit.conc_connection : CONC-640: unit.conc_connection fails on test_conc21
+versioning.autoinc : MDEV-33381
+versioning.online : MDEV-33381
+versioning.partition : MDEV-33381
+versioning.trx_id : MDEV-33381
diff --git a/unstable-tests.hppa b/unstable-tests.hppa
new file mode 100644 (file)
index 0000000..d273b15
--- /dev/null
@@ -0,0 +1,19 @@
+index_intersect_innodb : MDEV-23921
+main.analyze_engine_stats : MDEV-32375
+main.analyze_stmt_orderby : MDEV-32375
+main.analyze_stmt_slow_query_log : MDEV-12237
+main.cte_recursive : MDEV-32375
+main.derived_split_innodb : MDEV-32375
+main.explain_json_format_partitions : MDEV-32375
+main.func_json_notembedded : MDEV-27955 / MDEV-30518 / https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1006529 (timeout)
+main.index_intersect : MDEV-23921
+main.index_intersect : MDEV-23921
+main.index_intersect_innodb : MDEV-23921
+main.join_cache_notasan : MDEV-31893 (fixed but perhaps not for hppa)
+main.join_cache_notasan : MDEV-34084
+main.rowid_filter_innodb : MDEV-32375
+main.table_value_constr : MDEV-33520
+maria.maria-purge : MDEV-31349
+repair_symlink-5543  : MDEV-23920
+type_test.type_test_double : MDEV-22243, but wasn't actually fixed yet
+unit.conc_connection : CONC-640: unit.conc_connection fails on test_conc21
diff --git a/unstable-tests.hurd b/unstable-tests.hurd
new file mode 100644 (file)
index 0000000..dbc096b
--- /dev/null
@@ -0,0 +1 @@
+# MDEV-8535: auth_socket does not build on hurd-i368
diff --git a/unstable-tests.hurd-i386 b/unstable-tests.hurd-i386
new file mode 120000 (symlink)
index 0000000..32dbff6
--- /dev/null
@@ -0,0 +1 @@
+unstable-tests.hurd
\ No newline at end of file
diff --git a/unstable-tests.m68k b/unstable-tests.m68k
new file mode 100644 (file)
index 0000000..1d55cfd
--- /dev/null
@@ -0,0 +1,3 @@
+# The m68k build on Debian runs in a qemu builder and has
+# DEB_BUILD_OPTIONS="nobench nocheck" defined, so *all* tests are skipped
+# intentionally (Bug#972057)
diff --git a/unstable-tests.powerpc b/unstable-tests.powerpc
new file mode 100644 (file)
index 0000000..4438338
--- /dev/null
@@ -0,0 +1,5 @@
+main.func_json_notembedded : MDEV-30518 / MDEV-27955
+main.table_value_constr : MDEV-33520
+maria.maria-purge : MDEV-31349
+type_test.type_test_double : MDEV-22243, but wasn't actually fixed yet
+unit.conc_connection : CONC-640: unit.conc_connection fails on test_conc21
diff --git a/unstable-tests.ppc64 b/unstable-tests.ppc64
new file mode 100644 (file)
index 0000000..a78b633
--- /dev/null
@@ -0,0 +1,6 @@
+main.func_json_notembedded : MDEV-30518 / MDEV-27955
+main.index_merge_innodb : MDEV-30728
+main.mysql_upgrade : https://bugs.debian.org/1053486
+maria.maria-purge : MDEV-31349
+type_test.type_test_double : MDEV-22243, but wasn't actually fixed yet
+unit.conc_connection : CONC-640: unit.conc_connection fails on test_conc21
diff --git a/unstable-tests.ppc64el b/unstable-tests.ppc64el
new file mode 100644 (file)
index 0000000..2bf1d69
--- /dev/null
@@ -0,0 +1,6 @@
+main.index_merge_innodb : MDEV-30728
+main.innodb_ext_key : MDEV-30728
+maria.maria-purge : MDEV-31349
+spider.spider_fixes_part : MDEV-30929 - sporadic, not just ppc64el
+type_test.type_test_double : MDEV-22243, but wasn't actually fixed yet
+unit.conc_connection : CONC-640: unit.conc_connection fails on test_conc21
diff --git a/unstable-tests.riscv64 b/unstable-tests.riscv64
new file mode 100644 (file)
index 0000000..1cdbf93
--- /dev/null
@@ -0,0 +1,4 @@
+maria.maria-purge : MDEV-31349
+rpl.parallel_backup_slave_binlog_off : MDEV-30676
+type_test.type_test_double : MDEV-22243, but wasn't actually fixed yet
+unit.conc_connection : CONC-640: unit.conc_connection fails on test_conc21
diff --git a/unstable-tests.s390x b/unstable-tests.s390x
new file mode 100644 (file)
index 0000000..0090e77
--- /dev/null
@@ -0,0 +1,5 @@
+innodb.row_size_error_log_warnings_3 : MDEV-30918
+main.func_json_notembedded : MDEV-30518 / MDEV-27955
+maria.maria-purge : MDEV-31349
+type_test.type_test_double : MDEV-22243, but wasn't actually fixed yet
+unit.conc_connection : CONC-640: unit.conc_connection fails on test_conc21
diff --git a/unstable-tests.sh4 b/unstable-tests.sh4
new file mode 100644 (file)
index 0000000..1d55cfd
--- /dev/null
@@ -0,0 +1,3 @@
+# The m68k build on Debian runs in a qemu builder and has
+# DEB_BUILD_OPTIONS="nobench nocheck" defined, so *all* tests are skipped
+# intentionally (Bug#972057)
diff --git a/unstable-tests.sparc64 b/unstable-tests.sparc64
new file mode 100644 (file)
index 0000000..e397067
--- /dev/null
@@ -0,0 +1,19 @@
+main.ctype_binary : https://bugs.debian.org/1053485
+main.ctype_latin1 : https://bugs.debian.org/1053485
+main.features : MDEV-27954
+main.func_json_notembedded : MDEV-27955 / MDEV-30518
+main.func_like : MDEV-27954
+main.func_math : MDEV-27954
+main.func_str : MDEV-27954
+main.group_by : MDEV-27954
+main.group_by_null : MDEV-27954
+main.index_merge_innodb : MDEV-30728
+main.long_unique_bugs : MDEV-30928
+main.partition_order : MDEV-27954
+main.repair_symlink-5543 : MDEV-23920
+main.type_datetime : MDEV-27954
+main.xa_prepared_binlog_off : Likely also MDEV-30728
+main.xml : MDEV-27954
+maria.maria-purge : MDEV-31349
+type_test.type_test_double : MDEV-22243, but wasn't actually fixed yet
+unit.conc_connection : CONC-640: unit.conc_connection fails on test_conc21
diff --git a/upstream/metadata b/upstream/metadata
new file mode 100644 (file)
index 0000000..184baa4
--- /dev/null
@@ -0,0 +1,6 @@
+Bug-Database: https://jira.mariadb.org
+Bug-Submit: https://jira.mariadb.org
+Donation: https://mariadb.org/donate/
+Repository: git://github.com/MariaDB/server.git
+Repository-Browse: https://github.com/MariaDB/server
+Security-Contact: security@mariadb.org
diff --git a/upstream/signing-key.asc b/upstream/signing-key.asc
new file mode 100644 (file)
index 0000000..708d206
--- /dev/null
@@ -0,0 +1,51 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+mQINBFb8EKsBEADwGmleOSVThrbCyCVUdCreMTKpmD5p5aPz/0jc66050MAb71Hv
+TVcfuMqHYO8O66qXLpEdqZpuk4D+rw1oKyC+d8uPD2PSHRqBXnR0Qf+LVTZvtO92
+3R7pYnC2x6V6iVGpKQYFP8cwh2B1qgIa+9y/N8cQIqfD+0ghyiUjjTYek3YFBnqa
+L/2h2V0Mt0DkBrDK80LqEY10PAFDfJjINAW9XNHZzi2KqUx5w1z8rItokXV6fYE5
+ItyGMR6WVajJg5D4VCiZd0ymuQP2bGkrRbl6FH5vofVSkahKMJeHs2lbvMvNyS3c
+n8vxoBvbbcwSAV1gvB1uzXXxv0kdkFZjhU1Tss4+Dak8qeEmIrC5qYycLxIdVEhT
+Z8N8+P7Dll+QGOZKu9+OzhQ+byzpLFhUHKys53eXo/HrfWtw3DdP21yyb5P3QcgF
+scxfZHzZtFNUL6XaVnauZM2lqquUW+lMNdKKGCBJ6co4QxjocsxfISyarcFj6ZR0
+5Hf6VU3Y7AyuFZdL0SQWPv9BSu/swBOimrSiiVHbtE49Nx1x/d1wn1peYl07WRUv
+C10eF36ZoqEuSGmDz59mWlwB3daIYAsAAiBwgcmN7aSB8XD4ZPUVSEZvwSm/IwuS
+Rkpde+kIhTLjyv5bRGqU2P/Mi56dB4VFmMJaF26CiRXatxhXOAIAF9dXCwARAQAB
+tC1NYXJpYURCIFNpZ25pbmcgS2V5IDxzaWduaW5nLWtleUBtYXJpYWRiLm9yZz6J
+AjgEEwEIACIFAlb8EKsCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEPFl
+byTHTNHYJZ0P/2Z2RURRkSTHLKZ/GqSvPReReeB7AI+ZrDapkpG/26xp1Yw1isCO
+y99pvQ7hjTFhdZQ7xSRUiT/e27wJxR7s4G/ck5VOVjuJzGnByNLmwMjdN1ONIO9P
+hQAs2iF3uoIbVTxzXof2F8C0WSbKgEWbtqlCWlaapDpN8jKAWdsQsNMdXcdpJ2os
+WiacQRxLREBGjVRkAiqdjYkegQ4BZ0GtPULKjZWCUNkaat51b7O7V19nSy/T7MM7
+n+kqYQLMIHCF8LGd3QQsNppRnolWVRzXMdtR2+9iI21qv6gtHcMiAg6QcKA7halL
+kCdIS2nWR8g7nZeZjq5XhckeNGrGX/3w/m/lwczYjMUer+qs2ww5expZJ7qhtSta
+lE3EtL/l7zE4RlknqwDZ0IXtxCNPu2UovCzZmdZm8UWfMSKk/3VgL8HgzYRr8fo0
+yj0XkckJ7snXvuhoviW2tjm46PyHPWRKgW4iEzUrB+hiXpy3ikt4rLRg/iMqKjyf
+mvcE/VdmFVtsfbfRVvlaWiIWCndRTVBkAaTu8DwrGyugQsbjEcK+4E25/SaKIJIw
+qfxpyBVhru21ypgEMAw1Y8KC7KntB7jzpFotE4wpv1jZKUZuy71ofr7g3/2O+7nW
+LrR1mncbuT6yXo316r56dfKzOxQJBnYFwTjXfa65yBArjQBUCPNYOKr0uQINBFb8
+EKsBEADDfCMsu2U1CdJhr4xp6z4J89/tMnpCQASC8DQhtZ6bWG/ksyKt2DnDQ050
+XBEng+7epzHWA2UgT0liY05zZmFs1X7QeZr16B7JANq6fnHOdZB0ThS7JEYbProk
+MxcqAFLAZJCpZT534GpzW7qHwzjV+d13IziCHdi6+DD5eavYzBqY8QzjlOXbmIlY
+7dJUCwXTECUfirc6kH86CS8fXZTke4QYZ55VnrOomB4QGqP371kwBETnhlhi74+p
+vi3jW05Z5x1tVMwuugyzzkseZp1VYmJq5SHNFZ/pnAQLE9gUDTb6UWcPBwQh9Sw+
+7ahSK74lJKYm3wktyvZhzAxbNyzs1M56yeFP6uFwJTBfNByyMAa6TGUhNkxlLcYj
+xKbVmoAnKCVM8t41TlLv/a0ki8iQxqvphVLufksR9IpN6d3F15j6GeyVtxBEv04i
+v4vbuKthWytb+gjX4bI8CAo9jGHevmtdiw/SbeKx2YBM1MF6eua37rFMooOBj4X7
+VfQCyS+crNsOQn8nJGahYbzUDCCgnX+pqN9iZvXisMS79wVyD5DyISFDvT/5jY7I
+XxPibxr10P/8lfW1d72uxyI2UiZKZpyHCt4k47yMq4KQGLGuhxJ6q6O3bi2aXRuz
+8bLqTBLca9dmx9wZFvRh6jS/SKEg7eFcY0xbb6RVIv1UwGDYfQARAQABiQIfBBgB
+CAAJBQJW/BCrAhsMAAoJEPFlbyTHTNHYEBIQAJhFTh1u34Q+5bnfiM2dAdCr6T6w
+4Y1v9ePiIYdSImeseJS2yRglpLcMjW0uEA9KXiRtC/Nm/ClnqYJzCKeIaweHqH6d
+IgJKaXZFt1Uaia7X9tDDwqALGu97irUrrV1Kh9IkM0J29Vid5amakrdS4mwt2uEI
+SSnCi7pfVoEro+S7tYQ9iH6APVIwqWvcaty3cANdwKWfUQZ6a9IQ08xqzaMhMp2V
+zhVrWkq3B0j2aRoZR7BNLH2I7Z0giIM8ARjZs99aTRL+SfMEQ3sUxNLb3KWP/n1l
+SFbrk4HGzqUBBfczESlNc0970C6znK0H0HD11/3BTkMuPqww+Tzex4dpMQllMEKZ
+3wEyd9v6ba+nj/P1FHSEy/VN6IXzd82s1lYOonKTdmXAIROcHnb0QUzwsd/mhB3j
+KhEDOV2ZcBTD3yHv8m7C9G9y4hV+7yQlnPlSg3DjBp3SS5r+sOObCIy2Ad32upoX
+kilWa9g7GZSuhY9kyKqeEba1lgXXaQykEeqx0pexkWavNnb9JaPrAZHDjUGcXrRE
+mjEyXyElRoD4CrWXySe46jCuNhVVlkLGo7osefynXa/+PNjQjURtx8en7M9A1FkQ
+uRAxE8KIZgZzYxkGl5o5POSFCA4JUoRPDcrl/sI3fuq2dIOE/BJ2r8dV+LddiR+i
+ukhXRwJXH8RVVEUS
+=ihRo
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/watch b/watch
new file mode 100644 (file)
index 0000000..0417109
--- /dev/null
+++ b/watch
@@ -0,0 +1,17 @@
+version=4
+opts=\
+pgpsigurlmangle=s/$/.asc/,\
+uversionmangle=s/-(rc|beta)/$1/,pasv \
+https://archive.mariadb.org/mariadb-10.11.([\d\.]*(?:-beta|-rc)?)/source/ mariadb-([\d\.]*(?:-beta|-rc)?).tar.gz
+
+# String "-10.11." needs to be in path as MariaDB releases several series in
+# parallel (e.g 10.11, 10.4, 10.3 etc) and uscan should check for updates only
+# in the 10.11-series.
+
+# Automated signature checking with pgpsigurlmangle has been available
+# only since devscripts version 2.13.3
+
+# Specifically use archive.mariadb.org because it supports https and the main
+# page has a file listing suitable for scanning new releases.
+# The archive.mariadb.org service is under MariaDB Foundation control and is
+# the official source for new releases.