--- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.mysql.init +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.mysql.init @@ -0,0 +1,190 @@ +#!/bin/bash +# +### BEGIN INIT INFO +# Provides: mysql +# Required-Start: $remote_fs $syslog mysql-ndb +# Required-Stop: $remote_fs $syslog mysql-ndb +# 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 mysql database server daemon +# Description: Controls the main MySQL database server daemon "mysqld" +# and its wrapper script "mysqld_safe". +### END INIT INFO +# +set -e +set -u +${DEBIAN_SCRIPT_DEBUG:+ set -v -x} + +test -x /usr/sbin/mysqld || exit 0 + +. /lib/lsb/init-functions + +SELF=$(cd $(dirname $0); pwd -P)/$(basename $0) +CONF=/etc/mysql/my.cnf +MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" + +# priority can be overriden and "-s" adds output to stderr +ERR_LOGGER="logger -p daemon.err -t /etc/init.d/mysql -i" + +# 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 mysqld_get_param option +mysqld_get_param() { + /usr/sbin/mysqld --print-defaults \ + | tr " " "\n" \ + | grep -- "--$1" \ + | tail -n 1 \ + | cut -d= -f2 +} + +## Do some sanity checks before even trying to start mysqld. +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=`mysqld_get_param datadir` + if LC_ALL=C BLOCKSIZE= df --portability $datadir/. | tail -n 1 | awk '{ exit ($4>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 mysqld in the process list +# +# Usage: boolean mysqld_status [check_alive|check_dead] [warn|nowarn] +mysqld_status () { + ping_output=`$MYADMIN ping 2>&1`; ping_alive=$(( ! $? )) + + ps_alive=0 + pidfile=`mysqld_get_param pid-file` + if [ -f "$pidfile" ] && ps `cat $pidfile` >/dev/null 2>&1; then ps_alive=1; fi + + 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 MySQL database server" "mysqld" + if mysqld_status check_alive nowarn; then + log_progress_msg "already running" + log_end_msg 0 + else + /usr/bin/mysqld_safe > /dev/null 2>&1 & + # 6s was reported in #352070 to be too few when using ndbcluster + for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14; do + sleep 1 + if mysqld_status check_alive nowarn ; then break; fi + log_progress_msg "." + done + if mysqld_status check_alive warn; then + log_end_msg 0 + # Now start mysqlcheck or whatever the admin wants. + output=$(/etc/mysql/debian-start) + [ -n "$output" ] && log_action_msg "$output" + else + log_end_msg 1 + log_failure_msg "Please take a look at the syslog" + fi + fi + + # Some warnings + if $MYADMIN variables | egrep -q have_bdb.*YES; then + echo "BerkeleyDB is obsolete, see /usr/share/doc/mysql-server-5.0/README.Debian.gz" | $ERR_LOGGER -p daemon.info + fi + if [ -f /etc/mysql/debian-log-rotate.conf ]; then + echo "/etc/mysql/debian-log-rotate.conf is obsolete, see /usr/share/doc/mysql-server-5.0/NEWS.Debian.gz" | $ERR_LOGGER -p daemon.info + 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 MySQL database server" "mysqld" + if ! mysqld_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 MySQL database server by signal" "mysqld" + killall -15 mysqld + server_down= + for i in 1 2 3 4 5 6 7 8 9 10; do + sleep 1 + if mysqld_status check_dead nowarn; then server_down=1; break; fi + done + if test -z "$server_down"; then killall -9 mysqld; fi + fi + fi + + if ! mysqld_status check_dead warn; then + log_end_msg 1 + log_failure_msg "Please stop MySQL manually and read /usr/share/doc/mysql-server-5.0/README.Debian.gz!" + exit -1 + else + log_end_msg 0 + fi + ;; + + 'restart') + set +e; $SELF stop; set -e + $SELF start + ;; + + 'reload'|'force-reload') + log_daemon_msg "Reloading MySQL database server" "mysqld" + $MYADMIN reload + log_end_msg 0 + ;; + + 'status') + if mysqld_status check_alive nowarn; then + log_action_msg "$($MYADMIN version)" + else + log_action_msg "MySQL is stopped." + exit 3 + fi + ;; + + *) + echo "Usage: $SELF start|stop|restart|reload|force-reload|status" + exit 1 + ;; +esac + --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.lintian-overrides +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.lintian-overrides @@ -0,0 +1,4 @@ +mysql-server-5.0: possible-bashism-in-maintainer-script postinst:81 'p{("a".."z","A".."Z",0..9)[int(rand(62))]}' +mysql-server-5.0: possible-bashism-in-maintainer-script preinst:33 '${cmd/ */}' +mysql-server-5.0: statically-linked-binary ./usr/bin/mysql_tzinfo_to_sql +mysql-server-5.0: statically-linked-binary ./usr/sbin/mysqld --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.README.Debian +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.README.Debian @@ -0,0 +1,141 @@ + +* REMEMBER TO SET THE ROOT PASSWORD !!! +============================================================================ + +* MYSQL WON'T INSTALL? +====================== +MySQL will only install if you have a non-numeric hostname that is resolvable +via the /etc/hosts file. E.g. if the "hostname" command returns "myhostname" +then there must be a line like "10.0.0.1 myhostname". + +On upgrades from MySQL 3.23, as shipped with Debian Woody, symlinks in place of +/var/lib/mysql or /var/log/mysql gets accidently removed and have manually be +restored. + +* MYSQL WON'T START OR STOP? +============================ +You may never ever delete the special mysql user "debian-sys-maint". This +user together with the credentials in /etc/mysql/debian.cnf are used by the +init scripts to stop the server as they would require knowledge of the mysql +root users password else. +So in most of the times you can fix the situation by making sure that the +debian.cnf file contains the right password, e.g. by setting a new one +(remember to do a "flush privileges" then). + +* WHAT TO DO AFTER UPGRADES: +============================ +The privilege tables are automatically updated so all there is left is read +the changelogs on dev.mysql.com to see if any changes affect custom apps. + +* WHAT TO DO AFTER INSTALLATION: +================================ +The MySQL manual describes certain steps to do at this stage in a separate +chapter. They are not necessary as the Debian packages does them +automatically. + +The only thing that is left over for the admin is + - setting the *passwords* !!! + - creating new users and databases + - read the rest of this text + +* DOWNGRADING TO 4.0 or 4.1: +============================ +Unsupported. Period. +But if you do and get problems or make interesting experiences, mail me, it +might help others. +Ok, if you really want, I would recommend to "mysqldump --opt" all tables, +then purge 4.1, delete /var/lib/mysql, install 4.0 and insert the dumps. Be +carefully, though, with the "mysql" table, you might not simply overwrite that +one as the password for the mysql "debian-sys-maint" user is stored in +/etc/mysql/debian.cnf and needed by /etc/init.d/ to start mysql and check if +it's alive. + +* SOME APPLICATION CAN NO LONGER CONNECT: +========================================= +This application is probably linked against libmysqlclient12 or below and +somebody has created a mysql user with new-style passwords. +The old_passwords option which forces backwards compatibility, can be set +with "dpkg-reconfigure mysql-server-5.0". +If that does not help, the password can be set manually, the application that +inserted the user should be changed or the application that tries to connect +should be updated to libmysqlclient14 or -15. +Read http://dev.mysql.com/doc/refman/5.0/en/old-client.html + +* NETWORKING: +============= +For security reasons, the Debian package has enabled networking only on the +loop-back device using "bind-address" in /etc/mysql/my.cnf. Check with +"netstat -tlnp" where it is listening. If your connection is aborted +immediately see if "mysqld: all" or similar is in /etc/hosts.allow and read +hosts_access(5). + +* WHERE IS THE DOCUMENTATION?: +============================== +Unfortunately due to licensing restrictions, debian currently not able +to provide the mysql-doc package in any format. For the most up to date +documentation, please go to http://dev.mysql.com/doc. + +* PASSWORDS: +============ +It is strongly recommended to set a password for the mysql root user (which +is NOT the same as the "normal" root user) with these commands: + /usr/bin/mysql -u root -D mysql -e "update user set password=password('new-password') where user='root'" + /usr/bin/mysql -u root -e "flush privileges" +If you already had a password set add "-p" before "-u" to the lines above. + +If you are tired to type the password in every time or want to automate your +scripts you can store it in the file $HOME/.my.cnf. It should be chmod 0600 +(-rw------- username username .my.cnf) to ensure that nobody else can read +it. Every other configuration parameter can be stored there, too. You will +find an example below and more information in the MySQL manual in +/usr/share/doc/mysql-doc or www.mysql.com. + +ATTENTION: It is necessary, that a .my.cnf from root always contains a "user" +line wherever there is a "password" line, else, the Debian maintenance +scripts, that use /etc/mysql/debian.cnf, will use the username +"debian-sys-maint" but the password that is in root's .my.cnf. Also note, +that every change you make in the /root/.my.cnf will affect the mysql cron +script, too. + + # an example of $HOME/.my.cnf + [client] + user = your-mysql-username + password = enter-your-good-new-password-here + +* BIG_ROWS FOR EVEN MORE ROWS IN A TABLE: +========================================= +If you ever run out of rows in a table there is the possibility of building +the package with "-DBIG_ROWS" which, according to a MySQL employee on +packagers@lists.mysql.com should lead to a 64bit row index (I guess > 2^32 +rows) but also to an approx. 5% performance loss. + +* NDB CLUSTER ENGINE: +===================== +NDB is the shared-nothing cluster engine since MySQL-4.1. +This package contains the all three components, the mysql backend, the NDB +Data Node and the NDB Management Node. The init scripts of the cluster +daemons will silently exit unless their configuration is provided: + mysql-ndb: needs "ndb-connectstring" in /etc/mysql/my.cnf + mysql-ndb-mgm: needs /etc/mysql/ndb_mgmd.cnf +Because of the need to perform rolling restarts of the cluster during an +upgrade, neither ndbd or ndb_mgmd will restart during a package upgrade. + +* FURTHER NOTES ON REPLICATION +=============================== +Іf the MySQL server is acting as a replication slave, you should not +set --tmpdir to point to a directory on a memory-based filesystem or to +a directory that is cleared when the server host restarts. A replication +slave needs some of its temporary files to survive a machine restart so +that it can replicate temporary tables or LOAD DATA INFILE operations. If +files in the temporary file directory are lost when the server restarts, +replication fails. + + +* APPARMOR PROFILE +================== +If your system uses apparmor, please note that the shipped enforcing profile +works with the default installation, and changes in your configuration may +require changes to the installed apparmor profile. Please see +https://wiki.ubuntu.com/DebuggingApparmor before filing a bug against this +software. + --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.mysql-server.logrotate +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.mysql-server.logrotate @@ -0,0 +1,28 @@ +# - I put everything in one block and added sharedscripts, so that mysql gets +# flush-logs'd only once. +# Else the binary logs would automatically increase by n times every day. +# - The error log is obsolete, messages go to syslog now. +/var/log/mysql.log /var/log/mysql/mysql.log /var/log/mysql/mysql-slow.log { + daily + rotate 7 + missingok + create 640 mysql adm + compress + sharedscripts + postrotate + test -x /usr/bin/mysqladmin || exit 0 + + # If this fails, check debian.conf! + export HOME=/etc/mysql/my.cnf + MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" + if [ -z "`$MYADMIN ping 2>/dev/null`" ]; then + # Really no mysqld or rather a missing debian-sys-maint user? + # If this occurs and is not a error please report a bug. + if ps cax | grep -q mysqld; then + exit 1 + fi + else + $MYADMIN flush-logs + fi + endscript +} --- mysql-dfsg-5.0-5.0.51a.orig/debian/libmysqlclient15-dev.examples +++ mysql-dfsg-5.0-5.0.51a/debian/libmysqlclient15-dev.examples @@ -0,0 +1 @@ +sql/udf_example.c --- mysql-dfsg-5.0-5.0.51a.orig/debian/libmysqlclient15off.dirs +++ mysql-dfsg-5.0-5.0.51a/debian/libmysqlclient15off.dirs @@ -0,0 +1 @@ +usr/lib/ --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.config +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.config @@ -0,0 +1,70 @@ +#!/bin/bash -e + +. /usr/share/debconf/confmodule + +if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi +${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 } + +CNF=/etc/mysql/my.cnf + +# Beware that there are two ypwhich one of them needs the 2>/dev/null! +if test -n "`which ypwhich 2>/dev/null`" && ypwhich >/dev/null 2>&1; then + db_input high mysql-server-5.0/nis_warning || true + db_go +fi + +# only ask this question on fresh installs and during "reconfiguration". +# there is also an additional check for empty root passwords in the +# postinst script when the tools are available for us to use. +if [ "$1" = "configure" ] && [ -z "$2" ] || [ "$1" = "reconfigure" ]; then + while :; do + RET="" + db_input high mysql-server/root_password || true + db_go + db_get mysql-server/root_password + # if password isn't empty we ask for password verification + if [ -z "$RET" ]; then + db_fset mysql-server/root_password seen false + db_fset mysql-server/root_password_again seen false + break + fi + ROOT_PW="$RET" + db_input high mysql-server/root_password_again || true + db_go + db_get mysql-server/root_password_again + if [ "$RET" == "$ROOT_PW" ]; then + ROOT_PW='' + break + fi + db_fset mysql-server/password_mismatch seen false + db_input critical mysql-server/password_mismatch + db_set mysql-server/root_password "" + db_set mysql-server/root_password_again "" + db_go + done +fi + +# If this is an upgrade of an already existing installation ask the user if +# we may use the backwards incompatible but more secure password format. +# This should not be shown at dpkg-reconfigure, except for the dist-upgrade, +# my.cnf is for the admin only! +# Read: If mysql was already installed but not from Etch and it was either 4.0 +# or had old_passwords enabled before then the system is affected. +if [ -n "$DEBIAN_SCRIPT_TRACE" ]; then + set +e + [ "$1" = "configure" ]; x1=$? + [ -f $CNF ]; x2=$? + [ ! -f /var/lib/mysql/debian-4.1.flag ]; x31=$? + egrep -q -i '^[[:space:]]*old.passwords[[:space:]]*=[[:space:]]*(1|true)' $CNF; x32=$? + set -e +fi +if [ "$1" = "configure" ] && + [ -f $CNF ] && + ( + [ ! -f /var/lib/mysql/debian-4.1.flag ] || + egrep -q -i '^[[:space:]]*old.passwords[[:space:]]*=[[:space:]]*(1|true)' $CNF + ) +then + db_input medium mysql-server-5.0/need_sarge_compat || true + db_go +fi --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-client-5.0.lintian-overrides +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-client-5.0.lintian-overrides @@ -0,0 +1,3 @@ +mysql-client-5.0: package-has-a-duplicate-relation +mysql-client-5.0: wrong-name-for-upstream-changelog usr/share/doc/mysql-client-5.0/changelog.innotop.gz +mysql-client-5.0: pkg-not-in-package-test innotop --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.mysql-ndb.init +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.mysql-ndb.init @@ -0,0 +1,103 @@ +#!/bin/bash +# +### BEGIN INIT INFO +# Provides: mysql-ndb +# Required-Start: $remote_fs $syslog mysql-ndb-mgm +# Required-Stop: $remote_fs $syslog mysql-ndb-mgm +# 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 mysql database cluster server daemon +# Description: Controls the MySQL NDB Data Node daemon "ndbd". +### END INIT INFO +# +set -e +set -u +${DEBIAN_SCRIPT_DEBUG:+ set -v -x} + +# Variables +SELF=$(cd $(dirname $0); pwd -P)/$(basename $0) +DAEMON=/usr/sbin/ndbd +CONF=/etc/mysql/my.cnf +export HOME=/etc/mysql/ + +# Safeguard (relative paths, core dumps..) +cd / +umask 077 + +# Exit *silently* if we're not supposed to be started. +# +# The Debian scripts should execute these scripts to stop and start +# the daemon when upgrading if it is started. On the other hand it should +# remain silently if the server has not even been configured. +# See /usr/share/doc/mysql-server-*/README.Debian for more information. +test -x $DAEMON || exit 0 +if $DAEMON --help | grep -q '^ndb-connectstring.*No default value'; then exit 0; fi +. /lib/lsb/init-functions + +# +# main() +# +case "${1:-''}" in + 'start') + # Start daemon + # Creatign a PID file does not work as the master process forks + # a child with different PID and then terminates itself. + log_daemon_msg "Starting MySQL NDB Data Node" "ndbd" + if start-stop-daemon \ + --start \ + --exec $DAEMON \ + --user mysql + then + log_end_msg 0 + else + log_end_msg 1 + log_warning_msg "Please take a look at the syslog." + exit 1 + fi + ;; + + 'start-initial') + # Perform an initial start of ndbd + log_daemon_msg "Initial start of MySQL NDB Data Node" "ndbd" + if start-stop-daemon \ + --start \ + --exec $DAEMON \ + --user mysql \ + -- --initial + then + log_end_msg 0 + else + log_end_msg 1 + log_warning_msg "Please take a look at the syslog." + exit 1 + fi + ;; + + 'stop') + log_daemon_msg "Stopping MySQL NDB Data Node" "ndbd" + if start-stop-daemon \ + --stop \ + --oknodo \ + --exec $DAEMON + then + log_end_msg 0 + else + log_end_msg 1 + exit 1 + fi + ;; + + 'restart'|'force-reload') + set +e; $SELF stop; set -e + $SELF start + ;; + + *) + echo "Usage: $SELF start|start-initial|stop|restart|force-reload" + echo " * start-initial starts ndbd with '--initial'" + exit 1 + ;; +esac + --- mysql-dfsg-5.0-5.0.51a.orig/debian/libmysqlclient15off.README.Debian +++ mysql-dfsg-5.0-5.0.51a/debian/libmysqlclient15off.README.Debian @@ -0,0 +1,30 @@ +* Crashs on systems with Cyrix or other old i486 CPUs +===================================================== + +As reported http://bugs.mysql.com/bug.php?id=21765 MySQL will segfault on very +old CPUs that do not have support for the "cpuid" instruction. + + + +* Self-build binaries that are linked against libmysqlclient15 MUST be rebuild! +=============================================================================== + +This only affects binaries that are build on a Debian unstable/testing system +before 2006-03-31 or version 5.0.19. "objdump -T myprogram | grep MYSQL_5.0" +will give a couple of lines output in such a case. + +Until now libmysqlclient.so.15 had versioned symbols provided by a Debian +patch. Now MySQL finally decided to adopt this patch but sadly chosed a +different symbol name. + +Binaries linked against the old version of the library with my symbol name will +not run with the new version with MySQL's symbol name ("version `MYSQL_5.0' not +found"). The actual name /usr/lib/libmysqlclient.so.15 must stay because else +binaries coming from systems other than Debian would never run on a Debian +server. + +So the Debian package had to be renamed from "libmysqlclient15" to +"libmysqlclient15off" and do now conflict with their former version. + +-- 2006-03-14, Christian Hammers + --- mysql-dfsg-5.0-5.0.51a.orig/debian/apparmor-profile +++ mysql-dfsg-5.0-5.0.51a/debian/apparmor-profile @@ -0,0 +1,33 @@ +# vim:syntax=apparmor +# Last Modified: Tue Jun 19 17:37:30 2007 +#include + +/usr/sbin/mysqld { + #include + #include + #include + #include + + capability dac_override, + capability setgid, + capability setuid, + + /etc/hosts.allow r, + /etc/hosts.deny r, + + /etc/group m, + /etc/passwd m, + + /etc/mysql/*.pem r, + /etc/mysql/conf.d/ r, + /etc/mysql/conf.d/* r, + /etc/mysql/my.cnf r, + /usr/sbin/mysqld mr, + /usr/share/mysql/** r, + /var/lib/mysql/ r, + /var/lib/mysql/** rwk, + /var/log/mysql/ r, + /var/log/mysql/* rw, + /var/run/mysqld/mysqld.pid w, + /var/run/mysqld/mysqld.sock w, +} --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/mysqlreport/mysqlreport +++ mysql-dfsg-5.0-5.0.51a/debian/additions/mysqlreport/mysqlreport @@ -0,0 +1,1151 @@ +#!/usr/bin/perl -w + +# mysqlreport v3.4a Jan 23 2008 +# http://hackmysql.com/mysqlreport + +# mysqlreport makes an easy-to-read report of important MySQL status values. +# Copyright 2006-2008 Daniel Nichter +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# The GNU General Public License is available at: +# http://www.gnu.org/copyleft/gpl.html + +use strict; +use File::Temp qw(tempfile); +use DBI; +use Getopt::Long; +eval { require Term::ReadKey; }; +my $RK = ($@ ? 0 : 1); + +sub have_op; + +my $WIN = ($^O eq 'MSWin32' ? 1 : 0); +my %op; +my %mycnf; # ~/.my.cnf +my ($tmpfile_fh, $tmpfile); +my ($stat_name, $stat_val, $stat_label); +my ($major, $minor, $patch, $x); # MySQL version +my (%stats, %vars); # SHOW STATUS, SHOW VARIABLES +my (%DMS_vals, %Com_vals, %ib_vals); +my ($dbh, $query); +my ($questions, $key_read_ratio, $key_write_ratio, $dms, $slow_query_t); +my ($key_cache_block_size, $key_buffer_used, $key_buffer_usage); +my ($qc_mem_used, $qc_hi_r, $qc_ip_r); # Query Cache +my $have_innodb_vals; +my ($ib_bp_used, $ib_bp_total, $ib_bp_read_ratio); +my ($relative_live, $relative_infiles); +my $real_uptime; +my (%stats_present, %stats_past); # For relative reports + +GetOptions ( + \%op, + "user=s", + "password:s", + "host=s", + "port=s", + "socket=s", + "no-mycnf", + "infile|in=s", + "outfile=s", + "flush-status", + "email=s", + "r|relative:i", + "c|report-count=i", + "detach", + "help|?", + "debug" +); + +show_help_and_exit() if $op{'help'}; + +get_user_mycnf() unless $op{'no-mycnf'}; + +# Command line options override ~/.my.cnf +$mycnf{'host'} = $op{'host'} if have_op 'host'; +$mycnf{'port'} = $op{'port'} if have_op 'port'; +$mycnf{'socket'} = $op{'socket'} if have_op 'socket'; +$mycnf{'user'} = $op{'user'} if have_op 'user'; + +$mycnf{'user'} ||= $ENV{'USER'}; + +if(exists $op{'password'}) +{ + if($op{'password'} eq '') # Prompt for password + { + Term::ReadKey::ReadMode(2) if $RK; + print "Password for database user $mycnf{'user'}: "; + chomp($mycnf{'pass'} = ); + 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 + +if(defined $op{'r'}) +{ + if($op{r}) { $relative_live = 1; } + else { $relative_infiles = 1; } +} + +# The report is written to a tmp file first. +# Later it will be moved to $op{'outfile'} or emailed $op{'email'} if needed. +($tmpfile_fh, $tmpfile) = tempfile() or die("Cannot open temporary file for writing: $!\n"); + +if($op{'detach'}) +{ + $SIG{'TERM'} = 'sig_handler'; + + if(fork()) + { + print "mysqlreport has forked and detached.\n"; + print "While running detached, mysqlreport writes reports to '$tmpfile'.\n"; + + exit; + } + + open(STDIN, " $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); + +# Connect to MySQL +if(!$op{'infile'} && !$relative_infiles) +{ + my $dsn; + + if($mycnf{'socket'} && -S $mycnf{'socket'}) + { + $dsn = "DBI:mysql:mysql_socket=$mycnf{socket}"; + } + elsif($mycnf{'host'}) + { + $dsn = "DBI:mysql:host=$mycnf{host}" . ($mycnf{port} ? ";port=$mycnf{port}" : ""); + } + else + { + $dsn = "DBI:mysql:host=localhost"; + } + + if($op{debug}) + { + print "DBI DSN: $dsn\n"; + } + + $dbh = DBI->connect($dsn, $mycnf{'user'}, $mycnf{'pass'}) or die; +} + +$have_innodb_vals = 1; # This might be set to 0 later in get_MySQL_version() + +if(defined $op{'r'}) +{ + if($relative_live) + { + print STDERR "mysqlreport is writing relative reports to '$tmpfile'.\n" unless $op{'detach'}; + get_MySQL_version(); + collect_reports(); + } + + if($relative_infiles) { read_relative_infiles(); } +} +else +{ + if(!$op{'infile'}) + { + get_MySQL_version(); + get_vals(); + get_vars(); + } + else + { + read_infile($op{'infile'}); + } + + get_Com_values(); + + set_myisam_vals(); + set_ib_vals() if $have_innodb_vals; + + write_report(); +} + +exit_tasks_and_cleanup(); + +exit; + +# +# Subroutines +# +sub show_help_and_exit +{ + print <<"HELP"; +mysqlreport v3.4a Jan 23 2008 +mysqlreport makes an easy-to-read report of important MySQL status values. + +Command line options (abbreviations work): + --user USER Connect to MySQL as USER + --password PASS Use PASS or prompt for MySQL user's password + --host ADDRESS Connect to MySQL at ADDRESS + --port PORT Connect to MySQL at PORT + --socket SOCKET Connect to MySQL at SOCKET + --no-mycnf Don't read ~/.my.cnf + --infile FILE Read status values from FILE instead of MySQL + --outfile FILE Write report to FILE + --email ADDRESS Email report to ADDRESS (doesn't work on Windows) + --flush-status Issue FLUSH STATUS; after getting current values + --relative X Generate relative reports. If X is an integer, + reports are live from the MySQL server X seconds apart. + If X is a list of infiles (file1 file2 etc.), + reports are generated from the infiles in the order + that they are given. + --report-count N Collect N number of live relative reports (default 1) + --detach Fork and detach from terminal (run in background) + --help Prints this + --debug Print debugging information + +Visit http://hackmysql.com/mysqlreport for more information. +HELP + + exit; +} + +sub get_user_mycnf +{ + return if $WIN; + open MYCNF, "$ENV{HOME}/.my.cnf" or return; + while() + { + 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 collect_reports +{ + my $i; + + get_vals(); + get_vars(); + + get_Com_values(); + + %stats_past = %stats; + + set_myisam_vals(); + set_ib_vals() if $have_innodb_vals; + + print "#\n# Beginning report, 0 0:0:0\n#\n"; + + write_report(); + + for($i = 0; $i < $op{'c'}; $i++) + { + sleep($op{'r'}); + + 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 +{ + 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 $/; }; + 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'\n" if $op{debug}; + } + + $i = 0; + $stat_n = 0; + + select $tmpfile_fh[$i]; + + # Read infile again and copy each set of status values + # to seperate tmp files + open INFILE, "< $infile" or warn and next; + while() + { + next if /^\+/; + next if /^$/; + + print; + + if(/Aborted_clients/) + { + # The infile should begin with manually inserted system + # var values (like key_buffer_size = 128M). Therefore, + # the first occurance of /Aborted_clients/ indicates + # the first set of status values only if no sets have + # occured yet ($stat_n = 0). In this case, the following + # status values are printed to the current fh along with + # the system var values read so far until /Aborted_clients/ + # occurs again. Then begins the second and subsequent sets + # of status values. + next if $stat_n++ == 0; + + select $tmpfile_fh[++$i]; + } + } + 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]; + + 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 tmp file '$tmpfile_name[$i]'\n" + if $op{debug}; + } + + } # if($n_stats > 1) + } # foreach $infile (@files) +} + +sub relative_infile_report +{ + my $report_n = shift; + + if($report_n == 1) + { + get_Com_values(); + + %stats_past = %stats; + + set_myisam_vals(); + set_ib_vals() if $have_innodb_vals; + + print "#\n# Beginning report, 0 0:0:0\n#\n"; + + write_report(); + } + else + { + print "\n#\n# Interval report ", $report_n - 1, ", +", + sec_to_dhms($stats{Uptime} - $stats_past{Uptime}), + "\n#\n"; + + write_relative_report(); + } +} + +sub get_vals +{ + my @row; + + # Get status values + if($major >= 5 && (($minor == 0 && $patch >= 2) || $minor > 0)) + { + $query = $dbh->prepare("SHOW GLOBAL STATUS;"); + } + else + { + $query = $dbh->prepare("SHOW STATUS;"); + } + $query->execute(); + while(@row = $query->fetchrow_array()) { $stats{$row[0]} = $row[1]; } + + $real_uptime = $stats{'Uptime'}; +} + +sub get_vars +{ + my @row; + + # Get server system variables + $query = $dbh->prepare("SHOW VARIABLES;"); + $query->execute(); + while(@row = $query->fetchrow_array()) { $vars{$row[0]} = $row[1]; } + + # table_cache was renamed to table_open_cache in MySQL 5.1.3 + if($major >= 5 && (($minor == 1 && $patch >= 3) || $minor > 1)) + { + $vars{'table_cache'} = $vars{'table_open_cache'}; + } +} + +sub read_infile +{ + my $infile = shift; + + # Default values if not set in INFILE + $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 their infile if needed. + + open INFILE, "< $infile" or warn; + while() + { + next if /^\+\-/; + next if /^$/; + + chomp; + + if(/([A-Za-z_]+)[\s\t|]+(\d+)/) + { + $stats{$1} = $2; + next; + } + + # Explicit var = val (e.g. key_buffer_size = 128M) + if( /^\s*(\w+)\s*=\s*([0-9.]+)(M*)\s*$/ ) + { + $vars{$1} = ($3 ? $2 * 1024 * 1024 : $2); + print "read_infile: read '$_' as $1 = $vars{$1}\n" if $op{debug}; + next; + } + 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 +{ + return if $major; + + if($op{'infile'} || $relative_infiles) + { + ($major, $minor, $patch) = ($vars{'version'} =~ /(\d{1,2})\.(\d{1,2})\.(\d{1,2})/); + } + else + { + my @row; + + $query = $dbh->prepare("SHOW VARIABLES LIKE 'version';"); + $query->execute(); + @row = $query->fetchrow_array(); + ($major, $minor, $patch) = ($row[1] =~ /(\d{1,2})\.(\d{1,2})\.(\d{1,2})/); + } + + # Innodb_ status values were added in 5.0.2 + if($major <= 4 || $patch < 2) + { + $have_innodb_vals = 0; + print "get_MySQL_version: no InnoDB reports because MySQL version is older than 5.0.2\n" if $op{debug}; + } +} + +sub set_myisam_vals +{ + $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 = "($vars{long_query_time})"; + +} + +sub set_ib_vals +{ + $ib_bp_used = ($stats{'Innodb_buffer_pool_pages_total'} - + $stats{'Innodb_buffer_pool_pages_free'}) * + $stats{'Innodb_page_size'}; + + $ib_bp_total = $stats{'Innodb_buffer_pool_pages_total'} * $stats{'Innodb_page_size'}; + + $ib_bp_read_ratio = sprintf "%.2f", + ($stats{'Innodb_buffer_pool_read_requests'} ? + 100 - ($stats{'Innodb_buffer_pool_reads'} / + $stats{'Innodb_buffer_pool_read_requests'}) * 100 : + 0); +} + +sub write_relative_report +{ + %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((($minor == 0 && $patch >= 3) || $minor > 0)) + { + $stats{'Innodb_row_lock_current_waits'} = $stats_present{'Innodb_row_lock_current_waits'}; + $stats{'Innodb_row_lock_time_avg'} = $stats_present{'Innodb_row_lock_time_avg'}; + $stats{'Innodb_row_lock_time_max'} = $stats_present{'Innodb_row_lock_time_max'}; + } + } + + get_Com_values(); + + %stats_past = %stats_present; + + set_myisam_vals(); + set_ib_vals() if $have_innodb_vals; + + write_report(); +} + +sub write_report +{ + $~ = 'MYSQL_TIME', write; + $~ = 'KEY_BUFF_MAX', write; + if($key_buffer_usage != -1) { $~ = 'KEY_BUFF_USAGE', write } + $~ = 'KEY_RATIOS', write; + write_DTQ(); + $~ = 'SLOW_DMS', write; + write_DMS(); + write_Com(); + $~ = 'SAS', write; + write_qcache(); + $~ = 'REPORT_END', write; + $~ = 'TAB', write; + + write_InnoDB() if $have_innodb_vals; +} + +sub sec_to_dhms # Seconds to days hours:minutes:seconds +{ + my $s = shift; + my ($d, $h, $m) = (0, 0, 0); + + return '0 0:0:0' if $s <= 0; + + if($s >= 86400) + { + $d = int $s / 86400; + $s -= $d * 86400; + } + + if($s >= 3600) + { + $h = int $s / 3600; + $s -= $h * 3600; + } + + $m = int $s / 60; + $s -= $m * 60; + + return "$d $h:$m:$s"; +} + +sub make_short +{ + my ($number, $kb, $d) = @_; + my $n = 0; + my $short; + + $d ||= 2; + + if($kb) { while ($number > 1023) { $number /= 1024; $n++; }; } + else { while ($number > 999) { $number /= 1000; $n++; }; } + + $short = sprintf "%.${d}f%s", $number, ('','k','M','G','T')[$n]; + if($short =~ /^(.+)\.(00)$/) { return $1; } # 12.00 -> 12 but not 12.00k -> 12k + + return $short; +} + +sub perc # Percentage +{ + my($is, $of) = @_; + 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'} +{ + return if $WIN; + + my $report = shift; + + open SENDMAIL, "|/usr/sbin/sendmail -t"; + print SENDMAIL "From: mysqlreport\n"; + print SENDMAIL "To: $op{email}\n"; + print SENDMAIL "Subject: MySQL status report on " . ($mycnf{'host'} || 'localhost') . "\n\n"; + print SENDMAIL `cat $report`; + close SENDMAIL; +} + +sub cat_report # Print given report to screen +{ + my $report = shift; + my @report; + + open REPORT, "< $report"; + @report = ; + close REPORT; + print @report; +} + +sub get_Com_values +{ + %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 +{ + $~ = '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 +{ + $~ = '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 +{ + 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 +{ + # Query cache was added in 4.0.1, but have_query_cache was added in 4.0.2, + # ergo this method is slightly more reliable + return if not exists $vars{'query_cache_size'}; + return if $vars{'query_cache_size'} == 0; + + $qc_mem_used = $vars{'query_cache_size'} - $stats{'Qcache_free_memory'}; + $qc_hi_r = sprintf "%.2f", $stats{'Qcache_hits'} / ($stats{'Qcache_inserts'} ||= 1); + $qc_ip_r = sprintf "%.2f", $stats{'Qcache_inserts'} / ($stats{'Qcache_lowmem_prunes'} ||= 1); + + $~ = 'QCACHE'; + write; +} + +sub write_InnoDB +{ + # Innodb_ status values were added in MySQL 5.0.2 + if(! ($major >= 5 && (($minor == 0 && $patch >= 2) || $minor > 0)) ) + { + # In case infile has Innodb_ values but didn't specify the MySQL version + if(not defined $stats{'Innodb_page_size'}) { return; } + } + + $~ = 'IB'; + write; + + # Innodb_row_lock_ values were added in MySQL 5.0.3 + if((($minor == 0 && $patch >= 3) || $minor > 0)) + { + $~ = 'IB_LOCK'; + write; + } + + # Data, Pages, Rows + $~ = 'IB_DPR'; + write; +} + +sub have_op +{ + my $key = shift; + return 1 if (exists $op{$key} && $op{$key} ne ''); + return 0; +} + +sub sig_handler +{ + print "\nReceived signal at " , scalar localtime , "\n"; + exit_tasks_and_cleanup(); + exit; +} + +sub exit_tasks_and_cleanup +{ + close $tmpfile_fh; + select STDOUT unless $op{'detach'}; + + email_report($tmpfile) if $op{'email'}; + + cat_report($tmpfile) unless $op{'detach'}; + + if($op{'outfile'}) + { + if($WIN) { `move $tmpfile $op{outfile}`; } + else { `mv $tmpfile $op{outfile}`; } + } + else + { + if($WIN) { `del $tmpfile`; } + else { `rm -f $tmpfile`; } + } + + if(!$op{'infile'} && !$relative_infiles) + { + if($op{'flush-status'}) + { + $query = $dbh->prepare("FLUSH STATUS;"); + $query->execute(); + } + + $query->finish(); + $dbh->disconnect(); + } +} + +# +# Formats +# + +format MYSQL_TIME = +MySQL @<<<<<<<<<<<<<<<< uptime @<<<<<<<<<<< @>>>>>>>>>>>>>>>>>>>>>>>> +$vars{'version'}, sec_to_dhms($real_uptime), (($op{infile} || $relative_infiles) ? '' : scalar localtime) +. + +format KEY_BUFF_MAX = + +__ Key _________________________________________________________________ +Buffer used @>>>>>> of @>>>>>> %Used: @>>>>> +make_short($key_buffer_used, 1), make_short($vars{'key_buffer_size'}, 1), perc($key_buffer_used, $vars{'key_buffer_size'}) +. + +format KEY_BUFF_USAGE = + Current @>>>>>> %Usage: @>>>>> +make_short($key_buffer_usage, 1), perc($key_buffer_usage, $vars{'key_buffer_size'}) +. + +format KEY_RATIOS = +Write hit @>>>>>% +$key_write_ratio +Read hit @>>>>>% +$key_read_ratio + +__ Questions ___________________________________________________________ +Total @>>>>>>>> @>>>>>/s +make_short($questions), t($questions) +. + +format DTQ = + @<<<<<<< @>>>>>>>> @>>>>>/s @>>>>>> @>>>>> +$stat_name, make_short($stat_val), t($stat_val), $stat_label, perc($stat_val, $questions) +. + +format SLOW_DMS = +Slow @<<<<< @>>>>>>>> @>>>>>/s @>>>>> %DMS: @>>>>> Log: @>> +$slow_query_t, make_short($stats{'Slow_queries'}), t($stats{'Slow_queries'}), perc($stats{'Slow_queries'}, $questions), perc($stats{'Slow_queries'}, $dms), $vars{'log_slow_queries'} +DMS @>>>>>>>> @>>>>>/s @>>>>> +make_short($dms), t($dms), perc($dms, $questions) +. + +format DMS = + @<<<<<<< @>>>>>>>> @>>>>>/s @>>>>> @>>>>> +$stat_name, make_short($stat_val), t($stat_val), perc($stat_val, $questions), perc($stat_val, $dms) +. + +format COM_1 = +Com_ @>>>>>>>> @>>>>>/s @>>>>> +make_short($stat_val), t($stat_val), perc($stat_val, $questions) +. + +format COM_2 = + @<<<<<<<<<< @>>>>>> @>>>>>/s @>>>>> +$stat_name, make_short($stat_val), t($stat_val), perc($stat_val, $questions) +. + +format SAS = + +__ SELECT and Sort _____________________________________________________ +Scan @>>>>>> @>>>>/s %SELECT: @>>>>> +make_short($stats{'Select_scan'}), t($stats{'Select_scan'}), perc($stats{'Select_scan'}, $stats{'Com_select'}) +Range @>>>>>> @>>>>/s @>>>>> +make_short($stats{'Select_range'}), t($stats{'Select_range'}), perc($stats{'Select_range'}, $stats{'Com_select'}) +Full join @>>>>>> @>>>>/s @>>>>> +make_short($stats{'Select_full_join'}), t($stats{'Select_full_join'}), perc($stats{'Select_full_join'}, $stats{'Com_select'}) +Range check @>>>>>> @>>>>/s @>>>>> +make_short($stats{'Select_range_check'}), t($stats{'Select_range_check'}), perc($stats{'Select_range_check'}, $stats{'Com_select'}) +Full rng join @>>>>>> @>>>>/s @>>>>> +make_short($stats{'Select_full_range_join'}), t($stats{'Select_full_range_join'}), perc($stats{'Select_full_range_join'}, $stats{'Com_select'}) +Sort scan @>>>>>> @>>>>/s +make_short($stats{'Sort_scan'}), t($stats{'Sort_scan'}) +Sort range @>>>>>> @>>>>/s +make_short($stats{'Sort_range'}), t($stats{'Sort_range'}) +Sort mrg pass @>>>>>> @>>>>/s +make_short($stats{'Sort_merge_passes'}), t($stats{'Sort_merge_passes'}) +. + +format QCACHE = + +__ Query Cache _________________________________________________________ +Memory usage @>>>>>> of @>>>>>> %Used: @>>>>> +make_short($qc_mem_used, 1), make_short($vars{'query_cache_size'}, 1), perc($qc_mem_used, $vars{'query_cache_size'}) +Block Fragmnt @>>>>>% +perc($stats{'Qcache_free_blocks'}, $stats{'Qcache_total_blocks'}) +Hits @>>>>>> @>>>>/s +make_short($stats{'Qcache_hits'}), t($stats{'Qcache_hits'}) +Inserts @>>>>>> @>>>>/s +make_short($stats{'Qcache_inserts'}), t($stats{'Qcache_inserts'}) +Insrt:Prune @>>>>>>:1 @>>>>/s +make_short($qc_ip_r), t($stats{'Qcache_inserts'} - $stats{'Qcache_lowmem_prunes'}) +Hit:Insert @>>>>>>:1 +$qc_hi_r, t($qc_hi_r) +. + +# Not really the end... +format REPORT_END = + +__ Table Locks _________________________________________________________ +Waited @>>>>>>>> @>>>>>/s %Total: @>>>>> +make_short($stats{'Table_locks_waited'}), t($stats{'Table_locks_waited'}), perc($stats{'Table_locks_waited'}, $stats{'Table_locks_waited'} + $stats{'Table_locks_immediate'}); +Immediate @>>>>>>>> @>>>>>/s +make_short($stats{'Table_locks_immediate'}), t($stats{'Table_locks_immediate'}) + +__ Tables ______________________________________________________________ +Open @>>>>>>>> of @>>> %Cache: @>>>>> +$stats{'Open_tables'}, $vars{'table_cache'}, perc($stats{'Open_tables'}, $vars{'table_cache'}) +Opened @>>>>>>>> @>>>>>/s +make_short($stats{'Opened_tables'}), t($stats{'Opened_tables'}) + +__ Connections _________________________________________________________ +Max used @>>>>>>>> of @>>> %Max: @>>>>> +$stats{'Max_used_connections'}, $vars{'max_connections'}, perc($stats{'Max_used_connections'}, $vars{'max_connections'}) +Total @>>>>>>>> @>>>>>/s +make_short($stats{'Connections'}), t($stats{'Connections'}) + +__ Created Temp ________________________________________________________ +Disk table @>>>>>>>> @>>>>>/s +make_short($stats{'Created_tmp_disk_tables'}), t($stats{'Created_tmp_disk_tables'}) +Table @>>>>>>>> @>>>>>/s Size: @>>>>> +make_short($stats{'Created_tmp_tables'}), t($stats{'Created_tmp_tables'}), make_short($vars{'tmp_table_size'}, 1, 1) +File @>>>>>>>> @>>>>>/s +make_short($stats{'Created_tmp_files'}), t($stats{'Created_tmp_files'}) +. + +format TAB = + +__ Threads _____________________________________________________________ +Running @>>>>>>>> of @>>> +$stats{'Threads_running'}, $stats{'Threads_connected'} +Cached @>>>>>>>> of @>>> %Hit: @>>>>> +$stats{'Threads_cached'}, $vars{'thread_cache_size'}, make_short(100 - perc($stats{'Threads_created'}, $stats{'Connections'})) +Created @>>>>>>>> @>>>>>/s +make_short($stats{'Threads_created'}), t($stats{'Threads_created'}) +Slow @>>>>>>>> @>>>>>/s +$stats{'Slow_launch_threads'}, t($stats{'Slow_launch_threads'}) + +__ Aborted _____________________________________________________________ +Clients @>>>>>>>> @>>>>>/s +make_short($stats{'Aborted_clients'}), t($stats{'Aborted_clients'}) +Connects @>>>>>>>> @>>>>>/s +make_short($stats{'Aborted_connects'}), t($stats{'Aborted_connects'}) + +__ Bytes _______________________________________________________________ +Sent @>>>>>>>> @>>>>>/s +make_short($stats{'Bytes_sent'}), t($stats{'Bytes_sent'}) +Received @>>>>>>>> @>>>>>/s +make_short($stats{'Bytes_received'}), t($stats{'Bytes_received'}) +. + +format IB = + +__ InnoDB Buffer Pool __________________________________________________ +Usage @>>>>>> of @>>>>>> %Used: @>>>>> +make_short($ib_bp_used, 1), make_short($ib_bp_total, 1), perc($ib_bp_used, $ib_bp_total) +Read hit @>>>>>% +$ib_bp_read_ratio; +Pages + Free @>>>>>>>> %Total: @>>>>> +make_short($stats{'Innodb_buffer_pool_pages_free'}), perc($stats{'Innodb_buffer_pool_pages_free'}, $stats{'Innodb_buffer_pool_pages_total'}) + Data @>>>>>>>> @>>>>> %Drty: @>>>>> +make_short($stats{'Innodb_buffer_pool_pages_data'}), perc($stats{'Innodb_buffer_pool_pages_data'}, $stats{'Innodb_buffer_pool_pages_total'}), perc($stats{'Innodb_buffer_pool_pages_dirty'}, $stats{'Innodb_buffer_pool_pages_data'}) + Misc @>>>>>>>> @>>>>> + $stats{'Innodb_buffer_pool_pages_misc'}, perc($stats{'Innodb_buffer_pool_pages_misc'}, $stats{'Innodb_buffer_pool_pages_total'}) + Latched @>>>>>>>> @>>>>> +$stats{'Innodb_buffer_pool_pages_latched'}, perc($stats{'Innodb_buffer_pool_pages_latched'}, $stats{'Innodb_buffer_pool_pages_total'}) +Reads @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_buffer_pool_read_requests'}), t($stats{'Innodb_buffer_pool_read_requests'}) + From file @>>>>>>>> @>>>>>/s @>>>>> +make_short($stats{'Innodb_buffer_pool_reads'}), t($stats{'Innodb_buffer_pool_reads'}), perc($stats{'Innodb_buffer_pool_reads'}, $stats{'Innodb_buffer_pool_read_requests'}) + Ahead Rnd @>>>>>>>> @>>>>>/s +$stats{'Innodb_buffer_pool_read_ahead_rnd'}, t($stats{'Innodb_buffer_pool_read_ahead_rnd'}) + Ahead Sql @>>>>>>>> @>>>>>/s +$stats{'Innodb_buffer_pool_read_ahead_seq'}, t($stats{'Innodb_buffer_pool_read_ahead_seq'}) +Writes @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_buffer_pool_write_requests'}), t($stats{'Innodb_buffer_pool_write_requests'}) +Flushes @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_buffer_pool_pages_flushed'}), t($stats{'Innodb_buffer_pool_pages_flushed'}) +Wait Free @>>>>>>>> @>>>>>/s +$stats{'Innodb_buffer_pool_wait_free'}, t($stats{'Innodb_buffer_pool_wait_free'}) +. + +format IB_LOCK = + +__ InnoDB Lock _________________________________________________________ +Waits @>>>>>>>> @>>>>>/s +$stats{'Innodb_row_lock_waits'}, t($stats{'Innodb_row_lock_waits'}) +Current @>>>>>>>> +$stats{'Innodb_row_lock_current_waits'} +Time acquiring + Total @>>>>>>>> ms +$stats{'Innodb_row_lock_time'} + Average @>>>>>>>> ms +$stats{'Innodb_row_lock_time_avg'} + Max @>>>>>>>> ms +$stats{'Innodb_row_lock_time_max'} +. + +format IB_DPR = + +__ InnoDB Data, Pages, Rows ____________________________________________ +Data + Reads @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_data_reads'}), t($stats{'Innodb_data_reads'}) + Writes @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_data_writes'}), t($stats{'Innodb_data_writes'}) + fsync @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_data_fsyncs'}), t($stats{'Innodb_data_fsyncs'}) + Pending + Reads @>>>>>>>> +$stats{'Innodb_data_pending_reads'}, t($stats{'Innodb_data_pending_reads'}) + Writes @>>>>>>>> +$stats{'Innodb_data_pending_writes'}, t($stats{'Innodb_data_pending_writes'}) + fsync @>>>>>>>> +$stats{'Innodb_data_pending_fsyncs'}, t($stats{'Innodb_data_pending_fsyncs'}) + +Pages + Created @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_pages_created'}), t($stats{'Innodb_pages_created'}) + Read @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_pages_read'}), t($stats{'Innodb_pages_read'}) + Written @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_pages_written'}), t($stats{'Innodb_pages_written'}) + +Rows + Deleted @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_rows_deleted'}), t($stats{'Innodb_rows_deleted'}) + Inserted @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_rows_inserted'}), t($stats{'Innodb_rows_inserted'}) + Read @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_rows_read'}), t($stats{'Innodb_rows_read'}) + Updated @>>>>>>>> @>>>>>/s +make_short($stats{'Innodb_rows_updated'}), t($stats{'Innodb_rows_updated'}) +. --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/mysqlreport/mysqlreport.1 +++ mysql-dfsg-5.0-5.0.51a/debian/additions/mysqlreport/mysqlreport.1 @@ -0,0 +1,180 @@ +.TH "mysqlreport" "1" "2.5 2006-09-01 (docrev 2006-05-19)" "Daniel Nichter" "MYSQL" +.SH "NAME" +.LP +mysqlreport \- Makes a friendly report of important MySQL status values +.SH "SYNTAX" +.LP +mysqlreport [\fIoptions\fP] +.SH "DESCRIPTION" +.LP +mysqlreport makes a friendly report of important MySQL status values. Actually, +it makes a friendly report of nearly every status value from SHOW STATUS. +Unlike SHOW STATUS which simply dumps over 100 values to screen in one long +list, mysqlreport interprets and formats the values and presents the basic +values and many more inferred values in a human\-readable format. Numerous +example reports are available at the mysqlreport web page at +http://hackmysql.com/mysqlreport. + +The benefit of mysqlreport is that it allows you to very quickly see a wide +array of performance indicators for your MySQL server which would otherwise +need to be calculated by hand from all the various SHOW STATUS values. For +example, the Index Read Ratio is an important value but it's not present in +SHOW STATUS; it's an inferred value (the ratio of Key_reads to +Key_read_requests). + +This documentation outlines all the command line options in mysqlreport, most +of which control which reports are printed. This document does not address +how to interpret these reports; that topic is covered in the document Guide +To Understanding mysqlreport at http://hackmysql.com/mysqlreportguide. + +.SH "OPTIONS" +Technically, command line options are in the form \-\-option, but \-option works +too. All options can be abbreviated if the abbreviation is unique. For example, +option \-\-host can be abbreviated \-\-ho but not \-\-h because \-\-h is ambiguous: it +could mean \-\-host or \-\-help. + +.LP + +.TP +\fB\-\-help\fR +Output help information and exit. + +.TP +\fB\-\-user USER\fR + +.TP +\fB\-\-password\fR +As of version 2.3 \-\-password can take the password on the +command line like "\-\-password FOO". Using \-\-password +alone without giving a password on the command line +causes mysqlreport to prompt for a password. + +.TP +\fB\-\-host ADDRESS\fR + +.TP +\fB\-\-port PORT\fR + +.TP +\fB\-\-socket SOCKET\fR + +.TP +\fB\-\-no\-mycnf\fR +\-\-no\-mycnf makes mysqlreport not read ~/.my.cnf which it does by default +otherwise. \-\-user and \-\-password always override values from ~/.my.cnf. + +.TP +\fB\-\-dtq\fR +Print Distribution of Total Queries (DTQ) report (under +Total in Questions report). Queries (or Questions) can +be divided into four main areas: DMS (see \-\-dms below), +Com_ (see \-\-com below), COM_QUIT (see COM_QUIT and +Questions at http://hackmysql.com/com_quit), and +Unknown. \-\-dtq lists the number of queries in each of +these areas in descending order. + +.TP +\fB\-\-dms\fR +Print Data Manipulation Statements (DMS) report (under +DMS in Questions report). DMS are those from the MySQL +manual section 13.2. Data Manipulation Statements. +(Currently, mysqlreport considers only SELECT, INSERT, +REPLACE, UPDATE, and DELETE.) Each DMS is listed in +descending order by count. + +.TP +\fB\-\-com N\fR +Print top N number of non\-DMS Com_ status values in +descending order (after DMS in Questions report). If N +is not given, default is 3. Such non\-DMS Com_ values +include Com_change_db, Com_show_tables, Com_rollback, +etc. + +.TP +\fB\-\-sas\fR +Print report for Select_ and Sort_ status values (after +Questions report). See MySQL Select and Sort Status +Variables at http://hackmysql.com/selectandsort. + +.TP +\fB\-\-tab\fR +Print Threads, Aborted, and Bytes status reports (after +Created temp report). As of mysqlreport v2.3 the +Threads report reports on all Threads_ status values. + +.TP +\fB\-\-qcache\fR +Print Query Cache report. +.TP +\fB\-\-all\fR +Equivalent to "\-\-dtq \-\-dms \-\-com 3 \-\-sas \-\-qcache". +(Notice \-\-tab is not invoked by \-\-all.) + +.TP +\fB\-\-infile FILE\fR +Instead of getting SHOW STATUS values from MySQL, read +values from FILE. FILE is often a copy of the output of +SHOW STATUS including formatting characters (|, +, \-). +mysqlreport expects FILE to have the format +" value number " where value is only alpha and +underscore characters (A\-Z and _) and number is a +positive integer. Anything before, between, or after +value and number is ignored. mysqlreport also needs +the following MySQL server variables: version, +table_cache, max_connections, key_buffer_size, +query_cache_size. These values can be specified in +INFILE in the format "name = value" where name is one +of the aforementioned server variables and value is a +positive integer with or without a trailing M and +possible periods (for version). For example, to specify +an 18M key_buffer_size: key_buffer_size = 18M. Or, a +256 table_cache: table_cache = 256. The M implies +Megabytes not million, so 18M means 18,874,368 not +18,000,000. If these server variables are not specified +the following defaults are used (respectively) which +may cause strange values to be reported: 0.0.0, 64, +100, 8M, 0. + +.TP +\fB\-\-outfile FILE\fR +After printing the report to screen, print the report +to FILE too. Internally, mysqlreport always writes the +report to a temp file first: /tmp/mysqlreport.PID on +*nix, c:\mysqlreport.PID on Windows (PID is the +script's process ID). Then it prints the temp file to +screen. Then if \-\-outfile is specified, the temp file +is copied to OUTFILE. After \-\-email (below), the temp +file is deleted. + +.TP +\fB\-\-email ADDRESS\fR +After printing the report to screen, email the report +to ADDRESS. This option requires sendmail in +/usr/sbin/, therefore it does not work on Windows. +/usr/sbin/sendmail can be a sym link to qmail, for +example, or any MTA that emulates sendmail's \-t +command line option and operation. The FROM: field is +"mysqlreport", SUBJECT: is "MySQL status report". + +.TP +\fB\-\-flush\-status\fR +Execute a "FLUSH STATUS;" after generating the reports. +If you do not have permissions in MySQL to do this an +error from DBD::mysql::st will be printed after the +reports. + +.SH "AUTHORS" +.LP +Daniel Nichter + +If mysqlreport breaks, send me a message from +http://hackmysql.com/feedback +with the error. + +.SH "SEE ALSO" +.LP +mytop(1) +.LP +The comprehensive Guide To Understanding mysqlreport at +http://hackmysql.com/mysqlreportguide. + --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/manpages/mysqlbug.1 +++ mysql-dfsg-5.0-5.0.51a/debian/additions/manpages/mysqlbug.1 @@ -0,0 +1,14 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysqlbug \- MySQL bug reporting tool. +.SH SYNOPSIS +mysqlbug [options] +.SH DESCRIPTION +Interactive bug reporting tool. Use reportbug on Debian systems. +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers . + +MySQL is available at http://www.mysql.com/. +.\" end of man page --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/manpages/mysqldumpslow.1 +++ mysql-dfsg-5.0-5.0.51a/debian/additions/manpages/mysqldumpslow.1 @@ -0,0 +1,50 @@ +.TH mysql 1 "17 March 2003" "MySQL 3.23" "MySQL database" +.SH NAME +mysqldumpslow \- Parse and summarize the MySQL slow query log. +.SH SYNOPSIS +mysqldumpslow [options] +.SH DESCRIPTION +This program parses and summarizes a 'slow query log'. + +.TP +\fB\-v\fR +verbose +.TP +\fB\-d\fR +debug +.TP +\fB\-s=WORD\fR +what to sort by (t, at, l, al, r, ar etc) +.TP +\fB\-r\fR +reverse the sort order (largest last instead of first) +.TP +\fB\-t=NUMBER\fR +just show the top n queries +.TP +\fB\-a\fR +don't abstract all numbers to N and strings to 'S' +.TP +\fB\-n=NUMBER\fR +abstract numbers with at least n digits within names +.TP +\fB\-g=WORD\fR +grep: only consider stmts that include this string +.TP +\fB\-h=WORD\fR +hostname of db server for *-slow.log filename (can be wildcard) +.TP +\fB\-i=WORD\fR +name of server instance (if using mysql.server startup script) +.TP +\fB\-l\fR +don't subtract lock time from total time + +.SH "SEE ALSO" +mysql (1), mysqld (1) +.SH AUTHOR +This manpage was written by Christian Hammers based on +the commends in the code. + +MySQL is available at http://www.mysql.com/. +.\" end of man page --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/Docs__Makefile.in +++ mysql-dfsg-5.0-5.0.51a/debian/additions/Docs__Makefile.in @@ -0,0 +1,6 @@ +all: + +distclean: + -rm -f Makefile + +.PHONY: all distclean clean install check --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/mysql-server.lintian-overrides +++ mysql-dfsg-5.0-5.0.51a/debian/additions/mysql-server.lintian-overrides @@ -0,0 +1,2 @@ +W: mysql-dfsg source: maintainer-script-lacks-debhelper-token debian/mysql-server.postinst +W: mysql-server: possible-bashism-in-maintainer-script postinst:68 'p{("a".."z","A".."Z",0..9)[int(rand(62))]}' --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/ndb_mgmd.cnf +++ mysql-dfsg-5.0-5.0.51a/debian/additions/ndb_mgmd.cnf @@ -0,0 +1,35 @@ +[NDBD DEFAULT] +NoOfReplicas=2 +DataMemory=10MB +IndexMemory=25MB +MaxNoOfTables=256 +MaxNoOfOrderedIndexes=256 +MaxNoOfUniqueHashIndexes=128 + +[MYSQLD DEFAULT] + +[NDB_MGMD DEFAULT] + +[TCP DEFAULT] + +[NDB_MGMD] +Id=1 # the NDB Management Node (this one) +HostName=127.0.0.1 + +[NDBD] +Id=2 # the first NDB Data Node +HostName=127.0.0.1 +DataDir= /var/lib/mysql-cluster + +[NDBD] +Id=3 # the second NDB Data Node +HostName=127.0.0.1 +DataDir=/var/lib/mysql-cluster + +[MYSQLD] +Id=4 # the first SQL node +HostName=127.0.0.1 + +# [MYSQLD] +# Id=5 # the second SQL node +# HostName=127.0.0.10 --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/debian-start.inc.sh +++ mysql-dfsg-5.0-5.0.51a/debian/additions/debian-start.inc.sh @@ -0,0 +1,66 @@ +#!/bin/bash +# +# This file is included by /etc/mysql/debian-start +# + +## Check all unclosed tables. +# - Requires the server to be up. +# - Is supposed to run silently in background. +function check_for_crashed_tables() { + set -e + set -u + + # But do it in the background to not stall the boot process. + logger -p daemon.info -i -t$0 "Checking for crashed MySQL tables." + + # Checking for $? is unreliable so the size of the output is checked. + # Some table handlers like HEAP do not support CHECK TABLE. + tempfile=`tempfile` + LC_ALL=C $MYCHECK $MYCHECK_PARAMS \ + 2>&1 \ + | perl -e '$_=join("", <>); s/^[^\n]+\n(error|note)\s+: The (handler|storage engine) for the table doesn.t support check\n//smg;print;' \ + > $tempfile + if [ -s $tempfile ]; then + ( + /bin/echo -e "\n" \ + "Improperly closed tables are also reported if clients are accessing\n" \ + "the tables *now*. A list of current connections is below.\n"; + $MYADMIN processlist status + ) >> $tempfile + # Check for presence as a dependency on mailx would require an MTA. + if [ -x /usr/bin/mailx ]; then mailx -e -s"$MYCHECK_SUBJECT" $MYCHECK_RCPT < $tempfile; fi + (echo "$MYCHECK_SUBJECT"; cat $tempfile) | logger -p daemon.warn -i -t$0 + fi + rm $tempfile +} + +## Check for tables needing an upgrade. +# - Requires the server to be up. +# - Is supposed to run silently in background. +function upgrade_system_tables_if_necessary() { + set -e + set -u + + logger -p daemon.info -i -t$0 "Upgrading MySQL tables if necessary." + + # Filter all "duplicate column", "duplicate key" and "unknown column" + # errors as the script is designed to be idempotent. + LC_ALL=C $MYUPGRADE \ + 2>&1 \ + | egrep -v '^(1|@had|ERROR (1054|1060|1061))' \ + | logger -p daemon.warn -i -t$0 +} + +## Check for the presence of both, root accounts with and without password. +# This might have been caused by a bug related to mysql_install_db (#418672). +function check_root_accounts() { + set -e + set -u + + logger -p daemon.info -i -t$0 "Checking for insecure root accounts." + + ret=$( echo "SELECT count(*) FROM mysql.user WHERE user='root' and password='';" | $MYSQL --skip-column-names ) + if [ "$ret" -ne "0" ]; then + logger -p daemon.warn -i -t$0 "WARNING: mysql.user contains $ret root accounts without password!" + fi +} --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/my.cnf +++ mysql-dfsg-5.0-5.0.51a/debian/additions/my.cnf @@ -0,0 +1,147 @@ +# +# The MySQL database server configuration file. +# +# You can copy this to one of: +# - "/etc/mysql/my.cnf" to set global options, +# - "~/.my.cnf" to set user-specific options. +# +# One can use all long options that the program supports. +# Run program with --help to get a list of available options and with +# --print-defaults to see which it would actually understand and use. +# +# For explanations see +# http://dev.mysql.com/doc/mysql/en/server-system-variables.html + +# This will be passed to all mysql clients +# It has been reported that passwords should be enclosed with ticks/quotes +# escpecially if they contain "#" chars... +# Remember to edit /etc/mysql/debian.cnf when changing the socket location. +[client] +port = 3306 +socket = /var/run/mysqld/mysqld.sock + +# Here is entries for some specific programs +# The following values assume you have at least 32M ram + +# This was formally known as [safe_mysqld]. Both versions are currently parsed. +[mysqld_safe] +socket = /var/run/mysqld/mysqld.sock +nice = 0 + +[mysqld] +# +# * Basic Settings +# + +# +# * IMPORTANT +# If you make changes to these settings and your system uses apparmor, you may +# also need to also adjust /etc/apparmor.d/usr.sbin.mysqld. +# + +user = mysql +pid-file = /var/run/mysqld/mysqld.pid +socket = /var/run/mysqld/mysqld.sock +port = 3306 +basedir = /usr +datadir = /var/lib/mysql +tmpdir = /tmp +language = /usr/share/mysql/english +skip-external-locking +# +# Instead of skip-networking the default is now to listen only on +# localhost which is more compatible and is not less secure. +bind-address = 127.0.0.1 +# +# * Fine Tuning +# +key_buffer = 16M +max_allowed_packet = 16M +thread_stack = 128K +thread_cache_size = 8 +#max_connections = 100 +#table_cache = 64 +#thread_concurrency = 10 +# +# * Query Cache Configuration +# +query_cache_limit = 1M +query_cache_size = 16M +# +# * Logging and Replication +# +# Both location gets rotated by the cronjob. +# Be aware that this log type is a performance killer. +#log = /var/log/mysql/mysql.log +# +# Error logging goes to syslog. This is a Debian improvement :) +# +# Here you can see queries with especially long duration +#log_slow_queries = /var/log/mysql/mysql-slow.log +#long_query_time = 2 +#log-queries-not-using-indexes +# +# The following can be used as easy to replay backup logs or for replication. +# note: if you are setting up a replication slave, see README.Debian about +# other settings you may need to change. +#server-id = 1 +#log_bin = /var/log/mysql/mysql-bin.log +expire_logs_days = 10 +max_binlog_size = 100M +#binlog_do_db = include_database_name +#binlog_ignore_db = include_database_name +# +# * BerkeleyDB +# +# Using BerkeleyDB is now discouraged as its support will cease in 5.1.12. +skip-bdb +# +# * 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! +# You might want to disable InnoDB to shrink the mysqld process by circa 100MB. +#skip-innodb +# +# * Security Features +# +# Read the manual, too, if you want chroot! +# chroot = /var/lib/mysql/ +# +# For generating SSL certificates I recommend the OpenSSL GUI "tinyca". +# +# ssl-ca=/etc/mysql/cacert.pem +# ssl-cert=/etc/mysql/server-cert.pem +# ssl-key=/etc/mysql/server-key.pem + + + +[mysqldump] +quick +quote-names +max_allowed_packet = 16M + +[mysql] +#no-auto-rehash # faster start of mysql but no tab completition + +[isamchk] +key_buffer = 16M + +# +# * NDB Cluster +# +# See /usr/share/doc/mysql-server-*/README.Debian for more information. +# +# The following configuration is read by the NDB Data Nodes (ndbd processes) +# not from the NDB Management Nodes (ndb_mgmd processes). +# +# [MYSQL_CLUSTER] +# ndb-connectstring=127.0.0.1 + + +# +# * IMPORTANT: Additional settings that can override those from this file! +# The files must end with '.cnf', otherwise they'll be ignored. +# +!includedir /etc/mysql/conf.d/ + --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/Docs__Images__Makefile.in +++ mysql-dfsg-5.0-5.0.51a/debian/additions/Docs__Images__Makefile.in @@ -0,0 +1,6 @@ +all: + +distclean: + -rm -f Makefile + +.PHONY: all distclean clean install check --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/echo_stderr +++ mysql-dfsg-5.0-5.0.51a/debian/additions/echo_stderr @@ -0,0 +1,2 @@ +#!/bin/bash +echo "$*" 1>&2 --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/debian-start +++ mysql-dfsg-5.0-5.0.51a/debian/additions/debian-start @@ -0,0 +1,31 @@ +#!/bin/bash +# +# This script is executed by "/etc/init.d/mysql" on every (re)start. +# +# Changes to this file will be preserved when updating the Debian package. +# + +source /usr/share/mysql/debian-start.inc.sh + +MYSQL="/usr/bin/mysql --defaults-file=/etc/mysql/debian.cnf" +MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" +MYUPGRADE="/usr/bin/mysql_upgrade --defaults-extra-file=/etc/mysql/debian.cnf" +MYCHECK="/usr/bin/mysqlcheck --defaults-file=/etc/mysql/debian.cnf" +MYCHECK_SUBJECT="WARNING: mysqlcheck has found corrupt tables" +MYCHECK_PARAMS="--all-databases --fast --silent" +MYCHECK_RCPT="root" + +# The following commands should be run when the server is up but in background +# where they do not block the server start and in one shell instance so that +# they run sequentially. They are supposed not to echo anything to stdout. +# If you want to disable the check for crashed tables comment +# "check_for_crashed_tables" out. +# (There may be no output to stdout inside the background process!) +echo "Checking for corrupt, not cleanly closed and upgrade needing tables." +( + upgrade_system_tables_if_necessary; + check_root_accounts; + check_for_crashed_tables; +) >&2 & + +exit 0 --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/innotop/changelog.innotop +++ mysql-dfsg-5.0-5.0.51a/debian/additions/innotop/changelog.innotop @@ -0,0 +1,318 @@ +Changelog for innotop and InnoDBParser: + +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. --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/innotop/innotop.1 +++ mysql-dfsg-5.0-5.0.51a/debian/additions/innotop/innotop.1 @@ -0,0 +1,2086 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.if n .na +.\" +.\" 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 1p" +.TH INNOTOP 1p "2007-11-09" "perl v5.8.8" "User Contributed Perl Documentation" +.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 +.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"\s-1QUICK\-START\s0\*(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 +The first thing innotop needs to know is how to connect to a MySQL server. You +can just enter the hostname of the server, for example \*(L"localhost\*(R" or +\&\*(L"127.0.0.1\*(R" if the server is on the same machine as innotop. After this innotop +will prompt you for a \s-1DSN\s0 (data source name). You should be able to just accept +the defaults by pressing Enter. +.PP +When innotop asks you about a table to use when resetting InnoDB deadlock +information, just accept the default for now. This is an advanced feature you +can configure later (see \*(L"D: InnoDB Deadlocks\*(R" for more). +.PP +If you have a .my.cnf file with your MySQL connection defaults, innotop can read +it, and you won't need to specify a username and password if it's in that file. +Otherwise, you should answer 'y' to the next couple of prompts. +.PP +After this, you should be connected, and innotop should show you something like +the following: +.PP +.Vb 1 +\& InnoDB Txns (? for help) localhost, 01:11:19, InnoDB 10s :\-), 50 QPS, +.Ve +.PP +.Vb 2 +\& CXN History Versions Undo Dirty Buf Used Bufs Txns MaxTxn +\& localhost 7 2035 0 0 0.00% 92.19% 1 07:34 +.Ve +.PP +.Vb 5 +\& CXN ID User Host Txn Status Time Undo Query Tex +\& localhost 98379 user1 webserver ACTIVE 07:34 0 SELECT `c +\& localhost 98450 user1 webserver ACTIVE 01:06 0 INSERT IN +\& localhost 97750 user1 webserver not starte 00:00 0 +\& localhost 98375 user1 appserver not starte 00:00 0 +.Ve +.PP +(This sample is truncated at the right so it will fit on a terminal when running +\&'man innotop') +.PP +This sample comes from a quiet server with few transactions active. If your +server is busy, you'll see more output. Notice the first line on the screen, +which tells you what mode you're in and what server you're connected to. You +can change to other modes with keystrokes; press 'Q' to switch to a list of +currently running queries. +.PP +Press the '?' key to see what keys are active in the current mode. You can +press any of these keys and innotop will either take the requested action or +prompt you for more input. If your system has Term::ReadLine support, you can +use \s-1TAB\s0 and other keys to auto-complete and edit input. +.PP +To quit innotop, press the 'q' key. +.SH "OPTIONS" +.IX Header "OPTIONS" +innotop is mostly configured via its configuration file, but some of the +configuration options can come from the command line. You can also specify a +file to monitor for InnoDB status output; see \*(L"\s-1MONITORING\s0 A \s-1FILE\s0\*(R" for more +details. +.PP +You can negate some options by prefixing the option name with \-\-no. For +example, \-\-noinc (or \-\-no\-inc) negates \*(L"\-\-inc\*(R". +.IP "\-\-help" 4 +.IX Item "--help" +Print a summary of command-line usage and exit. +.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 "\-\-nonint" 4 +.IX Item "--nonint" +Enable non-interactive operation. See \*(L"\s-1NON\-INTERACTIVE\s0 \s-1OPERATION\s0\*(R" for more. +.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 "\-\-mode" 4 +.IX Item "--mode" +Specifies the mode in which innotop should start. Corresponds to the +configuration option \*(L"mode\*(R". +.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 "\-\-version" 4 +.IX Item "--version" +Output version information and exit. +.SH "HOTKEYS" +.IX Header "HOTKEYS" +innotop is interactive, and you control it with key\-presses. +.IP "\(bu" 4 +Uppercase keys switch between modes. +.IP "\(bu" 4 +Lowercase keys initiate some action within the current mode. +.IP "\(bu" 4 +Other keys do something special like change configuration or show the +innotop license. +.PP +Press '?' at any time to see the currently active keys and what they do. +.SH "MODES" +.IX Header "MODES" +Each of innotop's modes retrieves and displays a particular type of data from +the servers you're monitoring. You switch between modes with uppercase keys. +The following is a brief description of each mode, in alphabetical order. To +switch to the mode, press the key listed in front of its heading in the +following list: +.IP "B: InnoDB Buffers" 4 +.IX Item "B: InnoDB Buffers" +This mode displays information about the InnoDB buffer pool, page statistics, +insert buffer, and adaptive hash index. The data comes from \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. +.Sp +This mode contains the \*(L"buffer_pool\*(R", \*(L"page_statistics\*(R", +\&\*(L"insert_buffers\*(R", and \*(L"adaptive_hash_index\*(R" tables by default. +.IP "C: Command Summary" 4 +.IX Item "C: Command Summary" +This mode is similar to mytop's Command Summary mode. It shows the +\&\*(L"cmd_summary\*(R" table, which looks something like the following: +.Sp +.Vb 8 +\& Command Summary (? for help) localhost, 25+07:16:43, 2.45 QPS, 3 thd, 5.0.40 +\& _____________________ Command Summary _____________________ +\& Name Value Pct Last Incr Pct +\& Select_scan 3244858 69.89% 2 100.00% +\& Select_range 1354177 29.17% 0 0.00% +\& Select_full_join 39479 0.85% 0 0.00% +\& Select_full_range_join 4097 0.09% 0 0.00% +\& Select_range_check 0 0.00% 0 0.00% +.Ve +.Sp +The command summary table is built by extracting variables from +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". The variables must be numeric and must match the prefix +given by the \*(L"cmd_filter\*(R" configuration variable. The variables are then +sorted by value descending and compared to the last variable, as shown above. +The percentage columns are percentage of the total of all variables in the +table, so you can see the relative weight of the variables. +.Sp +The example shows what you see if the prefix is \*(L"Select_\*(R". The default +prefix is \*(L"Com_\*(R". You can choose a prefix with the 's' key. +.Sp +It's rather like running \s-1SHOW\s0 \s-1VARIABLES\s0 \s-1LIKE\s0 \*(L"prefix%\*(R" with memory and +nice formatting. +.Sp +Values are aggregated across all servers. The Pct columns are not correctly +aggregated across multiple servers. This is a known limitation of the grouping +algorithm that may be fixed in the future. +.IP "D: InnoDB Deadlocks" 4 +.IX Item "D: InnoDB Deadlocks" +This mode shows the transactions involved in the last InnoDB deadlock. A second +table shows the locks each transaction held and waited for. A deadlock is +caused by a cycle in the waits-for graph, so there should be two locks held and +one waited for unless the deadlock information is truncated. +.Sp +InnoDB puts deadlock information before some other information in the \s-1SHOW\s0 +\&\s-1INNODB\s0 \s-1STATUS\s0 output. If there are a lot of locks, the deadlock information can +grow very large, and there is a limit on the size of the \s-1SHOW\s0 \s-1INNODB\s0 +\&\s-1STATUS\s0 output. A large deadlock can fill the entire output, or even be +truncated, and prevent you from seeing other information at all. If you are +running innotop in another mode, for example T mode, and suddenly you don't see +anything, you might want to check and see if a deadlock has wiped out the data +you need. +.Sp +If it has, you can create a small deadlock to replace the large one. Use the +\&'w' key to 'wipe' the large deadlock with a small one. This will not work +unless you have defined a deadlock table for the connection (see \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R"). +.Sp +You can also configure innotop to automatically detect when a large deadlock +needs to be replaced with a small one (see \*(L"auto_wipe_dl\*(R"). +.Sp +This mode displays the \*(L"deadlock_transactions\*(R" and \*(L"deadlock_locks\*(R" tables +by default. +.IP "F: InnoDB Foreign Key Errors" 4 +.IX Item "F: InnoDB Foreign Key Errors" +This mode shows the last InnoDB foreign key error information, such as the +table where it happened, when and who and what query caused it, and so on. +.Sp +InnoDB has a huge variety of foreign key error messages, and many of them are +just hard to parse. innotop doesn't always do the best job here, but there's +so much code devoted to parsing this messy, unparseable output that innotop is +likely never to be perfect in this regard. If innotop doesn't show you what +you need to see, just look at the status text directly. +.Sp +This mode displays the \*(L"fk_error\*(R" table by default. +.IP "I: InnoDB I/O Info" 4 +.IX Item "I: InnoDB I/O Info" +This mode shows InnoDB's I/O statistics, including the I/O threads, pending I/O, +file I/O miscellaneous, and log statistics. It displays the \*(L"io_threads\*(R", +\&\*(L"pending_io\*(R", \*(L"file_io_misc\*(R", and \*(L"log_statistics\*(R" tables by default. +.IP "L: Locks" 4 +.IX Item "L: Locks" +This mode shows information about current locks. At the moment only InnoDB +locks are supported, and by default you'll only see locks for which transactions +are waiting. This information comes from the \s-1TRANSACTIONS\s0 section of the InnoDB +status text. If you have a very busy server, you may have frequent lock waits; +it helps to be able to see which tables and indexes are the \*(L"hot spot\*(R" for +locks. If your server is running pretty well, this mode should show nothing. +.Sp +You can configure MySQL and innotop to monitor not only locks for which a +transaction is waiting, but those currently held, too. You can do this with the +InnoDB Lock Monitor (). It's +not documented in the MySQL manual, but creating the lock monitor with the +following statement also affects the output of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0, which innotop +uses: +.Sp +.Vb 1 +\& CREATE TABLE innodb_lock_monitor(a int) ENGINE=INNODB; +.Ve +.Sp +This causes InnoDB to print its output to the MySQL file every 16 seconds or so, +as stated in the manual, but it also makes the normal \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0 output +include lock information, which innotop can parse and display (that's the +undocumented feature). +.Sp +This means you can do what may have seemed impossible: to a limited extent +(InnoDB truncates some information in the output), you can see which transaction +holds the locks something else is waiting for. You can also enable and disable +the InnoDB Lock Monitor with the key mappings in this mode. +.Sp +This mode displays the \*(L"innodb_locks\*(R" table by default. Here's a sample of +the screen when one connection is waiting for locks another connection holds: +.Sp +.Vb 7 +\& _________________________________ InnoDB Locks __________________________ +\& CXN ID Type Waiting Wait Active Mode DB Table Index +\& localhost 12 RECORD 1 00:10 00:10 X test t1 PRIMARY +\& localhost 12 TABLE 0 00:10 00:10 IX test t1 +\& localhost 12 RECORD 1 00:10 00:10 X test t1 PRIMARY +\& localhost 11 TABLE 0 00:00 00:25 IX test t1 +\& localhost 11 RECORD 0 00:00 00:25 X test t1 PRIMARY +.Ve +.Sp +You can see the first connection, \s-1ID\s0 12, is waiting for a lock on the \s-1PRIMARY\s0 +key on test.t1, and has been waiting for 10 seconds. The second connection +isn't waiting, because the Waiting column is 0, but it holds locks on the same +index. That tells you connection 11 is blocking connection 12. +.IP "M: Master/Slave Replication Status" 4 +.IX Item "M: Master/Slave Replication Status" +This mode shows the output of \s-1SHOW\s0 \s-1SLAVE\s0 \s-1STATUS\s0 and \s-1SHOW\s0 \s-1MASTER\s0 \s-1STATUS\s0 in three +tables. The first two divide the slave's status into \s-1SQL\s0 and I/O thread status, +and the last shows master status. Filters are applied to eliminate non-slave +servers from the slave tables, and non-master servers from the master table. +.Sp +This mode displays the \*(L"slave_sql_status\*(R", \*(L"slave_io_status\*(R", and +\&\*(L"master_status\*(R" tables by default. +.IP "O: Open Tables" 4 +.IX Item "O: Open Tables" +This section comes from MySQL's \s-1SHOW\s0 \s-1OPEN\s0 \s-1TABLES\s0 command. By default it is +filtered to show tables which are in use by one or more queries, so you can +get a quick look at which tables are 'hot'. You can use this to guess which +tables might be locked implicitly. +.Sp +This mode displays the \*(L"open_tables\*(R" mode by default. +.IP "Q: Query List" 4 +.IX Item "Q: Query List" +This mode displays the output from \s-1SHOW\s0 \s-1FULL\s0 \s-1PROCESSLIST\s0, much like \fBmytop\fR's +query list mode. This mode does \fBnot\fR show InnoDB-related information. This +is probably one of the most useful modes for general usage. +.Sp +There is an informative header that shows general status information about +your server. You can toggle it on and off with the 'h' key. By default, +innotop hides inactive processes and its own process. You can toggle these on +and off with the 'i' and 'a' keys. +.Sp +You can \s-1EXPLAIN\s0 a query from this mode with the 'e' key. This displays the +query's full text, the results of \s-1EXPLAIN\s0, and in newer MySQL versions, even +the optimized query resulting from \s-1EXPLAIN\s0 \s-1EXTENDED\s0. innotop also tries to +rewrite certain queries to make them EXPLAIN\-able. For example, \s-1INSERT/SELECT\s0 +statements are rewritable. +.Sp +This mode displays the \*(L"q_header\*(R" and \*(L"processlist\*(R" tables by default. +.IP "R: InnoDB Row Operations and Semaphores" 4 +.IX Item "R: InnoDB Row Operations and Semaphores" +This mode shows InnoDB row operations, row operation miscellaneous, semaphores, +and information from the wait array. It displays the \*(L"row_operations\*(R", +\&\*(L"row_operation_misc\*(R", \*(L"semaphores\*(R", and \*(L"wait_array\*(R" tables by default. +.IP "S: Variables & Status" 4 +.IX Item "S: Variables & Status" +This mode calculates statistics, such as queries per second, and prints them out +in several different styles. You can show absolute values, or incremental values +between ticks. +.Sp +You can switch between the views by pressing a key. The 's' key prints a +single line each time the screen updates, in the style of \fBvmstat\fR. The 'g' +key changes the view to a graph of the same numbers, sort of like \fBtload\fR. +The 'v' key changes the view to a pivoted table of variable names on the left, +with successive updates scrolling across the screen from left to right. You can +choose how many updates to put on the screen with the \*(L"num_status_sets\*(R" +configuration variable. +.Sp +Headers may be abbreviated to fit on the screen in interactive operation. You +choose which variables to display with the 'c' key, which selects from +predefined sets, or lets you create your own sets. You can edit the current set +with the 'e' key. +.Sp +This mode doesn't really display any tables like other modes. Instead, it uses +a table definition to extract and format the data, but it then transforms the +result in special ways before outputting it. It uses the \*(L"var_status\*(R" table +definition for this. +.IP "T: InnoDB Transactions" 4 +.IX Item "T: InnoDB Transactions" +This mode shows transactions from the InnoDB monitor's output, in \fBtop\fR\-like +format. This mode is the reason I wrote innotop. +.Sp +You can kill queries or processes with the 'k' and 'x' keys, and \s-1EXPLAIN\s0 a query +with the 'e' or 'f' keys. InnoDB doesn't print the full query in transactions, +so explaining may not work right if the query is truncated. +.Sp +The informational header can be toggled on and off with the 'h' key. By +default, innotop hides inactive transactions and its own transaction. You can +toggle this on and off with the 'i' and 'a' keys. +.Sp +This mode displays the \*(L"t_header\*(R" and \*(L"innodb_transactions\*(R" tables by +default. +.SH "INNOTOP STATUS" +.IX Header "INNOTOP STATUS" +The first line innotop displays is a \*(L"status bar\*(R" of sorts. What it contains +depends on the mode you're in, and what servers you're monitoring. The first +few words are always the innotop mode, such as \*(L"InnoDB Txns\*(R" for T mode, +followed by a reminder to press '?' for help at any time. +.Sh "\s-1ONE\s0 \s-1SERVER\s0" +.IX Subsection "ONE SERVER" +The simplest case is when you're monitoring a single server. In this case, the +name of the connection is next on the status line. This is the name you gave +when you created the connection \*(-- most likely the MySQL server's hostname. +This is followed by the server's uptime. +.PP +If you're in an InnoDB mode, such as T or B, the next word is \*(L"InnoDB\*(R" followed +by some information about the \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0 output used to render the +screen. The first word is the number of seconds since the last \s-1SHOW\s0 \s-1INNODB\s0 +\&\s-1STATUS\s0, which InnoDB uses to calculate some per-second statistics. The next is +a smiley face indicating whether the InnoDB output is truncated. If the smiley +face is a :\-), all is well; there is no truncation. A :^| means the transaction +list is so long, InnoDB has only printed out some of the transactions. Finally, +a frown :\-( means the output is incomplete, which is probably due to a deadlock +printing too much lock information (see \*(L"D: InnoDB Deadlocks\*(R"). +.PP +The next two words indicate the server's queries per second (\s-1QPS\s0) and how many +threads (connections) exist. Finally, the server's version number is the last +thing on the line. +.Sh "\s-1MULTIPLE\s0 \s-1SERVERS\s0" +.IX Subsection "MULTIPLE SERVERS" +If you are monitoring multiple servers (see \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R"), the status +line does not show any details about individual servers. Instead, it shows the +names of the connections that are active. Again, these are connection names you +specified, which are likely to be the server's hostname. A connection that has +an error is prefixed with an exclamation point. +.PP +If you are monitoring a group of servers (see \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R"), the status +line shows the name of the group. If any connection in the group has an +error, the group's name is followed by the fraction of the connections that +don't have errors. +.PP +See \*(L"\s-1ERROR\s0 \s-1HANDLING\s0\*(R" for more details about innotop's error handling. +.Sh "\s-1MONITORING\s0 A \s-1FILE\s0" +.IX Subsection "MONITORING A FILE" +If you give a filename on the command line, innotop will not connect to \s-1ANY\s0 +servers at all. It will watch the specified file for InnoDB status output and +use that as its data source. It will always show a single connection called +\&'file'. And since it can't connect to a server, it can't determine how long the +server it's monitoring has been up; so it calculates the server's uptime as time +since innotop started running. +.SH "SERVER ADMINISTRATION" +.IX Header "SERVER ADMINISTRATION" +While innotop is primarily a monitor that lets you watch and analyze your +servers, it can also send commands to servers. The most frequently useful +commands are killing queries and stopping or starting slaves. +.PP +You can kill a connection, or in newer versions of MySQL kill a query but not a +connection, from \*(L"Q: Query List\*(R" and \*(L"T: InnoDB Transactions\*(R" modes. +Press 'k' to issue a \s-1KILL\s0 command, or 'x' to issue a \s-1KILL\s0 \s-1QUERY\s0 command. +innotop will prompt you for the server and/or connection \s-1ID\s0 to kill (innotop +does not prompt you if there is only one possible choice for any input). +innotop pre-selects the longest-running query, or the oldest connection. +Confirm the command with 'y'. +.PP +In \*(L"M: Master/Slave Replication Status\*(R" mode, you can start and stop slaves +with the 'a' and 'o' keys, respectively. You can send these commands to many +slaves at once. innotop fills in a default command of \s-1START\s0 \s-1SLAVE\s0 or \s-1STOP\s0 \s-1SLAVE\s0 +for you, but you can actually edit the command and send anything you wish, such +as \s-1SET\s0 \s-1GLOBAL\s0 SQL_SLAVE_SKIP_COUNTER=1 to make the slave skip one binlog event +when it starts. +.PP +You can also ask innotop to calculate the earliest binlog in use by any slave +and issue a \s-1PURGE\s0 \s-1MASTER\s0 \s-1LOGS\s0 on the master. Use the 'b' key for this. innotop +will prompt you for a master to run the command on, then prompt you for the +connection names of that master's slaves (there is no way for innotop to +determine this reliably itself). innotop will find the minimum binlog in use by +these slave connections and suggest it as the argument to \s-1PURGE\s0 \s-1MASTER\s0 \s-1LOGS\s0. +.SH "SERVER CONNECTIONS" +.IX Header "SERVER CONNECTIONS" +When you create a server connection, innotop asks you for a series of inputs, as +follows: +.IP "\s-1DSN\s0" 4 +.IX Item "DSN" +A \s-1DSN\s0 is a Data Source Name, which is the initial argument passed to the \s-1DBI\s0 +module for connecting to a server. It is usually of the form +.Sp +.Vb 1 +\& DBI:mysql:;mysql_read_default_group=mysql;host=HOSTNAME +.Ve +.Sp +Since this \s-1DSN\s0 is passed to the DBD::mysql driver, you should read the driver's +documentation at \*(L"http://search.cpan.org/dist/DBD\-mysql/lib/DBD/mysql.pm\*(R" 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 , and especially at +. +.Sp +The mysql_read_default_group=mysql option lets the \s-1DBD\s0 driver read your MySQL +options files, such as ~/.my.cnf on UNIX-ish systems. You can use this to avoid +specifying a username or password for the connection. +.IP "InnoDB Deadlock Table" 4 +.IX Item "InnoDB Deadlock Table" +This optional item tells innotop a table name it can use to deliberately create +a small deadlock (see \*(L"D: InnoDB Deadlocks\*(R"). If you specify this option, +you just need to be sure the table doesn't exist, and that innotop can create +and drop the table with the InnoDB storage engine. You can safely omit or just +accept the default if you don't intend to use this. +.IP "Username" 4 +.IX Item "Username" +innotop will ask you if you want to specify a username. If you say 'y', it will +then prompt you for a user name. If you have a MySQL option file that specifies +your username, you don't have to specify a username. +.Sp +The username defaults to your login name on the system you're running innotop on. +.IP "Password" 4 +.IX Item "Password" +innotop will ask you if you want to specify a password. Like the username, the +password is optional, but there's an additional prompt that asks if you want to +save the password in the innotop configuration file. If you don't save it in +the configuration file, innotop will prompt you for a password each time it +starts. Passwords in the innotop configuration file are saved in plain text, +not encrypted in any way. +.PP +Once you finish answering these questions, you should be connected to a server. +But innotop isn't limited to monitoring a single server; you can define many +server connections and switch between them by pressing the '@' key. See +\&\*(L"\s-1SWITCHING\s0 \s-1BETWEEN\s0 \s-1CONNECTIONS\s0\*(R". +.PP +To create a new connection, press the '@' key and type the name of the new +connection, then follow the steps given above. +.SH "SERVER GROUPS" +.IX Header "SERVER GROUPS" +If you have multiple MySQL instances, you can put them into named groups, such +as 'all', 'masters', and 'slaves', which innotop can monitor all together. +.PP +You can choose which group to monitor with the '#' key, and you can press the +\&\s-1TAB\s0 key to switch to the next group. If you're not currently monitoring a +group, pressing \s-1TAB\s0 selects the first group. +.PP +To create a group, press the '#' key and type the name of your new group, then +type the names of the connections you want the group to contain. +.SH "SWITCHING BETWEEN CONNECTIONS" +.IX Header "SWITCHING BETWEEN CONNECTIONS" +innotop lets you quickly switch which servers you're monitoring. The most basic +way is by pressing the '@' key and typing the name(s) of the connection(s) you +want to use. This setting is per\-mode, so you can monitor different connections +in each mode, and innotop remembers which connections you choose. +.PP +You can quickly switch to the 'next' connection in alphabetical order with the +\&'n' key. If you're monitoring a server group (see \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R") this will +switch to the first connection. +.PP +You can also type many connection names, and innotop will fetch and display data +from them all. Just separate the connection names with spaces, for example +\&\*(L"server1 server2.\*(R" Again, if you type the name of a connection that doesn't +exist, innotop will prompt you for connection information and create the +connection. +.PP +Another way to monitor multiple connections at once is with server groups. You +can use the \s-1TAB\s0 key to switch to the 'next' group in alphabetical order, or if +you're not monitoring any groups, \s-1TAB\s0 will switch to the first group. +.PP +innotop does not fetch data in parallel from connections, so if you are +monitoring a large group or many connections, you may notice increased delay +between ticks. +.PP +When you monitor more than one connection, innotop's status bar changes. See +\&\*(L"\s-1INNOTOP\s0 \s-1STATUS\s0\*(R". +.SH "ERROR HANDLING" +.IX Header "ERROR HANDLING" +Error handling is not that important when monitoring a single connection, but is +crucial when you have many active connections. A crashed server or lost +connection should not crash innotop. As a result, innotop will continue to run +even when there is an error; it just won't display any information from the +connection that had an error. Because of this, innotop's behavior might confuse +you. It's a feature, not a bug! +.PP +innotop does not continue to query connections that have errors, because they +may slow innotop and make it hard to use, especially if the error is a problem +connecting and causes a long time\-out. Instead, innotop retries the connection +occasionally to see if the error still exists. If so, it will wait until some +point in the future. The wait time increases in ticks as the Fibonacci series, +so it tries less frequently as time passes. +.PP +Since errors might only happen in certain modes because of the \s-1SQL\s0 commands +issued in those modes, innotop keeps track of which mode caused the error. If +you switch to a different mode, innotop will retry the connection instead of +waiting. +.PP +By default innotop will display the problem in red text at the bottom of the +first table on the screen. You can disable this behavior with the +\&\*(L"show_cxn_errors_in_tbl\*(R" configuration option, which is enabled by default. +If the \*(L"debug\*(R" option is enabled, innotop will display the error at the +bottom of every table, not just the first. And if \*(L"show_cxn_errors\*(R" is +enabled, innotop will print the error text to \s-1STDOUT\s0 as well. Error messages +might only display in the mode that caused the error, depending on the mode and +whether innotop is avoiding querying that connection. +.SH "NON-INTERACTIVE OPERATION" +.IX Header "NON-INTERACTIVE OPERATION" +You can run innotop in non-interactive mode, in which case it is entirely +controlled from the configuration file and command-line options. To start +innotop in non-interactive mode, give the L\*(L"<\-\-nonint\*(R"> command-line option. +This changes innotop's behavior in the following ways: +.IP "\(bu" 4 +Certain Perl modules are not loaded. Term::Readline is not loaded, since +innotop doesn't prompt interactively. Term::ANSIColor and Win32::Console::ANSI +modules are not loaded. Term::ReadKey is still used, since innotop may have to +prompt for connection passwords when starting up. +.IP "\(bu" 4 +innotop does not clear the screen after each tick. +.IP "\(bu" 4 +innotop does not persist any changes to the configuration file. +.IP "\(bu" 4 +If \*(L"\-\-count\*(R" is given and innotop is in incremental mode (see \*(L"status_inc\*(R" +and \*(L"\-\-inc\*(R"), innotop actually refreshes one more time than specified so it +can print incremental statistics. This suppresses output during the first +tick, so innotop may appear to hang. +.IP "\(bu" 4 +innotop only displays the first table in each mode. This is so the output can +be easily processed with other command-line utilities such as awk and sed. To +change which tables display in each mode, see \*(L"\s-1TABLES\s0\*(R". Since \*(L"Q: Query List\*(R" mode is so important, innotop automatically disables the \*(L"q_header\*(R" +table. This ensures you'll see the \*(L"processlist\*(R" table, even if you have +innotop configured to show the q_header table during interactive operation. +Similarly, in \*(L"T: InnoDB Transactions\*(R" mode, the \*(L"t_header\*(R" table is +suppressed so you see only the \*(L"innodb_transactions\*(R" table. +.IP "\(bu" 4 +All output is tab-separated instead of being column-aligned with whitespace, and +innotop prints the full contents of each table instead of only printing one +screenful at a time. +.IP "\(bu" 4 +innotop only prints column headers once instead of every tick (see +\&\*(L"hide_hdr\*(R"). innotop does not print table captions (see +\&\*(L"display_table_captions\*(R"). innotop ensures there are no empty lines in the +output. +.IP "\(bu" 4 +innotop does not honor the \*(L"shorten\*(R" transformation, which normally shortens +some numbers to human-readable formats. +.IP "\(bu" 4 +innotop does not print a status line (see \*(L"\s-1INNOTOP\s0 \s-1STATUS\s0\*(R"). +.SH "CONFIGURING" +.IX Header "CONFIGURING" +Nearly everything about innotop is configurable. Most things are possible to +change with built-in commands, but you can also edit the configuration file. +.PP +While running innotop, press the '$' key to bring up the configuration editing +dialog. Press another key to select the type of data you want to edit: +.IP "S: Statement Sleep Times" 4 +.IX Item "S: Statement Sleep Times" +Edits \s-1SQL\s0 statement sleep delays, which make innotop pause for the specified +amount of time after executing a statement. See \*(L"\s-1SQL\s0 \s-1STATEMENTS\s0\*(R" for a +definition of each statement and what it does. By default innotop does not +delay after any statements. +.Sp +This feature is included so you can customize the side-effects caused by +monitoring your server. You may not see any effects, but some innotop users +have noticed that certain MySQL versions under very high load with InnoDB +enabled take longer than usual to execute \s-1SHOW\s0 \s-1GLOBAL\s0 \s-1STATUS\s0. If innotop calls +\&\s-1SHOW\s0 \s-1FULL\s0 \s-1PROCESSLIST\s0 immediately afterward, the processlist contains more +queries than the machine actually averages at any given moment. Configuring +innotop to pause briefly after calling \s-1SHOW\s0 \s-1GLOBAL\s0 \s-1STATUS\s0 alleviates this +effect. +.Sp +Sleep times are stored in the \*(L"stmt_sleep_times\*(R" section of the configuration +file. Fractional-second sleeps are supported, subject to your hardware's +limitations. +.IP "c: Edit Columns" 4 +.IX Item "c: Edit Columns" +Starts the table editor on one of the displayed tables. See \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R". +An alternative way to start the table editor without entering the configuration +dialog is with the '^' key. +.IP "g: General Configuration" 4 +.IX Item "g: General Configuration" +Starts the configuration editor to edit global and mode-specific configuration +variables (see \*(L"\s-1MODES\s0\*(R"). innotop prompts you to choose a variable from among +the global and mode-specific ones depending on the current mode. +.IP "k: Row-Coloring Rules" 4 +.IX Item "k: Row-Coloring Rules" +Starts the row-coloring rules editor on one of the displayed table(s). See +\&\*(L"\s-1COLORS\s0\*(R" for details. +.IP "p: Manage Plugins" 4 +.IX Item "p: Manage Plugins" +Starts the plugin configuration editor. See \*(L"\s-1PLUGINS\s0\*(R" for details. +.IP "s: Server Groups" 4 +.IX Item "s: Server Groups" +Lets you create and edit server groups. See \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R". +.IP "t: Choose Displayed Tables" 4 +.IX Item "t: Choose Displayed Tables" +Lets you choose which tables to display in this mode. See \*(L"\s-1MODES\s0\*(R" and +\&\*(L"\s-1TABLES\s0\*(R". +.SH "CONFIGURATION FILE" +.IX Header "CONFIGURATION FILE" +innotop's default configuration file location is in \f(CW$HOME\fR/.innotop, but can be +overridden with the \*(L"\-\-config\*(R" command-line option. You can edit it by hand +safely. innotop reads the configuration file when it starts, and writes it out +again when it exits, so any changes you make 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 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 can be made read\-only. See \*(L"readonly\*(R". +.PP +The configuration file is arranged into sections like an \s-1INI\s0 file. Each +section begins with [section\-name] and ends with [/section\-name]. Each +section's entries have a different syntax depending on the data they need to +store. You can put comments in the file; any line that begins with a # +character is a comment. innotop will not read the comments, so it won't write +them back out to the file when it exits. Comments in read-only configuration +files are still useful, though. +.PP +The first line in the file is innotop's version number. This lets innotop +notice when the file format is not backwards\-compatible, and upgrade smoothly +without destroying your customized configuration. +.PP +The following list describes each section of the configuration file and the data +it contains: +.IP "general" 4 +.IX Item "general" +The 'general' section contains global configuration variables and variables that +may be mode\-specific, but don't belong in any other section. The syntax is a +simple key=value list. innotop writes a comment above each value to help you +edit the file by hand. +.RS 4 +.IP "S_func" 4 +.IX Item "S_func" +Controls S mode presentation (see \*(L"S: Variables & Status\*(R"). If g, values are +graphed; if s, values are like vmstat; if p, values are in a pivoted table. +.IP "S_set" 4 +.IX Item "S_set" +Specifies which set of variables to display in \*(L"S: Variables & Status\*(R" mode. +See \*(L"\s-1VARIABLE\s0 \s-1SETS\s0\*(R". +.IP "auto_wipe_dl" 4 +.IX Item "auto_wipe_dl" +Instructs innotop to automatically wipe large deadlocks when it notices them. +When this happens you may notice a slight delay. At the next tick, you will +usually see the information that was being truncated by the large deadlock. +.IP "charset" 4 +.IX Item "charset" +Specifies what kind of characters to allow through the \*(L"no_ctrl_char\*(R" +transformation. This keeps non-printable characters from confusing a +terminal when you monitor queries that contain binary data, such as images. +.Sp +The default is 'ascii', which considers anything outside normal \s-1ASCII\s0 to be a +control character. The other allowable values are 'unicode' and 'none'. 'none' +considers every character a control character, which can be useful for +collapsing \s-1ALL\s0 text fields in queries. +.IP "cmd_filter" 4 +.IX Item "cmd_filter" +This is the prefix that filters variables in \*(L"C: Command Summary\*(R" mode. +.IP "color" 4 +.IX Item "color" +Whether terminal coloring is permitted. +.IP "cxn_timeout" 4 +.IX Item "cxn_timeout" +On MySQL versions 4.0.3 and newer, this variable is used to set the connection's +timeout, so MySQL doesn't close the connection if it is not used for a while. +This might happen because a connection isn't monitored in a particular mode, for +example. +.IP "debug" 4 +.IX Item "debug" +This option enables more verbose errors and makes innotop more strict in some +places. It can help in debugging filters and other user-defined code. It also +makes innotop write a lot of information to \*(L"debugfile\*(R" when there is a +crash. +.IP "debugfile" 4 +.IX Item "debugfile" +A file to which innotop will write information when there is a crash. See +\&\*(L"\s-1FILES\s0\*(R". +.IP "display_table_captions" 4 +.IX Item "display_table_captions" +innotop displays a table caption above most tables. This variable suppresses or +shows captions on all tables globally. Some tables are configured with the +hide_caption property, which overrides this. +.IP "global" 4 +.IX Item "global" +Whether to show \s-1GLOBAL\s0 variables and status. innotop only tries to do this on +servers which support the \s-1GLOBAL\s0 option to \s-1SHOW\s0 \s-1VARIABLES\s0 and \s-1SHOW\s0 \s-1STATUS\s0. In +some MySQL versions, you need certain privileges to do this; if you don't have +them, innotop will not be able to fetch any variable and status data. This +configuration variable lets you run innotop and fetch what data you can even +without the elevated privileges. +.Sp +I can no longer find or reproduce the situation where \s-1GLOBAL\s0 wasn't allowed, but +I know there was one. +.IP "graph_char" 4 +.IX Item "graph_char" +Defines the character to use when drawing graphs in \*(L"S: Variables & Status\*(R" +mode. +.IP "header_highlight" 4 +.IX Item "header_highlight" +Defines how to highlight column headers. This only works if Term::ANSIColor is +available. Valid values are 'bold' and 'underline'. +.IP "hide_hdr" 4 +.IX Item "hide_hdr" +Hides column headers globally. +.IP "interval" 4 +.IX Item "interval" +The interval at which innotop will refresh its data (ticks). The interval is +implemented as a sleep time between ticks, so the true interval will vary +depending on how long it takes innotop to fetch and render data. +.Sp +This variable accepts fractions of a second. +.IP "mode" 4 +.IX Item "mode" +The mode in which innotop should start. Allowable arguments are the same as the +key presses that select a mode interactively. See \*(L"\s-1MODES\s0\*(R". +.IP "num_digits" 4 +.IX Item "num_digits" +How many digits to show in fractional numbers and percents. This variable's +range is between 0 and 9 and can be set directly from \*(L"S: Variables & Status\*(R" +mode with the '+' and '\-' keys. It is used in the \*(L"set_precision\*(R", +\&\*(L"shorten\*(R", and \*(L"percent\*(R" transformations. +.IP "num_status_sets" 4 +.IX Item "num_status_sets" +Controls how many sets of status variables to display in pivoted \*(L"S: Variables & Status\*(R" mode. It also controls the number of old sets of variables innotop +keeps in its memory, so the larger this variable is, the more memory innotop +uses. +.IP "plugin_dir" 4 +.IX Item "plugin_dir" +Specifies where plugins can be found. By default, innotop stores plugins in the +\&'plugins' subdirectory of your innotop configuration directory. +.IP "readonly" 4 +.IX Item "readonly" +Whether the configuration file is readonly. This cannot be set interactively, +because it would prevent itself from being written to the configuration file. +.IP "show_cxn_errors" 4 +.IX Item "show_cxn_errors" +Makes innotop print connection errors to \s-1STDOUT\s0. See \*(L"\s-1ERROR\s0 \s-1HANDLING\s0\*(R". +.IP "show_cxn_errors_in_tbl" 4 +.IX Item "show_cxn_errors_in_tbl" +Makes innotop display connection errors as rows in the first table on screen. +See \*(L"\s-1ERROR\s0 \s-1HANDLING\s0\*(R". +.IP "show_percent" 4 +.IX Item "show_percent" +Adds a '%' character after the value returned by the \*(L"percent\*(R" +transformation. +.IP "show_statusbar" 4 +.IX Item "show_statusbar" +Controls whether to show the status bar in the display. See \*(L"\s-1INNOTOP\s0 \s-1STATUS\s0\*(R". +.IP "skip_innodb" 4 +.IX Item "skip_innodb" +Disables fetching \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0, in case your server(s) do not have InnoDB +enabled and you don't want innotop to try to fetch it. This can also be useful +when you don't have the \s-1SUPER\s0 privilege, required to run \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. +.IP "status_inc" 4 +.IX Item "status_inc" +Whether to show absolute or incremental values for status variables. +Incremental values are calculated as an offset from the last value innotop saw +for that variable. This is a global setting, but will probably become +mode-specific at some point. Right now it is honored a bit inconsistently; some +modes don't pay attention to it. +.RE +.RS 4 +.RE +.IP "plugins" 4 +.IX Item "plugins" +This section holds a list of package names of active plugins. If the plugin +exists, innotop will activate it. See \*(L"\s-1PLUGINS\s0\*(R" for more information. +.IP "filters" 4 +.IX Item "filters" +This section holds user-defined filters (see \*(L"\s-1FILTERS\s0\*(R"). Each line is in the +format filter_name=text='filter text' tbls='table list'. +.Sp +The filter text is the text of the subroutine's code. The table list is a list +of tables to which the filter can apply. By default, user-defined filters apply +to the table for which they were created, but you can manually override that by +editing the definition in the configuration file. +.IP "active_filters" 4 +.IX Item "active_filters" +This section stores which filters are active on each table. Each line is in the +format table_name=filter_list. +.IP "tbl_meta" 4 +.IX Item "tbl_meta" +This section stores user-defined or user-customized columns (see \*(L"\s-1COLUMNS\s0\*(R"). +Each line is in the format col_name=properties, where the properties are a +name=quoted\-value list. +.IP "connections" 4 +.IX Item "connections" +This section holds the server connections you have defined. Each line is in the +format name=properties, where the properties are a name=value list. The +properties are self\-explanatory, and the only one that is treated specially is +\&'pass' which is only present if 'savepass' is set. See \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R". +.IP "active_connections" 4 +.IX Item "active_connections" +This section holds a list of which connections are active in each mode. Each +line is in the format mode_name=connection_list. +.IP "server_groups" 4 +.IX Item "server_groups" +This section holds server groups. Each line is in the format +name=connection_list. See \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R". +.IP "active_server_groups" 4 +.IX Item "active_server_groups" +This section holds a list of which server group is active in each mode. Each +line is in the format mode_name=server_group. +.IP "max_values_seen" 4 +.IX Item "max_values_seen" +This section holds the maximum values seen for variables. This is used to scale +the graphs in \*(L"S: Variables & Status\*(R" mode. Each line is in the format +name=value. +.IP "active_columns" 4 +.IX Item "active_columns" +This section holds table column lists. Each line is in the format +tbl_name=column_list. See \*(L"\s-1COLUMNS\s0\*(R". +.IP "sort_cols" 4 +.IX Item "sort_cols" +This section holds the sort definition. Each line is in the format +tbl_name=column_list. If a column is prefixed with '\-', that column sorts +descending. See \*(L"\s-1SORTING\s0\*(R". +.IP "visible_tables" 4 +.IX Item "visible_tables" +This section defines which tables are visible in each mode. Each line is in the +format mode_name=table_list. See \*(L"\s-1TABLES\s0\*(R". +.IP "varsets" 4 +.IX Item "varsets" +This section defines variable sets for use in \*(L"S: Status & Variables\*(R" mode. +Each line is in the format name=variable_list. See \*(L"\s-1VARIABLE\s0 \s-1SETS\s0\*(R". +.IP "colors" 4 +.IX Item "colors" +This section defines colorization rules. Each line is in the format +tbl_name=property_list. See \*(L"\s-1COLORS\s0\*(R". +.IP "stmt_sleep_times" 4 +.IX Item "stmt_sleep_times" +This section contains statement sleep times. Each line is in the format +statement_name=sleep_time. See \*(L"S: Statement Sleep Times\*(R". +.IP "group_by" 4 +.IX Item "group_by" +This section contains column lists for table group_by expressions. Each line is +in the format tbl_name=column_list. See \*(L"\s-1GROUPING\s0\*(R". +.SH "CUSTOMIZING" +.IX Header "CUSTOMIZING" +You can customize innotop a great deal. For example, you can: +.IP "\(bu" 4 +Choose which tables to display, and in what order. +.IP "\(bu" 4 +Choose which columns are in those tables, and create new columns. +.IP "\(bu" 4 +Filter which rows display with built-in filters, user-defined filters, and +quick\-filters. +.IP "\(bu" 4 +Sort the rows to put important data first or group together related rows. +.IP "\(bu" 4 +Highlight rows with color. +.IP "\(bu" 4 +Customize the alignment, width, and formatting of columns, and apply +transformations to columns to extract parts of their values or format the values +as you wish (for example, shortening large numbers to familiar units). +.IP "\(bu" 4 +Design your own expressions to extract and combine data as you need. This gives +you unlimited flexibility. +.PP +All these and more are explained in the following sections. +.Sh "\s-1TABLES\s0" +.IX Subsection "TABLES" +A table is what you'd expect: a collection of columns. It also has some other +properties, such as a caption. Filters, sorting rules, and colorization rules +belong to tables and are covered in later sections. +.PP +Internally, table meta-data is defined in a data structure called \f(CW%tbl_meta\fR. +This hash holds all built-in table definitions, which contain a lot of default +instructions to innotop. The meta-data includes the caption, a list of columns +the user has customized, a list of columns, a list of visible columns, a list of +filters, color rules, a sort-column list, sort direction, and some information +about the table's data sources. Most of this is customizable via the table +editor (see \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R"). +.PP +You can choose which tables to show by pressing the '$' key. See \*(L"\s-1MODES\s0\*(R" and +\&\*(L"\s-1TABLES\s0\*(R". +.PP +The table life-cycle is as follows: +.IP "\(bu" 4 +Each table begins with a data source, which is an array of hashes. See below +for details on data sources. +.IP "\(bu" 4 +Each element of the data source becomes a row in the final table. +.IP "\(bu" 4 +For each element in the data source, innotop extracts values from the source and +creates a row. This row is another hash, which later steps will refer to as +\&\f(CW$set\fR. The values innotop extracts are determined by the table's columns. Each +column has an extraction subroutine, compiled from an expression (see +\&\*(L"\s-1EXPRESSIONS\s0\*(R"). The resulting row is a hash whose keys are named the same as +the column name. +.IP "\(bu" 4 +innotop filters the rows, removing those that don't need to be displayed. See +\&\*(L"\s-1FILTERS\s0\*(R". +.IP "\(bu" 4 +innotop sorts the rows. See \*(L"\s-1SORTING\s0\*(R". +.IP "\(bu" 4 +innotop groups the rows together, if specified. See \*(L"\s-1GROUPING\s0\*(R". +.IP "\(bu" 4 +innotop colorizes the rows. See \*(L"\s-1COLORS\s0\*(R". +.IP "\(bu" 4 +innotop transforms the column values in each row. See \*(L"\s-1TRANSFORMATIONS\s0\*(R". +.IP "\(bu" 4 +innotop optionally pivots the rows (see \*(L"\s-1PIVOTING\s0\*(R"), then filters and sorts +them. +.IP "\(bu" 4 +innotop formats and justifies the rows as a table. During this step, innotop +applies further formatting to the column values, including alignment, maximum +and minimum widths. innotop also does final error checking to ensure there are +no crashes due to undefined values. innotop then adds a caption if specified, +and the table is ready to print. +.PP +The lifecycle is slightly different if the table is pivoted, as noted above. To +clarify, if the table is pivoted, the process is extract, group, transform, +pivot, filter, sort, create. If it's not pivoted, the process is extract, +filter, sort, group, color, transform, create. This slightly convoluted process +doesn't map all that well to \s-1SQL\s0, but pivoting complicates things pretty +thoroughly. Roughly speaking, filtering and sorting happen as late as needed to +effect the final result as you might expect, but as early as possible for +efficiency. +.PP +Each built-in table is described below: +.IP "adaptive_hash_index" 4 +.IX Item "adaptive_hash_index" +Displays data about InnoDB's adaptive hash index. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "buffer_pool" 4 +.IX Item "buffer_pool" +Displays data about InnoDB's buffer pool. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "cmd_summary" 4 +.IX Item "cmd_summary" +Displays weighted status variables. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "deadlock_locks" 4 +.IX Item "deadlock_locks" +Shows which locks were held and waited for by the last detected deadlock. Data +source: \*(L"\s-1DEADLOCK_LOCKS\s0\*(R". +.IP "deadlock_transactions" 4 +.IX Item "deadlock_transactions" +Shows transactions involved in the last detected deadlock. Data source: +\&\*(L"\s-1DEADLOCK_TRANSACTIONS\s0\*(R". +.IP "explain" 4 +.IX Item "explain" +Shows the output of \s-1EXPLAIN\s0. Data source: \*(L"\s-1EXPLAIN\s0\*(R". +.IP "file_io_misc" 4 +.IX Item "file_io_misc" +Displays data about InnoDB's file and I/O operations. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "fk_error" 4 +.IX Item "fk_error" +Displays various data about InnoDB's last foreign key error. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "innodb_locks" 4 +.IX Item "innodb_locks" +Displays InnoDB locks. Data source: \*(L"\s-1INNODB_LOCKS\s0\*(R". +.IP "innodb_transactions" 4 +.IX Item "innodb_transactions" +Displays data about InnoDB's current transactions. Data source: +\&\*(L"\s-1INNODB_TRANSACTIONS\s0\*(R". +.IP "insert_buffers" 4 +.IX Item "insert_buffers" +Displays data about InnoDB's insert buffer. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "io_threads" 4 +.IX Item "io_threads" +Displays data about InnoDB's I/O threads. Data source: \*(L"\s-1IO_THREADS\s0\*(R". +.IP "log_statistics" 4 +.IX Item "log_statistics" +Displays data about InnoDB's logging system. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "master_status" 4 +.IX Item "master_status" +Displays replication master status. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "open_tables" 4 +.IX Item "open_tables" +Displays open tables. Data source: \*(L"\s-1OPEN_TABLES\s0\*(R". +.IP "page_statistics" 4 +.IX Item "page_statistics" +Displays InnoDB page statistics. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "pending_io" 4 +.IX Item "pending_io" +Displays InnoDB pending I/O operations. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "processlist" 4 +.IX Item "processlist" +Displays current MySQL processes (threads/connections). Data source: +\&\*(L"\s-1PROCESSLIST\s0\*(R". +.IP "q_header" 4 +.IX Item "q_header" +Displays various status values. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "row_operation_misc" 4 +.IX Item "row_operation_misc" +Displays data about InnoDB's row operations. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "row_operations" 4 +.IX Item "row_operations" +Displays data about InnoDB's row operations. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "semaphores" 4 +.IX Item "semaphores" +Displays data about InnoDB's semaphores and mutexes. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "slave_io_status" 4 +.IX Item "slave_io_status" +Displays data about the slave I/O thread. Data source: +\&\*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "slave_sql_status" 4 +.IX Item "slave_sql_status" +Displays data about the slave \s-1SQL\s0 thread. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "t_header" 4 +.IX Item "t_header" +Displays various InnoDB status values. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "var_status" 4 +.IX Item "var_status" +Displays user-configurable data. Data source: \*(L"\s-1STATUS_VARIABLES\s0\*(R". +.IP "wait_array" 4 +.IX Item "wait_array" +Displays data about InnoDB's \s-1OS\s0 wait array. Data source: \*(L"\s-1OS_WAIT_ARRAY\s0\*(R". +.Sh "\s-1COLUMNS\s0" +.IX Subsection "COLUMNS" +Columns belong to tables. You can choose a table's columns by pressing the '^' +key, which starts the \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R" and lets you choose and edit columns. +Pressing 'e' from within the table editor lets you edit the column's properties: +.IP "\(bu" 4 +hdr: a column header. This appears in the first row of the table. +.IP "\(bu" 4 +just: justification. '\-' means left-justified and '' means right\-justified, +just as with printf formatting codes (not a coincidence). +.IP "\(bu" 4 +dec: whether to further align the column on the decimal point. +.IP "\(bu" 4 +num: whether the column is numeric. This affects how values are sorted +(lexically or numerically). +.IP "\(bu" 4 +label: a small note about the column, which appears in dialogs that help the +user choose columns. +.IP "\(bu" 4 +src: an expression that innotop uses to extract the column's data from its +source (see \*(L"\s-1DATA\s0 \s-1SOURCES\s0\*(R"). See \*(L"\s-1EXPRESSIONS\s0\*(R" for more on expressions. +.IP "\(bu" 4 +minw: specifies a minimum display width. This helps stabilize the display, +which makes it easier to read if the data is changing frequently. +.IP "\(bu" 4 +maxw: similar to minw. +.IP "\(bu" 4 +trans: a list of column transformations. See \*(L"\s-1TRANSFORMATIONS\s0\*(R". +.IP "\(bu" 4 +agg: an aggregate function. See \*(L"\s-1GROUPING\s0\*(R". The default is \*(L"first\*(R". +.IP "\(bu" 4 +aggonly: controls whether the column only shows when grouping is enabled on the +table (see \*(L"\s-1GROUPING\s0\*(R"). By default, this is disabled. This means columns +will always be shown by default, whether grouping is enabled or not. If a +column's aggonly is set true, the column will appear when you toggle grouping on +the table. Several columns are set this way, such as the count column on +\&\*(L"processlist\*(R" and \*(L"innodb_transactions\*(R", so you don't see a count when the +grouping isn't enabled, but you do when it is. +.Sh "\s-1FILTERS\s0" +.IX Subsection "FILTERS" +Filters remove rows from the display. They behave much like a \s-1WHERE\s0 clause in +\&\s-1SQL\s0. innotop has several built-in filters, which remove irrelevant information +like inactive queries, but you can define your own as well. innotop also lets +you create quick\-filters, which do not get saved to the configuration file, and +are just an easy way to quickly view only some rows. +.PP +You can enable or disable a filter on any table. Press the '%' key (mnemonic: % +looks kind of like a line being filtered between two circles) and choose which +table you want to filter, if asked. You'll then see a list of possible filters +and a list of filters currently enabled for that table. Type the names of +filters you want to apply and press Enter. +.PP +\fIUSER-DEFINED \s-1FILTERS\s0\fR +.IX Subsection "USER-DEFINED FILTERS" +.PP +If you type a name that doesn't exist, innotop will prompt you to create the +filter. Filters are easy to create if you know Perl, and not hard if you don't. +What you're doing is creating a subroutine that returns true if the row should +be displayed. The row is a hash reference passed to your subroutine as \f(CW$set\fR. +.PP +For example, imagine you want to filter the processlist table so you only see +queries that have been running more than five minutes. Type a new name for your +filter, and when prompted for the subroutine body, press \s-1TAB\s0 to initiate your +terminal's auto\-completion. You'll see the names of the columns in the +\&\*(L"processlist\*(R" table (innotop generally tries to help you with auto-completion +lists). You want to filter on the 'time' column. Type the text \*(L"$set\->{time} > +300\*(R" to return true when the query is more than five minutes old. That's all +you need to do. +.PP +In other words, the code you're typing is surrounded by an implicit context, +which looks like this: +.PP +.Vb 4 +\& sub filter { +\& my ( $set ) = @_; +\& # YOUR CODE HERE +\& } +.Ve +.PP +If your filter doesn't work, or if something else suddenly behaves differently, +you might have made an error in your filter, and innotop is silently catching +the error. Try enabling \*(L"debug\*(R" to make innotop throw an error instead. +.PP +\fIQUICK-FILTERS\fR +.IX Subsection "QUICK-FILTERS" +.PP +innotop's quick-filters are a shortcut to create a temporary filter that doesn't +persist when you restart innotop. To create a quick\-filter, press the '/' key. +innotop will prompt you for the column name and filter text. Again, you can use +auto-completion on column names. The filter text can be just the text you want +to \*(L"search for.\*(R" For example, to filter the \*(L"processlist\*(R" table on queries +that refer to the products table, type '/' and then 'info product'. +.PP +The filter text can actually be any Perl regular expression, but of course a +literal string like 'product' works fine as a regular expression. +.PP +Behind the scenes innotop compiles the quick-filter into a specially tagged +filter that is otherwise like any other filter. It just isn't saved to the +configuration file. +.PP +To clear quick\-filters, press the '\e' key and innotop will clear them all at +once. +.Sh "\s-1SORTING\s0" +.IX Subsection "SORTING" +innotop has sensible built-in defaults to sort the most important rows to the +top of the table. Like anything else in innotop, you can customize how any +table is sorted. +.PP +To start the sort dialog, start the \*(L"\s-1TABLE\s0 \s-1EDITOR\s0\*(R" with the '^' key, choose a +table if necessary, and press the 's' key. You'll see a list of columns you can +use in the sort expression and the current sort expression, if any. Enter a +list of columns by which you want to sort and press Enter. If you want to +reverse sort, prefix the column name with a minus sign. For example, if you +want to sort by column a ascending, then column b descending, type 'a \-b'. You +can also explicitly add a + in front of columns you want to sort ascending, but +it's not required. +.PP +Some modes have keys mapped to open this dialog directly, and to quickly reverse +sort direction. Press '?' as usual to see which keys are mapped in any mode. +.Sh "\s-1GROUPING\s0" +.IX Subsection "GROUPING" +innotop can group, or aggregate, rows together (I use the terms +interchangeably). This is quite similar to an \s-1SQL\s0 \s-1GROUP\s0 \s-1BY\s0 clause. You can +specify to group on certain columns, or if you don't specify any, the entire set +of rows is treated as one group. This is quite like \s-1SQL\s0 so far, but unlike \s-1SQL\s0, +you can also select un-grouped columns. innotop actually aggregates every +column. If you don't explicitly specify a grouping function, the default is +\&'first'. This is basically a convenience so you don't have to specify an +aggregate function for every column you want in the result. +.PP +You can quickly toggle grouping on a table with the '=' key, which toggles its +aggregate property. This property doesn't persist to the config file. +.PP +The columns by which the table is grouped are specified in its group_by +property. When you turn grouping on, innotop places the group_by columns at the +far left of the table, even if they're not supposed to be visible. The rest of +the visible columns appear in order after them. +.PP +Two tables have default group_by lists and a count column built in: +\&\*(L"processlist\*(R" and \*(L"innodb_transactions\*(R". The grouping is by connection +and status, so you can quickly see how many queries or transactions are in a +given status on each server you're monitoring. The time columns are aggregated +as a sum; other columns are left at the default 'first' aggregation. +.PP +By default, the table shown in \*(L"S: Variables & Status\*(R" mode also uses +grouping so you can monitor variables and status across many servers. The +default aggregation function in this mode is 'avg'. +.PP +Valid grouping functions are defined in the \f(CW%agg_funcs\fR hash. They include +.IP "first" 4 +.IX Item "first" +Returns the first element in the group. +.IP "count" 4 +.IX Item "count" +Returns the number of elements in the group, including undefined elements, much +like \s-1SQL\s0's \s-1COUNT\s0(*). +.IP "avg" 4 +.IX Item "avg" +Returns the average of defined elements in the group. +.IP "sum" 4 +.IX Item "sum" +Returns the sum of elements in the group. +.PP +Here's an example of grouping at work. Suppose you have a very busy server with +hundreds of open connections, and you want to see how many connections are in +what status. Using the built-in grouping rules, you can press 'Q' to enter +\&\*(L"Q: Query List\*(R" mode. Press '=' to toggle grouping (if necessary, select the +\&\*(L"processlist\*(R" table when prompted). +.PP +Your display might now look like the following: +.PP +.Vb 1 +\& Query List (? for help) localhost, 32:33, 0.11 QPS, 1 thd, 5.0.38\-log +.Ve +.PP +.Vb 5 +\& CXN Cmd Cnt ID User Host Time Query +\& localhost Query 49 12933 webusr localhost 19:38 SELECT * FROM +\& localhost Sending Da 23 2383 webusr localhost 12:43 SELECT col1, +\& localhost Sleep 120 140 webusr localhost 5:18:12 +\& localhost Statistics 12 19213 webusr localhost 01:19 SELECT * FROM +.Ve +.PP +That's actually quite a worrisome picture. You've got a lot of idle connections +(Sleep), and some connections executing queries (Query and Sending Data). +That's okay, but you also have a lot in Statistics status, collectively spending +over a minute. That means the query optimizer is having a really hard time +optimizing your statements. Something is wrong; it should normally take +milliseconds to optimize queries. You might not have seen this pattern if you +didn't look at your connections in aggregate. (This is a made-up example, but +it can happen in real life). +.Sh "\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. +.Sh "\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. +.Sh "\s-1EXPRESSIONS\s0" +.IX Subsection "EXPRESSIONS" +Expressions are at the core of how innotop works, and are what enables you to +extend innotop as you wish. Recall the table lifecycle explained in +\&\*(L"\s-1TABLES\s0\*(R". Expressions are used in the earliest step, where it extracts +values from a data source to form rows. +.PP +It does this by calling a subroutine for each column, passing it the source data +set, a set of current values, and a set of previous values. These are all +needed so the subroutine can calculate things like the difference between this +tick and the previous tick. +.PP +The subroutines that extract the data from the set are compiled from +expressions. This gives significantly more power than just naming the values to +fill the columns, because it allows the column's value to be calculated from +whatever data is necessary, but avoids the need to write complicated and lengthy +Perl code. +.PP +innotop begins with a string of text that can look as simple as a value's name +or as complicated as a full-fledged Perl expression. It looks at each +\&'bareword' token in the string and decides whether it's supposed to be a key +into the \f(CW$set\fR hash. A bareword is an unquoted value that isn't already +surrounded by code-ish things like dollar signs or curly brackets. If innotop +decides that the bareword isn't a function or other valid Perl code, it converts +it into a hash access. After the whole string is processed, innotop compiles a +subroutine, like this: +.PP +.Vb 5 +\& sub compute_column_value { +\& my ( $set, $cur, $pre ) = @_; +\& my $val = # EXPANDED STRING GOES HERE +\& return $val; +\& } +.Ve +.PP +Here's a concrete example, taken from the header table \*(L"q_header\*(R" in \*(L"Q: Query List\*(R" mode. This expression calculates the qps, or Queries Per Second, +column's values, from the values returned by \s-1SHOW\s0 \s-1STATUS:\s0 +.PP +.Vb 1 +\& Questions/Uptime_hires +.Ve +.PP +innotop decides both words are barewords, and transforms this expression into +the following Perl code: +.PP +.Vb 1 +\& $set\->{Questions}/$set\->{Uptime_hires} +.Ve +.PP +When surrounded by the rest of the subroutine's code, this is executable Perl +that calculates a high-resolution queries-per-second value. +.PP +The arguments to the subroutine are named \f(CW$set\fR, \f(CW$cur\fR, and \f(CW$pre\fR. In most cases, +\&\f(CW$set\fR and \f(CW$cur\fR will be the same values. However, if \*(L"status_inc\*(R" is set, \f(CW$cur\fR +will not be the same as \f(CW$set\fR, because \f(CW$set\fR will already contain values that are +the incremental difference between \f(CW$cur\fR and \f(CW$pre\fR. +.PP +Every column in innotop is computed by subroutines compiled in the same fashion. +There is no difference between innotop's built-in columns and user-defined +columns. This keeps things consistent and predictable. +.Sh "\s-1TRANSFORMATIONS\s0" +.IX Subsection "TRANSFORMATIONS" +Transformations change how a value is rendered. For example, they can take a +number of seconds and display it in H:M:S format. The following transformations +are defined: +.IP "commify" 4 +.IX Item "commify" +Adds commas to large numbers every three decimal places. +.IP "dulint_to_int" 4 +.IX Item "dulint_to_int" +Accepts two unsigned integers and converts them into a single longlong. This is +useful for certain operations with InnoDB, which uses two integers as +transaction identifiers, for example. +.IP "no_ctrl_char" 4 +.IX Item "no_ctrl_char" +Removes quoted control characters from the value. This is affected by the +\&\*(L"charset\*(R" configuration variable. +.Sp +This transformation only operates within quoted strings, for example, values to +a \s-1SET\s0 clause in an \s-1UPDATE\s0 statement. It will not alter the \s-1UPDATE\s0 statement, +but will collapse the quoted string to [\s-1BINARY\s0] or [\s-1TEXT\s0], depending on the +charset. +.IP "percent" 4 +.IX Item "percent" +Converts a number to a percentage by multiplying it by two, formatting it with +\&\*(L"num_digits\*(R" digits after the decimal point, and optionally adding a percent +sign (see \*(L"show_percent\*(R"). +.IP "secs_to_time" 4 +.IX Item "secs_to_time" +Formats a number of seconds as time in days+hours:minutes:seconds format. +.IP "set_precision" 4 +.IX Item "set_precision" +Formats numbers with \*(L"num_digits\*(R" number of digits after the decimal point. +.IP "shorten" 4 +.IX Item "shorten" +Formats a number as a unit of 1024 (k/M/G/T) and with \*(L"num_digits\*(R" number of +digits after the decimal point. +.Sh "\s-1TABLE\s0 \s-1EDITOR\s0" +.IX Subsection "TABLE EDITOR" +The innotop table editor lets you customize tables with keystrokes. You start +the table editor with the '^' key. If there's more than one table on the +screen, it will prompt you to choose one of them. Once you do, innotop will +show you something like this: +.PP +.Vb 1 +\& Editing table definition for Buffer Pool. Press ? for help, q to quit. +.Ve +.PP +.Vb 9 +\& name hdr label src +\& cxn CXN Connection from which cxn +\& buf_pool_size Size Buffer pool size IB_bp_buf_poo +\& buf_free Free Bufs Buffers free in the b IB_bp_buf_fre +\& pages_total Pages Pages total IB_bp_pages_t +\& pages_modified Dirty Pages Pages modified (dirty IB_bp_pages_m +\& buf_pool_hit_rate Hit Rate Buffer pool hit rate IB_bp_buf_poo +\& total_mem_alloc Memory Total memory allocate IB_bp_total_m +\& add_pool_alloc Add\(aql Pool Additonal pool alloca IB_bp_add_poo +.Ve +.PP +The first line shows which table you're editing, and reminds you again to press +\&'?' for a list of key mappings. The rest is a tabular representation of the +table's columns, because that's likely what you're trying to edit. However, you +can edit more than just the table's columns; this screen can start the filter +editor, color rule editor, and more. +.PP +Each row in the display shows a single column in the table you're editing, along +with a couple of its properties such as its header and source expression (see +\&\*(L"\s-1EXPRESSIONS\s0\*(R"). +.PP +The key mappings are Vim\-style, as in many other places. Pressing 'j' and 'k' +moves the highlight up or down. You can then (d)elete or (e)dit the highlighted +column. You can also (a)dd a column to the table. This actually just activates +one of the columns already defined for the table; it prompts you to choose from +among the columns available but not currently displayed. Finally, you can +re-order the columns with the '+' and '\-' keys. +.PP +You can do more than just edit the columns with the table editor, you can also +edit other properties, such as the table's sort expression and group-by +expression. Press '?' to see the full list, of course. +.PP +If you want to really customize and create your own column, as opposed to just +activating a built-in one that's not currently displayed, press the (n)ew key, +and innotop will prompt you for the information it needs: +.IP "\(bu" 4 +The column name: this needs to be a word without any funny characters, e.g. just +letters, numbers and underscores. +.IP "\(bu" 4 +The column header: this is the label that appears at the top of the column, in +the table header. This can have spaces and funny characters, but be careful not +to make it too wide and waste space on\-screen. +.IP "\(bu" 4 +The column's data source: this is an expression that determines what data from +the source (see \*(L"\s-1TABLES\s0\*(R") innotop will put into the column. This can just be +the name of an item in the source, or it can be a more complex expression, as +described in \*(L"\s-1EXPRESSIONS\s0\*(R". +.PP +Once you've entered the required data, your table has a new column. There is no +difference between this column and the built-in ones; it can have all the same +properties and behaviors. innotop will write the column's definition to the +configuration file, so it will persist across sessions. +.PP +Here's an example: suppose you want to track how many times your slaves have +retried transactions. According to the MySQL manual, the +Slave_retried_transactions status variable gives you that data: \*(L"The total +number of times since startup that the replication slave \s-1SQL\s0 thread has retried +transactions. This variable was added in version 5.0.4.\*(R" This is appropriate to +add to the \*(L"slave_sql_status\*(R" table. +.PP +To add the column, switch to the replication-monitoring mode with the 'M' key, +and press the '^' key to start the table editor. When prompted, choose +slave_sql_status as the table, then press 'n' to create the column. Type +\&'retries' as the column name, 'Retries' as the column header, and +\&'Slave_retried_transactions' as the source. Now the column is created, and you +see the table editor screen again. Press 'q' to exit the table editor, and +you'll see your column at the end of the table. +.SH "VARIABLE SETS" +.IX Header "VARIABLE SETS" +Variable sets are used in \*(L"S: Variables & Status\*(R" mode to define more easily +what variables you want to monitor. Behind the scenes they are compiled to a +list of expressions, and then into a column list so they can be treated just +like columns in any other table, in terms of data extraction and +transformations. However, you're protected from the tedious details by a syntax +that ought to feel very natural to you: a \s-1SQL\s0 \s-1SELECT\s0 list. +.PP +The data source for variable sets, and indeed the entire S mode, is the +combination of \s-1SHOW\s0 \s-1STATUS\s0, \s-1SHOW\s0 \s-1VARIABLES\s0, and \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. Imagine +that you had a huge table with one column per variable returned from those +statements. That's the data source for variable sets. You can now query this +data source just like you'd expect. For example: +.PP +.Vb 1 +\& Questions, Uptime, Questions/Uptime as QPS +.Ve +.PP +Behind the scenes innotop will split that variable set into three expressions, +compile them and turn them into a table definition, then extract as usual. This +becomes a \*(L"variable set,\*(R" or a \*(L"list of variables you want to monitor.\*(R" +.PP +innotop lets you name and save your variable sets, and writes them to the +configuration file. You can choose which variable set you want to see with the +\&'c' key, or activate the next and previous sets with the '>' and '<' keys. +There are many built-in variable sets as well, which should give you a good +start for creating your own. Press 'e' to edit the current variable set, or +just to see how it's defined. To create a new one, just press 'c' and type its +name. +.PP +You may want to use some of the functions listed in \*(L"\s-1TRANSFORMATIONS\s0\*(R" to help +format the results. In particular, \*(L"set_precision\*(R" is often useful to limit +the number of digits you see. Extending the above example, here's how: +.PP +.Vb 1 +\& Questions, Uptime, set_precision(Questions/Uptime) as QPS +.Ve +.PP +Actually, this still needs a little more work. If your \*(L"interval\*(R" is less +than one second, you might be dividing by zero because Uptime is incremental in +this mode by default. Instead, use Uptime_hires: +.PP +.Vb 1 +\& Questions, Uptime, set_precision(Questions/Uptime_hires) as QPS +.Ve +.PP +This example is simple, but it shows how easy it is to choose which variables +you want to monitor. +.SH "PLUGINS" +.IX Header "PLUGINS" +innotop has a simple but powerful plugin mechanism by which you can extend +or modify its existing functionality, and add new functionality. innotop's +plugin functionality is event\-based: plugins register themselves to be called +when events happen. They then have a chance to influence the event. +.PP +An innotop plugin is a Perl module placed in innotop's \*(L"plugin_dir\*(R" +directory. On \s-1UNIX\s0 systems, you can place a symbolic link to the module instead +of putting the actual file there. innotop automatically discovers the file. If +there is a corresponding entry in the \*(L"plugins\*(R" configuration file section, +innotop loads and activates the plugin. +.PP +The module must conform to innotop's plugin interface. Additionally, the source +code of the module must be written in such a way that innotop can inspect the +file and determine the package name and description. +.Sh "Package Source Convention" +.IX Subsection "Package Source Convention" +innotop inspects the plugin module's source to determine the Perl package name. +It looks for a line of the form \*(L"package Foo;\*(R" and if found, considers the +plugin's package name to be Foo. Of course the package name can be a valid Perl +package name, with double semicolons and so on. +.PP +It also looks for a description in the source code, to make the plugin editor +more human\-friendly. The description is a comment line of the form \*(L"# +description: Foo\*(R", where \*(L"Foo\*(R" is the text innotop will consider to be the +plugin's description. +.Sh "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. +.Sh "Plugin Variables" +.IX Subsection "Plugin Variables" +The plugin's constructor is passed a hash of innotop's variables, which it can +manipulate. It is probably a good idea if the plugin object saves a copy of it +for later use. The variables are defined in the innotop variable +\&\f(CW%pluggable_vars\fR, and are as follows: +.IP "action_for" 4 +.IX Item "action_for" +A hashref of key mappings. These are innotop's global hot\-keys. +.IP "agg_funcs" 4 +.IX Item "agg_funcs" +A hashref of functions that can be used for grouping. See \*(L"\s-1GROUPING\s0\*(R". +.IP "config" 4 +.IX Item "config" +The global configuration hash. +.IP "connections" 4 +.IX Item "connections" +A hashref of connection specifications. These are just specifications of how to +connect to a server. +.IP "dbhs" 4 +.IX Item "dbhs" +A hashref of innotop's database connections. These are actual \s-1DBI\s0 connection +objects. +.IP "filters" 4 +.IX Item "filters" +A hashref of filters applied to table rows. See \*(L"\s-1FILTERS\s0\*(R" for more. +.IP "modes" 4 +.IX Item "modes" +A hashref of modes. See \*(L"\s-1MODES\s0\*(R" for more. +.IP "server_groups" 4 +.IX Item "server_groups" +A hashref of server groups. See \*(L"\s-1SERVER\s0 \s-1GROUPS\s0\*(R". +.IP "tbl_meta" 4 +.IX Item "tbl_meta" +A hashref of innotop's table meta\-data, with one entry per table (see +\&\*(L"\s-1TABLES\s0\*(R" for more information). +.IP "trans_funcs" 4 +.IX Item "trans_funcs" +A hashref of transformation functions. See \*(L"\s-1TRANSFORMATIONS\s0\*(R". +.IP "var_sets" 4 +.IX Item "var_sets" +A hashref of variable sets. See \*(L"\s-1VARIABLE\s0 \s-1SETS\s0\*(R". +.Sh "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\fR, \f(CW$pre\fR, \f(CW$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. +.Sh "Simple Plugin Example" +.IX Subsection "Simple Plugin Example" +The easiest way to explain the plugin functionality is probably with a simple +example. The following module adds a column to the beginning of every table and +sets its value to 1. +.PP +.Vb 2 +\& use strict; +\& use warnings FATAL => \(aqall\(aq; +.Ve +.PP +.Vb 2 +\& package Innotop::Plugin::Example; +\& # description: Adds an \(aqexample\(aq column to every table +.Ve +.PP +.Vb 4 +\& sub new { +\& my ( $class, %vars ) = @_; +\& # Store reference to innotop\(aqs variables in $self +\& my $self = bless { %vars }, $class; +.Ve +.PP +.Vb 11 +\& # 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 => [], +\& }; +.Ve +.PP +.Vb 8 +\& # 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; +\& } +.Ve +.PP +.Vb 3 +\& # Be sure to return a reference to the object. +\& return $self; +\& } +.Ve +.PP +.Vb 5 +\& # 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); +\& } +.Ve +.PP +.Vb 8 +\& # 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; +\& } +\& } +.Ve +.PP +.Vb 1 +\& 1; +.Ve +.Sh "Plugin Editor" +.IX Subsection "Plugin Editor" +The plugin editor lets you view the plugins innotop discovered and activate or +deactivate them. Start the editor by pressing $ to start the configuration +editor from any mode. Press the 'p' key to start the plugin editor. You'll see +a list of plugins innotop discovered. You can use the 'j' and 'k' keys to move +the highlight to the desired one, then press the * key to toggle it active or +inactive. Exit the editor and restart innotop for the changes to take effect. +.SH "SQL STATEMENTS" +.IX Header "SQL STATEMENTS" +innotop uses a limited set of \s-1SQL\s0 statements to retrieve data from MySQL for +display. The statements are customized depending on the server version against +which they are executed; for example, on MySQL 5 and newer, \s-1INNODB_STATUS\s0 +executes \*(L"\s-1SHOW\s0 \s-1ENGINE\s0 \s-1INNODB\s0 \s-1STATUS\s0\*(R", while on earlier versions it executes +\&\*(L"\s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0\*(R". The statements are as follows: +.PP +.Vb 12 +\& Statement SQL executed +\& =================== =============================== +\& INNODB_STATUS SHOW [ENGINE] INNODB STATUS +\& KILL_CONNECTION KILL +\& KILL_QUERY KILL QUERY +\& OPEN_TABLES SHOW OPEN TABLES +\& PROCESSLIST SHOW FULL PROCESSLIST +\& SHOW_MASTER_LOGS SHOW MASTER LOGS +\& SHOW_MASTER_STATUS SHOW MASTER STATUS +\& SHOW_SLAVE_STATUS SHOW SLAVE STATUS +\& SHOW_STATUS SHOW [GLOBAL] STATUS +\& SHOW_VARIABLES SHOW [GLOBAL] VARIABLES +.Ve +.SH "DATA SOURCES" +.IX Header "DATA SOURCES" +Each time innotop extracts values to create a table (see \*(L"\s-1EXPRESSIONS\s0\*(R" and +\&\*(L"\s-1TABLES\s0\*(R"), it does so from a particular data source. Largely because of the +complex data extracted from \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0, this is slightly messy. \s-1SHOW\s0 +\&\s-1INNODB\s0 \s-1STATUS\s0 contains a mixture of single values and repeated values that form +nested data sets. +.PP +Whenever innotop fetches data from MySQL, it adds two extra bits to each set: +cxn and Uptime_hires. cxn is the name of the connection from which the data +came. Uptime_hires is a high-resolution version of the server's Uptime status +variable, which is important if your \*(L"interval\*(R" setting is sub\-second. +.PP +Here are the kinds of data sources from which data is extracted: +.IP "\s-1STATUS_VARIABLES\s0" 4 +.IX Item "STATUS_VARIABLES" +This is the broadest category, into which the most kinds of data fall. It +begins with the combination of \s-1SHOW\s0 \s-1STATUS\s0 and \s-1SHOW\s0 \s-1VARIABLES\s0, but other sources +may be included as needed, for example, \s-1SHOW\s0 \s-1MASTER\s0 \s-1STATUS\s0 and \s-1SHOW\s0 \s-1SLAVE\s0 +\&\s-1STATUS\s0, as well as many of the non-repeated values from \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. +.IP "\s-1DEADLOCK_LOCKS\s0" 4 +.IX Item "DEADLOCK_LOCKS" +This data is extracted from the transaction list in the \s-1LATEST\s0 \s-1DETECTED\s0 \s-1DEADLOCK\s0 +section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. It is nested two levels deep: transactions, then +locks. +.IP "\s-1DEADLOCK_TRANSACTIONS\s0" 4 +.IX Item "DEADLOCK_TRANSACTIONS" +This data is from the transaction list in the \s-1LATEST\s0 \s-1DETECTED\s0 \s-1DEADLOCK\s0 +section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. It is nested one level deep. +.IP "\s-1EXPLAIN\s0" 4 +.IX Item "EXPLAIN" +This data is from the result set returned by \s-1EXPLAIN\s0. +.IP "\s-1INNODB_TRANSACTIONS\s0" 4 +.IX Item "INNODB_TRANSACTIONS" +This data is from the \s-1TRANSACTIONS\s0 section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0. +.IP "\s-1IO_THREADS\s0" 4 +.IX Item "IO_THREADS" +This data is from the list of threads in the the \s-1FILE\s0 I/O section of \s-1SHOW\s0 \s-1INNODB\s0 +\&\s-1STATUS\s0. +.IP "\s-1INNODB_LOCKS\s0" 4 +.IX Item "INNODB_LOCKS" +This data is from the \s-1TRANSACTIONS\s0 section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0 and is nested +two levels deep. +.IP "\s-1OPEN_TABLES\s0" 4 +.IX Item "OPEN_TABLES" +This data is from \s-1SHOW\s0 \s-1OPEN\s0 \s-1TABLES\s0. +.IP "\s-1PROCESSLIST\s0" 4 +.IX Item "PROCESSLIST" +This data is from \s-1SHOW\s0 \s-1FULL\s0 \s-1PROCESSLIST\s0. +.IP "\s-1OS_WAIT_ARRAY\s0" 4 +.IX Item "OS_WAIT_ARRAY" +This data is from the \s-1SEMAPHORES\s0 section of \s-1SHOW\s0 \s-1INNODB\s0 \s-1STATUS\s0 and is nested one +level deep. It comes from the lines that look like this: +.Sp +.Vb 1 +\& \-\-Thread 1568861104 has waited at btr0cur.c line 424 .... +.Ve +.SH "MYSQL PRIVILEGES" +.IX Header "MYSQL PRIVILEGES" +.IP "\(bu" 4 +You must connect to MySQL as a user who has the \s-1SUPER\s0 privilege for many of the +functions. +.IP "\(bu" 4 +If you don't have the \s-1SUPER\s0 privilege, you can still run some functions, but you +won't necessarily see all the same data. +.IP "\(bu" 4 +You need the \s-1PROCESS\s0 privilege to see the list of currently running queries in Q +mode. +.IP "\(bu" 4 +You need special privileges to start and stop slave servers. +.IP "\(bu" 4 +You need appropriate privileges to create and drop the deadlock tables if needed +(see \*(L"\s-1SERVER\s0 \s-1CONNECTIONS\s0\*(R"). +.SH "SYSTEM REQUIREMENTS" +.IX Header "SYSTEM REQUIREMENTS" +You need Perl to run innotop, of course. You also need a few Perl modules: \s-1DBI\s0, +DBD::mysql, Term::ReadKey, and Time::HiRes. These should be included with most +Perl distributions, but in case they are not, I recommend using versions +distributed with your operating system or Perl distribution, not from \s-1CPAN\s0. +Term::ReadKey in particular has been known to cause problems if installed from +\&\s-1CPAN\s0. +.PP +If you have Term::ANSIColor, innotop will use it to format headers more readably +and compactly. (Under Microsoft Windows, you also need Win32::Console::ANSI for +terminal formatting codes to be honored). If you install Term::ReadLine, +preferably Term::ReadLine::Gnu, you'll get nice auto-completion support. +.PP +I run innotop on Gentoo GNU/Linux, Debian and Ubuntu, and I've had feedback from +people successfully running it on Red Hat, CentOS, Solaris, and Mac \s-1OSX\s0. I +don't see any reason why it won't work on other UNIX-ish operating systems, but +I don't know for sure. It also runs on Windows under ActivePerl without +problem. +.PP +I use innotop 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 and I hope you +report it. +.SH "FILES" +.IX Header "FILES" +$HOMEDIR/.innotop is used to store configuration information. Files include the +configuration file innotop.ini, 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" +I'm grateful to the following people for various reasons, and hope I haven't +forgotten to include anyone: +.PP +Allen K. Smith, +Aurimas Mikalauskas, +Bartosz Fenski, +Brian Miezejewski, +Christian Hammers, +Cyril Scetbon, +Dane Miller, +David Multer, +Dr. Frank Ullrich, +Giuseppe Maxia, +Google.com Site Reliability Engineers, +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 I've neglected to include. +.PP +(If I misspelled your name, it's probably because I'm afraid of putting +international characters into this documentation; earlier versions of Perl might +not be able to compile it then). +.SH "COPYRIGHT, LICENSE AND WARRANTY" +.IX Header "COPYRIGHT, LICENSE AND WARRANTY" +This program is copyright (c) 2006 Baron Schwartz. +Feedback and improvements are welcome. +.PP +\&\s-1THIS\s0 \s-1PROGRAM\s0 \s-1IS\s0 \s-1PROVIDED\s0 \*(L"\s-1AS\s0 \s-1IS\s0\*(R" \s-1AND\s0 \s-1WITHOUT\s0 \s-1ANY\s0 \s-1EXPRESS\s0 \s-1OR\s0 \s-1IMPLIED\s0 +\&\s-1WARRANTIES\s0, \s-1INCLUDING\s0, \s-1WITHOUT\s0 \s-1LIMITATION\s0, \s-1THE\s0 \s-1IMPLIED\s0 \s-1WARRANTIES\s0 \s-1OF\s0 +\&\s-1MERCHANTIBILITY\s0 \s-1AND\s0 \s-1FITNESS\s0 \s-1FOR\s0 A \s-1PARTICULAR\s0 \s-1PURPOSE\s0. +.PP +This program is free software; you can redistribute it and/or modify it under +the terms of the \s-1GNU\s0 General Public License as published by the Free Software +Foundation, version 2; \s-1OR\s0 the Perl Artistic License. On \s-1UNIX\s0 and similar +systems, you can issue `man perlgpl' or `man perlartistic' to read these +licenses. +.PP +You should have received a copy of the \s-1GNU\s0 General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, \s-1MA\s0 02111\-1307 \s-1USA\s0. +.PP +Execute innotop and press '!' to see this information at any time. +.SH "AUTHOR" +.IX Header "AUTHOR" +Baron Schwartz. +.SH "BUGS" +.IX Header "BUGS" +You can report bugs, ask for improvements, and get other help and support at +. There are mailing lists, forums, +a bug tracker, etc. Please use these instead of contacting me directly, as it +makes my job easier and benefits others if the discussions are permanent and +public. Of course, if you need to contact me in private, please do. --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/innotop/innotop +++ mysql-dfsg-5.0-5.0.51a/debian/additions/innotop/innotop @@ -0,0 +1,9485 @@ +#!/usr/bin/perl + +# vim: tw=160:nowrap:expandtab:tabstop=3:shiftwidth=3:softtabstop=3 + +use strict; +use warnings FATAL => 'all'; +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 Getopt::Long; +use List::Util qw(max min maxstr sum); +use InnoDBParser; +use POSIX qw(ceil); +use Time::HiRes qw(time sleep); +use Term::ReadKey qw(ReadMode ReadKey); + +# Version, license and warranty information. {{{1 +# ########################################################################### +our $VERSION = '1.6.0'; +our $SVN_REV = sprintf("%d", q$Revision: 383 $ =~ m/(\d+)/g); +our $SVN_URL = sprintf("%s", q$URL: https://innotop.svn.sourceforge.net/svnroot/innotop/trunk/innotop $ =~ m$svnroot/innotop/(\S+)$g); + +my $innotop_license = <<"LICENSE"; + +This is innotop version $VERSION, a MySQL and InnoDB monitor. + +This program is copyright (c) 2006 Baron Schwartz. +Feedback and improvements are welcome. + +THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, version 2; OR the Perl Artistic License. On UNIX and similar +systems, you can issue `man perlgpl' or `man perlartistic' to read these +licenses. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA. +LICENSE + +# Configuration information and global setup {{{1 +# ########################################################################### + +# Really, really, super-global variables. +my @config_versions = ( + "000-000-000", "001-003-000", # config file was one big name-value hash. + "001-003-000", "001-004-002", # config file contained non-user-defined stuff. +); + +my $clear_screen_sub; + +# This defines expected properties and defaults for the column definitions that +# eventually end up in tbl_meta. +my %col_props = ( + hdr => '', + just => '-', + dec => 0, # Whether to align the column on the decimal point + num => 0, + label => '', + user => 0, + src => '', + tbl => '', # Helps when writing/reading custom columns in config files + minw => 0, + maxw => 0, + trans => [], + agg => 'first', # Aggregate function + aggonly => 0, # Whether to show only when tbl_meta->{aggregate} is true +); + +# Actual DBI connections to MySQL servers. +my %dbhs; + +# Command-line parameters {{{2 +# ########################################################################### + +my @opt_spec = ( + { s => 'help', d => 'Show this help message' }, + { s => 'color|C!', d => 'Use terminal coloring (default)', c => 'color' }, + { s => 'config|c=s', d => 'Config file to read' }, + { s => 'nonint|n', d => 'Non-interactive, output tab-separated fields' }, + { s => 'count=i', d => 'Number of updates before exiting' }, + { s => 'delay|d=f', d => 'Delay between updates in seconds', c => 'interval' }, + { s => 'mode|m=s', d => 'Operating mode to start in', c => 'mode' }, + { s => 'inc|i!', d => 'Measure incremental differences', c => 'status_inc' }, + { s => 'version', d => 'Output version information and exit' }, +); + +# 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 Changeset $SVN_REV from $SVN_URL\n"; + exit(0); +} + +if ( $opts{'help'} ) { + print "Usage: innotop \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 < q{my $host = host || hostname || ''; ($host) = $host =~ m/^((?:[\d.]+(?=:))|(?:[a-zA-Z]\w+))/; return $host || ''}, + Port => q{my ($p) = host =~ m/:(.*)$/; return $p || 0}, + OldVersions => q{dulint_to_int(IB_tx_trx_id_counter) - dulint_to_int(IB_tx_purge_done_for)}, + MaxTxnTime => q/max(map{ $_->{active_secs} } @{ IB_tx_transactions }) || 0/, + NumTxns => q{scalar @{ IB_tx_transactions } }, + DirtyBufs => q{ $cur->{IB_bp_pages_modified} / ($cur->{IB_bp_buf_pool_size} || 1) }, + BufPoolFill => q{ $cur->{IB_bp_pages_total} / ($cur->{IB_bp_buf_pool_size} || 1) }, + ServerLoad => q{ $cur->{Threads_connected}/(Questions||1)/Uptime_hires }, + TxnTimeRemain => q{ defined undo_log_entries && defined $pre->{undo_log_entries} && undo_log_entries < $pre->{undo_log_entries} ? undo_log_entries / (($pre->{undo_log_entries} - undo_log_entries)/((active_secs-$pre->{active_secs})||1))||1 : 0}, + SlaveCatchupRate => ' defined $cur->{seconds_behind_master} && defined $pre->{seconds_behind_master} && $cur->{seconds_behind_master} < $pre->{seconds_behind_master} ? ($pre->{seconds_behind_master}-$cur->{seconds_behind_master})/($cur->{Uptime_hires}-$pre->{Uptime_hires}) : 0', + QcacheHitRatio => q{(Qcache_hits||0)/(((Com_select||0)+(Qcache_hits||0))||1)}, +); + +# ########################################################################### +# Column definitions {{{3 +# Defines every column in every table. A named column has the following +# properties: +# * hdr Column header/title +# * label Documentation for humans. +# * num Whether it's numeric (for sorting). +# * just Alignment; generated from num, user-overridable in tbl_meta +# * minw, maxw Auto-generated, user-overridable. +# Values from this hash are just copied to tbl_meta, which is where everything +# else in the program should read from. +# ########################################################################### + +my %columns = ( + active_secs => { hdr => 'SecsActive', num => 1, label => 'Seconds transaction has been active', }, + add_pool_alloc => { hdr => 'Add\'l Pool', num => 1, label => 'Additonal pool allocated' }, + attempted_op => { hdr => 'Action', num => 0, label => 'The action that caused the error' }, + awe_mem_alloc => { hdr => 'AWE Memory', num => 1, label => '[Windows] AWE memory allocated' }, + binlog_cache_overflow => { hdr => 'Binlog Cache', num => 1, label => 'Transactions too big for binlog cache that went to disk' }, + binlog_do_db => { hdr => 'Binlog Do DB', num => 0, label => 'binlog-do-db setting' }, + binlog_ignore_db => { hdr => 'Binlog Ignore DB', num => 0, label => 'binlog-ignore-db setting' }, + bps_in => { hdr => 'BpsIn', num => 1, label => 'Bytes per second received by the server', }, + bps_out => { hdr => 'BpsOut', num => 1, label => 'Bytes per second sent by the server', }, + buf_free => { hdr => 'Free Bufs', num => 1, label => 'Buffers free in the buffer pool' }, + buf_pool_hit_rate => { hdr => 'Hit Rate', num => 0, label => 'Buffer pool hit rate' }, + buf_pool_hits => { hdr => 'Hits', num => 1, label => 'Buffer pool hits' }, + buf_pool_reads => { hdr => 'Reads', num => 1, label => 'Buffer pool reads' }, + buf_pool_size => { hdr => 'Size', num => 1, label => 'Buffer pool size' }, + bufs_in_node_heap => { hdr => 'Node Heap Bufs', num => 1, label => 'Buffers in buffer pool node heap' }, + bytes_behind_master => { hdr => 'ByteLag', num => 1, label => 'Bytes the slave lags the master in binlog' }, + cell_event_set => { hdr => 'Ending?', num => 1, label => 'Whether the cell event is set' }, + cell_waiting => { hdr => 'Waiting?', num => 1, label => 'Whether the cell is waiting' }, + child_db => { hdr => 'Child DB', num => 0, label => 'The database of the child table' }, + child_index => { hdr => 'Child Index', num => 0, label => 'The index in the child table' }, + child_table => { hdr => 'Child Table', num => 0, label => 'The child table' }, + cmd => { hdr => 'Cmd', num => 0, label => 'Type of command being executed', }, + cnt => { hdr => 'Cnt', num => 0, label => 'Count', agg => 'count', aggonly => 1 }, + connect_retry => { hdr => 'Connect Retry', num => 1, label => 'Slave connect-retry timeout' }, + cxn => { hdr => 'CXN', num => 0, label => 'Connection from which the data came', }, + db => { hdr => 'DB', num => 0, label => 'Current database', }, + dict_mem_alloc => { hdr => 'Dict Mem', num => 1, label => 'Dictionary memory allocated' }, + dirty_bufs => { hdr => 'Dirty Buf', num => 1, label => 'Dirty buffer pool pages' }, + dl_txn_num => { hdr => 'Num', num => 0, label => 'Deadlocked transaction number', }, + event_set => { hdr => 'Evt Set?', num => 1, label => '[Win32] if a wait event is set', }, + exec_master_log_pos => { hdr => 'Exec Master Log Pos', num => 1, label => 'Exec Master Log Position' }, + fk_name => { hdr => 'Constraint', num => 0, label => 'The name of the FK constraint' }, + free_list_len => { hdr => 'Free List Len', num => 1, label => 'Length of the free list' }, + has_read_view => { hdr => 'Rd View', num => 1, label => 'Whether the transaction has a read view' }, + hash_searches_s => { hdr => 'Hash/Sec', num => 1, label => 'Number of hash searches/sec' }, + hash_table_size => { hdr => 'Size', num => 1, label => 'Number of non-hash searches/sec' }, + heap_no => { hdr => 'Heap', num => 1, label => 'Heap number' }, + heap_size => { hdr => 'Heap', num => 1, label => 'Heap size' }, + history_list_len => { hdr => 'History', num => 1, label => 'History list length' }, + host_and_domain => { hdr => 'Host', num => 0, label => 'Hostname/IP and domain' }, + host_and_port => { hdr => 'Host/IP', num => 0, label => 'Hostname or IP address, and port number', }, + hostname => { hdr => 'Host', num => 0, label => 'Hostname' }, + index => { hdr => 'Index', num => 0, label => 'The index involved' }, + index_ref => { hdr => 'Index Ref', num => 0, label => 'Index referenced' }, + info => { hdr => 'Query', num => 0, label => 'Info or the current query', }, + insert_intention => { hdr => 'Ins Intent', num => 1, label => 'Whether the thread was trying to insert' }, + inserts => { hdr => 'Inserts', num => 1, label => 'Inserts' }, + io_bytes_s => { hdr => 'Bytes/Sec', num => 1, label => 'Average I/O bytes/sec' }, + io_flush_type => { hdr => 'Flush Type', num => 0, label => 'I/O Flush Type' }, + io_fsyncs_s => { hdr => 'fsyncs/sec', num => 1, label => 'I/O fsyncs/sec' }, + io_reads_s => { hdr => 'Reads/Sec', num => 1, label => 'Average I/O reads/sec' }, + io_writes_s => { hdr => 'Writes/Sec', num => 1, label => 'Average I/O writes/sec' }, + ip => { hdr => 'IP', num => 0, label => 'IP address' }, + is_name_locked => { hdr => 'Locked', num => 1, label => 'Whether table is name locked', }, + key_buffer_hit => { hdr => 'KCacheHit', num => 1, label => 'Key cache hit ratio', }, + key_len => { hdr => 'Key Length', num => 1, label => 'Number of bytes used in the key' }, + last_chkp => { hdr => 'Last Checkpoint', num => 0, label => 'Last log checkpoint' }, + last_errno => { hdr => 'Last Errno', num => 1, label => 'Last error number' }, + last_error => { hdr => 'Last Error', num => 0, label => 'Last error' }, + last_s_file_name => { hdr => 'S-File', num => 0, label => 'Filename where last read locked' }, + last_s_line => { hdr => 'S-Line', num => 1, label => 'Line where last read locked' }, + last_x_file_name => { hdr => 'X-File', num => 0, label => 'Filename where last write locked' }, + last_x_line => { hdr => 'X-Line', num => 1, label => 'Line where last write locked' }, + last_pct => { hdr => 'Pct', num => 1, label => 'Last Percentage' }, + last_total => { hdr => 'Last Total', num => 1, label => 'Last Total' }, + last_value => { hdr => 'Last Incr', num => 1, label => 'Last Value' }, + load => { hdr => 'Load', num => 1, label => 'Server load' }, + lock_cfile_name => { hdr => 'Crtd File', num => 0, label => 'Filename where lock created' }, + lock_cline => { hdr => 'Crtd Line', num => 1, label => 'Line where lock created' }, + lock_mem_addr => { hdr => 'Addr', num => 0, label => 'The lock memory address' }, + lock_mode => { hdr => 'Mode', num => 0, label => 'The lock mode' }, + lock_structs => { hdr => 'LStrcts', num => 1, label => 'Number of lock structs' }, + lock_type => { hdr => 'Type', num => 0, label => 'The lock type' }, + lock_var => { hdr => 'Lck Var', num => 1, label => 'The lock variable' }, + lock_wait_time => { hdr => 'Wait', num => 1, label => 'How long txn has waited for a lock' }, + log_flushed_to => { hdr => 'Flushed To', num => 0, label => 'Log position flushed to' }, + log_ios_done => { hdr => 'IO Done', num => 1, label => 'Log I/Os done' }, + log_ios_s => { hdr => 'IO/Sec', num => 1, label => 'Average log I/Os per sec' }, + log_seq_no => { hdr => 'Sequence No.', num => 0, label => 'Log sequence number' }, + main_thread_id => { hdr => 'Main Thread ID', num => 1, label => 'Main thread ID' }, + main_thread_proc_no => { hdr => 'Main Thread Proc', num => 1, label => 'Main thread process number' }, + main_thread_state => { hdr => 'Main Thread State', num => 0, label => 'Main thread state' }, + master_file => { hdr => 'File', num => 0, label => 'Master file' }, + master_host => { hdr => 'Master', num => 0, label => 'Master server hostname' }, + master_log_file => { hdr => 'Master Log File', num => 0, label => 'Master log file' }, + master_port => { hdr => 'Master Port', num => 1, label => 'Master port' }, + master_pos => { hdr => 'Position', num => 1, label => 'Master position' }, + master_ssl_allowed => { hdr => 'Master SSL Allowed', num => 0, label => 'Master SSL Allowed' }, + master_ssl_ca_file => { hdr => 'Master SSL CA File', num => 0, label => 'Master SSL Cert Auth File' }, + master_ssl_ca_path => { hdr => 'Master SSL CA Path', num => 0, label => 'Master SSL Cert Auth Path' }, + master_ssl_cert => { hdr => 'Master SSL Cert', num => 0, label => 'Master SSL Cert' }, + master_ssl_cipher => { hdr => 'Master SSL Cipher', num => 0, label => 'Master SSL Cipher' }, + master_ssl_key => { hdr => 'Master SSL Key', num => 0, label => 'Master SSL Key' }, + master_user => { hdr => 'Master User', num => 0, label => 'Master username' }, + max_txn => { hdr => 'MaxTxnTime', num => 1, label => 'MaxTxn' }, + merged_recs => { hdr => 'Merged Recs', num => 1, label => 'Merged records' }, + merges => { hdr => 'Merges', num => 1, label => 'Merges' }, + mutex_os_waits => { hdr => 'Waits', num => 1, label => 'Mutex OS Waits' }, + mutex_spin_rounds => { hdr => 'Rounds', num => 1, label => 'Mutex Spin Rounds' }, + mutex_spin_waits => { hdr => 'Spins', num => 1, label => 'Mutex Spin Waits' }, + mysql_thread_id => { hdr => 'ID', num => 1, label => 'MySQL connection (thread) ID', }, + name => { hdr => 'Name', num => 0, label => 'Variable Name' }, + n_bits => { hdr => '# Bits', num => 1, label => 'Number of bits' }, + non_hash_searches_s => { hdr => 'Non-Hash/Sec', num => 1, label => 'Non-hash searches/sec' }, + num_deletes => { hdr => 'Del', num => 1, label => 'Number of deletes' }, + num_deletes_sec => { hdr => 'Del/Sec', num => 1, label => 'Number of deletes' }, + num_inserts => { hdr => 'Ins', num => 1, label => 'Number of inserts' }, + num_inserts_sec => { hdr => 'Ins/Sec', num => 1, label => 'Number of inserts' }, + num_readers => { hdr => 'Readers', num => 1, label => 'Number of readers' }, + num_reads => { hdr => 'Read', num => 1, label => 'Number of reads' }, + num_reads_sec => { hdr => 'Read/Sec', num => 1, label => 'Number of reads' }, + num_res_ext => { hdr => 'BTree Extents', num => 1, label => 'Number of extents reserved for B-Tree' }, + num_rows => { hdr => 'Row Count', num => 1, label => 'Number of rows estimated to examine' }, + num_times_open => { hdr => 'In Use', num => 1, label => '# times table is opened', }, + num_txns => { hdr => 'Txns', num => 1, label => 'Number of transactions' }, + num_updates => { hdr => 'Upd', num => 1, label => 'Number of updates' }, + num_updates_sec => { hdr => 'Upd/Sec', num => 1, label => 'Number of updates' }, + os_file_reads => { hdr => 'OS Reads', num => 1, label => 'OS file reads' }, + os_file_writes => { hdr => 'OS Writes', num => 1, label => 'OS file writes' }, + os_fsyncs => { hdr => 'OS fsyncs', num => 1, label => 'OS fsyncs' }, + os_thread_id => { hdr => 'OS Thread', num => 1, label => 'The operating system thread ID' }, + p_aio_writes => { hdr => 'Async Wrt', num => 1, label => 'Pending asynchronous I/O writes' }, + p_buf_pool_flushes => { hdr => 'Buffer Pool Flushes', num => 1, label => 'Pending buffer pool flushes' }, + p_ibuf_aio_reads => { hdr => 'IBuf Async Rds', num => 1, label => 'Pending insert buffer asynch I/O reads' }, + p_log_flushes => { hdr => 'Log Flushes', num => 1, label => 'Pending log flushes' }, + p_log_ios => { hdr => 'Log I/Os', num => 1, label => 'Pending log I/O operations' }, + p_normal_aio_reads => { hdr => 'Async Rds', num => 1, label => 'Pending asynchronous I/O reads' }, + p_preads => { hdr => 'preads', num => 1, label => 'Pending p-reads' }, + p_pwrites => { hdr => 'pwrites', num => 1, label => 'Pending p-writes' }, + p_sync_ios => { hdr => 'Sync I/Os', num => 1, label => 'Pending synchronous I/O operations' }, + page_creates_sec => { hdr => 'Creates/Sec', num => 1, label => 'Page creates/sec' }, + page_no => { hdr => 'Page', num => 1, label => 'Page number' }, + page_reads_sec => { hdr => 'Reads/Sec', num => 1, label => 'Page reads per second' }, + page_writes_sec => { hdr => 'Writes/Sec', num => 1, label => 'Page writes per second' }, + pages_created => { hdr => 'Created', num => 1, label => 'Pages created' }, + pages_modified => { hdr => 'Dirty Pages', num => 1, label => 'Pages modified (dirty)' }, + pages_read => { hdr => 'Reads', num => 1, label => 'Pages read' }, + pages_total => { hdr => 'Pages', num => 1, label => 'Pages total' }, + pages_written => { hdr => 'Writes', num => 1, label => 'Pages written' }, + parent_col => { hdr => 'Parent Column', num => 0, label => 'The referred column in the parent table', }, + parent_db => { hdr => 'Parent DB', num => 0, label => 'The database of the parent table' }, + parent_index => { hdr => 'Parent Index', num => 0, label => 'The referred index in the parent table' }, + parent_table => { hdr => 'Parent Table', num => 0, label => 'The parent table' }, + part_id => { hdr => 'Part ID', num => 1, label => 'Sub-part ID of the query' }, + partitions => { hdr => 'Partitions', num => 0, label => 'Query partitions used' }, + pct => { hdr => 'Pct', num => 1, label => 'Percentage' }, + pending_chkp_writes => { hdr => 'Chkpt Writes', num => 1, label => 'Pending log checkpoint writes' }, + pending_log_writes => { hdr => 'Log Writes', num => 1, label => 'Pending log writes' }, + port => { hdr => 'Port', num => 1, label => 'Client port number', }, + possible_keys => { hdr => 'Poss. Keys', num => 0, label => 'Possible keys' }, + proc_no => { hdr => 'Proc', num => 1, label => 'Process number' }, + q_cache_hit => { hdr => 'QCacheHit', num => 1, label => 'Query cache hit ratio', }, + qps => { hdr => 'QPS', num => 1, label => 'How many queries/sec', }, + queries_in_queue => { hdr => 'Queries Queued', num => 1, label => 'Queries in queue' }, + queries_inside => { hdr => 'Queries Inside', num => 1, label => 'Queries inside InnoDB' }, + query_id => { hdr => 'Query ID', num => 1, label => 'Query ID' }, + query_status => { hdr => 'Query Status', num => 0, label => 'The query status' }, + query_text => { hdr => 'Query Text', num => 0, label => 'The query text' }, + questions => { hdr => 'Questions', num => 1, label => 'How many queries the server has gotten', }, + read_master_log_pos => { hdr => 'Read Master Pos', num => 1, label => 'Read master log position' }, + read_views_open => { hdr => 'Rd Views', num => 1, label => 'Number of read views open' }, + reads_pending => { hdr => 'Pending Reads', num => 1, label => 'Reads pending' }, + relay_log_file => { hdr => 'Relay File', num => 0, label => 'Relay log file' }, + relay_log_pos => { hdr => 'Relay Pos', num => 1, label => 'Relay log position' }, + relay_log_size => { hdr => 'Relay Size', num => 1, label => 'Relay log size' }, + relay_master_log_file => { hdr => 'Relay Master File', num => 0, label => 'Relay master log file' }, + replicate_do_db => { hdr => 'Do DB', num => 0, label => 'Replicate-do-db setting' }, + replicate_do_table => { hdr => 'Do Table', num => 0, label => 'Replicate-do-table setting' }, + replicate_ignore_db => { hdr => 'Ignore DB', num => 0, label => 'Replicate-ignore-db setting' }, + replicate_ignore_table => { hdr => 'Ignore Table', num => 0, label => 'Replicate-do-table setting' }, + replicate_wild_do_table => { hdr => 'Wild Do Table', num => 0, label => 'Replicate-wild-do-table setting' }, + replicate_wild_ignore_table => { hdr => 'Wild Ignore Table', num => 0, label => 'Replicate-wild-ignore-table setting' }, + request_type => { hdr => 'Type', num => 0, label => 'Type of lock the thread waits for' }, + reservation_count => { hdr => 'ResCnt', num => 1, label => 'Reservation Count' }, + row_locks => { hdr => 'RLocks', num => 1, label => 'Number of row locks' }, + rw_excl_os_waits => { hdr => 'RW Waits', num => 1, label => 'R/W Excl. OS Waits' }, + rw_excl_spins => { hdr => 'RW Spins', num => 1, label => 'R/W Excl. Spins' }, + rw_shared_os_waits => { hdr => 'Sh Waits', num => 1, label => 'R/W Shared OS Waits' }, + rw_shared_spins => { hdr => 'Sh Spins', num => 1, label => 'R/W Shared Spins' }, + scan_type => { hdr => 'Type', num => 0, label => 'Scan type in chosen' }, + seg_size => { hdr => 'Seg. Size', num => 1, label => 'Segment size' }, + select_type => { hdr => 'Select Type', num => 0, label => 'Type of select used' }, + signal_count => { hdr => 'Signals', num => 1, label => 'Signal Count' }, + size => { hdr => 'Size', num => 1, label => 'Size of the tablespace' }, + skip_counter => { hdr => 'Skip Counter', num => 1, label => 'Skip counter' }, + slave_catchup_rate => { hdr => 'Catchup', num => 1, label => 'How fast the slave is catching up in the binlog' }, + slave_io_running => { hdr => 'Slave-IO', num => 0, label => 'Whether the slave I/O thread is running' }, + slave_io_state => { hdr => 'Slave IO State', num => 0, label => 'Slave I/O thread state' }, + slave_open_temp_tables => { hdr => 'Temp', num => 1, label => 'Slave open temp tables' }, + slave_sql_running => { hdr => 'Slave-SQL', num => 0, label => 'Whether the slave SQL thread is running' }, + slow => { hdr => 'Slow', num => 1, label => 'How many slow queries', }, + space_id => { hdr => 'Space', num => 1, label => 'Tablespace ID' }, + special => { hdr => 'Special', num => 0, label => 'Special/Other info' }, + state => { hdr => 'State', num => 0, label => 'Connection state', maxw => 18, }, + tables_in_use => { hdr => 'Tbl Used', num => 1, label => 'Number of tables in use' }, + tables_locked => { hdr => 'Tbl Lck', num => 1, label => 'Number of tables locked' }, + tbl => { hdr => 'Table', num => 0, label => 'Table', }, + thread => { hdr => 'Thread', num => 1, label => 'Thread number' }, + thread_decl_inside => { hdr => 'Thread Inside', num => 0, label => 'What the thread is declared inside' }, + thread_purpose => { hdr => 'Purpose', num => 0, label => "The thread's purpose" }, + thread_status => { hdr => 'Thread Status', num => 0, label => 'The thread status' }, + time => { hdr => 'Time', num => 1, label => 'Time since the last event', }, + time_behind_master => { hdr => 'TimeLag', num => 1, label => 'Time slave lags master' }, + timestring => { hdr => 'Timestring', num => 0, label => 'Time the event occurred' }, + total => { hdr => 'Total', num => 1, label => 'Total' }, + total_mem_alloc => { hdr => 'Memory', num => 1, label => 'Total memory allocated' }, + truncates => { hdr => 'Trunc', num => 0, label => 'Whether the deadlock is truncating InnoDB status' }, + txn_doesnt_see_ge => { hdr => "Txn Won't See", num => 0, label => 'Where txn read view is limited' }, + txn_id => { hdr => 'ID', num => 0, label => 'Transaction ID' }, + txn_sees_lt => { hdr => 'Txn Sees', num => 1, label => 'Where txn read view is limited' }, + txn_status => { hdr => 'Txn Status', num => 0, label => 'Transaction status' }, + txn_time_remain => { hdr => 'Remaining', num => 1, label => 'Time until txn rollback/commit completes' }, + undo_log_entries => { hdr => 'Undo', num => 1, label => 'Number of undo log entries' }, + undo_for => { hdr => 'Undo', num => 0, label => 'Undo for' }, + until_condition => { hdr => 'Until Condition', num => 0, label => 'Slave until condition' }, + until_log_file => { hdr => 'Until Log File', num => 0, label => 'Slave until log file' }, + until_log_pos => { hdr => 'Until Log Pos', num => 1, label => 'Slave until log position' }, + used_cells => { hdr => 'Cells Used', num => 1, label => 'Number of cells used' }, + used_bufs => { hdr => 'Used Bufs', num => 1, label => 'Number of buffer pool pages used' }, + user => { hdr => 'User', num => 0, label => 'Database username', }, + value => { hdr => 'Value', num => 1, label => 'Value' }, + versions => { hdr => 'Versions', num => 1, label => 'Number of InnoDB MVCC versions unpurged' }, + victim => { hdr => 'Victim', num => 0, label => 'Whether this txn was the deadlock victim' }, + wait_array_size => { hdr => 'Wait Array Size', num => 1, label => 'Wait Array Size' }, + wait_status => { hdr => 'Lock Status', num => 0, label => 'Status of txn locks' }, + waited_at_filename => { hdr => 'File', num => 0, label => 'Filename at which thread waits' }, + waited_at_line => { hdr => 'Line', num => 1, label => 'Line at which thread waits' }, + waiters_flag => { hdr => 'Waiters', num => 1, label => 'Waiters Flag' }, + waiting => { hdr => 'Waiting', num => 1, label => 'Whether lock is being waited for' }, + when => { hdr => 'When', num => 0, label => 'Time scale' }, + writer_lock_mode => { hdr => 'Wrtr Lck Mode', num => 0, label => 'Writer lock mode' }, + writer_thread => { hdr => 'Wrtr Thread', num => 1, label => 'Writer thread ID' }, + writes_pending => { hdr => 'Writes', num => 1, label => 'Number of writes pending' }, + writes_pending_flush_list => { hdr => 'Flush List Writes', num => 1, label => 'Number of flush list writes pending' }, + writes_pending_lru => { hdr => 'LRU Writes', num => 1, label => 'Number of LRU writes pending' }, + writes_pending_single_page => { hdr => '1-Page Writes', num => 1, label => 'Number of 1-page writes pending' }, +); + +# Apply a default property or three. By default, columns are not width-constrained, +# aligned left, and sorted alphabetically, not numerically. +foreach my $col ( values %columns ) { + map { $col->{$_} ||= 0 } qw(num minw maxw); + $col->{just} = $col->{num} ? '' : '-'; +} + +# Filters {{{3 +# This hash defines every filter that can be applied to a table. These +# become part of tbl_meta as well. Each filter is just an expression that +# returns true or false. +# Properties of each entry: +# * func: the subroutine +# * name: the name, repeated +# * user: whether it's a user-defined filter (saved in config) +# * text: text of the subroutine +# * note: explanation +my %filters = (); + +# These are pre-processed to live in %filters above, by compiling them. +my %builtin_filters = ( + hide_self => { + text => <<' END', + return ( !$set->{info} || $set->{info} ne 'SHOW FULL PROCESSLIST' ) + && ( !$set->{query_text} || $set->{query_text} !~ m/INNODB STATUS$/ ); + END + note => 'Removes the innotop processes from the list', + tbls => [qw(innodb_transactions processlist)], + }, + hide_inactive => { + text => <<' END', + return ( !defined($set->{txn_status}) || $set->{txn_status} ne 'not started' ) + && ( !defined($set->{cmd}) || $set->{cmd} !~ m/Sleep|Binlog Dump/ ) + && ( !defined($set->{info}) || $set->{info} =~ m/\S/ ); + END + note => 'Removes processes which are not doing anything', + tbls => [qw(innodb_transactions processlist)], + }, + hide_slave_io => { + text => <<' END', + return !$set->{state} || $set->{state} !~ m/^(?:Waiting for master|Has read all relay)/; + END + note => 'Removes slave I/O threads from the list', + tbls => [qw(processlist slave_io_status)], + }, + table_is_open => { + text => <<' END', + return $set->{num_times_open} + $set->{is_name_locked}; + END + note => 'Removes tables that are not in use or locked', + tbls => [qw(open_tables)], + }, + cxn_is_master => { + text => <<' END', + return $set->{master_file} ? 1 : 0; + END + note => 'Removes servers that are not masters', + tbls => [qw(master_status)], + }, + cxn_is_slave => { + text => <<' END', + return $set->{master_host} ? 1 : 0; + END + note => 'Removes servers that are not slaves', + tbls => [qw(slave_io_status slave_sql_status)], + }, + thd_is_not_waiting => { + text => <<' END', + return $set->{thread_status} !~ m#waiting for i/o request#; + END + note => 'Removes idle I/O threads', + tbls => [qw(io_threads)], + }, +); +foreach my $key ( keys %builtin_filters ) { + my ( $sub, $err ) = compile_filter($builtin_filters{$key}->{text}); + $filters{$key} = { + func => $sub, + text => $builtin_filters{$key}->{text}, + user => 0, + name => $key, # useful for later + note => $builtin_filters{$key}->{note}, + tbls => $builtin_filters{$key}->{tbls}, + } +} + +# Variable sets {{{3 +# Sets (arrayrefs) of variables that are used in S mode. They are read/written to +# the config file. +my %var_sets = ( + general => { + text => join( + ', ', + 'set_precision(Questions/Uptime_hires) as QPS', + 'set_precision(Com_commit/Uptime_hires) as Commit_PS', + 'set_precision((Com_rollback||0)/(Com_commit||1)) as Rollback_Commit', + 'set_precision((' + . join('+', map { "($_||0)" } + qw(Com_delete Com_delete_multi Com_insert Com_insert_select Com_replace + Com_replace_select Com_select Com_update Com_update_multi)) + . ')/(Com_commit||1)) as Write_Commit', + 'set_precision((Com_select+(Qcache_hits||0))/((' + . join('+', map { "($_||0)" } + qw(Com_delete Com_delete_multi Com_insert Com_insert_select Com_replace + Com_replace_select Com_select Com_update Com_update_multi)) + . ')||1)) as R_W_Ratio', + 'set_precision(Opened_tables/Uptime_hires) as Opens_PS', + 'percent($cur->{Open_tables}/($cur->{table_cache})) as Table_Cache_Used', + 'set_precision(Threads_created/Uptime_hires) as Threads_PS', + 'percent($cur->{Threads_cached}/($cur->{thread_cache_size}||1)) as Thread_Cache_Used', + 'percent($cur->{Max_used_connections}/($cur->{max_connections}||1)) as CXN_Used_Ever', + 'percent($cur->{Threads_connected}/($cur->{max_connections}||1)) as CXN_Used_Now', + ), + }, + commands => { + text => join( + ', ', + qw(Uptime Questions Com_delete Com_delete_multi Com_insert + Com_insert_select Com_replace Com_replace_select Com_select Com_update + Com_update_multi) + ), + }, + query_status => { + text => join( + ',', + qw( Uptime Select_full_join Select_full_range_join Select_range + Select_range_check Select_scan Slow_queries Sort_merge_passes + Sort_range Sort_rows Sort_scan) + ), + }, + innodb => { + text => join( + ',', + qw( Uptime Innodb_row_lock_current_waits Innodb_row_lock_time + Innodb_row_lock_time_avg Innodb_row_lock_time_max Innodb_row_lock_waits + Innodb_rows_deleted Innodb_rows_inserted Innodb_rows_read + Innodb_rows_updated) + ), + }, + txn => { + text => join( + ',', + qw( Uptime Com_begin Com_commit Com_rollback Com_savepoint + Com_xa_commit Com_xa_end Com_xa_prepare Com_xa_recover Com_xa_rollback + Com_xa_start) + ), + }, + key_cache => { + text => join( + ',', + qw( Uptime Key_blocks_not_flushed Key_blocks_unused Key_blocks_used + Key_read_requests Key_reads Key_write_requests Key_writes ) + ), + }, + query_cache => { + text => join( + ',', + "percent($exprs{QcacheHitRatio}) as Hit_Pct", + 'set_precision((Qcache_hits||0)/(Qcache_inserts||1)) as Hit_Ins', + 'set_precision((Qcache_lowmem_prunes||0)/Uptime_hires) as Lowmem_Prunes_sec', + 'percent(1-((Qcache_free_blocks||0)/(Qcache_total_blocks||1))) as Blocks_used', + qw( Qcache_free_blocks Qcache_free_memory Qcache_not_cached Qcache_queries_in_cache) + ), + }, + handler => { + text => join( + ',', + qw( Uptime Handler_read_key Handler_read_first Handler_read_next + Handler_read_prev Handler_read_rnd Handler_read_rnd_next Handler_delete + Handler_update Handler_write) + ), + }, + cxns_files_threads => { + text => join( + ',', + qw( Uptime Aborted_clients Aborted_connects Bytes_received Bytes_sent + Compression Connections Created_tmp_disk_tables Created_tmp_files + Created_tmp_tables Max_used_connections Open_files Open_streams + Open_tables Opened_tables Table_locks_immediate Table_locks_waited + Threads_cached Threads_connected Threads_created Threads_running) + ), + }, + prep_stmt => { + text => join( + ',', + qw( Uptime Com_dealloc_sql Com_execute_sql Com_prepare_sql Com_reset + Com_stmt_close Com_stmt_execute Com_stmt_fetch Com_stmt_prepare + Com_stmt_reset Com_stmt_send_long_data ) + ), + }, + innodb_health => { + text => join( + ',', + "$exprs{OldVersions} as OldVersions", + qw(IB_sm_mutex_spin_waits IB_sm_mutex_spin_rounds IB_sm_mutex_os_waits), + "$exprs{NumTxns} as NumTxns", + "$exprs{MaxTxnTime} as MaxTxnTime", + qw(IB_ro_queries_inside IB_ro_queries_in_queue), + "set_precision($exprs{DirtyBufs} * 100) as dirty_bufs", + "set_precision($exprs{BufPoolFill} * 100) as buf_fill", + qw(IB_bp_pages_total IB_bp_pages_read IB_bp_pages_written IB_bp_pages_created) + ), + }, + innodb_health2 => { + text => join( + ', ', + 'percent(1-((Innodb_buffer_pool_pages_free||0)/($cur->{Innodb_buffer_pool_pages_total}||1))) as BP_page_cache_usage', + 'percent(1-((Innodb_buffer_pool_reads||0)/(Innodb_buffer_pool_read_requests||1))) as BP_cache_hit_ratio', + 'Innodb_buffer_pool_wait_free', + 'Innodb_log_waits', + ), + }, + slow_queries => { + text => join( + ', ', + 'set_precision(Slow_queries/Uptime_hires) as Slow_PS', + 'set_precision(Select_full_join/Uptime_hires) as Full_Join_PS', + 'percent(Select_full_join/(Com_select||1)) as Full_Join_Ratio', + ), + }, +); + +# Server sets {{{3 +# Defines sets of servers between which the user can quickly switch. +my %server_groups; + +# Connections {{{3 +# This hash defines server connections. Each connection is a string that can be passed to +# the DBI connection. These are saved in the connections section in the config file. +my %connections; +# Defines the parts of connections. +my @conn_parts = qw(user have_user pass have_pass dsn savepass dl_table); + +# Graph widths {{{3 +# This hash defines the max values seen for various status/variable values, for graphing. +# These are stored in their own section in the config file. These are just initial values: +my %mvs = ( + Com_select => 50, + Com_insert => 50, + Com_update => 50, + Com_delete => 50, + Questions => 100, +); + +# ########################################################################### +# Valid Term::ANSIColor color strings. +# ########################################################################### +my %ansicolors = map { $_ => 1 } + qw( black blink blue bold clear concealed cyan dark green magenta on_black + on_blue on_cyan on_green on_magenta on_red on_white on_yellow red reset + reverse underline underscore white yellow); + +# ########################################################################### +# Valid comparison operators for color rules +# ########################################################################### +my %comp_ops = ( + '==' => 'Numeric equality', + '>' => 'Numeric greater-than', + '<' => 'Numeric less-than', + '>=' => 'Numeric greater-than/equal', + '<=' => 'Numeric less-than/equal', + '!=' => 'Numeric not-equal', + 'eq' => 'String equality', + 'gt' => 'String greater-than', + 'lt' => 'String less-than', + 'ge' => 'String greater-than/equal', + 'le' => 'String less-than/equal', + 'ne' => 'String not-equal', + '=~' => 'Pattern match', + '!~' => 'Negated pattern match', +); + +# ########################################################################### +# Valid aggregate functions. +# ########################################################################### +my %agg_funcs = ( + first => sub { + return $_[0] + }, + count => sub { + return 0 + @_; + }, + avg => sub { + my @args = grep { defined $_ } @_; + return (sum(map { m/([\d\.-]+)/g } @args) || 0) / (scalar(@args) || 1); + }, + sum => \&sum, +); + +# ########################################################################### +# Valid functions for transformations. +# ########################################################################### +my %trans_funcs = ( + shorten => \&shorten, + secs_to_time => \&secs_to_time, + no_ctrl_char => \&no_ctrl_char, + percent => \&percent, + commify => \&commify, + dulint_to_int => \&dulint_to_int, + set_precision => \&set_precision, +); + +# Table definitions {{{3 +# This hash defines every table that can get displayed in every mode. Each +# table specifies columns and column data sources. The column is +# defined by the %columns hash. +# +# Example: foo => { src => 'bar' } means the foo column (look at +# $columns{foo} for its definition) gets its data from the 'bar' element of +# the current data set, whatever that is. +# +# These columns are post-processed after being defined, because they get stuff +# from %columns. After all the config is loaded for columns, there's more +# post-processing too; the subroutines compiled from src get added to +# the hash elements for extract_values to use. +# ########################################################################### + +my %tbl_meta = ( + adaptive_hash_index => { + capt => 'Adaptive Hash Index', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + hash_table_size => { src => 'IB_ib_hash_table_size', trans => [qw(shorten)], }, + used_cells => { src => 'IB_ib_used_cells' }, + bufs_in_node_heap => { src => 'IB_ib_bufs_in_node_heap' }, + hash_searches_s => { src => 'IB_ib_hash_searches_s' }, + non_hash_searches_s => { src => 'IB_ib_non_hash_searches_s' }, + }, + visible => [ qw(cxn hash_table_size used_cells bufs_in_node_heap hash_searches_s non_hash_searches_s) ], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'ib', + group_by => [], + aggregate => 0, + }, + buffer_pool => { + capt => 'Buffer Pool', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + total_mem_alloc => { src => 'IB_bp_total_mem_alloc', trans => [qw(shorten)], }, + awe_mem_alloc => { src => 'IB_bp_awe_mem_alloc', trans => [qw(shorten)], }, + add_pool_alloc => { src => 'IB_bp_add_pool_alloc', trans => [qw(shorten)], }, + buf_pool_size => { src => 'IB_bp_buf_pool_size', trans => [qw(shorten)], }, + buf_free => { src => 'IB_bp_buf_free' }, + buf_pool_hit_rate => { src => 'IB_bp_buf_pool_hit_rate' }, + buf_pool_reads => { src => 'IB_bp_buf_pool_reads' }, + buf_pool_hits => { src => 'IB_bp_buf_pool_hits' }, + dict_mem_alloc => { src => 'IB_bp_dict_mem_alloc' }, + pages_total => { src => 'IB_bp_pages_total' }, + pages_modified => { src => 'IB_bp_pages_modified' }, + reads_pending => { src => 'IB_bp_reads_pending' }, + writes_pending => { src => 'IB_bp_writes_pending' }, + writes_pending_lru => { src => 'IB_bp_writes_pending_lru' }, + writes_pending_flush_list => { src => 'IB_bp_writes_pending_flush_list' }, + writes_pending_single_page => { src => 'IB_bp_writes_pending_single_page' }, + page_creates_sec => { src => 'IB_bp_page_creates_sec' }, + page_reads_sec => { src => 'IB_bp_page_reads_sec' }, + page_writes_sec => { src => 'IB_bp_page_writes_sec' }, + pages_created => { src => 'IB_bp_pages_created' }, + pages_read => { src => 'IB_bp_pages_read' }, + pages_written => { src => 'IB_bp_pages_written' }, + }, + visible => [ qw(cxn buf_pool_size buf_free pages_total pages_modified buf_pool_hit_rate total_mem_alloc add_pool_alloc)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'bp', + group_by => [], + aggregate => 0, + }, + # TODO: a new step in set_to_tbl: join result to itself, grouped? + # TODO: this would also enable pulling Q and T data together. + # TODO: using a SQL-ish language would also allow pivots to be easier -- treat the pivoted data as a view and SELECT from it. + cmd_summary => { + capt => 'Command Summary', + cust => {}, + cols => { + name => { src => 'name' }, + total => { src => 'total' }, + value => { src => 'value', agg => 'sum'}, + pct => { src => 'value/total', trans => [qw(percent)] }, + last_total => { src => 'last_total' }, + last_value => { src => 'last_value', agg => 'sum'}, + last_pct => { src => 'last_value/last_total', trans => [qw(percent)] }, + }, + visible => [qw(name value pct last_value last_pct)], + filters => [qw()], + sort_cols => '-value', + sort_dir => '1', + innodb => '', + group_by => [qw(name)], + aggregate => 1, + }, + deadlock_locks => { + capt => 'Deadlock Locks', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + mysql_thread_id => { src => 'mysql_thread_id' }, + dl_txn_num => { src => 'dl_txn_num' }, + lock_type => { src => 'lock_type' }, + space_id => { src => 'space_id' }, + page_no => { src => 'page_no' }, + heap_no => { src => 'heap_no' }, + n_bits => { src => 'n_bits' }, + index => { src => 'index' }, + db => { src => 'db' }, + tbl => { src => 'table' }, + lock_mode => { src => 'lock_mode' }, + special => { src => 'special' }, + insert_intention => { src => 'insert_intention' }, + waiting => { src => 'waiting' }, + }, + visible => [ qw(cxn mysql_thread_id waiting lock_mode db tbl index special insert_intention)], + filters => [], + sort_cols => 'cxn mysql_thread_id', + sort_dir => '1', + innodb => 'dl', + group_by => [], + aggregate => 0, + }, + deadlock_transactions => { + capt => 'Deadlock Transactions', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + active_secs => { src => 'active_secs' }, + dl_txn_num => { src => 'dl_txn_num' }, + has_read_view => { src => 'has_read_view' }, + heap_size => { src => 'heap_size' }, + host_and_domain => { src => 'hostname' }, + hostname => { src => $exprs{Host} }, + ip => { src => 'ip' }, + lock_structs => { src => 'lock_structs' }, + lock_wait_time => { src => 'lock_wait_time', trans => [ qw(secs_to_time) ] }, + mysql_thread_id => { src => 'mysql_thread_id' }, + os_thread_id => { src => 'os_thread_id' }, + proc_no => { src => 'proc_no' }, + query_id => { src => 'query_id' }, + query_status => { src => 'query_status' }, + query_text => { src => 'query_text', trans => [ qw(no_ctrl_char) ] }, + row_locks => { src => 'row_locks' }, + tables_in_use => { src => 'tables_in_use' }, + tables_locked => { src => 'tables_locked' }, + thread_decl_inside => { src => 'thread_decl_inside' }, + thread_status => { src => 'thread_status' }, + 'time' => { src => 'active_secs', trans => [ qw(secs_to_time) ] }, + timestring => { src => 'timestring' }, + txn_doesnt_see_ge => { src => 'txn_doesnt_see_ge' }, + txn_id => { src => 'txn_id' }, + txn_sees_lt => { src => 'txn_sees_lt' }, + txn_status => { src => 'txn_status' }, + truncates => { src => 'truncates' }, + undo_log_entries => { src => 'undo_log_entries' }, + user => { src => 'user' }, + victim => { src => 'victim' }, + wait_status => { src => 'lock_wait_status' }, + }, + visible => [ qw(cxn mysql_thread_id timestring user hostname victim time undo_log_entries lock_structs query_text)], + filters => [], + sort_cols => 'cxn mysql_thread_id', + sort_dir => '1', + innodb => 'dl', + group_by => [], + aggregate => 0, + }, + explain => { + capt => 'EXPLAIN Results', + cust => {}, + cols => { + part_id => { src => 'id' }, + select_type => { src => 'select_type' }, + tbl => { src => 'table' }, + partitions => { src => 'partitions' }, + scan_type => { src => 'type' }, + possible_keys => { src => 'possible_keys' }, + index => { src => 'key' }, + key_len => { src => 'key_len' }, + index_ref => { src => 'ref' }, + num_rows => { src => 'rows' }, + special => { src => 'extra' }, + }, + visible => [ qw(select_type tbl partitions scan_type possible_keys index key_len index_ref num_rows special)], + filters => [], + sort_cols => '', + sort_dir => '1', + innodb => '', + group_by => [], + aggregate => 0, + }, + file_io_misc => { + capt => 'File I/O Misc', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + io_bytes_s => { src => 'IB_io_avg_bytes_s' }, + io_flush_type => { src => 'IB_io_flush_type' }, + io_fsyncs_s => { src => 'IB_io_fsyncs_s' }, + io_reads_s => { src => 'IB_io_reads_s' }, + io_writes_s => { src => 'IB_io_writes_s' }, + os_file_reads => { src => 'IB_io_os_file_reads' }, + os_file_writes => { src => 'IB_io_os_file_writes' }, + os_fsyncs => { src => 'IB_io_os_fsyncs' }, + }, + visible => [ qw(cxn os_file_reads os_file_writes os_fsyncs io_reads_s io_writes_s io_bytes_s)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'io', + group_by => [], + aggregate => 0, + }, + fk_error => { + capt => 'Foreign Key Error Info', + cust => {}, + cols => { + timestring => { src => 'IB_fk_timestring' }, + child_db => { src => 'IB_fk_child_db' }, + child_table => { src => 'IB_fk_child_table' }, + child_index => { src => 'IB_fk_child_index' }, + fk_name => { src => 'IB_fk_fk_name' }, + parent_db => { src => 'IB_fk_parent_db' }, + parent_table => { src => 'IB_fk_parent_table' }, + parent_col => { src => 'IB_fk_parent_col' }, + parent_index => { src => 'IB_fk_parent_index' }, + attempted_op => { src => 'IB_fk_attempted_op' }, + }, + visible => [ qw(timestring child_db child_table child_index parent_db parent_table parent_col parent_index fk_name attempted_op)], + filters => [], + sort_cols => '', + sort_dir => '1', + innodb => 'fk', + group_by => [], + aggregate => 0, + }, + insert_buffers => { + capt => 'Insert Buffers', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + inserts => { src => 'IB_ib_inserts' }, + merged_recs => { src => 'IB_ib_merged_recs' }, + merges => { src => 'IB_ib_merges' }, + size => { src => 'IB_ib_size' }, + free_list_len => { src => 'IB_ib_free_list_len' }, + seg_size => { src => 'IB_ib_seg_size' }, + }, + visible => [ qw(cxn inserts merged_recs merges size free_list_len seg_size)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'ib', + group_by => [], + aggregate => 0, + }, + innodb_locks => { + capt => 'InnoDB Locks', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + db => { src => 'db' }, + index => { src => 'index' }, + insert_intention => { src => 'insert_intention' }, + lock_mode => { src => 'lock_mode' }, + lock_type => { src => 'lock_type' }, + lock_wait_time => { src => 'lock_wait_time', trans => [ qw(secs_to_time) ] }, + mysql_thread_id => { src => 'mysql_thread_id' }, + n_bits => { src => 'n_bits' }, + page_no => { src => 'page_no' }, + space_id => { src => 'space_id' }, + special => { src => 'special' }, + tbl => { src => 'table' }, + 'time' => { src => 'active_secs', hdr => 'Active', trans => [ qw(secs_to_time) ] }, + txn_id => { src => 'txn_id' }, + waiting => { src => 'waiting' }, + }, + visible => [ qw(cxn mysql_thread_id lock_type waiting lock_wait_time time lock_mode db tbl index insert_intention special)], + filters => [], + sort_cols => 'cxn -lock_wait_time', + sort_dir => '1', + innodb => 'tx', + colors => [ + { col => 'lock_wait_time', op => '>', arg => 60, color => 'red' }, + { col => 'lock_wait_time', op => '>', arg => 30, color => 'yellow' }, + { col => 'lock_wait_time', op => '>', arg => 10, color => 'green' }, + ], + group_by => [], + aggregate => 0, + }, + innodb_transactions => { + capt => 'InnoDB Transactions', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + active_secs => { src => 'active_secs' }, + has_read_view => { src => 'has_read_view' }, + heap_size => { src => 'heap_size' }, + hostname => { src => $exprs{Host} }, + ip => { src => 'ip' }, + wait_status => { src => 'lock_wait_status' }, + lock_wait_time => { src => 'lock_wait_time', trans => [ qw(secs_to_time) ] }, + lock_structs => { src => 'lock_structs' }, + mysql_thread_id => { src => 'mysql_thread_id' }, + os_thread_id => { src => 'os_thread_id' }, + proc_no => { src => 'proc_no' }, + query_id => { src => 'query_id' }, + query_status => { src => 'query_status' }, + query_text => { src => 'query_text', trans => [ qw(no_ctrl_char) ] }, + txn_time_remain => { src => $exprs{TxnTimeRemain}, trans => [ qw(secs_to_time) ] }, + row_locks => { src => 'row_locks' }, + tables_in_use => { src => 'tables_in_use' }, + tables_locked => { src => 'tables_locked' }, + thread_decl_inside => { src => 'thread_decl_inside' }, + thread_status => { src => 'thread_status' }, + 'time' => { src => 'active_secs', trans => [ qw(secs_to_time) ], agg => 'sum' }, + txn_doesnt_see_ge => { src => 'txn_doesnt_see_ge' }, + txn_id => { src => 'txn_id' }, + txn_sees_lt => { src => 'txn_sees_lt' }, + txn_status => { src => 'txn_status', minw => 10, maxw => 10 }, + undo_log_entries => { src => 'undo_log_entries' }, + user => { src => 'user', maxw => 10 }, + cnt => { src => 'mysql_thread_id', minw => 0 }, + }, + visible => [ qw(cxn cnt mysql_thread_id user hostname txn_status time undo_log_entries query_text)], + filters => [ qw( hide_self hide_inactive ) ], + sort_cols => '-active_secs txn_status cxn mysql_thread_id', + sort_dir => '1', + innodb => 'tx', + hide_caption => 1, + colors => [ + { col => 'wait_status', op => 'eq', arg => 'LOCK WAIT', color => 'black on_red' }, + { col => 'time', op => '>', arg => 600, color => 'red' }, + { col => 'time', op => '>', arg => 300, color => 'yellow' }, + { col => 'time', op => '>', arg => 60, color => 'green' }, + { col => 'time', op => '>', arg => 30, color => 'cyan' }, + { col => 'txn_status', op => 'eq', arg => 'not started', color => 'white' }, + ], + group_by => [ qw(cxn txn_status) ], + aggregate => 0, + }, + io_threads => { + capt => 'I/O Threads', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + thread => { src => 'thread' }, + thread_purpose => { src => 'purpose' }, + event_set => { src => 'event_set' }, + thread_status => { src => 'state' }, + }, + visible => [ qw(cxn thread thread_purpose thread_status)], + filters => [ qw() ], + sort_cols => 'cxn thread', + sort_dir => '1', + innodb => 'io', + group_by => [], + aggregate => 0, + }, + log_statistics => { + capt => 'Log Statistics', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + last_chkp => { src => 'IB_lg_last_chkp' }, + log_flushed_to => { src => 'IB_lg_log_flushed_to' }, + log_ios_done => { src => 'IB_lg_log_ios_done' }, + log_ios_s => { src => 'IB_lg_log_ios_s' }, + log_seq_no => { src => 'IB_lg_log_seq_no' }, + pending_chkp_writes => { src => 'IB_lg_pending_chkp_writes' }, + pending_log_writes => { src => 'IB_lg_pending_log_writes' }, + }, + visible => [ qw(cxn log_seq_no log_flushed_to last_chkp log_ios_done log_ios_s)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'lg', + group_by => [], + aggregate => 0, + }, + master_status => { + capt => 'Master Status', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + binlog_do_db => { src => 'binlog_do_db' }, + binlog_ignore_db => { src => 'binlog_ignore_db' }, + master_file => { src => 'file' }, + master_pos => { src => 'position' }, + binlog_cache_overflow => { src => '(Binlog_cache_disk_use||0)/(Binlog_cache_use||1)', trans => [ qw(percent) ] }, + }, + visible => [ qw(cxn master_file master_pos binlog_cache_overflow)], + filters => [ qw(cxn_is_master) ], + sort_cols => 'cxn', + sort_dir => '1', + innodb => '', + group_by => [], + aggregate => 0, + }, + pending_io => { + capt => 'Pending I/O', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + p_normal_aio_reads => { src => 'IB_io_pending_normal_aio_reads' }, + p_aio_writes => { src => 'IB_io_pending_aio_writes' }, + p_ibuf_aio_reads => { src => 'IB_io_pending_ibuf_aio_reads' }, + p_sync_ios => { src => 'IB_io_pending_sync_ios' }, + p_buf_pool_flushes => { src => 'IB_io_pending_buffer_pool_flushes' }, + p_log_flushes => { src => 'IB_io_pending_log_flushes' }, + p_log_ios => { src => 'IB_io_pending_log_ios' }, + p_preads => { src => 'IB_io_pending_preads' }, + p_pwrites => { src => 'IB_io_pending_pwrites' }, + }, + visible => [ qw(cxn p_normal_aio_reads p_aio_writes p_ibuf_aio_reads p_sync_ios p_log_flushes p_log_ios)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'io', + group_by => [], + aggregate => 0, + }, + open_tables => { + capt => 'Open Tables', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + db => { src => 'database' }, + tbl => { src => 'table' }, + num_times_open => { src => 'in_use' }, + is_name_locked => { src => 'name_locked' }, + }, + visible => [ qw(cxn db tbl num_times_open is_name_locked)], + filters => [ qw(table_is_open) ], + sort_cols => '-num_times_open cxn db tbl', + sort_dir => '1', + innodb => '', + group_by => [], + aggregate => 0, + }, + page_statistics => { + capt => 'Page Statistics', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + pages_read => { src => 'IB_bp_pages_read' }, + pages_written => { src => 'IB_bp_pages_written' }, + pages_created => { src => 'IB_bp_pages_created' }, + page_reads_sec => { src => 'IB_bp_page_reads_sec' }, + page_writes_sec => { src => 'IB_bp_page_writes_sec' }, + page_creates_sec => { src => 'IB_bp_page_creates_sec' }, + }, + visible => [ qw(cxn pages_read pages_written pages_created page_reads_sec page_writes_sec page_creates_sec)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'bp', + group_by => [], + aggregate => 0, + }, + processlist => { + capt => 'MySQL Process List', + cust => {}, + cols => { + cxn => { src => 'cxn', minw => 6, maxw => 10 }, + mysql_thread_id => { src => 'id', minw => 6, maxw => 0 }, + user => { src => 'user', minw => 5, maxw => 8 }, + hostname => { src => $exprs{Host}, minw => 13, maxw => 8, }, + port => { src => $exprs{Port}, minw => 0, maxw => 0, }, + host_and_port => { src => 'host', minw => 0, maxw => 0 }, + db => { src => 'db', minw => 6, maxw => 12 }, + cmd => { src => 'command', minw => 5, maxw => 0 }, + time => { src => 'time', minw => 5, maxw => 0, trans => [ qw(secs_to_time) ], agg => 'sum' }, + state => { src => 'state', minw => 0, maxw => 0 }, + info => { src => 'info', minw => 0, maxw => 0, trans => [ qw(no_ctrl_char) ] }, + cnt => { src => 'id', minw => 0, maxw => 0 }, + }, + visible => [ qw(cxn cmd cnt mysql_thread_id user hostname db time info)], + filters => [ qw(hide_self hide_inactive hide_slave_io) ], + sort_cols => '-time cxn hostname mysql_thread_id', + sort_dir => '1', + innodb => '', + hide_caption => 1, + colors => [ + { col => 'state', op => 'eq', arg => 'Locked', color => 'black on_red' }, + { col => 'cmd', op => 'eq', arg => 'Sleep', color => 'white' }, + { col => 'user', op => 'eq', arg => 'system user', color => 'white' }, + { col => 'cmd', op => 'eq', arg => 'Connect', color => 'white' }, + { col => 'cmd', op => 'eq', arg => 'Binlog Dump', color => 'white' }, + { col => 'time', op => '>', arg => 600, color => 'red' }, + { col => 'time', op => '>', arg => 120, color => 'yellow' }, + { col => 'time', op => '>', arg => 60, color => 'green' }, + { col => 'time', op => '>', arg => 30, color => 'cyan' }, + ], + group_by => [qw(cxn cmd)], + aggregate => 0, + }, + + # TODO: some more columns: + # kb_used=hdr='BufUsed' minw='0' num='0' src='percent(1 - ((Key_blocks_unused * key_cache_block_size) / (key_buffer_size||1)))' dec='0' trans='' tbl='q_header' just='-' user='1' maxw='0' label='User-defined' + # retries=hdr='Retries' minw='0' num='0' src='Slave_retried_transactions' dec='0' trans='' tbl='slave_sql_status' just='-' user='1' maxw='0' label='User-defined' + # thd=hdr='Thd' minw='0' num='0' src='Threads_connected' dec='0' trans='' tbl='slave_sql_status' just='-' user='1' maxw='0' label='User-defined' + + q_header => { + capt => 'Q-mode Header', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + questions => { src => 'Questions' }, + qps => { src => 'Questions/Uptime_hires', dec => 1, trans => [qw(shorten)] }, + load => { src => $exprs{ServerLoad}, dec => 1, trans => [qw(shorten)] }, + slow => { src => 'Slow_queries', dec => 1, trans => [qw(shorten)] }, + q_cache_hit => { src => $exprs{QcacheHitRatio}, dec => 1, trans => [qw(percent)] }, + key_buffer_hit => { src => '1-(Key_reads/(Key_read_requests||1))', dec => 1, trans => [qw(percent)] }, + bps_in => { src => 'Bytes_received/Uptime_hires', dec => 1, trans => [qw(shorten)] }, + bps_out => { src => 'Bytes_sent/Uptime_hires', dec => 1, trans => [qw(shorten)] }, + when => { src => 'when' }, + }, + visible => [ qw(cxn when load qps slow q_cache_hit key_buffer_hit bps_in bps_out)], + filters => [], + sort_cols => 'when cxn', + sort_dir => '1', + innodb => '', + hide_caption => 1, + group_by => [], + aggregate => 0, + }, + row_operations => { + capt => 'InnoDB Row Operations', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + num_inserts => { src => 'IB_ro_num_rows_ins' }, + num_updates => { src => 'IB_ro_num_rows_upd' }, + num_reads => { src => 'IB_ro_num_rows_read' }, + num_deletes => { src => 'IB_ro_num_rows_del' }, + num_inserts_sec => { src => 'IB_ro_ins_sec' }, + num_updates_sec => { src => 'IB_ro_upd_sec' }, + num_reads_sec => { src => 'IB_ro_read_sec' }, + num_deletes_sec => { src => 'IB_ro_del_sec' }, + }, + visible => [ qw(cxn num_inserts num_updates num_reads num_deletes num_inserts_sec + num_updates_sec num_reads_sec num_deletes_sec)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'ro', + group_by => [], + aggregate => 0, + }, + row_operation_misc => { + capt => 'Row Operation Misc', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + queries_in_queue => { src => 'IB_ro_queries_in_queue' }, + queries_inside => { src => 'IB_ro_queries_inside' }, + read_views_open => { src => 'IB_ro_read_views_open' }, + main_thread_id => { src => 'IB_ro_main_thread_id' }, + main_thread_proc_no => { src => 'IB_ro_main_thread_proc_no' }, + main_thread_state => { src => 'IB_ro_main_thread_state' }, + num_res_ext => { src => 'IB_ro_n_reserved_extents' }, + }, + visible => [ qw(cxn queries_in_queue queries_inside read_views_open main_thread_state)], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'ro', + group_by => [], + aggregate => 0, + }, + semaphores => { + capt => 'InnoDB Semaphores', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + mutex_os_waits => { src => 'IB_sm_mutex_os_waits' }, + mutex_spin_rounds => { src => 'IB_sm_mutex_spin_rounds' }, + mutex_spin_waits => { src => 'IB_sm_mutex_spin_waits' }, + reservation_count => { src => 'IB_sm_reservation_count' }, + rw_excl_os_waits => { src => 'IB_sm_rw_excl_os_waits' }, + rw_excl_spins => { src => 'IB_sm_rw_excl_spins' }, + rw_shared_os_waits => { src => 'IB_sm_rw_shared_os_waits' }, + rw_shared_spins => { src => 'IB_sm_rw_shared_spins' }, + signal_count => { src => 'IB_sm_signal_count' }, + wait_array_size => { src => 'IB_sm_wait_array_size' }, + }, + visible => [ qw(cxn mutex_os_waits mutex_spin_waits mutex_spin_rounds + rw_excl_os_waits rw_excl_spins rw_shared_os_waits rw_shared_spins + signal_count reservation_count )], + filters => [], + sort_cols => 'cxn', + sort_dir => '1', + innodb => 'sm', + group_by => [], + aggregate => 0, + }, + slave_io_status => { + capt => 'Slave I/O Status', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + connect_retry => { src => 'connect_retry' }, + master_host => { src => 'master_host', hdr => 'Master'}, + master_log_file => { src => 'master_log_file', hdr => 'File' }, + master_port => { src => 'master_port' }, + master_ssl_allowed => { src => 'master_ssl_allowed' }, + master_ssl_ca_file => { src => 'master_ssl_ca_file' }, + master_ssl_ca_path => { src => 'master_ssl_ca_path' }, + master_ssl_cert => { src => 'master_ssl_cert' }, + master_ssl_cipher => { src => 'master_ssl_cipher' }, + master_ssl_key => { src => 'master_ssl_key' }, + master_user => { src => 'master_user' }, + read_master_log_pos => { src => 'read_master_log_pos', hdr => 'Pos' }, + relay_log_size => { src => 'relay_log_space', trans => [qw(shorten)] }, + slave_io_running => { src => 'slave_io_running', hdr => 'On?' }, + slave_io_state => { src => 'slave_io_state', hdr => 'State' }, + }, + visible => [ qw(cxn master_host slave_io_running master_log_file relay_log_size read_master_log_pos slave_io_state)], + filters => [ qw( cxn_is_slave ) ], + sort_cols => 'slave_io_running cxn', + colors => [ + { col => 'slave_io_running', op => 'ne', arg => 'Yes', color => 'black on_red' }, + ], + sort_dir => '1', + innodb => '', + group_by => [], + aggregate => 0, + }, + slave_sql_status => { + capt => 'Slave SQL Status', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + exec_master_log_pos => { src => 'exec_master_log_pos', hdr => 'Master Pos' }, + last_errno => { src => 'last_errno' }, + last_error => { src => 'last_error' }, + master_host => { src => 'master_host', hdr => 'Master' }, + relay_log_file => { src => 'relay_log_file' }, + relay_log_pos => { src => 'relay_log_pos' }, + relay_log_size => { src => 'relay_log_space', trans => [qw(shorten)] }, + relay_master_log_file => { src => 'relay_master_log_file', hdr => 'Master File' }, + replicate_do_db => { src => 'replicate_do_db' }, + replicate_do_table => { src => 'replicate_do_table' }, + replicate_ignore_db => { src => 'replicate_ignore_db' }, + replicate_ignore_table => { src => 'replicate_ignore_table' }, + replicate_wild_do_table => { src => 'replicate_wild_do_table' }, + replicate_wild_ignore_table => { src => 'replicate_wild_ignore_table' }, + skip_counter => { src => 'skip_counter' }, + slave_sql_running => { src => 'slave_sql_running', hdr => 'On?' }, + until_condition => { src => 'until_condition' }, + until_log_file => { src => 'until_log_file' }, + until_log_pos => { src => 'until_log_pos' }, + time_behind_master => { src => 'seconds_behind_master', trans => [ qw(secs_to_time) ] }, + bytes_behind_master => { src => 'master_log_file && master_log_file eq relay_master_log_file ? read_master_log_pos - exec_master_log_pos : 0', trans => [qw(shorten)] }, + slave_catchup_rate => { src => $exprs{SlaveCatchupRate}, trans => [ qw(set_precision) ] }, + slave_open_temp_tables => { src => 'Slave_open_temp_tables' }, + }, + visible => [ qw(cxn master_host slave_sql_running time_behind_master slave_catchup_rate slave_open_temp_tables relay_log_pos last_error)], + filters => [ qw( cxn_is_slave ) ], + sort_cols => 'slave_sql_running cxn', + sort_dir => '1', + innodb => '', + colors => [ + { col => 'slave_sql_running', op => 'ne', arg => 'Yes', color => 'black on_red' }, + { col => 'time_behind_master', op => '>', arg => 600, color => 'red' }, + { col => 'time_behind_master', op => '>', arg => 60, color => 'yellow' }, + { col => 'time_behind_master', op => '==', arg => 0, color => 'white' }, + ], + group_by => [], + aggregate => 0, + }, + t_header => { + capt => 'T-Mode Header', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + dirty_bufs => { src => $exprs{DirtyBufs}, trans => [qw(percent)] }, + history_list_len => { src => 'IB_tx_history_list_len' }, + lock_structs => { src => 'IB_tx_num_lock_structs' }, + num_txns => { src => $exprs{NumTxns} }, + max_txn => { src => $exprs{MaxTxnTime}, trans => [qw(secs_to_time)] }, + undo_for => { src => 'IB_tx_purge_undo_for' }, + used_bufs => { src => $exprs{BufPoolFill}, trans => [qw(percent)]}, + versions => { src => $exprs{OldVersions} }, + }, + visible => [ qw(cxn history_list_len versions undo_for dirty_bufs used_bufs num_txns max_txn lock_structs)], + filters => [ ], + sort_cols => 'cxn', + sort_dir => '1', + innodb => '', + colors => [], + hide_caption => 1, + group_by => [], + aggregate => 0, + }, + var_status => { + capt => 'Variables & Status', + cust => {}, + cols => {}, # Generated from current varset + visible => [], # Generated from current varset + filters => [], + sort_cols => '', + sort_dir => 1, + innodb => '', + temp => 1, # Do not persist to config file. + hide_caption => 1, + pivot => 0, + group_by => [], + aggregate => 0, + }, + wait_array => { + capt => 'InnoDB Wait Array', + cust => {}, + cols => { + cxn => { src => 'cxn' }, + thread => { src => 'thread' }, + waited_at_filename => { src => 'waited_at_filename' }, + waited_at_line => { src => 'waited_at_line' }, + 'time' => { src => 'waited_secs', trans => [ qw(secs_to_time) ] }, + request_type => { src => 'request_type' }, + lock_mem_addr => { src => 'lock_mem_addr' }, + lock_cfile_name => { src => 'lock_cfile_name' }, + lock_cline => { src => 'lock_cline' }, + writer_thread => { src => 'writer_thread' }, + writer_lock_mode => { src => 'writer_lock_mode' }, + num_readers => { src => 'num_readers' }, + lock_var => { src => 'lock_var' }, + waiters_flag => { src => 'waiters_flag' }, + last_s_file_name => { src => 'last_s_file_name' }, + last_s_line => { src => 'last_s_line' }, + last_x_file_name => { src => 'last_x_file_name' }, + last_x_line => { src => 'last_x_line' }, + cell_waiting => { src => 'cell_waiting' }, + cell_event_set => { src => 'cell_event_set' }, + }, + visible => [ qw(cxn thread time waited_at_filename waited_at_line request_type num_readers lock_var waiters_flag cell_waiting cell_event_set)], + filters => [], + sort_cols => 'cxn -time', + sort_dir => '1', + innodb => 'sm', + group_by => [], + aggregate => 0, + }, +); + +# Initialize %tbl_meta from %columns and do some checks. +foreach my $table_name ( keys %tbl_meta ) { + my $table = $tbl_meta{$table_name}; + my $cols = $table->{cols}; + + foreach my $col_name ( keys %$cols ) { + my $col_def = $table->{cols}->{$col_name}; + die "I can't find a column named '$col_name' for '$table_name'" unless $columns{$col_name}; + $columns{$col_name}->{referenced} = 1; + + foreach my $prop ( keys %col_props ) { + # Each column gets non-existing values set from %columns or defaults from %col_props. + if ( !$col_def->{$prop} ) { + $col_def->{$prop} + = defined($columns{$col_name}->{$prop}) + ? $columns{$col_name}->{$prop} + : $col_props{$prop}; + } + } + + # Ensure transformations and aggregate functions are valid + die "Unknown aggregate function '$col_def->{agg}' " + . "for column '$col_name' in table '$table_name'" + unless exists $agg_funcs{$col_def->{agg}}; + foreach my $trans ( @{$col_def->{trans}} ) { + die "Unknown transformation '$trans' " + . "for column '$col_name' in table '$table_name'" + unless exists $trans_funcs{$trans}; + } + } + + # Ensure each column in visible and group_by exists in cols + foreach my $place ( qw(visible group_by) ) { + foreach my $col_name ( @{$table->{$place}} ) { + if ( !exists $cols->{$col_name} ) { + die "Column '$col_name' is listed in '$place' for '$table_name', but doesn't exist"; + } + } + } + + # Compile sort and color subroutines + $table->{sort_func} = make_sort_func($table); + $table->{color_func} = make_color_func($table); +} + +# This is for code cleanup: +{ + my @unused_cols = grep { !$columns{$_}->{referenced} } sort keys %columns; + if ( @unused_cols ) { + die "The following columns are not used: " + . join(' ', @unused_cols); + } +} + +# ########################################################################### +# Operating modes {{{3 +# ########################################################################### +my %modes = ( + B => { + hdr => 'InnoDB Buffers', + cust => {}, + note => 'Shows buffer info from InnoDB', + action_for => { + i => { + action => sub { toggle_config('status_inc') }, + label => 'Toggle incremental status display', + }, + }, + display_sub => \&display_B, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(buffer_pool page_statistics insert_buffers adaptive_hash_index)], + visible_tables => [qw(buffer_pool page_statistics insert_buffers adaptive_hash_index)], + }, + C => { + hdr => 'Command Summary', + cust => {}, + note => 'Shows relative magnitude of variables', + action_for => { + s => { + action => sub { get_config_interactive('cmd_filter') }, + label => 'Choose variable prefix', + }, + }, + display_sub => \&display_C, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(cmd_summary)], + visible_tables => [qw(cmd_summary)], + }, + D => { + hdr => 'InnoDB Deadlocks', + cust => {}, + note => 'View InnoDB deadlock information', + action_for => { + c => { + action => sub { edit_table('deadlock_transactions') }, + label => 'Choose visible columns', + }, + w => { + action => \&create_deadlock, + label => 'Wipe deadlock status info by creating a deadlock', + }, + }, + display_sub => \&display_D, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(deadlock_transactions deadlock_locks)], + visible_tables => [qw(deadlock_transactions deadlock_locks)], + }, + F => { + hdr => 'InnoDB FK Err', + cust => {}, + note => 'View the latest InnoDB foreign key error', + action_for => {}, + display_sub => \&display_F, + connections => [], + server_group => '', + one_connection => 1, + tables => [qw(fk_error)], + visible_tables => [qw(fk_error)], + }, + I => { + hdr => 'InnoDB I/O Info', + cust => {}, + note => 'Shows I/O info (i/o, log...) from InnoDB', + action_for => { + i => { + action => sub { toggle_config('status_inc') }, + label => 'Toggle incremental status display', + }, + }, + display_sub => \&display_I, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(io_threads pending_io file_io_misc log_statistics)], + visible_tables => [qw(io_threads pending_io file_io_misc log_statistics)], + }, + L => { + hdr => 'Locks', + cust => {}, + note => 'Shows transaction locks', + action_for => { + a => { + action => sub { send_cmd_to_servers('CREATE TABLE IF NOT EXISTS test.innodb_lock_monitor(a int) ENGINE=InnoDB', 0, '', []); }, + label => 'Start the InnoDB Lock Monitor', + }, + o => { + action => sub { send_cmd_to_servers('DROP TABLE IF EXISTS test.innodb_lock_monitor', 0, '', []); }, + label => 'Stop the InnoDB Lock Monitor', + }, + }, + display_sub => \&display_L, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(innodb_locks)], + visible_tables => [qw(innodb_locks)], + }, + M => { + hdr => 'Replication Status', + cust => {}, + note => 'Shows replication (master and slave) status', + action_for => { + a => { + action => sub { send_cmd_to_servers('START SLAVE', 0, 'START SLAVE SQL_THREAD UNTIL MASTER_LOG_FILE = ?, MASTER_LOG_POS = ?', []); }, + label => 'Start slave(s)', + }, + i => { + action => sub { toggle_config('status_inc') }, + label => 'Toggle incremental status display', + }, + o => { + action => sub { send_cmd_to_servers('STOP SLAVE', 0, '', []); }, + label => 'Stop slave(s)', + }, + b => { + action => sub { purge_master_logs() }, + label => 'Purge unused master logs', + }, + }, + display_sub => \&display_M, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(slave_sql_status slave_io_status master_status)], + visible_tables => [qw(slave_sql_status slave_io_status master_status)], + }, + O => { + hdr => 'Open Tables', + cust => {}, + note => 'Shows open tables in MySQL', + action_for => { + r => { + action => sub { reverse_sort('open_tables'); }, + label => 'Reverse sort order', + }, + s => { + action => sub { choose_sort_cols('open_tables'); }, + label => "Choose sort column", + }, + }, + display_sub => \&display_O, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(open_tables)], + visible_tables => [qw(open_tables)], + }, + Q => { + hdr => 'Query List', + cust => {}, + note => 'Shows queries from SHOW FULL PROCESSLIST', + action_for => { + a => { + action => sub { toggle_filter('processlist', 'hide_self') }, + label => 'Toggle the innotop process', + }, + c => { + action => sub { edit_table('processlist') }, + label => 'Choose visible columns', + }, + e => { + action => sub { analyze_query('e'); }, + label => "Explain a thread's query", + }, + f => { + action => sub { analyze_query('f'); }, + label => "Show a thread's full query", + }, + h => { + action => sub { toggle_visible_table('Q', 'q_header') }, + label => 'Toggle the header on and off', + }, + i => { + action => sub { toggle_filter('processlist', 'hide_inactive') }, + label => 'Toggle idle processes', + }, + k => { + action => sub { kill_query('CONNECTION') }, + label => "Kill a query's connection", + }, + r => { + action => sub { reverse_sort('processlist'); }, + label => 'Reverse sort order', + }, + s => { + action => sub { choose_sort_cols('processlist'); }, + label => "Change the display's sort column", + }, + x => { + action => sub { kill_query('QUERY') }, + label => "Kill a query", + }, + }, + display_sub => \&display_Q, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(q_header processlist)], + visible_tables => [qw(q_header processlist)], + }, + R => { + hdr => 'InnoDB Row Ops', + cust => {}, + note => 'Shows InnoDB row operation and semaphore info', + action_for => { + i => { + action => sub { toggle_config('status_inc') }, + label => 'Toggle incremental status display', + }, + }, + display_sub => \&display_R, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(row_operations row_operation_misc semaphores wait_array)], + visible_tables => [qw(row_operations row_operation_misc semaphores wait_array)], + }, + S => { + hdr => 'Variables & Status', + cust => {}, + note => 'Shows query load statistics a la vmstat', + action_for => { + '>' => { + action => sub { switch_var_set('S_set', 1) }, + label => 'Switch to next variable set', + }, + '<' => { + action => sub { switch_var_set('S_set', -1) }, + label => 'Switch to prev variable set', + }, + c => { + action => sub { + choose_var_set('S_set'); + start_S_mode(); + }, + label => "Choose which set to display", + }, + e => { + action => \&edit_current_var_set, + label => 'Edit the current set of variables', + }, + i => { + action => sub { $clear_screen_sub->(); toggle_config('status_inc') }, + label => 'Toggle incremental status display', + }, + '-' => { + action => sub { set_display_precision(-1) }, + label => 'Decrease fractional display precision', + }, + '+' => { + action => sub { set_display_precision(1) }, + label => 'Increase fractional display precision', + }, + g => { + action => sub { set_s_mode('g') }, + label => 'Switch to graph (tload) view', + }, + s => { + action => sub { set_s_mode('s') }, + label => 'Switch to standard (vmstat) view', + }, + v => { + action => sub { set_s_mode('v') }, + label => 'Switch to pivoted view', + }, + }, + display_sub => \&display_S, + no_clear_screen => 1, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(var_status)], + visible_tables => [qw(var_status)], + }, + T => { + hdr => 'InnoDB Txns', + cust => {}, + note => 'Shows InnoDB transactions in top-like format', + action_for => { + a => { + action => sub { toggle_filter('innodb_transactions', 'hide_self') }, + label => 'Toggle the innotop process', + }, + c => { + action => sub { edit_table('innodb_transactions') }, + label => 'Choose visible columns', + }, + e => { + action => sub { analyze_query('e'); }, + label => "Explain a thread's query", + }, + f => { + action => sub { analyze_query('f'); }, + label => "Show a thread's full query", + }, + h => { + action => sub { toggle_visible_table('T', 't_header') }, + label => 'Toggle the header on and off', + }, + i => { + action => sub { toggle_filter('innodb_transactions', 'hide_inactive') }, + label => 'Toggle inactive transactions', + }, + k => { + action => sub { kill_query('CONNECTION') }, + label => "Kill a transaction's connection", + }, + r => { + action => sub { reverse_sort('innodb_transactions'); }, + label => 'Reverse sort order', + }, + s => { + action => sub { choose_sort_cols('innodb_transactions'); }, + label => "Change the display's sort column", + }, + x => { + action => sub { kill_query('QUERY') }, + label => "Kill a query", + }, + }, + display_sub => \&display_T, + connections => [], + server_group => '', + one_connection => 0, + tables => [qw(t_header innodb_transactions)], + visible_tables => [qw(t_header innodb_transactions)], + }, +); + +# ########################################################################### +# Global key mappings {{{3 +# Keyed on a single character, which is read from the keyboard. Uppercase +# letters switch modes. Lowercase letters access commands when in a mode. +# These can be overridden by action_for in %modes. +# ########################################################################### +my %action_for = ( + '$' => { + action => \&edit_configuration, + label => 'Edit configuration settings', + }, + '?' => { + action => \&display_help, + label => 'Show help', + }, + '!' => { + action => \&display_license, + label => 'Show license and warranty', + }, + '^' => { + action => \&edit_table, + label => "Edit the displayed table(s)", + }, + '#' => { + action => \&choose_server_groups, + label => 'Select/create server groups', + }, + '@' => { + action => \&choose_servers, + label => 'Select/create server connections', + }, + '/' => { + action => \&add_quick_filter, + label => 'Quickly filter what you see', + }, + '\\' => { + action => \&clear_quick_filters, + label => 'Clear quick-filters', + }, + '%' => { + action => \&choose_filters, + label => 'Choose and edit table filters', + }, + "\t" => { + action => \&next_server_group, + label => 'Switch to the next server group', + key => 'TAB', + }, + '=' => { + action => \&toggle_aggregate, + label => 'Toggle aggregation', + }, + # TODO: can these be auto-generated from %modes? + B => { + action => sub { switch_mode('B') }, + label => '', + }, + C => { + action => sub { switch_mode('C') }, + label => '', + }, + D => { + action => sub { switch_mode('D') }, + label => '', + }, + F => { + action => sub { switch_mode('F') }, + label => '', + }, + I => { + action => sub { switch_mode('I') }, + label => '', + }, + L => { + action => sub { switch_mode('L') }, + label => '', + }, + M => { + action => sub { switch_mode('M') }, + label => '', + }, + O => { + action => sub { switch_mode('O') }, + label => '', + }, + Q => { + action => sub { switch_mode('Q') }, + label => '', + }, + R => { + action => sub { switch_mode('R') }, + label => '', + }, + S => { + action => \&start_S_mode, + label => '', + }, + T => { + action => sub { switch_mode('T') }, + label => '', + }, + d => { + action => sub { get_config_interactive('interval') }, + label => 'Change refresh interval', + }, + n => { action => \&next_server, label => 'Switch to the next connection' }, + p => { action => \&pause, label => 'Pause innotop', }, + q => { action => \&finish, label => 'Quit innotop', }, +); + +# ########################################################################### +# Sleep times after certain statements {{{3 +# ########################################################################### +my %stmt_sleep_time_for = (); + +# ########################################################################### +# Config editor key mappings {{{3 +# ########################################################################### +my %cfg_editor_action = ( + c => { + note => 'Edit columns, etc in the displayed table(s)', + func => \&edit_table, + }, + g => { + note => 'Edit general configuration', + func => \&edit_configuration_variables, + }, + k => { + note => 'Edit row-coloring rules', + func => \&edit_color_rules, + }, + p => { + note => 'Manage plugins', + func => \&edit_plugins, + }, + s => { + note => 'Edit server groups', + func => \&edit_server_groups, + }, + S => { + note => 'Edit SQL statement sleep delays', + func => \&edit_stmt_sleep_times, + }, + t => { + note => 'Choose which table(s) to display in this mode', + func => \&choose_mode_tables, + }, +); + +# ########################################################################### +# Color editor key mappings {{{3 +# ########################################################################### +my %color_editor_action = ( + n => { + note => 'Create a new color rule', + func => sub { + my ( $tbl, $idx ) = @_; + my $meta = $tbl_meta{$tbl}; + + $clear_screen_sub->(); + my $col; + do { + $col = prompt_list( + 'Choose the target column for the rule', + '', + sub { return keys %{$meta->{cols}} }, + { map { $_ => $meta->{cols}->{$_}->{label} } keys %{$meta->{cols}} }); + } while ( !$col ); + ( $col ) = grep { $_ } split(/\W+/, $col); + return $idx unless $col && exists $meta->{cols}->{$col}; + + $clear_screen_sub->(); + my $op; + do { + $op = prompt_list( + 'Choose the comparison operator for the rule', + '', + sub { return keys %comp_ops }, + { map { $_ => $comp_ops{$_} } keys %comp_ops } ); + } until ( $op ); + $op =~ s/\s+//g; + return $idx unless $op && exists $comp_ops{$op}; + + my $arg; + do { + $arg = prompt('Specify an argument for the comparison'); + } until defined $arg; + + my $color; + do { + $color = prompt_list( + 'Choose the color(s) the row should be when the rule matches', + '', + sub { return keys %ansicolors }, + { map { $_ => $_ } keys %ansicolors } ); + } until defined $color; + $color = join(' ', unique(grep { exists $ansicolors{$_} } split(/\W+/, $color))); + return $idx unless $color; + + push @{$tbl_meta{$tbl}->{colors}}, { + col => $col, + op => $op, + arg => $arg, + color => $color + }; + $tbl_meta{$tbl}->{cust}->{colors} = 1; + + return $idx; + }, + }, + d => { + note => 'Remove the selected rule', + func => sub { + my ( $tbl, $idx ) = @_; + my @rules = @{ $tbl_meta{$tbl}->{colors} }; + return 0 unless @rules > 0 && $idx < @rules && $idx >= 0; + splice(@{$tbl_meta{$tbl}->{colors}}, $idx, 1); + $tbl_meta{$tbl}->{cust}->{colors} = 1; + return $idx == @rules ? $#rules : $idx; + }, + }, + j => { + note => 'Move highlight down one', + func => sub { + my ( $tbl, $idx ) = @_; + my $num_rules = scalar @{$tbl_meta{$tbl}->{colors}}; + return ($idx + 1) % $num_rules; + }, + }, + k => { + note => 'Move highlight up one', + func => sub { + my ( $tbl, $idx ) = @_; + my $num_rules = scalar @{$tbl_meta{$tbl}->{colors}}; + return ($idx - 1) % $num_rules; + }, + }, + '+' => { + note => 'Move selected rule up one', + func => sub { + my ( $tbl, $idx ) = @_; + my $meta = $tbl_meta{$tbl}; + my $dest = $idx == 0 ? scalar(@{$meta->{colors}} - 1) : $idx - 1; + my $temp = $meta->{colors}->[$idx]; + $meta->{colors}->[$idx] = $meta->{colors}->[$dest]; + $meta->{colors}->[$dest] = $temp; + $meta->{cust}->{colors} = 1; + return $dest; + }, + }, + '-' => { + note => 'Move selected rule down one', + func => sub { + my ( $tbl, $idx ) = @_; + my $meta = $tbl_meta{$tbl}; + my $dest = $idx == scalar(@{$meta->{colors}} - 1) ? 0 : $idx + 1; + my $temp = $meta->{colors}->[$idx]; + $meta->{colors}->[$idx] = $meta->{colors}->[$dest]; + $meta->{colors}->[$dest] = $temp; + $meta->{cust}->{colors} = 1; + return $dest; + }, + }, +); + +# ########################################################################### +# Plugin editor key mappings {{{3 +# ########################################################################### +my %plugin_editor_action = ( + '*' => { + note => 'Toggle selected plugin active/inactive', + func => sub { + my ( $plugins, $idx ) = @_; + my $plugin = $plugins->[$idx]; + $plugin->{active} = $plugin->{active} ? 0 : 1; + return $idx; + }, + }, + j => { + note => 'Move highlight down one', + func => sub { + my ( $plugins, $idx ) = @_; + return ($idx + 1) % scalar(@$plugins); + }, + }, + k => { + note => 'Move highlight up one', + func => sub { + my ( $plugins, $idx ) = @_; + return $idx == 0 ? @$plugins - 1 : $idx - 1; + }, + }, +); + +# ########################################################################### +# Table editor key mappings {{{3 +# ########################################################################### +my %tbl_editor_action = ( + a => { + note => 'Add a column to the table', + func => sub { + my ( $tbl, $col ) = @_; + my @visible_cols = @{ $tbl_meta{$tbl}->{visible} }; + my %all_cols = %{ $tbl_meta{$tbl}->{cols} }; + delete @all_cols{@visible_cols}; + my $choice = prompt_list( + 'Choose a column', + '', + sub { return keys %all_cols; }, + { map { $_ => $all_cols{$_}->{label} || $all_cols{$_}->{hdr} } keys %all_cols }); + if ( $all_cols{$choice} ) { + push @{$tbl_meta{$tbl}->{visible}}, $choice; + $tbl_meta{$tbl}->{cust}->{visible} = 1; + return $choice; + } + return $col; + }, + }, + n => { + note => 'Create a new column and add it to the table', + func => sub { + my ( $tbl, $col ) = @_; + + $clear_screen_sub->(); + print word_wrap("Choose a name for the column. This name is not displayed, and is used only " + . "for internal reference. It can contain only lowercase letters, numbers, " + . "and underscores."); + print "\n\n"; + do { + $col = prompt("Enter column name"); + $col = '' if $col =~ m/[^a-z0-9_]/; + } while ( !$col ); + + $clear_screen_sub->(); + my $hdr; + do { + $hdr = prompt("Enter column header"); + } while ( !$hdr ); + + $clear_screen_sub->(); + print "Choose a source for the column's data\n\n"; + my ( $src, $sub, $err ); + do { + if ( $err ) { + print "Error: $err\n\n"; + } + $src = prompt("Enter column source"); + if ( $src ) { + ( $sub, $err ) = compile_expr($src); + } + } until ( !$err); + + # TODO: this duplicates %col_props. + $tbl_meta{$tbl}->{cols}->{$col} = { + hdr => $hdr, + src => $src, + just => '-', + num => 0, + label => 'User-defined', + user => 1, + tbl => $tbl, + minw => 0, + maxw => 0, + trans => [], + func => $sub, + dec => 0, + agg => 0, + aggonly => 0, + }; + + $tbl_meta{$tbl}->{visible} = [ unique(@{$tbl_meta{$tbl}->{visible}}, $col) ]; + $tbl_meta{$tbl}->{cust}->{visible} = 1; + return $col; + }, + }, + d => { + note => 'Remove selected column', + func => sub { + my ( $tbl, $col ) = @_; + my @visible_cols = @{ $tbl_meta{$tbl}->{visible} }; + my $idx = 0; + return $col unless @visible_cols > 1; + while ( $visible_cols[$idx] ne $col ) { + $idx++; + } + $tbl_meta{$tbl}->{visible} = [ grep { $_ ne $col } @visible_cols ]; + $tbl_meta{$tbl}->{cust}->{visible} = 1; + return $idx == $#visible_cols ? $visible_cols[$idx - 1] : $visible_cols[$idx + 1]; + }, + }, + e => { + note => 'Edit selected column', + func => sub { + # TODO: make this editor hotkey-driven and give readline support. + my ( $tbl, $col ) = @_; + $clear_screen_sub->(); + my $meta = $tbl_meta{$tbl}->{cols}->{$col}; + my @prop = qw(hdr label src just num minw maxw trans agg); # TODO redundant + + my $answer; + do { + # Do what the user asked... + if ( $answer && grep { $_ eq $answer } @prop ) { + # Some properties are arrays, others scalars. + my $ini = ref $col_props{$answer} ? join(' ', @{$meta->{$answer}}) : $meta->{$answer}; + my $val = prompt("New value for $answer", undef, $ini); + $val = [ split(' ', $val) ] if ref($col_props{$answer}); + if ( $answer eq 'trans' ) { + $val = [ unique(grep{ exists $trans_funcs{$_} } @$val) ]; + } + @{$meta}{$answer, 'user', 'tbl' } = ( $val, 1, $tbl ); + } + + my @display_lines = ( + '', + "You are editing column $tbl.$col.\n", + ); + + push @display_lines, create_table2( + \@prop, + { map { $_ => $_ } @prop }, + { map { $_ => ref $meta->{$_} eq 'ARRAY' ? join(' ', @{$meta->{$_}}) + : ref $meta->{$_} ? '[expression code]' + : $meta->{$_} + } @prop + }, + { sep => ' ' }); + draw_screen(\@display_lines, { raw => 1 }); + print "\n\n"; # One to add space, one to clear readline artifacts + $answer = prompt('Edit what? (q to quit)'); + } while ( $answer ne 'q' ); + + return $col; + }, + }, + j => { + note => 'Move highlight down one', + func => sub { + my ( $tbl, $col ) = @_; + my @visible_cols = @{ $tbl_meta{$tbl}->{visible} }; + my $idx = 0; + while ( $visible_cols[$idx] ne $col ) { + $idx++; + } + return $visible_cols[ ($idx + 1) % @visible_cols ]; + }, + }, + k => { + note => 'Move highlight up one', + func => sub { + my ( $tbl, $col ) = @_; + my @visible_cols = @{ $tbl_meta{$tbl}->{visible} }; + my $idx = 0; + while ( $visible_cols[$idx] ne $col ) { + $idx++; + } + return $visible_cols[ $idx - 1 ]; + }, + }, + '+' => { + note => 'Move selected column up one', + func => sub { + my ( $tbl, $col ) = @_; + my $meta = $tbl_meta{$tbl}; + my @visible_cols = @{$meta->{visible}}; + my $idx = 0; + while ( $visible_cols[$idx] ne $col ) { + $idx++; + } + if ( $idx ) { + $visible_cols[$idx] = $visible_cols[$idx - 1]; + $visible_cols[$idx - 1] = $col; + $meta->{visible} = \@visible_cols; + } + else { + shift @{$meta->{visible}}; + push @{$meta->{visible}}, $col; + } + $meta->{cust}->{visible} = 1; + return $col; + }, + }, + '-' => { + note => 'Move selected column down one', + func => sub { + my ( $tbl, $col ) = @_; + my $meta = $tbl_meta{$tbl}; + my @visible_cols = @{$meta->{visible}}; + my $idx = 0; + while ( $visible_cols[$idx] ne $col ) { + $idx++; + } + if ( $idx == $#visible_cols ) { + unshift @{$meta->{visible}}, $col; + pop @{$meta->{visible}}; + } + else { + $visible_cols[$idx] = $visible_cols[$idx + 1]; + $visible_cols[$idx + 1] = $col; + $meta->{visible} = \@visible_cols; + } + $meta->{cust}->{visible} = 1; + return $col; + }, + }, + f => { + note => 'Choose filters', + func => sub { + my ( $tbl, $col ) = @_; + choose_filters($tbl); + return $col; + }, + }, + o => { + note => 'Edit color rules', + func => sub { + my ( $tbl, $col ) = @_; + edit_color_rules($tbl); + return $col; + }, + }, + s => { + note => 'Choose sort columns', + func => sub { + my ( $tbl, $col ) = @_; + choose_sort_cols($tbl); + return $col; + }, + }, + g => { + note => 'Choose group-by (aggregate) columns', + func => sub { + my ( $tbl, $col ) = @_; + choose_group_cols($tbl); + return $col; + }, + }, +); + +# ########################################################################### +# Global variables and environment {{{2 +# ########################################################################### + +my @this_term_size; # w_chars, h_chars, w_pix, h_pix +my @last_term_size; # w_chars, h_chars, w_pix, h_pix +my $char; +my $windows = $OSNAME =~ m/MSWin/; +my $have_color = 0; +my $MAX_ULONG = 4294967295; # 2^32-1 +my $num_regex = qr/^[+-]?(?=\d|\.)\d*(?:\.\d+)?(?:E[+-]?\d+|)$/i; +my $int_regex = qr/^\d+$/; +my $bool_regex = qr/^[01]$/; +my $term = undef; +my $file = undef; # File to watch for InnoDB monitor output +my $file_mtime = undef; # Status of watched file +my $file_data = undef; # Last chunk of text read from file +my $innodb_parser = InnoDBParser->new; + +my $nonfatal_errs = join('|', + 'Access denied for user', + 'Unknown MySQL server host', + 'Unknown database', + 'Can\'t connect to local MySQL server through socket', + 'Can\'t connect to MySQL server on', + 'MySQL server has gone away', + 'Cannot call SHOW INNODB STATUS', + 'Access denied', + 'AutoCommit', +); + +if ( !$opts{n} ) { + require Term::ReadLine; + $term = Term::ReadLine->new('innotop'); +} + +# Stores status, variables, innodb status, master/slave status etc. +# Keyed on connection name. Each entry is a hashref of current and past data sets, +# keyed on clock tick. +my %vars; +my %info_gotten = (); # Which things have been retrieved for the current clock tick. + +# Stores info on currently displayed queries: cxn, connection ID, query text. +my @current_queries; + +my $lines_printed = 0; +my $clock = 0; # Incremented with every wake-sleep cycle +my $clearing_deadlocks = 0; + +# Find the home directory; it's different on different OSes. +my $homepath = $ENV{HOME} || $ENV{HOMEPATH} || $ENV{USERPROFILE} || '.'; + +# 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 => 0, + 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 => "T", + note => "Which mode to start in", + cmdline => 1, + }, + status_inc => { + val => 0, + note => 'Whether to show raw or incremental values for status variables', + pat => $bool_regex, + }, + interval => { + val => 10, + pat => qr/^(?:(?:\d*?[1-9]\d*(?:\.\d*)?)|(?:\d*\.\d*?[1-9]\d*))$/, + note => "The interval at which the display will be refreshed. Fractional values allowed.", + }, + num_status_sets => { + val => 9, + pat => $int_regex, + note => 'How many sets of STATUS and VARIABLES values to show', + conf => [ qw(S) ], + }, + S_set => { + val => 'general', + pat => qr/^\w+$/, + note => 'Which set of variables to display in S (Variables & Status) mode', + conf => [ qw(S) ], + }, +); + +# ########################################################################### +# Config file sections {{{2 +# The configuration file is broken up into sections like a .ini file. This +# variable defines those sections and the subroutines responsible for reading +# and writing them. +# ########################################################################### +my %config_file_sections = ( + plugins => { + reader => \&load_config_plugins, + writer => \&save_config_plugins, + }, + group_by => { + reader => \&load_config_group_by, + writer => \&save_config_group_by, + }, + filters => { + reader => \&load_config_filters, + writer => \&save_config_filters, + }, + active_filters => { + reader => \&load_config_active_filters, + writer => \&save_config_active_filters, + }, + visible_tables => { + reader => \&load_config_visible_tables, + writer => \&save_config_visible_tables, + }, + sort_cols => { + reader => \&load_config_sort_cols, + writer => \&save_config_sort_cols, + }, + active_columns => { + reader => \&load_config_active_columns, + writer => \&save_config_active_columns, + }, + tbl_meta => { + reader => \&load_config_tbl_meta, + writer => \&save_config_tbl_meta, + }, + general => { + reader => \&load_config_config, + writer => \&save_config_config, + }, + connections => { + reader => \&load_config_connections, + writer => \&save_config_connections, + }, + active_connections => { + reader => \&load_config_active_connections, + writer => \&save_config_active_connections, + }, + server_groups => { + reader => \&load_config_server_groups, + writer => \&save_config_server_groups, + }, + active_server_groups => { + reader => \&load_config_active_server_groups, + writer => \&save_config_active_server_groups, + }, + max_values_seen => { + reader => \&load_config_mvs, + writer => \&save_config_mvs, + }, + varsets => { + reader => \&load_config_varsets, + writer => \&save_config_varsets, + }, + colors => { + reader => \&load_config_colors, + writer => \&save_config_colors, + }, + stmt_sleep_times => { + reader => \&load_config_stmt_sleep_times, + writer => \&save_config_stmt_sleep_times, + }, +); + +# Config file sections have some dependencies, so they have to be read/written in order. +my @ordered_config_file_sections = qw(general plugins filters active_filters tbl_meta + connections active_connections server_groups active_server_groups max_values_seen + active_columns sort_cols visible_tables varsets colors stmt_sleep_times + group_by); + +# All events for which plugins may register themselves. Entries are arrayrefs. +my %event_listener_for = map { $_ => [] } + qw( + extract_values + set_to_tbl_pre_filter set_to_tbl_pre_sort set_to_tbl_pre_group + set_to_tbl_pre_colorize set_to_tbl_pre_transform set_to_tbl_pre_pivot + set_to_tbl_pre_create set_to_tbl_post_create + draw_screen + ); + +# All variables to which plugins have access. +my %pluggable_vars = ( + action_for => \%action_for, + agg_funcs => \%agg_funcs, + config => \%config, + connections => \%connections, + dbhs => \%dbhs, + filters => \%filters, + modes => \%modes, + server_groups => \%server_groups, + tbl_meta => \%tbl_meta, + trans_funcs => \%trans_funcs, + var_sets => \%var_sets, +); + +# ########################################################################### +# Contains logic to generate prepared statements for a given function for a +# given DB connection. Returns a $sth. +# ########################################################################### +my %stmt_maker_for = ( + INNODB_STATUS => sub { + my ( $dbh ) = @_; + return $dbh->prepare(version_ge( $dbh, '5.0.0' ) + ? 'SHOW ENGINE INNODB STATUS' + : 'SHOW INNODB STATUS'); + }, + SHOW_VARIABLES => sub { + my ( $dbh ) = @_; + return $dbh->prepare($config{global}->{val} && version_ge( $dbh, '4.0.3' ) + ? 'SHOW GLOBAL VARIABLES' + : 'SHOW VARIABLES'); + }, + SHOW_STATUS => sub { + my ( $dbh ) = @_; + return $dbh->prepare($config{global}->{val} && version_ge( $dbh, '5.0.2' ) + ? 'SHOW GLOBAL STATUS' + : 'SHOW STATUS'); + }, + KILL_QUERY => sub { + my ( $dbh ) = @_; + return $dbh->prepare(version_ge( $dbh, '5.0.0' ) + ? 'KILL QUERY ?' + : 'KILL ?'); + }, + SHOW_MASTER_LOGS => sub { + my ( $dbh ) = @_; + return $dbh->prepare('SHOW MASTER LOGS'); + }, + SHOW_MASTER_STATUS => sub { + my ( $dbh ) = @_; + return $dbh->prepare('SHOW MASTER STATUS'); + }, + SHOW_SLAVE_STATUS => sub { + my ( $dbh ) = @_; + return $dbh->prepare('SHOW SLAVE STATUS'); + }, + KILL_CONNECTION => sub { + my ( $dbh ) = @_; + return $dbh->prepare(version_ge( $dbh, '5.0.0' ) + ? 'KILL CONNECTION ?' + : 'KILL ?'); + }, + OPEN_TABLES => sub { + my ( $dbh ) = @_; + return version_ge($dbh, '4.0.0') + ? $dbh->prepare('SHOW OPEN TABLES') + : undef; + }, + PROCESSLIST => sub { + my ( $dbh ) = @_; + return $dbh->prepare('SHOW FULL PROCESSLIST'); + }, +); + +# Plugins! +my %plugins = ( +); + +# ########################################################################### +# Run the program {{{1 +# ########################################################################### + +# This config variable is only useful for MS Windows because its terminal +# can't tell how tall it is. +if ( !$windows ) { + delete $config{max_height}; +} + +# Try to lower my priority. +eval { setpriority(0, 0, getpriority(0, 0) + 10); }; + +# Print stuff to the screen immediately, don't wait for a newline. +$OUTPUT_AUTOFLUSH = 1; + +# Clear the screen and load the configuration. +$clear_screen_sub->(); +load_config(); +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} || 'T'; + if ( !$modes{$mode} ) { + die "Mode '$mode' doesn't exist; try one of these:\n" + . join("\n", map { " $_ $modes{$_}->{hdr}" } sort keys %modes) + . "\n"; + } + + if ( !$opts{n} ) { + @last_term_size = @this_term_size; + @this_term_size = Term::ReadKey::GetTerminalSize(\*STDOUT); + if ( $windows ) { + $this_term_size[0]--; + $this_term_size[1] + = min($this_term_size[1], $config{max_height}->{val}); + } + die("Can't read terminal size") unless @this_term_size; + } + + # If there's no connection to a database server, we need to fix that... + if ( !%connections ) { + print "You have not defined any database connections.\n\n"; + add_new_dsn(); + } + + # See whether there are any connections defined for this mode. If there's only one + # connection total, assume the user wants to just use innotop for a single server + # and don't ask which server to connect to. Also, if we're monitoring from a file, + # we just use the first connection. + if ( !get_connections() ) { + if ( $file || 1 == scalar keys %connections ) { + $modes{$config{mode}->{val}}->{connections} = [ keys %connections ]; + } + else { + choose_connections(); + } + } + + # Term::ReadLine might have re-set $OUTPUT_AUTOFLUSH. + $OUTPUT_AUTOFLUSH = 1; + + # Prune old data + my $sets = $config{num_status_sets}->{val}; + foreach my $store ( values %vars ) { + delete @{$store}{ grep { $_ < $clock - $sets } keys %$store }; + } + %info_gotten = (); + + # Call the subroutine to display this mode. + $modes{$mode}->{display_sub}->(); + + # It may be time to quit now. + if ( $opts{count} && $clock >= $opts{count} ) { + finish(); + } + + # Wait for a bit. + if ( $opts{n} ) { + sleep($config{interval}->{val}); + } + else { + ReadMode('cbreak'); + $char = ReadKey($config{interval}->{val}); + ReadMode('normal'); + } + + # Handle whatever action the key indicates. + do_key_action(); + + } +}; +if ( $EVAL_ERROR ) { + core_dump( $EVAL_ERROR ); +} +finish(); + +# Subroutines {{{1 +# Mode functions{{{2 +# switch_mode {{{3 +sub switch_mode { + my $mode = shift; + $config{mode}->{val} = $mode; +} + +# Prompting functions {{{2 +# prompt_list {{{3 +# Prompts the user for a value, given a question, initial value, +# a completion function and a hashref of hints. +sub prompt_list { + die "Can't call in non-interactive mode" if $opts{n}; + my ( $question, $init, $completion, $hints ) = @_; + if ( $hints ) { + # Figure out how wide the table will be + my $max_name = max(map { length($_) } keys %$hints ); + $max_name ||= 0; + $max_name += 3; + my @meta_rows = create_table2( + [ sort keys %$hints ], + { map { $_ => $_ } keys %$hints }, + { map { $_ => trunc($hints->{$_}, $this_term_size[0] - $max_name) } keys %$hints }, + { sep => ' ' }); + if (@meta_rows > 10) { + # Try to split and stack the meta rows next to each other + my $split = int(@meta_rows / 2); + @meta_rows = stack_next( + [@meta_rows[0..$split - 1]], + [@meta_rows[$split..$#meta_rows]], + { pad => ' | '}, + ); + } + print join( "\n", + '', + map { ref $_ ? colored(@$_) : $_ } create_caption('Choose from', @meta_rows), ''), + "\n"; + } + $term->Attribs->{completion_function} = $completion; + my $answer = $term->readline("$question: ", $init); + $OUTPUT_AUTOFLUSH = 1; + $answer = '' if !defined($answer); + $answer =~ s/\s+$//; + return $answer; +} + +# prompt {{{3 +# Prints out a prompt and reads from the keyboard, then validates with the +# validation regex until the input is correct. +sub prompt { + die "Can't call in non-interactive mode" if $opts{n}; + my ( $prompt, $regex, $init, $completion ) = @_; + my $response; + my $success = 0; + do { + if ( $completion ) { + $term->Attribs->{completion_function} = $completion; + } + $response = $term->readline("$prompt: ", $init); + if ( $regex && $response !~ m/$regex/ ) { + print "Invalid response.\n\n"; + } + else { + $success = 1; + } + } while ( !$success ); + $OUTPUT_AUTOFLUSH = 1; + $response =~ s/\s+$//; + return $response; +} + +# prompt_noecho {{{3 +# Unfortunately, suppressing echo with Term::ReadLine isn't reliable; the user might not +# have that library, or it might not support that feature. +sub prompt_noecho { + my ( $prompt ) = @_; + print colored("$prompt: ", 'underline'); + my $response; + ReadMode('noecho'); + $response = ; + chomp($response); + ReadMode('normal'); + return $response; +} + +# do_key_action {{{3 +# Depending on whether a key was read, do something. Keys have certain +# actions defined in lookup tables. Each mode may have its own lookup table, +# which trumps the global table -- so keys can be context-sensitive. The key +# may be read and written in a subroutine, so it's a global. +sub do_key_action { + if ( defined $char ) { + my $mode = $config{mode}->{val}; + my $action + = defined($modes{$mode}->{action_for}->{$char}) + ? $modes{$mode}->{action_for}->{$char}->{action} + : defined($action_for{$char}) + ? $action_for{$char}->{action} + : sub{}; + $action->(); + } +} + +# pause {{{3 +sub pause { + die "Can't call in non-interactive mode" if $opts{n}; + my $msg = shift; + print defined($msg) ? "\n$msg" : "\nPress any key to continue"; + ReadMode('cbreak'); + my $char = ReadKey(0); + ReadMode('normal'); + return $char; +} + +# reverse_sort {{{3 +sub reverse_sort { + my $tbl = shift; + $tbl_meta{$tbl}->{sort_dir} *= -1; +} + +# select_cxn {{{3 +# Selects connection(s). If the mode (or argument list) has only one, returns +# it without prompt. +sub select_cxn { + my ( $prompt, @cxns ) = @_; + if ( !@cxns ) { + @cxns = get_connections(); + } + if ( @cxns == 1 ) { + return $cxns[0]; + } + my $choices = prompt_list( + $prompt, + $cxns[0], + sub{ return @cxns }, + { map { $_ => $connections{$_}->{dsn} } @cxns }); + my @result = unique(grep { my $a = $_; grep { $_ eq $a } @cxns } split(/\s+/, $choices)); + return @result; +} + +# kill_query {{{3 +# Kills a connection, or on new versions, optionally a query but not connection. +sub kill_query { + my ( $q_or_c ) = @_; + + my $info = choose_thread( + sub { 1 }, + 'Select a thread to kill the ' . $q_or_c, + ); + return unless $info; + return unless pause("Kill $info->{id}?") =~ m/y/i; + + eval { + do_stmt($info->{cxn}, $q_or_c eq 'QUERY' ? 'KILL_QUERY' : 'KILL_CONNECTION', $info->{id} ); + }; + + if ( $EVAL_ERROR ) { + print "\nError: $EVAL_ERROR"; + pause(); + } +} + +# set_display_precision {{{3 +sub set_display_precision { + my $dir = shift; + $config{num_digits}->{val} = min(9, max(0, $config{num_digits}->{val} + $dir)); +} + +sub toggle_visible_table { + my ( $mode, $table ) = @_; + my $visible = $modes{$mode}->{visible_tables}; + if ( grep { $_ eq $table } @$visible ) { + $modes{$mode}->{visible_tables} = [ grep { $_ ne $table } @$visible ]; + } + else { + unshift @$visible, $table; + } + $modes{$mode}->{cust}->{visible_tables} = 1; +} + +# toggle_filter{{{3 +sub toggle_filter { + my ( $tbl, $filter ) = @_; + my $filters = $tbl_meta{$tbl}->{filters}; + if ( grep { $_ eq $filter } @$filters ) { + $tbl_meta{$tbl}->{filters} = [ grep { $_ ne $filter } @$filters ]; + } + else { + push @$filters, $filter; + } + $tbl_meta{$tbl}->{cust}->{filters} = 1; +} + +# toggle_config {{{3 +sub toggle_config { + my ( $key ) = @_; + $config{$key}->{val} ^= 1; +} + +# create_deadlock {{{3 +sub create_deadlock { + $clear_screen_sub->(); + + print "This function will deliberately cause a small deadlock, " + . "clearing deadlock information from the InnoDB monitor.\n\n"; + + my $answer = prompt("Are you sure you want to proceed? Say 'y' if you do"); + return 0 unless $answer eq 'y'; + + my ( $cxn ) = select_cxn('Clear on which server? '); + return unless $cxn && exists($connections{$cxn}); + + clear_deadlock($cxn); +} + +# deadlock_thread {{{3 +sub deadlock_thread { + my ( $id, $tbl, $cxn ) = @_; + + eval { + my $dbh = get_new_db_connection($cxn, 1); + my @stmts = ( + "set transaction isolation level serializable", + (version_ge($dbh, '4.0.11') ? "start transaction" : 'begin'), + "select * from $tbl where a = $id", + "update $tbl set a = $id where a <> $id", + ); + + foreach my $stmt (@stmts[0..2]) { + $dbh->do($stmt); + } + sleep(1 + $id); + $dbh->do($stmts[-1]); + }; + if ( $EVAL_ERROR ) { + if ( $EVAL_ERROR !~ m/Deadlock found/ ) { + die $EVAL_ERROR; + } + } + exit(0); +} + +# Purges unused binlogs on the master, up to but not including the latest log. +# TODO: guess which connections are slaves of a given master. +sub purge_master_logs { + my @cxns = get_connections(); + + get_master_slave_status(@cxns); + + # Toss out the rows that don't have master/slave status... + my @vars = + grep { $_ && ($_->{file} || $_->{master_host}) } + map { $vars{$_}->{$clock} } @cxns; + @cxns = map { $_->{cxn} } @vars; + + # Figure out which master to purge ons. + my @masters = map { $_->{cxn} } grep { $_->{file} } @vars; + my ( $master ) = select_cxn('Which master?', @masters ); + return unless $master; + my ($master_status) = grep { $_->{cxn} eq $master } @vars; + + # Figure out the result order (not lexical order) of master logs. + my @master_logs = get_master_logs($master); + my $i = 0; + my %master_logs = map { $_->{log_name} => $i++ } @master_logs; + + # Ask which slave(s) are reading from this master. + my @slave_status = grep { $_->{master_host} } @vars; + my @slaves = map { $_->{cxn} } @slave_status; + @slaves = select_cxn("Which slaves are reading from $master?", @slaves); + @slave_status = grep { my $item = $_; grep { $item->{cxn} eq $_ } @slaves } @slave_status; + return unless @slave_status; + + # Find the minimum binary log in use. + my $min_log = min(map { $master_logs{$_->{master_log_file}} } @slave_status); + my $log_name = $master_logs[$min_log]->{log_name}; + + my $stmt = "PURGE MASTER LOGS TO '$log_name'"; + send_cmd_to_servers($stmt, 0, 'PURGE {MASTER | BINARY} LOGS {TO "log_name" | BEFORE "date"}', [$master]); +} + +sub send_cmd_to_servers { + my ( $cmd, $all, $hint, $cxns ) = @_; + if ( $all ) { + @$cxns = get_connections(); + } + elsif ( !@$cxns ) { + @$cxns = select_cxn('Which servers?', @$cxns); + } + if ( $hint ) { + print "\nHint: $hint\n"; + } + $cmd = prompt('Command to send', undef, $cmd); + foreach my $cxn ( @$cxns ) { + eval { + my $sth = do_query($cxn, $cmd); + }; + if ( $EVAL_ERROR ) { + print "Error from $cxn: $EVAL_ERROR\n"; + } + else { + print "Success on $cxn\n"; + } + } + pause(); +} + +# Display functions {{{2 + +sub set_s_mode { + my ( $func ) = @_; + $clear_screen_sub->(); + $config{S_func}->{val} = $func; +} + +# start_S_mode {{{3 +sub start_S_mode { + $clear_screen_sub->(); + switch_mode('S'); +} + +# display_B {{{3 +sub display_B { + my @display_lines; + my @cxns = get_connections(); + get_innodb_status(\@cxns); + + my @buffer_pool; + my @page_statistics; + my @insert_buffers; + my @adaptive_hash_index; + my %rows_for = ( + buffer_pool => \@buffer_pool, + page_statistics => \@page_statistics, + insert_buffers => \@insert_buffers, + adaptive_hash_index => \@adaptive_hash_index, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + foreach my $cxn ( @cxns ) { + my $set = $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock-1} || $set; + + if ( $set->{IB_bp_complete} ) { + if ( $wanted{buffer_pool} ) { + push @buffer_pool, extract_values($set, $set, $pre, 'buffer_pool'); + } + if ( $wanted{page_statistics} ) { + push @page_statistics, extract_values($set, $set, $pre, 'page_statistics'); + } + } + if ( $set->{IB_ib_complete} ) { + if ( $wanted{insert_buffers} ) { + push @insert_buffers, extract_values( + $config{status_inc}->{val} ? inc(0, $cxn) : $set, $set, $pre, + 'insert_buffers'); + } + if ( $wanted{adaptive_hash_index} ) { + push @adaptive_hash_index, extract_values($set, $set, $pre, 'adaptive_hash_index'); + } + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_C {{{3 +sub display_C { + my @display_lines; + my @cxns = get_connections(); + get_status_info(@cxns); + + my @cmd_summary; + my %rows_for = ( + cmd_summary => \@cmd_summary, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + # For now, I'm manually pulling these variables out and pivoting. Eventually a SQL-ish + # dialect should let me join a table to a grouped and pivoted table and do this more easily. + # TODO: make it so. + my $prefix = qr/^$config{cmd_filter}->{val}/; # TODO: this is a total hack + my @values; + my ($total, $last_total) = (0, 0); + foreach my $cxn ( @cxns ) { + my $set = $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock-1} || $set; + foreach my $key ( keys %$set ) { + next unless $key =~ m/$prefix/i; + my $val = $set->{$key}; + next unless defined $val && $val =~ m/^\d+$/; + my $last_val = $val - ($pre->{$key} || 0); + $total += $val; + $last_total += $last_val; + push @values, { + name => $key, + value => $val, + last_value => $last_val, + }; + } + } + + # Add aggregation and turn into a real set TODO: total hack + if ( $wanted{cmd_summary} ) { + foreach my $value ( @values ) { + @{$value}{qw(total last_total)} = ($total, $last_total); + push @cmd_summary, extract_values($value, $value, $value, 'cmd_summary'); + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_D {{{3 +sub display_D { + my @display_lines; + my @cxns = get_connections(); + get_innodb_status(\@cxns); + + my @deadlock_transactions; + my @deadlock_locks; + my %rows_for = ( + deadlock_transactions => \@deadlock_transactions, + deadlock_locks => \@deadlock_locks, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + foreach my $cxn ( @cxns ) { + my $innodb_status = $vars{$cxn}->{$clock}; + my $prev_status = $vars{$cxn}->{$clock-1} || $innodb_status; + + if ( $innodb_status->{IB_dl_timestring} ) { + + my $victim = $innodb_status->{IB_dl_rolled_back} || 0; + + if ( %wanted ) { + foreach my $txn_id ( keys %{$innodb_status->{IB_dl_txns}} ) { + my $txn = $innodb_status->{IB_dl_txns}->{$txn_id}; + my $pre = $prev_status->{IB_dl_txns}->{$txn_id} || $txn; + + if ( $wanted{deadlock_transactions} ) { + my $hash = extract_values($txn->{tx}, $txn->{tx}, $pre->{tx}, 'deadlock_transactions'); + $hash->{cxn} = $cxn; + $hash->{dl_txn_num} = $txn_id; + $hash->{victim} = $txn_id == $victim ? 'Yes' : 'No'; + $hash->{timestring} = $innodb_status->{IB_dl_timestring}; + $hash->{truncates} = $innodb_status->{IB_dl_complete} ? 'No' : 'Yes'; + push @deadlock_transactions, $hash; + } + + if ( $wanted{deadlock_locks} ) { + foreach my $lock ( @{$txn->{locks}} ) { + my $hash = extract_values($lock, $lock, $lock, 'deadlock_locks'); + $hash->{dl_txn_num} = $txn_id; + $hash->{cxn} = $cxn; + $hash->{mysql_thread_id} = $txn->{tx}->{mysql_thread_id}; + push @deadlock_locks, $hash; + } + } + + } + } + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_F {{{3 +sub display_F { + my @display_lines; + my ( $cxn ) = get_connections(); + get_innodb_status([$cxn]); + my $innodb_status = $vars{$cxn}->{$clock}; + + if ( $innodb_status->{IB_fk_timestring} ) { + + push @display_lines, 'Reason: ' . $innodb_status->{IB_fk_reason}; + + # Display FK errors caused by invalid DML. + if ( $innodb_status->{IB_fk_txn} ) { + my $txn = $innodb_status->{IB_fk_txn}; + push @display_lines, + '', + "User $txn->{user} from $txn->{hostname}, thread $txn->{mysql_thread_id} was executing:", + '', no_ctrl_char($txn->{query_text}); + } + + my @fk_table = create_table2( + $tbl_meta{fk_error}->{visible}, + meta_to_hdr('fk_error'), + extract_values($innodb_status, $innodb_status, $innodb_status, 'fk_error'), + { just => '-', sep => ' '}); + push @display_lines, '', @fk_table; + + } + else { + push @display_lines, '', 'No foreign key error data.'; + } + draw_screen(\@display_lines, { raw => 1 } ); +} + +# display_I {{{3 +sub display_I { + my @display_lines; + my @cxns = get_connections(); + get_innodb_status(\@cxns); + + my @io_threads; + my @pending_io; + my @file_io_misc; + my @log_statistics; + my %rows_for = ( + io_threads => \@io_threads, + pending_io => \@pending_io, + file_io_misc => \@file_io_misc, + log_statistics => \@log_statistics, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + foreach my $cxn ( @cxns ) { + my $set = $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock-1} || $set; + + if ( $set->{IB_io_complete} ) { + if ( $wanted{io_threads} ) { + my $cur_threads = $set->{IB_io_threads}; + my $pre_threads = $pre->{IB_io_threads} || $cur_threads; + foreach my $key ( sort keys %$cur_threads ) { + my $cur_thd = $cur_threads->{$key}; + my $pre_thd = $pre_threads->{$key} || $cur_thd; + my $hash = extract_values($cur_thd, $cur_thd, $pre_thd, 'io_threads'); + $hash->{cxn} = $cxn; + push @io_threads, $hash; + } + } + if ( $wanted{pending_io} ) { + push @pending_io, extract_values($set, $set, $pre, 'pending_io'); + } + if ( $wanted{file_io_misc} ) { + push @file_io_misc, extract_values( + $config{status_inc}->{val} ? inc(0, $cxn) : $set, + $set, $pre, 'file_io_misc'); + } + } + if ( $set->{IB_lg_complete} && $wanted{log_statistics} ) { + push @log_statistics, extract_values($set, $set, $pre, 'log_statistics'); + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_L {{{3 +sub display_L { + my @display_lines; + my @cxns = get_connections(); + get_innodb_status(\@cxns); + + my @innodb_locks; + my %rows_for = ( + innodb_locks => \@innodb_locks, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + # Get info on locks + foreach my $cxn ( @cxns ) { + my $set = $vars{$cxn}->{$clock} or next; + my $pre = $vars{$cxn}->{$clock-1} || $set; + + if ( $wanted{innodb_locks} && defined $set->{IB_tx_transactions} && @{$set->{IB_tx_transactions}} ) { + + my $cur_txns = $set->{IB_tx_transactions}; + my $pre_txns = $pre->{IB_tx_transactions} || $cur_txns; + my %cur_txns = map { $_->{mysql_thread_id} => $_ } @$cur_txns; + my %pre_txns = map { $_->{mysql_thread_id} => $_ } @$pre_txns; + foreach my $txn ( @$cur_txns ) { + foreach my $lock ( @{$txn->{locks}} ) { + my %hash = map { $_ => $txn->{$_} } qw(txn_id mysql_thread_id lock_wait_time active_secs); + map { $hash{$_} = $lock->{$_} } qw(lock_type space_id page_no n_bits index db table txn_id lock_mode special insert_intention waiting); + $hash{cxn} = $cxn; + push @innodb_locks, extract_values(\%hash, \%hash, \%hash, 'innodb_locks'); + } + } + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_M {{{3 +sub display_M { + my @display_lines; + my @cxns = get_connections(); + get_master_slave_status(@cxns); + get_status_info(@cxns); + + my @slave_sql_status; + my @slave_io_status; + my @master_status; + my %rows_for = ( + slave_sql_status => \@slave_sql_status, + slave_io_status => \@slave_io_status, + master_status => \@master_status, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + foreach my $cxn ( @cxns ) { + my $set = $config{status_inc}->{val} ? inc(0, $cxn) : $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock - 1} || $set; + if ( $wanted{slave_sql_status} ) { + push @slave_sql_status, extract_values($set, $set, $pre, 'slave_sql_status'); + } + if ( $wanted{slave_io_status} ) { + push @slave_io_status, extract_values($set, $set, $pre, 'slave_io_status'); + } + if ( $wanted{master_status} ) { + push @master_status, extract_values($set, $set, $pre, 'master_status'); + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_O {{{3 +sub display_O { + my @display_lines = (''); + my @cxns = get_connections(); + my @open_tables = get_open_tables(@cxns); + my @tables = map { extract_values($_, $_, $_, 'open_tables') } @open_tables; + push @display_lines, set_to_tbl(\@tables, 'open_tables'), get_cxn_errors(@cxns); + draw_screen(\@display_lines); +} + +# display_Q {{{3 +sub display_Q { + my @display_lines; + + my @q_header; + my @processlist; + my %rows_for = ( + q_header => \@q_header, + processlist => \@processlist, + ); + + my @visible = $opts{n} ? 'processlist' : get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + # Get the data + my @cxns = get_connections(); + my @full_processlist = get_full_processlist(@cxns); + + # Create header + if ( $wanted{q_header} ) { + get_status_info(@cxns); + foreach my $cxn ( @cxns ) { + my $set = $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock-1} || $set; + my $hash = extract_values($set, $set, $pre, 'q_header'); + $hash->{cxn} = $cxn; + $hash->{when} = 'Total'; + push @q_header, $hash; + + if ( exists $vars{$cxn}->{$clock - 1} ) { + my $inc = inc(0, $cxn); + my $hash = extract_values($inc, $set, $pre, 'q_header'); + $hash->{cxn} = $cxn; + $hash->{when} = 'Now'; + push @q_header, $hash; + } + } + } + + if ( $wanted{processlist} ) { + # TODO: save prev values + push @processlist, map { extract_values($_, $_, $_, 'processlist') } @full_processlist; + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + next unless $wanted{$tbl}; + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + # Save queries in global variable for analysis. The rows in %rows_for have been + # filtered, etc as a side effect of set_to_tbl(), so they are the same as the rows + # that get pushed to the screen. + @current_queries = map { + my %hash; + @hash{ qw(cxn id db query secs) } = @{$_}{ qw(cxn mysql_thread_id db info secs) }; + \%hash; + } @{$rows_for{processlist}}; + + draw_screen(\@display_lines); +} + +# display_R {{{3 +sub display_R { + my @display_lines; + my @cxns = get_connections(); + get_innodb_status(\@cxns); + + my @row_operations; + my @row_operation_misc; + my @semaphores; + my @wait_array; + my %rows_for = ( + row_operations => \@row_operations, + row_operation_misc => \@row_operation_misc, + semaphores => \@semaphores, + wait_array => \@wait_array, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + my $incvar = $config{status_inc}->{val}; + + foreach my $cxn ( @cxns ) { + my $set = $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock-1} || $set; + my $inc; # Only assigned to if wanted + + if ( $set->{IB_ro_complete} ) { + if ( $wanted{row_operations} ) { + $inc ||= $incvar ? inc(0, $cxn) : $set; + push @row_operations, extract_values($inc, $set, $pre, 'row_operations'); + } + if ( $wanted{row_operation_misc} ) { + push @row_operation_misc, extract_values($set, $set, $pre, 'row_operation_misc'), + } + } + + if ( $set->{IB_sm_complete} && $wanted{semaphores} ) { + $inc ||= $incvar ? inc(0, $cxn) : $set; + push @semaphores, extract_values($inc, $set, $pre, 'semaphores'); + } + + if ( $set->{IB_sm_wait_array_size} && $wanted{wait_array} ) { + foreach my $wait ( @{$set->{IB_sm_waits}} ) { + my $hash = extract_values($wait, $wait, $wait, 'wait_array'); + $hash->{cxn} = $cxn; + push @wait_array, $hash; + } + } + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + draw_screen(\@display_lines); +} + +# display_T {{{3 +sub display_T { + my @display_lines; + + my @t_header; + my @innodb_transactions; + my %rows_for = ( + t_header => \@t_header, + innodb_transactions => \@innodb_transactions, + ); + + my @visible = $opts{n} ? 'innodb_transactions' : get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + + my @cxns = get_connections(); + + # If the header is to be shown, buffer pool data is required. + get_innodb_status( \@cxns, [ $wanted{t_header} ? qw(bp) : () ] ); + + foreach my $cxn ( get_connections() ) { + my $set = $vars{$cxn}->{$clock}; + my $pre = $vars{$cxn}->{$clock-1} || $set; + + next unless $set->{IB_tx_transactions}; + + if ( $wanted{t_header} ) { + my $hash = extract_values($set, $set, $pre, 't_header'); + push @t_header, $hash; + } + + if ( $wanted{innodb_transactions} ) { + my $cur_txns = $set->{IB_tx_transactions}; + my $pre_txns = $pre->{IB_tx_transactions} || $cur_txns; + my %cur_txns = map { $_->{mysql_thread_id} => $_ } @$cur_txns; + my %pre_txns = map { $_->{mysql_thread_id} => $_ } @$pre_txns; + foreach my $thd_id ( sort keys %cur_txns ) { + my $cur_txn = $cur_txns{$thd_id}; + my $pre_txn = $pre_txns{$thd_id} || $cur_txn; + my $hash = extract_values($cur_txn, $cur_txn, $pre_txn, 'innodb_transactions'); + $hash->{cxn} = $cxn; + push @innodb_transactions, $hash; + } + } + + } + + my $first_table = 0; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + + # Save queries in global variable for analysis. The rows in %rows_for have been + # filtered, etc as a side effect of set_to_tbl(), so they are the same as the rows + # that get pushed to the screen. + @current_queries = map { + my %hash; + @hash{ qw(cxn id db query secs) } = @{$_}{ qw(cxn mysql_thread_id db query_text active_secs) }; + \%hash; + } @{$rows_for{innodb_transactions}}; + + draw_screen(\@display_lines); +} + +# display_S {{{3 +sub display_S { + my $fmt = get_var_set('S_set'); + my $func = $config{S_func}->{val}; + my $inc = $func eq 'g' || $config{status_inc}->{val}; + + # The table's meta-data is generated from the compiled var_set. + my ( $cols, $visible ); + if ( $tbl_meta{var_status}->{fmt} && $fmt eq $tbl_meta{var_status}->{fmt} ) { + ( $cols, $visible ) = @{$tbl_meta{var_status}}{qw(cols visible)}; + } + else { + ( $cols, $visible ) = compile_select_stmt($fmt); + + # Apply missing values to columns. Always apply averages across all connections. + map { + $_->{agg} = 'avg'; + $_->{label} = $_->{hdr}; + } values %$cols; + + $tbl_meta{var_status}->{cols} = $cols; + $tbl_meta{var_status}->{visible} = $visible; + $tbl_meta{var_status}->{fmt} = $fmt; + map { $tbl_meta{var_status}->{cols}->{$_}->{just} = ''} @$visible; + } + + my @var_status; + my %rows_for = ( + var_status => \@var_status, + ); + + my @visible = get_visible_tables(); + my %wanted = map { $_ => 1 } @visible; + my @cxns = get_connections(); + + get_status_info(@cxns); + get_innodb_status(\@cxns); + + # Set up whether to pivot and how many sets to extract. + $tbl_meta{var_status}->{pivot} = $func eq 'v'; + + my $num_sets + = $func eq 'v' + ? $config{num_status_sets}->{val} + : 0; + foreach my $set ( 0 .. $num_sets ) { + my @rows; + foreach my $cxn ( @cxns ) { + my $vars = $inc ? inc($set, $cxn) : $vars{$cxn}->{$clock - $set}; + my $cur = $vars{$cxn}->{$clock-$set}; + my $pre = $vars{$cxn}->{$clock-$set-1} || $cur; + next unless $vars && %$vars; + my $hash = extract_values($vars, $cur, $pre, 'var_status'); + push @rows, $hash; + } + @rows = apply_group_by('var_status', [], @rows); + push @var_status, @rows; + } + + # Recompile the sort func. TODO: avoid recompiling at every refresh. + # Figure out whether the data is all numeric and decide on a sort type. + # my $cmp + # = scalar( + # grep { !defined $_ || $_ !~ m/^\d+$/ } + # map { my $col = $_; map { $_->{$col} } @var_status } + # $tbl_meta{var_status}->{sort_cols} =~ m/(\w+)/g) + # ? 'cmp' + # : '<=>'; + $tbl_meta{var_status}->{sort_func} = make_sort_func($tbl_meta{var_status}); + + # ################################################################ + # Now there is specific display code based on $config{S_func} + # ################################################################ + if ( $func =~ m/s|g/ ) { + my $min_width = 4; + + # Clear the screen if the display width changed. + if ( @last_term_size && $this_term_size[0] != $last_term_size[0] ) { + $lines_printed = 0; + $clear_screen_sub->(); + } + + if ( $func eq 's' ) { + # Decide how wide columns should be. + my $num_cols = scalar(@$visible); + my $width = $opts{n} ? 0 : max($min_width, int(($this_term_size[0] - $num_cols + 1) / $num_cols)); + my $g_format = $opts{n} ? ( "%s\t" x $num_cols ) : ( "%-${width}s " x $num_cols ); + + # Print headers every now and then. Headers can get really long, so compact them. + my @hdr = @$visible; + if ( $opts{n} ) { + if ( $lines_printed == 0 ) { + print join("\t", @hdr), "\n"; + $lines_printed++; + } + } + elsif ( $lines_printed == 0 || $lines_printed > $this_term_size[1] - 2 ) { + @hdr = map { donut(crunch($_, $width), $width) } @hdr; + print join(' ', map { sprintf( "%${width}s", donut($_, $width)) } @hdr) . "\n"; + $lines_printed = 1; + } + + # Design a column format for the values. + my $format + = $opts{n} + ? join("\t", map { '%s' } @$visible) . "\n" + : join(' ', map { "%${width}s" } @hdr) . "\n"; + + foreach my $row ( @var_status ) { + printf($format, map { defined $_ ? $_ : '' } @{$row}{ @$visible }); + $lines_printed++; + } + } + else { # 'g' mode + # Design a column format for the values. + my $num_cols = scalar(@$visible); + my $width = $opts{n} ? 0 : int(($this_term_size[0] - $num_cols + 1) / $num_cols); + my $format = $opts{n} ? ( "%s\t" x $num_cols ) : ( "%-${width}s " x $num_cols ); + $format =~ s/\s$/\n/; + + # Print headers every now and then. + if ( $opts{n} ) { + if ( $lines_printed == 0 ) { + print join("\t", @$visible), "\n"; + print join("\t", map { shorten($mvs{$_}) } @$visible), "\n"; + } + } + elsif ( $lines_printed == 0 || $lines_printed > $this_term_size[1] - 2 ) { + printf($format, map { donut(crunch($_, $width), $width) } @$visible); + printf($format, map { shorten($mvs{$_} || 0) } @$visible); + $lines_printed = 2; + } + + # Update the max ever seen, and scale by the max ever seen. + my $set = $var_status[0]; + foreach my $col ( @$visible ) { + $set->{$col} = 1 unless defined $set->{$col} && $set->{$col} =~ m/$num_regex/; + $set->{$col} = ($set->{$col} || 1) / ($set->{Uptime_hires} || 1); + $mvs{$col} = max($mvs{$col} || 1, $set->{$col}); + $set->{$col} /= $mvs{$col}; + } + printf($format, map { ( $config{graph_char}->{val} x int( $width * $set->{$_} )) || '.' } @$visible ); + $lines_printed++; + + } + } + else { # 'v' + my $first_table = 0; + my @display_lines; + foreach my $tbl ( @visible ) { + push @display_lines, '', set_to_tbl($rows_for{$tbl}, $tbl); + push @display_lines, get_cxn_errors(@cxns) + if ( $config{debug}->{val} || !$first_table++ ); + } + $clear_screen_sub->(); + draw_screen( \@display_lines ); + } +} + +# display_explain {{{3 +sub display_explain { + my $info = shift; + my $cxn = $info->{cxn}; + my $db = $info->{db}; + + my ( $mods, $query ) = rewrite_for_explain($info->{query}); + + my @display_lines; + + if ( $query ) { + + my $part = version_ge($dbhs{$cxn}->{dbh}, '5.1.5') ? 'PARTITIONS' : ''; + $query = "EXPLAIN $part\n" . $query; + + eval { + if ( $db ) { + do_query($cxn, "use $db"); + } + my $sth = do_query($cxn, $query); + + my $res; + while ( $res = $sth->fetchrow_hashref() ) { + map { $res->{$_} ||= '' } ( 'partitions', keys %$res); + my @this_table = create_caption("Sub-Part $res->{id}", + create_table2( + $tbl_meta{explain}->{visible}, + meta_to_hdr('explain'), + extract_values($res, $res, $res, 'explain'))); + @display_lines = stack_next(\@display_lines, \@this_table, { pad => ' ', vsep => 2 }); + } + }; + + if ( $EVAL_ERROR ) { + push @display_lines, + '', + "The query could not be explained. Only SELECT queries can be " + . "explained; innotop tries to rewrite certain REPLACE and INSERT queries " + . "into SELECT, but this doesn't always succeed."; + } + + } + else { + push @display_lines, '', 'The query could not be explained.'; + } + + if ( $mods ) { + push @display_lines, '', '[This query has been re-written to be explainable]'; + } + + unshift @display_lines, no_ctrl_char($query); + draw_screen(\@display_lines, { raw => 1 } ); +} + +# rewrite_for_explain {{{3 +sub rewrite_for_explain { + my $query = shift; + + my $mods = 0; + my $orig = $query; + $mods += $query =~ s/^\s*(?:replace|insert).*?select/select/is; + $mods += $query =~ s/^ + \s*create\s+(?:temporary\s+)?table + \s+(?:\S+\s+)as\s+select/select/xis; + $mods += $query =~ s/\s+on\s+duplicate\s+key\s+update.*$//is; + return ( $mods, $query ); +} + +# show_optimized_query {{{3 +sub show_optimized_query { + my $info = shift; + my $cxn = $info->{cxn}; + my $db = $info->{db}; + my $meta = $dbhs{$cxn}; + + my @display_lines; + + my ( $mods, $query ) = rewrite_for_explain($info->{query}); + + if ( $mods ) { + push @display_lines, '[This query has been re-written to be explainable]'; + } + + if ( $query ) { + push @display_lines, no_ctrl_char($info->{query}); + + eval { + if ( $db ) { + do_query($cxn, "use $db"); + } + do_query( $cxn, 'EXPLAIN EXTENDED ' . $query ) or die "Can't explain query"; + my $sth = do_query($cxn, 'SHOW WARNINGS'); + my $res = $sth->fetchall_arrayref({}); + + if ( $res ) { + foreach my $result ( @$res ) { + push @display_lines, 'Note:', no_ctrl_char($result->{message}); + } + } + else { + push @display_lines, '', 'The query optimization could not be generated.'; + } + }; + + if ( $EVAL_ERROR ) { + push @display_lines, '', "The optimization could not be generated: $EVAL_ERROR"; + } + + } + else { + push @display_lines, '', 'The query optimization could not be generated.'; + } + + draw_screen(\@display_lines, { raw => 1 } ); +} + +# display_help {{{3 +sub display_help { + my $mode = $config{mode}->{val}; + + # Get globally mapped keys, then overwrite them with mode-specific ones. + my %keys = map { + $_ => $action_for{$_}->{label} + } keys %action_for; + foreach my $key ( keys %{$modes{$mode}->{action_for}} ) { + $keys{$key} = $modes{$mode}->{action_for}->{$key}->{label}; + } + delete $keys{'?'}; + + # Split them into three kinds of keys: MODE keys, action keys, and + # magic (special character) keys. + my @modes = sort grep { m/[A-Z]/ } keys %keys; + my @actions = sort grep { m/[a-z]/ } keys %keys; + my @magic = sort grep { m/[^A-Z]/i } keys %keys; + + my @display_lines = ( '', 'Switch to a different mode:' ); + + # Mode keys + my @all_modes = map { "$_ $modes{$_}->{hdr}" } @modes; + my @col1 = splice(@all_modes, 0, ceil(@all_modes/3)); + my @col2 = splice(@all_modes, 0, ceil(@all_modes/2)); + my $max1 = max(map {length($_)} @col1); + my $max2 = max(map {length($_)} @col2); + while ( @col1 ) { + push @display_lines, sprintf(" %-${max1}s %-${max2}s %s", + (shift @col1 || ''), + (shift @col2 || ''), + (shift @all_modes || '')); + } + + # Action keys + my @all_actions = map { "$_ $keys{$_}" } @actions; + @col1 = splice(@all_actions, 0, ceil(@all_actions/2)); + $max1 = max(map {length($_)} @col1); + push @display_lines, '', 'Actions:'; + while ( @col1 ) { + push @display_lines, sprintf(" %-${max1}s %s", + (shift @col1 || ''), + (shift @all_actions || '')); + } + + # Magic keys + my @all_magic = map { sprintf('%4s', $action_for{$_}->{key} || $_) . " $keys{$_}" } @magic; + @col1 = splice(@all_magic, 0, ceil(@all_magic/2)); + $max1 = max(map {length($_)} @col1); + push @display_lines, '', 'Other:'; + while ( @col1 ) { + push @display_lines, sprintf("%-${max1}s%s", + (shift @col1 || ''), + (shift @all_magic || '')); + } + + $clear_screen_sub->(); + draw_screen(\@display_lines, { show_all => 1 } ); + pause(); + $clear_screen_sub->(); +} + +# show_full_query {{{3 +sub show_full_query { + my $info = shift; + my @display_lines = no_ctrl_char($info->{query}); + draw_screen(\@display_lines, { raw => 1 }); +} + +# Formatting functions {{{2 + +# create_table2 {{{3 +# Makes a two-column table, labels on left, data on right. +# Takes refs of @cols, %labels and %data, %user_prefs +sub create_table2 { + my ( $cols, $labels, $data, $user_prefs ) = @_; + my @rows; + + if ( @$cols && %$data ) { + + # Override defaults + my $p = { + just => '', + sep => ':', + just1 => '-', + }; + if ( $user_prefs ) { + map { $p->{$_} = $user_prefs->{$_} } keys %$user_prefs; + } + + # Fix undef values + map { $data->{$_} = '' unless defined $data->{$_} } @$cols; + + # Format the table + my $max_l = max(map{ length($labels->{$_}) } @$cols); + my $max_v = max(map{ length($data->{$_}) } @$cols); + my $format = "%$p->{just}${max_l}s$p->{sep} %$p->{just1}${max_v}s"; + foreach my $col ( @$cols ) { + push @rows, sprintf($format, $labels->{$col}, $data->{$col}); + } + } + return @rows; +} + +# stack_next {{{3 +# Stacks one display section next to the other. Accepts left-hand arrayref, +# right-hand arrayref, and options hashref. Tries to stack as high as +# possible, so +# aaaaaa +# bbb +# can stack ccc next to the bbb. +# NOTE: this DOES modify its arguments, even though it returns a new array. +sub stack_next { + my ( $left, $right, $user_prefs ) = @_; + my @result; + + my $p = { + pad => ' ', + vsep => 0, + }; + if ( $user_prefs ) { + map { $p->{$_} = $user_prefs->{$_} } keys %$user_prefs; + } + + # Find out how wide the LHS can be and still let the RHS fit next to it. + my $pad = $p->{pad}; + my $max_r = max( map { length($_) } @$right) || 0; + my $max_l = $this_term_size[0] - $max_r - length($pad); + + # Find the minimum row on the LHS that the RHS will fit next to. + my $i = scalar(@$left) - 1; + while ( $i >= 0 && length($left->[$i]) <= $max_l ) { + $i--; + } + $i++; + my $offset = $i; + + if ( $i < scalar(@$left) ) { + # Find the max width of the section of the LHS against which the RHS + # will sit. + my $max_i_in_common = min($i + scalar(@$right) - 1, scalar(@$left) - 1); + my $max_width = max( map { length($_) } @{$left}[$i..$max_i_in_common]); + + # Append the RHS onto the LHS until one runs out. + while ( $i < @$left && $i - $offset < @$right ) { + my $format = "%-${max_width}s$pad%${max_r}s"; + $left->[$i] = sprintf($format, $left->[$i], $right->[$i - $offset]); + $i++; + } + while ( $i - $offset < @$right ) { + # There is more RHS to push on the end of the array + push @$left, + sprintf("%${max_width}s$pad%${max_r}s", ' ', $right->[$i - $offset]); + $i++; + } + push @result, @$left; + } + else { + # There is no room to put them side by side. Add them below, with + # a blank line above them if specified. + push @result, @$left; + push @result, (' ' x $this_term_size[0]) if $p->{vsep} && @$left; + push @result, @$right; + } + return @result; +} + +# create_caption {{{3 +sub create_caption { + my ( $caption, @rows ) = @_; + if ( @rows ) { + + # Calculate the width of what will be displayed, so it can be centered + # in that space. When the thing is wider than the display, center the + # caption in the display. + my $width = min($this_term_size[0], max(map { length(ref($_) ? $_->[0] : $_) } @rows)); + + my $cap_len = length($caption); + + # It may be narrow enough to pad the sides with underscores and save a + # line on the screen. + if ( $cap_len <= $width - 6 ) { + my $left = int(($width - 2 - $cap_len) / 2); + unshift @rows, + ("_" x $left) . " $caption " . ("_" x ($width - $left - $cap_len - 2)); + } + + # The caption is too wide to add underscores on each side. + else { + + # Color is supported, so we can use terminal underlining. + if ( $config{color}->{val} ) { + my $left = int(($width - $cap_len) / 2); + unshift @rows, [ + (" " x $left) . $caption . (" " x ($width - $left - $cap_len)), + 'underline', + ]; + } + + # Color is not supported, so we have to add a line underneath to separate the + # caption from whatever it's captioning. + else { + my $left = int(($width - $cap_len) / 2); + unshift @rows, ('-' x $width); + unshift @rows, (" " x $left) . $caption . (" " x ($width - $left - $cap_len)); + } + + # The caption is wider than the thing it labels, so we have to pad the + # thing it labels to a consistent width. + if ( $cap_len > $width ) { + @rows = map { + ref($_) + ? [ sprintf('%-' . $cap_len . 's', $_->[0]), $_->[1] ] + : sprintf('%-' . $cap_len . 's', $_); + } @rows; + } + + } + } + return @rows; +} + +# create_table {{{3 +# Input: an arrayref of columns, hashref of col info, and an arrayref of hashes +# Example: [ 'a', 'b' ] +# { a => spec, b => spec } +# [ { a => 1, b => 2}, { a => 3, b => 4 } ] +# The 'spec' is a hashref of hdr => label, just => ('-' or ''). It also supports min and max-widths +# vi the minw and maxw params. +# Output: an array of strings, one per row. +# Example: +# Column One Column Two +# ---------- ---------- +# 1 2 +# 3 4 +sub create_table { + my ( $cols, $info, $data, $prefs ) = @_; + $prefs ||= {}; + $prefs->{no_hdr} ||= ($opts{n} && $clock != 1); + + # Truncate rows that will surely be off screen even if this is the only table. + if ( !$opts{n} && !$prefs->{raw} && !$prefs->{show_all} && $this_term_size[1] < @$data-1 ) { + $data = [ @$data[0..$this_term_size[1] - 1] ]; + } + + my @rows = (); + + if ( @$cols && %$info ) { + + # Fix undef values, collapse whitespace. + foreach my $row ( @$data ) { + map { $row->{$_} = collapse_ws($row->{$_}) } @$cols; + } + + my $col_sep = $opts{n} ? "\t" : ' '; + + # Find each column's max width. + my %width_for; + if ( !$opts{n} ) { + %width_for = map { + my $col_name = $_; + if ( $info->{$_}->{dec} ) { + # Align along the decimal point + my $max_rodp = max(0, map { $_->{$col_name} =~ m/([^\s\d-].*)$/ ? length($1) : 0 } @$data); + foreach my $row ( @$data ) { + my $col = $row->{$col_name}; + my ( $l, $r ) = $col =~ m/^([\s\d]*)(.*)$/; + $row->{$col_name} = sprintf("%s%-${max_rodp}s", $l, $r); + } + } + my $max_width = max( length($info->{$_}->{hdr}), map { length($_->{$col_name}) } @$data); + if ( $info->{$col_name}->{maxw} ) { + $max_width = min( $max_width, $info->{$col_name}->{maxw} ); + } + if ( $info->{$col_name}->{minw} ) { + $max_width = max( $max_width, $info->{$col_name}->{minw} ); + } + $col_name => $max_width; + } @$cols; + } + + # The table header. + if ( !$config{hide_hdr}->{val} && !$prefs->{no_hdr} ) { + push @rows, $opts{n} + ? join( $col_sep, @$cols ) + : join( $col_sep, map { sprintf( "%-$width_for{$_}s", trunc($info->{$_}->{hdr}, $width_for{$_}) ) } @$cols ); + if ( $config{color}->{val} && $config{header_highlight}->{val} ) { + push @rows, [ pop @rows, $config{header_highlight}->{val} ]; + } + elsif ( !$opts{n} ) { + push @rows, join( $col_sep, map { "-" x $width_for{$_} } @$cols ); + } + } + + # The table data. + if ( $opts{n} ) { + foreach my $item ( @$data ) { + push @rows, join($col_sep, map { $item->{$_} } @$cols ); + } + } + else { + my $format = join( $col_sep, + map { "%$info->{$_}->{just}$width_for{$_}s" } @$cols ); + foreach my $item ( @$data ) { + my $row = sprintf($format, map { trunc($item->{$_}, $width_for{$_}) } @$cols ); + if ( $config{color}->{val} && $item->{_color} ) { + push @rows, [ $row, $item->{_color} ]; + } + else { + push @rows, $row; + } + } + } + } + + return @rows; +} + +# Aggregates a table. If $group_by is an arrayref of columns, the grouping key +# is the specified columns; otherwise it's just the empty string (e.g. +# everything is grouped as one group). +sub apply_group_by { + my ( $tbl, $group_by, @rows ) = @_; + my $meta = $tbl_meta{$tbl}; + my %is_group = map { $_ => 1 } @$group_by; + my @non_grp = grep { !$is_group{$_} } keys %{$meta->{cols}}; + + my %temp_table; + foreach my $row ( @rows ) { + my $group_key + = @$group_by + ? '{' . join('}{', map { defined $_ ? $_ : '' } @{$row}{@$group_by}) . '}' + : ''; + $temp_table{$group_key} ||= []; + push @{$temp_table{$group_key}}, $row; + } + + # Crush the rows together... + my @new_rows; + foreach my $key ( sort keys %temp_table ) { + my $group = $temp_table{$key}; + my %new_row; + @new_row{@$group_by} = @{$group->[0]}{@$group_by}; + foreach my $col ( @non_grp ) { + my $agg = $meta->{cols}->{$col}->{agg} || 'first'; + $new_row{$col} = $agg_funcs{$agg}->( map { $_->{$col} } @$group ); + } + push @new_rows, \%new_row; + } + return @new_rows; +} + +# set_to_tbl {{{3 +# Unifies all the work of filtering, sorting etc. Alters the input. +# TODO: pull all the little pieces out into subroutines and stick events in each of them. +sub set_to_tbl { + my ( $rows, $tbl ) = @_; + my $meta = $tbl_meta{$tbl} or die "No such table $tbl in tbl_meta"; + + 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. + if ( $aggregated ) { + my %is_group = map { $_ => 1 } @{$meta->{group_by}}; + $fmt_cols = [ @{$meta->{group_by}}, grep { !$is_group{$_} } @$fmt_cols ]; + } + } + + foreach my $listener ( @{$event_listener_for{set_to_tbl_pre_create}} ) { + $listener->set_to_tbl_pre_create(\@rows, $tbl); + } + + @rows = create_table( $fmt_cols, $fmt_meta, \@rows); + if ( !$meta->{hide_caption} && !$opts{n} && $config{display_table_captions}->{val} ) { + @rows = create_caption($meta->{capt}, @rows) + } + + foreach my $listener ( @{$event_listener_for{set_to_tbl_post_create}} ) { + $listener->set_to_tbl_post_create(\@rows, $tbl); + } + + return @rows; +} + +# meta_to_hdr {{{3 +sub meta_to_hdr { + my $tbl = shift; + my $meta = $tbl_meta{$tbl}; + my %labels = map { $_ => $meta->{cols}->{$_}->{hdr} } @{$meta->{visible}}; + return \%labels; +} + +# commify {{{3 +# From perlfaq5: add commas. +sub commify { + my ( $num ) = @_; + $num = 0 unless defined $num; + $num =~ s/(^[-+]?\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/g; + return $num; +} + +# set_precision {{{3 +# Trim to desired precision. +sub set_precision { + my ( $num, $precision ) = @_; + $precision = $config{num_digits}->{val} if !defined $precision; + sprintf("%.${precision}f", $num); +} + +# percent {{{3 +# Convert to percent +sub percent { + my ( $num ) = @_; + $num = 0 unless defined $num; + my $digits = $config{num_digits}->{val}; + return sprintf("%.${digits}f", $num * 100) + . ($config{show_percent}->{val} ? '%' : ''); +} + +# shorten {{{3 +sub shorten { + my ( $num, $opts ) = @_; + + return $num if !defined($num) || $opts{n} || $num !~ m/$num_regex/; + + $opts ||= {}; + my $pad = defined $opts->{pad} ? $opts->{pad} : ''; + my $num_digits = defined $opts->{num_digits} + ? $opts->{num_digits} + : $config{num_digits}->{val}; + my $force = defined $opts->{force}; + + my $n = 0; + while ( $num >= 1_024 ) { + $num /= 1_024; + ++$n; + } + return sprintf( + $num =~ m/\./ || $n || $force + ? "%.${num_digits}f%s" + : '%d', + $num, ($pad,'k','M','G', 'T')[$n]); + +} + +# Utility functions {{{2 +# unique {{{3 +sub unique { + my %seen; + return grep { !$seen{$_}++ } @_; +} + +# make_color_func {{{3 +sub make_color_func { + my ( $tbl ) = @_; + my @criteria; + foreach my $spec ( @{$tbl->{colors}} ) { + next unless exists $comp_ops{$spec->{op}}; + my $val = $spec->{op} =~ m/^(?:eq|ne|le|ge|lt|gt)$/ ? "'$spec->{arg}'" + : $spec->{op} =~ m/^(?:=~|!~)$/ ? "m/" . quotemeta($spec->{arg}) . "/" + : $spec->{arg}; + push @criteria, + "( defined \$set->{$spec->{col}} && \$set->{$spec->{col}} $spec->{op} $val ) { return '$spec->{color}'; }"; + } + return undef unless @criteria; + my $sub = eval 'sub { my ( $set ) = @_; if ' . join(" elsif ", @criteria) . '}'; + die if $EVAL_ERROR; + return $sub; +} + +# make_sort_func {{{3 +# Gets a list of sort columns from the table, like "+cxn -time" and returns a +# subroutine that will sort that way. +sub make_sort_func { + my ( $tbl ) = @_; + my @criteria; + + # Pivoted tables can be sorted by 'name' and set_x columns; others must be + # sorted by existing columns. TODO: this will crash if you toggle between + # pivoted and nonpivoted. I have several other 'crash' notes about this if + # this ever becomes possible. + + if ( $tbl->{pivot} ) { + # Sort type is not really possible on pivoted columns, because a 'column' + # contains data from an entire non-pivoted row, so there could be a mix of + # numeric and non-numeric data. Thus everything has to be 'cmp' type. + foreach my $col ( split(/\s+/, $tbl->{sort_cols} ) ) { + next unless $col; + my ( $dir, $name ) = $col =~ m/([+-])?(\w+)$/; + next unless $name && $name =~ m/^(?:name|set_\d+)$/; + $dir ||= '+'; + my $op = 'cmp'; + my $df = "''"; + push @criteria, + $dir eq '+' + ? "(\$a->{$name} || $df) $op (\$b->{$name} || $df)" + : "(\$b->{$name} || $df) $op (\$a->{$name} || $df)"; + } + } + else { + foreach my $col ( split(/\s+/, $tbl->{sort_cols} ) ) { + next unless $col; + my ( $dir, $name ) = $col =~ m/([+-])?(\w+)$/; + next unless $name && $tbl->{cols}->{$name}; + $dir ||= '+'; + my $op = $tbl->{cols}->{$name}->{num} ? "<=>" : "cmp"; + my $df = $tbl->{cols}->{$name}->{num} ? "0" : "''"; + push @criteria, + $dir eq '+' + ? "(\$a->{$name} || $df) $op (\$b->{$name} || $df)" + : "(\$b->{$name} || $df) $op (\$a->{$name} || $df)"; + } + } + return sub { return @_ } unless @criteria; + my $sub = eval 'sub { sort {' . join("||", @criteria) . '} @_; }'; + die if $EVAL_ERROR; + return $sub; +} + +# trunc {{{3 +# Shortens text to specified length. +sub trunc { + my ( $text, $len ) = @_; + if ( length($text) <= $len ) { + return $text; + } + return substr($text, 0, $len); +} + +# donut {{{3 +# Takes out the middle of text to shorten it. +sub donut { + my ( $text, $len ) = @_; + return $text if length($text) <= $len; + my $max = length($text) - $len; + my $min = $max - 1; + + # Try to remove a single "word" from somewhere in the center + if ( $text =~ s/_[^_]{$min,$max}_/_/ ) { + return $text; + } + + # Prefer removing the end of a "word" + if ( $text =~ s/([^_]+)[^_]{$max}_/$1_/ ) { + return $text; + } + + $text = substr($text, 0, int($len/2)) + . "_" + . substr($text, int($len/2) + $max + 1); + return $text; +} + +# crunch {{{3 +# Removes vowels and compacts repeated letters to shorten text. +sub crunch { + my ( $text, $len ) = @_; + return $text if $len && length($text) <= $len; + $text =~ s/^IB_\w\w_//; + $text =~ s/(?{val}; + if ( $charset && $charset eq 'unicode' ) { + $text =~ s/ + ("(?:(?!(?{val} ) { + unshift @$display_lines, create_statusbar(); + } + + foreach my $listener ( @{$event_listener_for{draw_screen}} ) { + $listener->draw_screen($display_lines); + } + + $clear_screen_sub->() + if $prefs->{clear} || !$modes{$config{mode}->{val}}->{no_clear_screen}; + if ( $opts{n} || $prefs->{raw} ) { + my $num_lines = 0; + print join("\n", + map { + $num_lines++; + ref $_ + ? colored($_->[0], $_->[1]) + : $_; + } + grep { !$opts{n} || $_ } # Suppress empty lines + @$display_lines); + if ( $opts{n} && $num_lines ) { + print "\n"; + } + } + else { + my $max_lines = $prefs->{show_all} + ? scalar(@$display_lines)- 1 + : min(scalar(@$display_lines), $this_term_size[1]); + print join("\n", + map { + ref $_ + ? colored(substr($_->[0], 0, $this_term_size[0]), $_->[1]) + : substr($_, 0, $this_term_size[0]); + } @$display_lines[0..$max_lines - 1]); + } +} + +# secs_to_time {{{3 +sub secs_to_time { + my ( $secs, $fmt ) = @_; + $secs ||= 0; + return '00:00' unless $secs; + + # Decide what format to use, if not given + $fmt ||= $secs >= 86_400 ? 'd' + : $secs >= 3_600 ? 'h' + : 'm'; + + return + $fmt eq 'd' ? sprintf( + "%d+%02d:%02d:%02d", + int($secs / 86_400), + int(($secs % 86_400) / 3_600), + int(($secs % 3_600) / 60), + $secs % 60) + : $fmt eq 'h' ? sprintf( + "%02d:%02d:%02d", + int(($secs % 86_400) / 3_600), + int(($secs % 3_600) / 60), + $secs % 60) + : sprintf( + "%02d:%02d", + int(($secs % 3_600) / 60), + $secs % 60); +} + +# dulint_to_int {{{3 +# Takes a number that InnoDB formats as two ulint integers, like transaction IDs +# and such, and turns it into a single integer +sub dulint_to_int { + my $num = shift; + return 0 unless $num; + my ( $high, $low ) = $num =~ m/^(\d+) (\d+)$/; + return $low unless $high; + return $low + ( $high * $MAX_ULONG ); +} + +# create_statusbar {{{3 +sub create_statusbar { + my $mode = $config{mode}->{val}; + my @cxns = sort { $a cmp $b } get_connections(); + + my $modeline = ( $config{readonly}->{val} ? '[RO] ' : '' ) + . $modes{$mode}->{hdr} . " (? for help)"; + my $mode_width = length($modeline); + my $remaining_width = $this_term_size[0] - $mode_width - 1; + my $result; + + # The thingie in top-right that says what we're monitoring. + my $cxn = ''; + + if ( 1 == @cxns && $dbhs{$cxns[0]} && $dbhs{$cxns[0]}->{dbh} ) { + $cxn = $dbhs{$cxns[0]}->{dbh}->{mysql_serverinfo} || ''; + } + else { + if ( $modes{$mode}->{server_group} ) { + $cxn = "Servers: " . $modes{$mode}->{server_group}; + my $err_count = grep { $dbhs{$_} && $dbhs{$_}->{err_count} } @cxns; + if ( $err_count ) { + $cxn .= "(" . ( scalar(@cxns) - $err_count ) . "/" . scalar(@cxns) . ")"; + } + } + else { + $cxn = join(' ', map { ($dbhs{$_}->{err_count} ? '!' : '') . $_ } + grep { $dbhs{$_} } @cxns); + } + } + + if ( 1 == @cxns ) { + get_driver_status(@cxns); + my $vars = $vars{$cxns[0]}->{$clock}; + my $inc = inc(0, $cxns[0]); + + # Format server uptime human-readably, calculate QPS... + my $uptime = secs_to_time( $vars->{Uptime_hires} ); + my $qps = ($inc->{Questions}||0) / ($inc->{Uptime_hires}||1); + my $ibinfo = ''; + + if ( exists $vars->{IB_last_secs} ) { + $ibinfo .= "InnoDB $vars->{IB_last_secs}s "; + if ( $vars->{IB_got_all} ) { + if ( ($mode eq 'T' || $mode eq 'W') + && $vars->{IB_tx_is_truncated} ) { + $ibinfo .= ':^|'; + } + else { + $ibinfo .= ':-)'; + } + } + else { + $ibinfo .= ':-('; + } + } + $result = sprintf( + "%-${mode_width}s %${remaining_width}s", + $modeline, + join(', ', grep { $_ } ( + $cxns[0], + $uptime, + $ibinfo, + shorten($qps) . " QPS", + ($vars->{Threads} || 0) . " thd", + $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 ) = @_; + + 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 ); + } + + my $dsn; + do { + $clear_screen_sub->(); + print "Typical DSN strings look like\n DBI:mysql:;host=hostname;port=port\n" + . "The db and port are optional and can usually be omitted.\n" + . "If you specify 'mysql_read_default_group=mysql' many options can be read\n" + . "from your mysql options files (~/.my.cnf, /etc/my.cnf).\n\n"; + $dsn = prompt("Enter a DSN string", undef, "DBI:mysql:;mysql_read_default_group=mysql;host=$name"); + } until ( $dsn ); + + $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, + }; +} + +sub add_new_server_group { + my ( $name ) = @_; + + if ( defined $name ) { + $name =~ s/[\s:;]//g; + } + + if ( !$name ) { + print word_wrap("Choose a name for the group. It cannot contain " + . "whitespace, colons or semicolons."), "\n\n"; + do { + $name = prompt("Enter a name"); + $name =~ s/[\s:;]//g; + } until ( $name ); + } + + my @cxns; + do { + $clear_screen_sub->(); + @cxns = select_cxn("Choose servers for $name", keys %connections); + } until ( @cxns ); + + $server_groups{$name} = \@cxns; + return $name; +} + +sub get_var_set { + my ( $name ) = @_; + while ( !$name || !exists($var_sets{$config{$name}->{val}}) ) { + $name = choose_var_set($name); + } + return $var_sets{$config{$name}->{val}}->{text}; +} + +sub add_new_var_set { + my ( $name ) = @_; + + if ( defined $name ) { + $name =~ s/\W//g; + } + + if ( !$name ) { + do { + $name = prompt("Enter a name"); + $name =~ s/\W//g; + } until ( $name ); + } + + my $variables; + do { + $clear_screen_sub->(); + $variables = prompt("Enter variables for $name", undef ); + } until ( $variables ); + + $var_sets{$name} = { text => $variables, user => 1 }; +} + +sub next_server { + my $mode = $config{mode}->{val}; + my @cxns = sort keys %connections; + my ($cur) = get_connections($mode); + $cur ||= $cxns[0]; + my $pos = grep { $_ lt $cur } @cxns; + my $newpos = ($pos + 1) % @cxns; + $modes{$mode}->{server_group} = ''; + $modes{$mode}->{connections} = [ $cxns[$newpos] ]; + $clear_screen_sub->(); +} + +sub next_server_group { + my $mode = shift || $config{mode}->{val}; + my @grps = sort keys %server_groups; + my $curr = $modes{$mode}->{server_group}; + + return unless @grps; + + if ( $curr ) { + # Find the current group's position. + my $pos = 0; + while ( $curr ne $grps[$pos] ) { + $pos++; + } + $modes{$mode}->{server_group} = $grps[ ($pos + 1) % @grps ]; + } + else { + $modes{$mode}->{server_group} = $grps[0]; + } +} + +# Get a list of connection names used in this mode. +sub get_connections { + if ( $file ) { + return qw(file); + } + my $mode = shift || $config{mode}->{val}; + my @connections = $modes{$mode}->{server_group} + ? @{$server_groups{$modes{$mode}->{server_group}}} + : @{$modes{$mode}->{connections}}; + if ( $modes{$mode}->{one_connection} ) { + @connections = @connections ? $connections[0] : (); + } + return unique(@connections); +} + +# Get a list of tables used in this mode. If innotop is running non-interactively, just use the first. +sub get_visible_tables { + my $mode = shift || $config{mode}->{val}; + my @tbls = @{$modes{$mode}->{visible_tables}}; + if ( $opts{n} ) { + return $tbls[0]; + } + else { + return @tbls; + } +} + +# Choose from among available connections or server groups. +# If the mode has a server set in use, prefers that instead. +sub choose_connections { + $clear_screen_sub->(); + my $mode = $config{mode}->{val}; + my $meta = { map { $_ => $connections{$_}->{dsn} } keys %connections }; + foreach my $group ( keys %server_groups ) { + $meta->{"#$group"} = join(' ', @{$server_groups{$group}}); + } + + my $choices = prompt_list("Choose connections or a group for $mode mode", + undef, sub { return keys %$meta }, $meta); + + my @choices = unique(grep { $_ } split(/\s+/, $choices)); + if ( @choices ) { + if ( $choices[0] =~ s/^#// && exists $server_groups{$choices[0]} ) { + $modes{$mode}->{server_group} = $choices[0]; + } + else { + $modes{$mode}->{connections} = [ grep { exists $connections{$_} } @choices ]; + } + } +} + +# Accepts a DB connection name and the name of a prepared query (e.g. status, kill). +# Also a list of params for the prepared query. This allows not storing prepared +# statements globally. Returns a $sth that's been executed. +# ERROR-HANDLING SEMANTICS: if the statement throws an error, propagate, but if the +# connection has gone away or can't connect, DO NOT. Just return undef. +sub do_stmt { + my ( $cxn, $stmt_name, @args ) = @_; + + return undef if $file; + + # Test if the cxn should not even be tried + return undef if $dbhs{$cxn} + && $dbhs{$cxn}->{err_count} + && ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} ) + && $dbhs{$cxn}->{wake_up} > $clock; + + my $sth; + my $retries = 1; + my $success = 0; + TRY: + while ( $retries-- >= 0 && !$success ) { + + eval { + my $dbh = connect_to_db($cxn); + + # If the prepared query doesn't exist, make it. + if ( !exists $dbhs{$cxn}->{stmts}->{$stmt_name} ) { + $dbhs{$cxn}->{stmts}->{$stmt_name} = $stmt_maker_for{$stmt_name}->($dbh); + } + + $sth = $dbhs{$cxn}->{stmts}->{$stmt_name}; + if ( $sth ) { + $sth->execute(@args); + } + $success = 1; + }; + if ( $EVAL_ERROR ) { + if ( $EVAL_ERROR =~ m/$nonfatal_errs/ ) { + handle_cxn_error($cxn, $EVAL_ERROR); + } + else { + die "$cxn $stmt_name: $EVAL_ERROR"; + } + if ( $retries < 0 ) { + $sth = undef; + } + } + } + + if ( $sth && $sth->{NUM_OF_FIELDS} ) { + sleep($stmt_sleep_time_for{$stmt_name}) if $stmt_sleep_time_for{$stmt_name}; + return $sth; + } +} + +# Keeps track of error count, sleep times till retries, etc etc. +# When there's an error we retry the connection every so often, increasing in +# Fibonacci series to prevent too much banging on the server. +sub handle_cxn_error { + my ( $cxn, $err ) = @_; + my $meta = $dbhs{$cxn}; + $meta->{err_count}++; + + # This is used so errors that have to do with permissions needed by the current + # mode will get displayed as long as we're in this mode, but get ignored if the + # mode changes. + $meta->{mode} = $config{mode}->{val}; + + # Strip garbage from the error text if possible. + $err =~ s/\s+/ /g; + if ( $err =~ m/failed: (.*?) at \S*innotop line/ ) { + $err = $1; + } + + $meta->{last_err} = $err; + my $sleep_time = $meta->{this_sleep} + $meta->{prev_sleep}; + $meta->{prev_sleep} = $meta->{this_sleep}; + $meta->{this_sleep} = $sleep_time; + $meta->{wake_up} = $clock + $sleep_time; + if ( $config{show_cxn_errors}->{val} ) { + print STDERR "Error at tick $clock $cxn $err" if $config{debug}->{val}; + } +} + +# Accepts a DB connection name and a (string) query. Returns a $sth that's been +# executed. +sub do_query { + my ( $cxn, $query ) = @_; + + return undef if $file; + + # Test if the cxn should not even be tried + return undef if $dbhs{$cxn} + && $dbhs{$cxn}->{err_count} + && ( !$dbhs{$cxn}->{dbh} || !$dbhs{$cxn}->{dbh}->{Active} || $dbhs{$cxn}->{mode} eq $config{mode}->{val} ) + && $dbhs{$cxn}->{wake_up} > $clock; + + my $sth; + my $retries = 1; + my $success = 0; + TRY: + while ( $retries-- >= 0 && !$success ) { + + eval { + my $dbh = connect_to_db($cxn); + + $sth = $dbh->prepare($query); + $sth->execute(); + $success = 1; + }; + if ( $EVAL_ERROR ) { + if ( $EVAL_ERROR =~ m/$nonfatal_errs/ ) { + handle_cxn_error($cxn, $EVAL_ERROR); + } + else { + die $EVAL_ERROR; + } + if ( $retries < 0 ) { + $sth = undef; + } + } + } + + return $sth; +} + +sub get_uptime { + my ( $cxn ) = @_; + $dbhs{$cxn}->{start_time} ||= time(); + # Avoid dividing by zero + return (time() - $dbhs{$cxn}->{start_time}) || .001; +} + +sub connect_to_db { + my ( $cxn ) = @_; + + $dbhs{$cxn} ||= { + stmts => {}, # bucket for prepared statements. + prev_sleep => 0, + this_sleep => 1, + wake_up => 0, + start_time => 0, + dbh => undef, + }; + my $href = $dbhs{$cxn}; + + if ( !$href->{dbh} || ref($href->{dbh}) !~ m/DBI/ || !$href->{dbh}->ping ) { + my $dbh = get_new_db_connection($cxn); + @{$href}{qw(dbh err_count wake_up this_sleep start_time prev_sleep)} + = ($dbh, 0, 0, 1, 0, 0); + + # Derive and store the server's start time in hi-res + my $uptime = $dbh->selectrow_hashref("show status like 'Uptime'")->{value}; + $href->{start_time} = time() - $uptime; + + # Set timeouts so an unused connection stays alive. + # For example, a connection might be used in Q mode but idle in T mode. + if ( version_ge($dbh, '4.0.3')) { + my $timeout = $config{cxn_timeout}->{val}; + $dbh->do("set session wait_timeout=$timeout, interactive_timeout=$timeout"); + } + } + return $href->{dbh}; +} + +# Compares versions like 5.0.27 and 4.1.15-standard-log +sub version_ge { + my ( $dbh, $target ) = @_; + my $version = sprintf('%03d%03d%03d', $dbh->{mysql_serverinfo} =~ m/(\d+)/g); + return $version ge sprintf('%03d%03d%03d', $target =~ m/(\d+)/g); +} + +# Extracts status values that can be gleaned from the DBD driver without doing a whole query. +sub get_driver_status { + my @cxns = @_; + if ( !$info_gotten{driver_status}++ ) { + foreach my $cxn ( @cxns ) { + next unless $dbhs{$cxn} && $dbhs{$cxn}->{dbh} && $dbhs{$cxn}->{dbh}->{Active}; + $vars{$cxn}->{$clock} ||= {}; + my $vars = $vars{$cxn}->{$clock}; + my %res = map { $_ =~ s/ +/_/g; $_ } $dbhs{$cxn}->{dbh}->{mysql_stat} =~ m/(\w[^:]+): ([\d\.]+)/g; + map { $vars->{$_} ||= $res{$_} } keys %res; + $vars->{Uptime_hires} ||= get_uptime($cxn); + $vars->{cxn} = $cxn; + } + } +} + +sub get_new_db_connection { + my ( $connection, $destroy ) = @_; + if ( $file ) { + die "You can't connect to a MySQL server while monitoring a file. This is probably a bug."; + } + + my $dsn = $connections{$connection} + or die "No connection named '$connection' is defined in your configuration"; + + if ( !defined $dsn->{have_user} ) { + my $answer = prompt("Do you want to specify a username for $connection?", undef, 'n'); + $dsn->{have_user} = $answer && $answer =~ m/1|y/i; + } + + if ( !defined $dsn->{have_pass} ) { + my $answer = prompt("Do you want to specify a password for $connection?", undef, 'n'); + $dsn->{have_pass} = $answer && $answer =~ m/1|y/i; + } + + if ( !$dsn->{user} && $dsn->{have_user} ) { + my $user = $ENV{USERNAME} || $ENV{USER} || getlogin() || getpwuid($REAL_USER_ID) || undef; + $dsn->{user} = prompt("Enter username for $connection", undef, $user); + } + + if ( !defined $dsn->{user} ) { + $dsn->{user} = ''; + } + + if ( !$dsn->{pass} && !$dsn->{savepass} && $dsn->{have_pass} ) { + $dsn->{pass} = prompt_noecho("Enter password for '$dsn->{user}' on $connection"); + print "\n"; + if ( !defined($dsn->{savepass}) ) { + my $answer = prompt("Save password in plain text in the config file?", undef, 'y'); + $dsn->{savepass} = $answer && $answer =~ m/1|y/i; + } + } + + my $dbh = DBI->connect( + $dsn->{dsn}, $dsn->{user}, $dsn->{pass}, + { RaiseError => 1, PrintError => 0, AutoCommit => 1 }); + $dbh->{InactiveDestroy} = 1 unless $destroy; # Can't be set in $db_options + $dbh->{FetchHashKeyName} = 'NAME_lc'; # Lowercases all column names for fetchrow_hashref + return $dbh; +} + +sub get_cxn_errors { + my @cxns = @_; + return () unless $config{show_cxn_errors_in_tbl}->{val}; + return + map { [ $_ . ': ' . $dbhs{$_}->{last_err}, 'red' ] } + grep { $dbhs{$_} && $dbhs{$_}->{err_count} && $dbhs{$_}->{mode} eq $config{mode}->{val} } + @cxns; +} + +# Setup and tear-down functions {{{2 + +# Takes a string and turns it into a hashref you can apply to %tbl_meta tables. The string +# can be in the form 'foo, bar, foo/bar, foo as bar' much like a SQL SELECT statement. +sub compile_select_stmt { + my ($str) = @_; + my @exps = $str =~ m/\s*([^,]+(?i:\s+as\s+[^,\s]+)?)\s*(?=,|$)/g; + my %cols; + my @visible; + foreach my $exp ( @exps ) { + my ( $text, $colname ); + if ( $exp =~ m/as\s+(\w+)\s*/ ) { + $colname = $1; + $exp =~ s/as\s+(\w+)\s*//; + $text = $exp; + } + else { + $text = $colname = $exp; + } + my ($func, $err) = compile_expr($text); + $cols{$colname} = { + src => $text, + hdr => $colname, + num => 0, + func => $func, + }; + push @visible, $colname; + } + return (\%cols, \@visible); +} + +# compile_filter {{{3 +sub compile_filter { + my ( $text ) = @_; + my ( $sub, $err ); + eval "\$sub = sub { my \$set = shift; $text }"; + if ( $EVAL_ERROR ) { + $EVAL_ERROR =~ s/at \(eval.*$//; + $sub = sub { return $EVAL_ERROR }; + $err = $EVAL_ERROR; + } + return ( $sub, $err ); +} + +# compile_expr {{{3 +sub compile_expr { + my ( $expr ) = @_; + # Leave built-in functions alone so they get called as Perl functions, unless + # they are the only word in $expr, in which case treat them as hash keys. + if ( $expr =~ m/\W/ ) { + $expr =~ s/(?{$1}"/eg; + } + else { + $expr = "\$set->{$expr}"; + } + my ( $sub, $err ); + my $quoted = quotemeta($expr); + eval qq{ + \$sub = sub { + my (\$set, \$cur, \$pre) = \@_; + my \$val = eval { $expr }; + if ( \$EVAL_ERROR && \$config{debug}->{val} ) { + \$EVAL_ERROR =~ s/ at \\(eval.*//s; + die "\$EVAL_ERROR in expression $quoted"; + } + return \$val; + } + }; + if ( $EVAL_ERROR ) { + if ( $config{debug}->{val} ) { + die $EVAL_ERROR; + } + $EVAL_ERROR =~ s/ at \(eval.*$//; + $sub = sub { return $EVAL_ERROR }; + $err = $EVAL_ERROR; + } + return ( $sub, $err ); +} + +# finish {{{3 +# This is a subroutine because it's called from a key to quit the program. +sub finish { + save_config(); + ReadMode('normal') unless $opts{n}; + print "\n"; + exit(0); +} + +# core_dump {{{3 +sub core_dump { + my $msg = shift; + if ($config{debugfile}->{val} && $config{debug}->{val}) { + eval { + open my $file, '>>', $config{debugfile}->{val}; + if ( %vars ) { + print $file "Current variables:\n" . Dumper(\%vars); + } + close $file; + }; + } + print $msg; +} + +# load_config {{{3 +sub load_config { + + my $filename = $opts{c} || "$homepath/.innotop/innotop.ini"; + my $dirname = dirname($filename); + if ( -f $dirname && !$opts{c} ) { + # innotop got upgraded and this is the old config file. + my $answer = pause("Innotop's default config location has moved to $filename. Move old config file $dirname there now? y/n"); + if ( lc $answer eq 'y' ) { + rename($dirname, "$homepath/innotop.ini") + or die "Can't rename '$dirname': $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("$homepath/innotop.ini", $filename) + or die "Can't rename '$homepath/innotop.ini' to '$filename': $OS_ERROR"; + } + else { + print "\nInnotop will now exit so you can fix the config file.\n"; + exit(0); + } + } + + if ( ! -d $dirname ) { + mkdir $dirname + or die "Can't create directory '$dirname': $OS_ERROR"; + } + if ( ! -d "$dirname/plugins" ) { + mkdir "$dirname/plugins" + or die "Can't create directory '$dirname/plugins': $OS_ERROR"; + } + + if ( -f $filename ) { + open my $file, "<", $filename or die("Can't open '$filename': $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 $filename? 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 $filename: $OS_ERROR"); + } + +} + +# Do some post-processing on %tbl_meta: compile src properties into func etc. +sub post_process_tbl_meta { + foreach my $table ( values %tbl_meta ) { + foreach my $col_name ( keys %{$table->{cols}} ) { + my $col_def = $table->{cols}->{$col_name}; + my ( $sub, $err ) = compile_expr($col_def->{src}); + $col_def->{func} = $sub; + } + } +} + +# load_config_plugins {{{3 +sub load_config_plugins { + my ( $file ) = @_; + + # First, find a list of all plugins that exist on disk, and get information about them. + my $dir = $config{plugin_dir}->{val}; + foreach my $p_file ( <$dir/*.pm> ) { + my ($package, $desc); + eval { + open my $p_in, "<", $p_file or die $OS_ERROR; + while ( my $line = <$p_in> ) { + chomp $line; + if ( $line =~ m/^package\s+(.*?);/ ) { + $package = $1; + } + elsif ( $line =~ m/^# description: (.*)/ ) { + $desc = $1; + } + last if $package && $desc; + } + close $p_in; + }; + if ( $package ) { + $plugins{$package} = { + file => $p_file, + desc => $desc, + class => $package, + active => 0, + }; + if ( $config{debug}->{val} && $EVAL_ERROR ) { + die $EVAL_ERROR; + } + } + } + + # Now read which ones the user has activated. Each line simply represents an active plugin. + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + next unless $line && $plugins{$line}; + + my $obj; + eval { + require $plugins{$line}->{file}; + $obj = $line->new(%pluggable_vars); + foreach my $event ( $obj->register_for_events() ) { + my $queue = $event_listener_for{$event}; + if ( $queue ) { + push @$queue, $obj; + } + } + }; + if ( $config{debug}->{val} && $EVAL_ERROR ) { + die $EVAL_ERROR; + } + if ( $obj ) { + $plugins{$line}->{active} = 1; + $plugins{$line}->{object} = $obj; + } + } +} + +# save_config_plugins {{{3 +sub save_config_plugins { + my $file = shift; + foreach my $class ( sort keys %plugins ) { + next unless $plugins{$class}->{active}; + print $file "$class\n"; + } +} + +# load_config_active_server_groups {{{3 +sub load_config_active_server_groups { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $mode, $group ) = $line =~ m/^(.*?)=(.*)$/; + next unless $mode && $group + && exists $modes{$mode} && exists $server_groups{$group}; + $modes{$mode}->{server_group} = $group; + } +} + +# save_config_active_server_groups {{{3 +sub save_config_active_server_groups { + my $file = shift; + foreach my $mode ( sort keys %modes ) { + print $file "$mode=$modes{$mode}->{server_group}\n"; + } +} + +# load_config_server_groups {{{3 +sub load_config_server_groups { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $name, $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $name && $rest; + my @vars = unique(grep { $_ && exists $connections{$_} } split(/\s+/, $rest)); + next unless @vars; + $server_groups{$name} = \@vars; + } +} + +# save_config_server_groups {{{3 +sub save_config_server_groups { + my $file = shift; + foreach my $set ( sort keys %server_groups ) { + print $file "$set=", join(' ', @{$server_groups{$set}}), "\n"; + } +} + +# load_config_varsets {{{3 +sub load_config_varsets { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $name, $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $name && $rest; + $var_sets{$name} = { + text => $rest, + user => 1, + }; + } +} + +# save_config_varsets {{{3 +sub save_config_varsets { + my $file = shift; + foreach my $varset ( sort keys %var_sets ) { + next unless $var_sets{$varset}->{user}; + print $file "$varset=$var_sets{$varset}->{text}\n"; + } +} + +# load_config_group_by {{{3 +sub load_config_group_by { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $tbl , $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $tbl && exists $tbl_meta{$tbl}; + my @parts = unique(grep { exists($tbl_meta{$tbl}->{cols}->{$_}) } split(/\s+/, $rest)); + $tbl_meta{$tbl}->{group_by} = [ @parts ]; + $tbl_meta{$tbl}->{cust}->{group_by} = 1; + } +} + +# save_config_group_by {{{3 +sub save_config_group_by { + my $file = shift; + foreach my $tbl ( sort keys %tbl_meta ) { + next if $tbl_meta{$tbl}->{temp}; + next unless $tbl_meta{$tbl}->{cust}->{group_by}; + my $aref = $tbl_meta{$tbl}->{group_by}; + print $file "$tbl=", join(' ', @$aref), "\n"; + } +} + +# load_config_filters {{{3 +sub load_config_filters { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $key, $rest ) = $line =~ m/^(.+?)=(.*)$/; + next unless $key && $rest; + + my %parts = $rest =~ m/(\w+)='((?:(?!(? $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 ) = @_; + + # Look in the command-line parameters for things stored in the same slot. + my %cmdline = + map { $_->{c} => $opts{$_->{k}} } + grep { exists $_->{c} && exists $opts{$_->{k}} } + @opt_spec; + + 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; + + # Values might already have been set at the command line. + $val = defined($cmdline{$name}) ? $cmdline{$name} : $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+)='((?:(?!(?{cols}->{$col} ||= {}; + + foreach my $prop ( keys %col_props ) { + if ( !defined($parts{$prop}) ) { + die "Undefined property $prop for column $col in table $tbl"; + } + + # Un-escape escaping + $parts{$prop} =~ s/\\\\/\\/g; + $parts{$prop} =~ s/\\'/'/g; + + if ( ref $col_props{$prop} ) { + if ( $prop eq 'trans' ) { + $meta->{cols}->{$col}->{trans} + = [ unique(grep { exists $trans_funcs{$_} } split(',', $parts{$prop})) ]; + } + else { + $meta->{cols}->{$col}->{$prop} = [ split(',', $parts{$prop}) ]; + } + } + else { + $meta->{cols}->{$col}->{$prop} = $parts{$prop}; + } + } + + } +} + +# save_config {{{3 +sub save_config { + return if $config{readonly}->{val}; + # Save to a temp file first, so a crash doesn't destroy the main config file + my $newname = $opts{c} || "$homepath/.innotop/innotop.ini"; + my $filename = $newname . '_tmp'; + open my $file, "+>", $filename + or die("Can't write to $filename: $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 $filename: $OS_ERROR"); + rename($filename, $newname) or die("Can't rename $filename to $newname: $OS_ERROR"); +} + +# load_config_connections {{{3 +sub load_config_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; + 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+)='((?:(?!(?{cols}->{$parts{col}}; + next unless $parts{op} && exists $comp_ops{$parts{op}}; + next unless defined $parts{arg}; + next unless defined $parts{color}; + my @colors = unique(grep { exists $ansicolors{$_} } split(/\W+/, $parts{color})); + next unless @colors; + + # Finally! Enough validation... + $rule_set_for{$tbl} ||= []; + push @{$rule_set_for{$tbl}}, \%parts; + } + + foreach my $tbl ( keys %rule_set_for ) { + $tbl_meta{$tbl}->{colors} = $rule_set_for{$tbl}; + $tbl_meta{$tbl}->{color_func} = make_color_func($tbl_meta{$tbl}); + $tbl_meta{$tbl}->{cust}->{colors} = 1; + } +} + +# save_config_colors {{{3 +sub save_config_colors { + my $file = shift; + foreach my $tbl ( sort keys %tbl_meta ) { + my $meta = $tbl_meta{$tbl}; + next unless $meta->{cust}->{colors}; + foreach my $rule ( @{$meta->{colors}} ) { + print $file "$tbl=", join( + ' ', + map { + my $val = $rule->{$_}; + $val =~ s/([\\'])/\\$1/g; # Escape backslashes and single quotes + "$_='$val'"; # Enclose in single quotes + } + qw(col op arg color) + ), "\n"; + } + } +} + +# load_config_active_connections {{{3 +sub load_config_active_connections { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $key , $rest ) = $line =~ m/^(.*?)=(.*)$/; + next unless $key && exists $modes{$key}; + my @parts = grep { exists $connections{$_} } split(/ /, $rest); + $modes{$key}->{connections} = [ @parts ] if exists $modes{$key}; + } +} + +# save_config_active_connections {{{3 +sub save_config_active_connections { + my $file = shift; + foreach my $mode ( sort keys %modes ) { + my @connections = get_connections($mode); + print $file "$mode=", join(' ', @connections), "\n"; + } +} + +# load_config_stmt_sleep_times {{{3 +sub load_config_stmt_sleep_times { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $key , $val ) = split('=', $line); + next unless $key && defined $val && $val =~ m/$num_regex/; + $stmt_sleep_time_for{$key} = $val; + } +} + +# save_config_stmt_sleep_times {{{3 +sub save_config_stmt_sleep_times { + my $file = shift; + foreach my $key ( sort keys %stmt_sleep_time_for ) { + print $file "$key=$stmt_sleep_time_for{$key}\n"; + } +} + +# load_config_mvs {{{3 +sub load_config_mvs { + my ( $file ) = @_; + while ( my $line = <$file> ) { + chomp $line; + next if $line =~ m/^#/; + last if $line =~ m/^\[/; + + my ( $key , $val ) = split('=', $line); + next unless $key && defined $val && $val =~ m/$num_regex/; + $mvs{$key} = $val; + } +} + +# save_config_mvs {{{3 +sub save_config_mvs { + my $file = shift; + foreach my $key ( sort keys %mvs ) { + print $file "$key=$mvs{$key}\n"; + } +} + +# edit_configuration {{{3 +sub edit_configuration { + my $key = ''; + while ( $key ne 'q' ) { + $clear_screen_sub->(); + my @display_lines = ''; + + if ( $key && $cfg_editor_action{$key} ) { + $cfg_editor_action{$key}->{func}->(); + } + + # Show help + push @display_lines, create_caption('What configuration do you want to edit?', + create_table2( + [ sort keys %cfg_editor_action ], + { map { $_ => $_ } keys %cfg_editor_action }, + { map { $_ => $cfg_editor_action{$_}->{note} } keys %cfg_editor_action }, + { sep => ' ' })); + + draw_screen(\@display_lines); + $key = pause(''); + } +} + +# edit_configuration_variables {{{3 +sub edit_configuration_variables { + $clear_screen_sub->(); + my $mode = $config{mode}->{val}; + + my %config_choices + = map { $_ => $config{$_}->{note} || '' } + # Only config values that are marked as applying to this mode. + grep { + my $key = $_; + $config{$key}->{conf} && + ( $config{$key}->{conf} eq 'ALL' + || grep { $mode eq $_ } @{$config{$key}->{conf}} ) + } keys %config; + + my $key = prompt_list( + "Enter the name of the variable you wish to configure", + '', + sub{ return keys %config_choices }, + \%config_choices); + + if ( exists($config_choices{$key}) ) { + get_config_interactive($key); + } +} + +# edit_color_rules {{{3 +sub edit_color_rules { + my ( $tbl ) = @_; + $clear_screen_sub->(); + $tbl ||= choose_visible_table(); + if ( $tbl && exists($tbl_meta{$tbl}) ) { + my $meta = $tbl_meta{$tbl}; + my @cols = ('', qw(col op arg color)); + my $info = { map { $_ => { hdr => $_, just => '-', } } @cols }; + $info->{label}->{maxw} = 30; + my $key; + my $selected_rule; + + # This loop builds a tabular view of the rules. + do { + + # Show help + if ( $key && $key eq '?' ) { + my @display_lines = ''; + push @display_lines, create_caption('Editor key mappings', + create_table2( + [ sort keys %color_editor_action ], + { map { $_ => $_ } keys %color_editor_action }, + { map { $_ => $color_editor_action{$_}->{note} } keys %color_editor_action }, + { sep => ' ' })); + draw_screen(\@display_lines); + pause(); + $key = ''; + } + else { + + # Do the action specified + $selected_rule ||= 0; + if ( $key && $color_editor_action{$key} ) { + $selected_rule = $color_editor_action{$key}->{func}->($tbl, $selected_rule); + $selected_rule ||= 0; + } + + # Build the table of rules. If the terminal has color, the selected rule + # will be highlighted; otherwise a > at the left will indicate. + my $data = $meta->{colors} || []; + foreach my $i ( 0..@$data - 1 ) { + $data->[$i]->{''} = $i == $selected_rule ? '>' : ''; + } + my @display_lines = create_table(\@cols, $info, $data); + + # Highlight selected entry + for my $i ( 0 .. $#display_lines ) { + if ( $display_lines[$i] =~ m/^>/ ) { + $display_lines[$i] = [ $display_lines[$i], 'reverse' ]; + } + } + + # Draw the screen and wait for a command. + unshift @display_lines, '', + "Editing color rules for $meta->{capt}. Press ? for help, q to " + . "quit.", ''; + draw_screen(\@display_lines); + print "\n\n", word_wrap('Rules are applied in order from top to ' + . 'bottom. The first matching rule wins and prevents the ' + . 'rest of the rules from being applied.'); + $key = pause(''); + } + } while ( $key ne 'q' ); + $meta->{color_func} = make_color_func($meta); + } +} + +# add_quick_filter {{{3 +sub add_quick_filter { + my $tbl = choose_visible_table(); + if ( $tbl && exists($tbl_meta{$tbl}) ) { + print "\n"; + my $response = prompt_list( + "Enter column name and filter text", + '', + sub { return keys %{$tbl_meta{$tbl}->{cols}} }, + () + ); + my ( $col, $text ) = split(/\s+/, $response, 2); + + # You can't filter on a nonexistent column. But if you filter on a pivoted + # table, the columns are different, so on a pivoted table, allow filtering + # on the 'name' column. + # NOTE: if a table is pivoted and un-pivoted, this will likely cause crashes. + # Currently not an issue since there's no way to toggle pivot/nopivot. + return unless $col && $text && + (exists($tbl_meta{$tbl}->{cols}->{$col}) + || ($tbl_meta{$tbl}->{pivot} && $col eq 'name')); + + my ( $sub, $err ) = compile_filter( "defined \$set->{$col} && \$set->{$col} =~ m/$text/" ); + return if !$sub || $err; + my $name = "quick_$tbl.$col"; + $filters{$name} = { + func => $sub, + text => $text, + user => 1, + quick => 1, + name => $name, + note => 'Quick-filter', + tbls => [$tbl], + }; + push @{$tbl_meta{$tbl}->{filters}}, $name; + } +} + +# clear_quick_filters {{{3 +sub clear_quick_filters { + my $tbl = choose_visible_table( + # Only tables that have quick-filters + sub { + my ( $tbl ) = @_; + return scalar grep { $filters{$_}->{quick} } @{ $tbl_meta{$tbl}->{filters} }; + } + ); + if ( $tbl && exists($tbl_meta{$tbl}) ) { + my @current = @{$tbl_meta{$tbl}->{filters}}; + @current = grep { !$filters{$_}->{quick} } @current; + $tbl_meta{$tbl}->{filters} = \@current; + } +} + +sub edit_plugins { + $clear_screen_sub->(); + + my @cols = ('', qw(class desc active)); + my $info = { map { $_ => { hdr => $_, just => '-', } } @cols }; + my @rows = map { $plugins{$_} } sort keys %plugins; + my $key; + my $selected; + + # This loop builds a tabular view of the plugins. + do { + + # Show help + if ( $key && $key eq '?' ) { + my @display_lines = ''; + push @display_lines, create_caption('Editor key mappings', + create_table2( + [ sort keys %plugin_editor_action ], + { map { $_ => $_ } keys %plugin_editor_action }, + { map { $_ => $plugin_editor_action{$_}->{note} } keys %plugin_editor_action }, + { sep => ' ' })); + draw_screen(\@display_lines); + pause(); + $key = ''; + } + + # Do the action specified + else { + $selected ||= 0; + if ( $key && $plugin_editor_action{$key} ) { + $selected = $plugin_editor_action{$key}->{func}->(\@rows, $selected); + $selected ||= 0; + } + + # Build the table of plugins. + foreach my $row ( 0.. $#rows ) { + $rows[$row]->{''} = $row eq $selected ? '>' : ' '; + } + my @display_lines = create_table(\@cols, $info, \@rows); + + # Highlight selected entry + for my $i ( 0 .. $#display_lines ) { + if ( $display_lines[$i] =~ m/^>/ ) { + $display_lines[$i] = [ $display_lines[$i], 'reverse' ]; + } + } + + # Draw the screen and wait for a command. + unshift @display_lines, '', + "Plugin Management. Press ? for help, q to quit.", ''; + draw_screen(\@display_lines); + $key = pause(''); + } + } while ( $key ne 'q' ); +} + +# edit_table {{{3 +sub edit_table { + $clear_screen_sub->(); + my ( $tbl ) = @_; + $tbl ||= choose_visible_table(); + if ( $tbl && exists($tbl_meta{$tbl}) ) { + my $meta = $tbl_meta{$tbl}; + my @cols = ('', qw(name hdr label src)); + my $info = { map { $_ => { hdr => $_, just => '-', } } @cols }; + $info->{label}->{maxw} = 30; + my $key; + my $selected_column; + + # This loop builds a tabular view of the tbl_meta's structure, showing each column + # in the entry as a row. + do { + + # Show help + if ( $key && $key eq '?' ) { + my @display_lines = ''; + push @display_lines, create_caption('Editor key mappings', + create_table2( + [ sort keys %tbl_editor_action ], + { map { $_ => $_ } keys %tbl_editor_action }, + { map { $_ => $tbl_editor_action{$_}->{note} } keys %tbl_editor_action }, + { sep => ' ' })); + draw_screen(\@display_lines); + pause(); + $key = ''; + } + else { + + # Do the action specified + $selected_column ||= $meta->{visible}->[0]; + if ( $key && $tbl_editor_action{$key} ) { + $selected_column = $tbl_editor_action{$key}->{func}->($tbl, $selected_column); + $selected_column ||= $meta->{visible}->[0]; + } + + # Build the pivoted view of the table's meta-data. If the terminal has color, + # The selected row will be highlighted; otherwise a > at the left will indicate. + my $data = []; + foreach my $row ( @{$meta->{visible}} ) { + my %hash; + @hash{ @cols } = @{$meta->{cols}->{$row}}{@cols}; + $hash{src} = '' if ref $hash{src}; + $hash{name} = $row; + $hash{''} = $row eq $selected_column ? '>' : ' '; + push @$data, \%hash; + } + my @display_lines = create_table(\@cols, $info, $data); + + # Highlight selected entry + for my $i ( 0 .. $#display_lines ) { + if ( $display_lines[$i] =~ m/^>/ ) { + $display_lines[$i] = [ $display_lines[$i], 'reverse' ]; + } + } + + # Draw the screen and wait for a command. + unshift @display_lines, '', + "Editing table definition for $meta->{capt}. Press ? for help, q to quit.", ''; + draw_screen(\@display_lines, { clear => 1 }); + $key = pause(''); + } + } while ( $key ne 'q' ); + } +} + +# choose_mode_tables {{{3 +# Choose which table(s), and in what order, to display in a given mode. +sub choose_mode_tables { + my $mode = $config{mode}->{val}; + my @tbls = @{$modes{$mode}->{visible_tables}}; + my $new = prompt_list( + "Choose tables to display", + join(' ', @tbls), + sub { return @{$modes{$mode}->{tables}} }, + { map { $_ => $tbl_meta{$_}->{capt} } @{$modes{$mode}->{tables}} } + ); + $modes{$mode}->{visible_tables} = + [ unique(grep { $_ && exists $tbl_meta{$_} } split(/\s+/, $new)) ]; + $modes{$mode}->{cust}->{visible_tables} = 1; +} + +# choose_visible_table {{{3 +sub choose_visible_table { + my ( $grep_cond ) = @_; + my $mode = $config{mode}->{val}; + my @tbls + = grep { $grep_cond ? $grep_cond->($_) : 1 } + @{$modes{$mode}->{visible_tables}}; + my $tbl = $tbls[0]; + if ( @tbls > 1 ) { + $tbl = prompt_list( + "Choose a table", + '', + sub { return @tbls }, + { map { $_ => $tbl_meta{$_}->{capt} } @tbls } + ); + } + return $tbl; +} + +sub toggle_aggregate { + my ( $tbl ) = @_; + $tbl ||= choose_visible_table(); + return unless $tbl && exists $tbl_meta{$tbl}; + my $meta = $tbl_meta{$tbl}; + $meta->{aggregate} ^= 1; +} + +sub choose_filters { + my ( $tbl ) = @_; + $tbl ||= choose_visible_table(); + return unless $tbl && exists $tbl_meta{$tbl}; + my $meta = $tbl_meta{$tbl}; + $clear_screen_sub->(); + + print "Choose filters for $meta->{capt}:\n"; + + my $ini = join(' ', @{$meta->{filters}}); + my $val = prompt_list( + 'Choose filters', + $ini, + sub { return keys %filters }, + { + map { $_ => $filters{$_}->{note} } + grep { grep { $tbl eq $_ } @{$filters{$_}->{tbls}} } + keys %filters + } + ); + + my @choices = unique(split(/\s+/, $val)); + foreach my $new ( grep { !exists($filters{$_}) } @choices ) { + my $answer = prompt("There is no filter called '$new'. Create it?", undef, 'y'); + if ( $answer eq 'y' ) { + create_new_filter($new, $tbl); + } + } + @choices = grep { exists $filters{$_} } @choices; + @choices = grep { grep { $tbl eq $_ } @{$filters{$_}->{tbls}} } @choices; + $meta->{filters} = [ @choices ]; + $meta->{cust}->{filters} = 1; +} + +sub choose_group_cols { + my ( $tbl ) = @_; + $tbl ||= choose_visible_table(); + return unless $tbl && exists $tbl_meta{$tbl}; + $clear_screen_sub->(); + my $meta = $tbl_meta{$tbl}; + my $curr = join(', ', @{$meta->{group_by}}); + my $val = prompt_list( + 'Group-by columns', + $curr, + sub { return keys %{$meta->{cols}} }, + { map { $_ => $meta->{cols}->{$_}->{label} } keys %{$meta->{cols}} }); + if ( $curr ne $val ) { + $meta->{group_by} = [ grep { exists $meta->{cols}->{$_} } $val =~ m/(\w+)/g ]; + $meta->{cust}->{group_by} = 1; + } +} + +sub choose_sort_cols { + my ( $tbl ) = @_; + $tbl ||= choose_visible_table(); + return unless $tbl && exists $tbl_meta{$tbl}; + $clear_screen_sub->(); + my $meta = $tbl_meta{$tbl}; + + my ( $cols, $hints ); + if ( $meta->{pivot} ) { + $cols = sub { qw(name set_0) }; + $hints = { name => 'name', set_0 => 'set_0' }; + } + else { + $cols = sub { return keys %{$meta->{cols}} }; + $hints = { map { $_ => $meta->{cols}->{$_}->{label} } keys %{$meta->{cols}} }; + } + + my $val = prompt_list( + 'Sort columns (reverse sort with -col)', + $meta->{sort_cols}, + $cols, + $hints ); + if ( $meta->{sort_cols} ne $val ) { + $meta->{sort_cols} = $val; + $meta->{cust}->{sort_cols} = 1; + $tbl_meta{$tbl}->{sort_func} = make_sort_func($tbl_meta{$tbl}); + } +} + +# create_new_filter {{{3 +sub create_new_filter { + my ( $filter, $tbl ) = @_; + $clear_screen_sub->(); + + if ( !$filter || $filter =~ m/\W/ ) { + print word_wrap("Choose a name for the filter. This name is not displayed, and is only used " + . "for internal reference. It can only contain lowercase letters, numbers, and underscores."); + print "\n\n"; + do { + $filter = prompt("Enter filter name"); + } while ( !$filter || $filter =~ m/\W/ ); + } + + my $completion = sub { keys %{$tbl_meta{$tbl}->{cols}} }; + my ( $err, $sub, $body ); + do { + $clear_screen_sub->(); + print word_wrap("A filter is a Perl subroutine that accepts a hashref of columns " + . "called \$set, and returns a true value if the filter accepts the row. Example:\n" + . " \$set->{active_secs} > 5\n" + . "will only allow rows if their active_secs column is greater than 5."); + print "\n\n"; + if ( $err ) { + print "There's an error in your filter expression: $err\n\n"; + } + $body = prompt("Enter subroutine body", undef, undef, $completion); + ( $sub, $err ) = compile_filter($body); + } while ( $err ); + + $filters{$filter} = { + func => $sub, + text => $body, + user => 1, + name => $filter, + note => 'User-defined filter', + tbls => [$tbl], + }; +} + +# get_config_interactive {{{3 +sub get_config_interactive { + my $key = shift; + $clear_screen_sub->(); + + # Print help first. + print "Enter a new value for '$key' ($config{$key}->{note}).\n"; + + my $current = ref($config{$key}->{val}) ? join(" ", @{$config{$key}->{val}}) : $config{$key}->{val}; + + my $new_value = prompt('Enter a value', $config{$key}->{pat}, $current); + $config{$key}->{val} = $new_value; +} + +sub edit_current_var_set { + my $mode = $config{mode}->{val}; + my $name = $config{"${mode}_set"}->{val}; + my $variables = $var_sets{$name}->{text}; + + my $new = $variables; + do { + $clear_screen_sub->(); + $new = prompt("Enter variables for $name", undef, $variables); + } until ( $new ); + + if ( $new ne $variables ) { + @{$var_sets{$name}}{qw(text user)} = ( $new, 1); + } +} + + +sub choose_var_set { + my ( $key ) = @_; + $clear_screen_sub->(); + + my $new_value = prompt_list( + 'Choose a set of values to display, or enter the name of a new one', + $config{$key}->{val}, + sub { return keys %var_sets }, + { map { $_ => $var_sets{$_}->{text} } keys %var_sets }); + + if ( !exists $var_sets{$new_value} ) { + add_new_var_set($new_value); + } + + $config{$key}->{val} = $new_value if exists $var_sets{$new_value}; +} + +sub switch_var_set { + my ( $cfg_var, $dir ) = @_; + my @var_sets = sort keys %var_sets; + my $cur = $config{$cfg_var}->{val}; + my $pos = grep { $_ lt $cur } @var_sets; + my $newpos = ($pos + $dir) % @var_sets; + $config{$cfg_var}->{val} = $var_sets[$newpos]; + $clear_screen_sub->(); +} + +# Online configuration and prompting functions {{{2 + +# edit_stmt_sleep_times {{{3 +sub edit_stmt_sleep_times { + $clear_screen_sub->(); + my $stmt = prompt_list('Specify a statement', '', sub { return sort keys %stmt_maker_for }); + return unless $stmt && exists $stmt_maker_for{$stmt}; + $clear_screen_sub->(); + my $curr_val = $stmt_sleep_time_for{$stmt} || 0; + my $new_val = prompt('Specify a sleep delay after calling this SQL', $num_regex, $curr_val); + if ( $new_val ) { + $stmt_sleep_time_for{$stmt} = $new_val; + } + else { + delete $stmt_sleep_time_for{$stmt}; + } +} + +# edit_server_groups {{{3 +# Choose which server connections are in a server group. First choose a group, +# then choose which connections are in it. +sub edit_server_groups { + $clear_screen_sub->(); + my $mode = $config{mode}->{val}; + my $group = $modes{$mode}->{server_group}; + my %curr = %server_groups; + my $new = choose_or_create_server_group($group, 'to edit'); + $clear_screen_sub->(); + if ( exists $curr{$new} ) { + # Don't do this step if the user just created a new server group, + # because part of that process was to choose connections. + my $cxns = join(' ', @{$server_groups{$new}}); + my @conns = choose_or_create_connection($cxns, 'for this group'); + $server_groups{$new} = \@conns; + } +} + +# choose_server_groups {{{3 +sub choose_server_groups { + $clear_screen_sub->(); + my $mode = $config{mode}->{val}; + my $group = $modes{$mode}->{server_group}; + my $new = choose_or_create_server_group($group, 'for this mode'); + $modes{$mode}->{server_group} = $new if exists $server_groups{$new}; +} + +sub choose_or_create_server_group { + my ( $group, $prompt ) = @_; + my $new = ''; + + my @available = sort keys %server_groups; + + if ( @available ) { + print "You can enter the name of a new group to create it.\n"; + + $new = prompt_list( + "Choose a server group $prompt", + $group, + sub { return @available }, + { map { $_ => join(' ', @{$server_groups{$_}}) } @available }); + + $new =~ s/\s.*//; + + if ( !exists $server_groups{$new} ) { + my $answer = prompt("There is no server group called '$new'. Create it?", undef, "y"); + if ( $answer eq 'y' ) { + add_new_server_group($new); + } + } + } + else { + $new = add_new_server_group(); + } + return $new; +} + +sub choose_or_create_connection { + my ( $cxns, $prompt ) = @_; + print "You can enter the name of a new connection to create it.\n"; + + my @available = sort keys %connections; + my $new_cxns = prompt_list( + "Choose connections $prompt", + $cxns, + sub { return @available }, + { map { $_ => $connections{$_}->{dsn} } @available }); + + my @new = unique(grep { !exists $connections{$_} } split(/\s+/, $new_cxns)); + foreach my $new ( @new ) { + my $answer = prompt("There is no connection called '$new'. Create it?", undef, "y"); + if ( $answer eq 'y' ) { + add_new_dsn($new); + } + } + + return unique(grep { exists $connections{$_} } split(/\s+/, $new_cxns)); +} + +# choose_servers {{{3 +sub choose_servers { + $clear_screen_sub->(); + my $mode = $config{mode}->{val}; + my $cxns = join(' ', get_connections()); + my @chosen = choose_or_create_connection($cxns, 'for this mode'); + $modes{$mode}->{connections} = \@chosen; + $modes{$mode}->{server_group} = ''; # Clear this because it overrides {connections} +} + +# display_license {{{3 +sub display_license { + $clear_screen_sub->(); + + print $innotop_license; + + pause(); +} + +# Data-retrieval functions {{{2 +# get_status_info {{{3 +# Get SHOW STATUS and SHOW VARIABLES together. +sub get_status_info { + my @cxns = @_; + if ( !$info_gotten{status}++ ) { + foreach my $cxn ( @cxns ) { + $vars{$cxn}->{$clock} ||= {}; + my $vars = $vars{$cxn}->{$clock}; + + my $sth = do_stmt($cxn, 'SHOW_STATUS') or next; + my $res = $sth->fetchall_arrayref(); + map { $vars->{$_->[0]} = $_->[1] || 0 } @$res; + + # Calculate hi-res uptime and add cxn to the hash. This duplicates get_driver_status, + # but it's most important to have consistency. + $vars->{Uptime_hires} ||= get_uptime($cxn); + $vars->{cxn} = $cxn; + + # Add SHOW VARIABLES to the hash + $sth = do_stmt($cxn, 'SHOW_VARIABLES') or next; + $res = $sth->fetchall_arrayref(); + map { $vars->{$_->[0]} = $_->[1] || 0 } @$res; + } + } +} + +# Chooses a thread for explaining, killing, etc... +# First arg is a func that can be called in grep. +sub choose_thread { + my ( $grep_cond, $prompt ) = @_; + + # Narrow the list to queries that can be explained. + my %thread_for = map { + # Eliminate innotop's own threads. + $_ => $dbhs{$_}->{dbh} ? $dbhs{$_}->{dbh}->{mysql_thread_id} : 0 + } keys %connections; + + my @candidates = grep { + $_->{id} != $thread_for{$_->{cxn}} && $grep_cond->($_) + } @current_queries; + return unless @candidates; + + # Find out which server. + my @cxns = unique map { $_->{cxn} } @candidates; + my ( $cxn ) = select_cxn('On which server', @cxns); + return unless $cxn && exists($connections{$cxn}); + + # Re-filter the list of candidates to only those on this server + @candidates = grep { $_->{cxn} eq $cxn } @candidates; + + # Find out which thread to do. + my $info; + if ( @candidates > 1 ) { + + # Sort longest-active first, then longest-idle. + my $sort_func = sub { + my ( $a, $b ) = @_; + return $a->{query} && !$b->{query} ? 1 + : $b->{query} && !$a->{query} ? -1 + : ($a->{time} || 0) <=> ($b->{time} || 0); + }; + my @threads = map { $_->{id} } reverse sort { $sort_func->($a, $b) } @candidates; + + print "\n"; + my $thread = prompt_list($prompt, + $threads[0], + sub { return @threads }); + return unless $thread && $thread =~ m/$int_regex/; + + # Find the info hash of that query on that server. + ( $info ) = grep { $thread == $_->{id} } @candidates; + } + else { + $info = $candidates[0]; + } + return $info; +} + +# analyze_query {{{3 +# Allows the user to show fulltext, explain, show optimized... +sub analyze_query { + my ( $action ) = @_; + + my $info = choose_thread( + sub { $_[0]->{query} }, + 'Select a thread to analyze', + ); + return unless $info; + + my %actions = ( + e => \&display_explain, + f => \&show_full_query, + o => \&show_optimized_query, + ); + do { + $actions{$action}->($info); + print "\n"; + $action = pause('Press e to explain, f for full query, o for optimized query'); + } while ( exists($actions{$action}) ); +} + +# inc {{{3 +# Returns the difference between two sets of variables/status/innodb stuff. +sub inc { + my ( $offset, $cxn ) = @_; + my $vars = $vars{$cxn}; + if ( $offset < 0 ) { + return $vars->{$clock}; + } + elsif ( exists $vars{$clock - $offset} && !exists $vars->{$clock - $offset - 1} ) { + return $vars->{$clock - $offset}; + } + my $cur = $vars->{$clock - $offset}; + my $pre = $vars->{$clock - $offset - 1}; + return { + # Numeric variables get subtracted, non-numeric get passed straight through. + map { + $_ => + ( (defined $cur->{$_} && $cur->{$_} =~ m/$num_regex/) + ? $cur->{$_} - ($pre->{$_} || 0) + : $cur->{$_} ) + } keys %{$cur} + }; +} + +# extract_values {{{3 +# Arguments are a set of values (which may be incremental, derived from +# current and previous), current, and previous values. +# TODO: there are a few places that don't remember prev set so can't pass it. +sub extract_values { + my ( $set, $cur, $pre, $tbl ) = @_; + + # Hook in event listeners + foreach my $listener ( @{$event_listener_for{extract_values}} ) { + $listener->extract_values($set, $cur, $pre, $tbl); + } + + my $result = {}; + my $meta = $tbl_meta{$tbl}; + my $cols = $meta->{cols}; + foreach my $key ( keys %$cols ) { + my $info = $cols->{$key} + or die "Column '$key' doesn't exist in $tbl"; + die "No func defined for '$key' in $tbl" + unless $info->{func}; + eval { + $result->{$key} = $info->{func}->($set, $cur, $pre) + }; + if ( $EVAL_ERROR ) { + if ( $config{debug}->{val} ) { + die $EVAL_ERROR; + } + $result->{$key} = $info->{num} ? 0 : ''; + } + } + return $result; +} + +# get_full_processlist {{{3 +sub get_full_processlist { + my @cxns = @_; + my @result; + foreach my $cxn ( @cxns ) { + my $stmt = do_stmt($cxn, 'PROCESSLIST') or next; + my $arr = $stmt->fetchall_arrayref({}); + push @result, map { $_->{cxn} = $cxn; $_ } @$arr; + } + return @result; +} + +# get_open_tables {{{3 +sub get_open_tables { + my @cxns = @_; + my @result; + foreach my $cxn ( @cxns ) { + my $stmt = do_stmt($cxn, 'OPEN_TABLES') or next; + my $arr = $stmt->fetchall_arrayref({}); + push @result, map { $_->{cxn} = $cxn; $_ } @$arr; + } + return @result; +} + +# get_innodb_status {{{3 +sub get_innodb_status { + my ( $cxns, $addl_sections ) = @_; + if ( !$config{skip_innodb}->{val} && !$info_gotten{innodb_status}++ ) { + + # Determine which sections need to be parsed + my %sections_required = + map { $tbl_meta{$_}->{innodb} => 1 } + grep { $_ && $tbl_meta{$_}->{innodb} } + get_visible_tables(); + + # Add in any other sections the caller requested. + foreach my $sec ( @$addl_sections ) { + $sections_required{$sec} = 1; + } + + foreach my $cxn ( @$cxns ) { + my $innodb_status_text; + + if ( $file ) { # Try to fetch status text from the file. + my @stat = stat($file); + + # Initialize the file. + if ( !$file_mtime ) { + # Initialize to 130k from the end of the file (because the limit + # on the size of innodb status is 128k even with Google's patches) + # and try to grab the last status from the file. + sysseek($file, (-128 * 1_024), 2); + } + + # Read from the file. + my $buffer; + if ( !$file_mtime || $file_mtime != $stat[9] ) { + $file_data = ''; + while ( sysread($file, $buffer, 4096) ) { + $file_data .= $buffer; + } + $file_mtime = $stat[9]; + } + + # Delete everything but the last InnoDB status text from the file. + $file_data =~ s/\A.*(?=^=====================================\n...... ........ INNODB MONITOR OUTPUT)//ms; + $innodb_status_text = $file_data; + } + + else { + my $stmt = do_stmt($cxn, 'INNODB_STATUS') or next; + $innodb_status_text = $stmt->fetchrow_hashref()->{status}; + } + + next unless $innodb_status_text + && substr($innodb_status_text, 0, 100) =~ m/INNODB MONITOR OUTPUT/; + + # Parse and merge into %vars storage + my %innodb_status = ( + $innodb_parser->get_status_hash( + $innodb_status_text, + $config{debug}->{val}, + \%sections_required, + 0, # don't parse full lock information + ) + ); + if ( !$innodb_status{IB_got_all} && $config{auto_wipe_dl}->{val} ) { + clear_deadlock($cxn); + } + + # Merge using a hash slice, which is the fastest way + $vars{$cxn}->{$clock} ||= {}; + my $hash = $vars{$cxn}->{$clock}; + @{$hash}{ keys %innodb_status } = values %innodb_status; + $hash->{cxn} = $cxn; + $hash->{Uptime_hires} ||= get_uptime($cxn); + } + } +} + +# clear_deadlock {{{3 +sub clear_deadlock { + my ( $cxn ) = @_; + return if $clearing_deadlocks++; + my $tbl = $connections{$cxn}->{dl_table}; + return unless $tbl; + + eval { + # Set up the table for creating a deadlock. + my $engine = version_ge($dbhs{$cxn}->{dbh}, '4.1.2') ? 'engine' : 'type'; + return unless do_query($cxn, "drop table if exists $tbl"); + return unless do_query($cxn, "create table $tbl(a int) $engine=innodb"); + return unless do_query($cxn, "delete from $tbl"); + return unless do_query($cxn, "insert into $tbl(a) values(0), (1)"); + return unless do_query($cxn, "commit"); # Or the children will block against the parent + + # Fork off two children to deadlock against each other. + my %children; + foreach my $child ( 0..1 ) { + my $pid = fork(); + if ( defined($pid) && $pid == 0 ) { # I am a child + deadlock_thread( $child, $tbl, $cxn ); + } + elsif ( !defined($pid) ) { + die("Unable to fork for clearing deadlocks!\n"); + } + # I already exited if I'm a child, so I'm the parent. + $children{$child} = $pid; + } + + # Wait for the children to exit. + foreach my $child ( keys %children ) { + my $pid = waitpid($children{$child}, 0); + } + + # Clean up. + do_query($cxn, "drop table $tbl"); + }; + if ( $EVAL_ERROR ) { + print $EVAL_ERROR; + pause(); + } + + $clearing_deadlocks = 0; +} + +sub get_master_logs { + my @cxns = @_; + my @result; + if ( !$info_gotten{master_logs}++ ) { + foreach my $cxn ( @cxns ) { + my $stmt = do_stmt($cxn, 'SHOW_MASTER_LOGS') or next; + push @result, @{$stmt->fetchall_arrayref({})}; + } + } + return @result; +} + +# get_master_slave_status {{{3 +sub get_master_slave_status { + my @cxns = @_; + if ( !$info_gotten{replication_status}++ ) { + foreach my $cxn ( @cxns ) { + $vars{$cxn}->{$clock} ||= {}; + my $vars = $vars{$cxn}->{$clock}; + $vars->{cxn} = $cxn; + + my $stmt = do_stmt($cxn, 'SHOW_MASTER_STATUS') or next; + my $res = $stmt->fetchall_arrayref({})->[0]; + @{$vars}{ keys %$res } = values %$res; + $stmt = do_stmt($cxn, 'SHOW_SLAVE_STATUS') or next; + $res = $stmt->fetchall_arrayref({})->[0]; + @{$vars}{ keys %$res } = values %$res; + $vars->{Uptime_hires} ||= get_uptime($cxn); + } + } +} + +sub is_func { + my ( $word ) = @_; + return defined(&$word) + || eval "my \$x= sub { $word }; 1" + || $EVAL_ERROR !~ m/^Bareword/; +} + +# Documentation {{{1 +# ############################################################################ +# I put this last as per the Dog book. +# ############################################################################ +=pod + +=head1 NAME + +innotop - MySQL and InnoDB transaction/status monitor. + +=head1 SYNOPSIS + +To monitor servers normally: + + innotop + +To monitor InnoDB status information from a file: + + innotop /var/log/mysql/mysqld.err + +To run innotop non-interactively in a pipe-and-filter configuration: + + innotop --count 5 -d 1 -n + +=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". + +The first thing innotop needs to know is how to connect to a MySQL server. You +can just enter the hostname of the server, for example "localhost" or +"127.0.0.1" if the server is on the same machine as innotop. After this innotop +will prompt you for a DSN (data source name). You should be able to just accept +the defaults by pressing Enter. + +When innotop asks you about a table to use when resetting InnoDB deadlock +information, just accept the default for now. This is an advanced feature you +can configure later (see L<"D: InnoDB Deadlocks"> for more). + +If you have a .my.cnf file with your MySQL connection defaults, innotop can read +it, and you won't need to specify a username and password if it's in that file. +Otherwise, you should answer 'y' to the next couple of prompts. + +After this, you should be connected, and innotop should show you something like +the following: + + InnoDB Txns (? for help) localhost, 01:11:19, InnoDB 10s :-), 50 QPS, + + CXN History Versions Undo Dirty Buf Used Bufs Txns MaxTxn + localhost 7 2035 0 0 0.00% 92.19% 1 07:34 + + CXN ID User Host Txn Status Time Undo Query Tex + localhost 98379 user1 webserver ACTIVE 07:34 0 SELECT `c + localhost 98450 user1 webserver ACTIVE 01:06 0 INSERT IN + localhost 97750 user1 webserver not starte 00:00 0 + localhost 98375 user1 appserver not starte 00:00 0 + +(This sample is truncated at the right so it will fit on a terminal when running +'man innotop') + +This sample comes from a quiet server with few transactions active. If your +server is busy, you'll see more output. Notice the first line on the screen, +which tells you what mode you're in and what server you're connected to. You +can change to other modes with keystrokes; press 'Q' to switch to a list of +currently running queries. + +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 --help + +Print a summary of command-line usage and exit. + +=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 --nonint + +Enable non-interactive operation. See L<"NON-INTERACTIVE OPERATION"> for more. + +=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 --mode + +Specifies the mode in which innotop should start. Corresponds to the +configuration option L<"mode">. + +=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 --version + +Output version information and exit. + +=back + +=head1 HOTKEYS + +innotop is interactive, and you control it with key-presses. + +=over + +=item * + +Uppercase keys switch between modes. + +=item * + +Lowercase keys initiate some action within the current mode. + +=item * + +Other keys do something special like change configuration or show the +innotop license. + +=back + +Press '?' at any time to see the currently active keys and what they do. + +=head1 MODES + +Each of innotop's modes retrieves and displays a particular type of data from +the servers you're monitoring. You switch between modes with uppercase keys. +The following is a brief description of each mode, in alphabetical order. To +switch to the mode, press the key listed in front of its heading in the +following list: + +=over + +=item B: InnoDB Buffers + +This mode displays information about the InnoDB buffer pool, page statistics, +insert buffer, and adaptive hash index. The data comes from SHOW INNODB STATUS. + +This mode contains the L<"buffer_pool">, L<"page_statistics">, +L<"insert_buffers">, and L<"adaptive_hash_index"> tables by default. + +=item C: Command Summary + +This mode is similar to mytop's Command Summary mode. It shows the +L<"cmd_summary"> table, which looks something like the following: + + Command Summary (? for help) localhost, 25+07:16:43, 2.45 QPS, 3 thd, 5.0.40 + _____________________ Command Summary _____________________ + Name Value Pct Last Incr Pct + Select_scan 3244858 69.89% 2 100.00% + Select_range 1354177 29.17% 0 0.00% + Select_full_join 39479 0.85% 0 0.00% + Select_full_range_join 4097 0.09% 0 0.00% + Select_range_check 0 0.00% 0 0.00% + +The command summary table is built by extracting variables from +L<"STATUS_VARIABLES">. The variables must be numeric and must match the prefix +given by the L<"cmd_filter"> configuration variable. The variables are then +sorted by value descending and compared to the last variable, as shown above. +The percentage columns are percentage of the total of all variables in the +table, so you can see the relative weight of the variables. + +The example shows what you see if the prefix is "Select_". The default +prefix is "Com_". You can choose a prefix with the 's' key. + +It's rather like running SHOW VARIABLES LIKE "prefix%" with memory and +nice formatting. + +Values are aggregated across all servers. The Pct columns are not correctly +aggregated across multiple servers. This is a known limitation of the grouping +algorithm that may be fixed in the future. + +=item D: InnoDB Deadlocks + +This mode shows the transactions involved in the last InnoDB deadlock. A second +table shows the locks each transaction held and waited for. A deadlock is +caused by a cycle in the waits-for graph, so there should be two locks held and +one waited for unless the deadlock information is truncated. + +InnoDB puts deadlock information before some other information in the SHOW +INNODB STATUS output. If there are a lot of locks, the deadlock information can +grow very large, and there is a limit on the size of the SHOW INNODB +STATUS output. A large deadlock can fill the entire output, or even be +truncated, and prevent you from seeing other information at all. If you are +running innotop in another mode, for example T mode, and suddenly you don't see +anything, you might want to check and see if a deadlock has wiped out the data +you need. + +If it has, you can create a small deadlock to replace the large one. Use the +'w' key to 'wipe' the large deadlock with a small one. This will not work +unless you have defined a deadlock table for the connection (see L<"SERVER +CONNECTIONS">). + +You can also configure innotop to automatically detect when a large deadlock +needs to be replaced with a small one (see L<"auto_wipe_dl">). + +This mode displays the L<"deadlock_transactions"> and L<"deadlock_locks"> tables +by default. + +=item F: InnoDB Foreign Key Errors + +This mode shows the last InnoDB foreign key error information, such as the +table where it happened, when and who and what query caused it, and so on. + +InnoDB has a huge variety of foreign key error messages, and many of them are +just hard to parse. innotop doesn't always do the best job here, but there's +so much code devoted to parsing this messy, unparseable output that innotop is +likely never to be perfect in this regard. If innotop doesn't show you what +you need to see, just look at the status text directly. + +This mode displays the L<"fk_error"> table by default. + +=item I: InnoDB I/O Info + +This mode shows InnoDB's I/O statistics, including the I/O threads, pending I/O, +file I/O miscellaneous, and log statistics. It displays the L<"io_threads">, +L<"pending_io">, L<"file_io_misc">, and L<"log_statistics"> tables by default. + +=item L: Locks + +This mode shows information about current locks. At the moment only InnoDB +locks are supported, and by default you'll only see locks for which transactions +are waiting. This information comes from the TRANSACTIONS section of the InnoDB +status text. If you have a very busy server, you may have frequent lock waits; +it helps to be able to see which tables and indexes are the "hot spot" for +locks. If your server is running pretty well, this mode should show nothing. + +You can configure MySQL and innotop to monitor not only locks for which a +transaction is waiting, but those currently held, too. You can do this with the +InnoDB Lock Monitor (L). It's +not documented in the MySQL manual, but creating the lock monitor with the +following statement also affects the output of SHOW INNODB STATUS, which innotop +uses: + + CREATE TABLE innodb_lock_monitor(a int) ENGINE=INNODB; + +This causes InnoDB to print its output to the MySQL file every 16 seconds or so, +as stated in the manual, but it also makes the normal SHOW INNODB STATUS output +include lock information, which innotop can parse and display (that's the +undocumented feature). + +This means you can do what may have seemed impossible: to a limited extent +(InnoDB truncates some information in the output), you can see which transaction +holds the locks something else is waiting for. You can also enable and disable +the InnoDB Lock Monitor with the key mappings in this mode. + +This mode displays the L<"innodb_locks"> table by default. Here's a sample of +the screen when one connection is waiting for locks another connection holds: + + _________________________________ InnoDB Locks __________________________ + CXN ID Type Waiting Wait Active Mode DB Table Index + localhost 12 RECORD 1 00:10 00:10 X test t1 PRIMARY + localhost 12 TABLE 0 00:10 00:10 IX test t1 + localhost 12 RECORD 1 00:10 00:10 X test t1 PRIMARY + localhost 11 TABLE 0 00:00 00:25 IX test t1 + localhost 11 RECORD 0 00:00 00:25 X test t1 PRIMARY + +You can see the first connection, ID 12, is waiting for a lock on the PRIMARY +key on test.t1, and has been waiting for 10 seconds. The second connection +isn't waiting, because the Waiting column is 0, but it holds locks on the same +index. That tells you connection 11 is blocking connection 12. + +=item M: Master/Slave Replication Status + +This mode shows the output of SHOW SLAVE STATUS and SHOW MASTER STATUS in three +tables. The first two divide the slave's status into SQL and I/O thread status, +and the last shows master status. Filters are applied to eliminate non-slave +servers from the slave tables, and non-master servers from the master table. + +This mode displays the L<"slave_sql_status">, L<"slave_io_status">, and +L<"master_status"> tables by default. + +=item O: Open Tables + +This section comes from MySQL's SHOW OPEN TABLES command. By default it is +filtered to show tables which are in use by one or more queries, so you can +get a quick look at which tables are 'hot'. You can use this to guess which +tables might be locked implicitly. + +This mode displays the L<"open_tables"> mode by default. + +=item Q: Query List + +This mode displays the output from SHOW FULL PROCESSLIST, much like B's +query list mode. This mode does B 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. The 'g' +key changes the view to a graph of the same numbers, sort of like B. +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-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 the innotop mode, such as "InnoDB Txns" for T mode, +followed by a reminder to press '?' for help at any time. + +=head2 ONE SERVER + +The simplest case is when you're monitoring a single server. In this case, the +name of the connection is next on the status line. This is the name you gave +when you created the connection -- most likely the MySQL server's hostname. +This is followed by the server's uptime. + +If you're in an InnoDB mode, such as T or B, the next word is "InnoDB" followed +by some information about the SHOW INNODB STATUS output used to render the +screen. The first word is the number of seconds since the last SHOW INNODB +STATUS, which InnoDB uses to calculate some per-second statistics. The next is +a smiley face indicating whether the InnoDB output is truncated. If the smiley +face is a :-), all is well; there is no truncation. A :^| means the transaction +list is so long, InnoDB has only printed out some of the transactions. Finally, +a frown :-( means the output is incomplete, which is probably due to a deadlock +printing too much lock information (see L<"D: InnoDB Deadlocks">). + +The next two words indicate the server's queries per second (QPS) and how many +threads (connections) exist. Finally, the server's version number is the last +thing on the line. + +=head2 MULTIPLE SERVERS + +If you are monitoring multiple servers (see L<"SERVER CONNECTIONS">), the status +line does not show any details about individual servers. Instead, it shows the +names of the connections that are active. Again, these are connection names you +specified, which are likely to be the server's hostname. A connection that has +an error is prefixed with an exclamation point. + +If you are monitoring a group of servers (see L<"SERVER GROUPS">), the status +line shows the name of the group. If any connection in the group has an +error, the group's name is followed by the fraction of the connections that +don't have errors. + +See L<"ERROR HANDLING"> for more details about innotop's error handling. + +=head2 MONITORING A FILE + +If you give a filename on the command line, innotop will not connect to ANY +servers at all. It will watch the specified file for InnoDB status output and +use that as its data source. It will always show a single connection called +'file'. And since it can't connect to a server, it can't determine how long the +server it's monitoring has been up; so it calculates the server's uptime as time +since innotop started running. + +=head1 SERVER ADMINISTRATION + +While innotop is primarily a monitor that lets you watch and analyze your +servers, it can also send commands to servers. The most frequently useful +commands are killing queries and stopping or starting slaves. + +You can kill a connection, or in newer versions of MySQL kill a query but not a +connection, from L<"Q: Query List"> and L<"T: InnoDB Transactions"> modes. +Press 'k' to issue a KILL command, or 'x' to issue a KILL QUERY command. +innotop will prompt you for the server and/or connection ID to kill (innotop +does not prompt you if there is only one possible choice for any input). +innotop pre-selects the longest-running query, or the oldest connection. +Confirm the command with 'y'. + +In L<"M: Master/Slave Replication Status"> mode, you can start and stop slaves +with the 'a' and 'o' keys, respectively. You can send these commands to many +slaves at once. innotop fills in a default command of START SLAVE or STOP SLAVE +for you, but you can actually edit the command and send anything you wish, such +as SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1 to make the slave skip one binlog event +when it starts. + +You can also ask innotop to calculate the earliest binlog in use by any slave +and issue a PURGE MASTER LOGS on the master. Use the 'b' key for this. innotop +will prompt you for a master to run the command on, then prompt you for the +connection names of that master's slaves (there is no way for innotop to +determine this reliably itself). innotop will find the minimum binlog in use by +these slave connections and suggest it as the argument to PURGE MASTER LOGS. + +=head1 SERVER CONNECTIONS + +When you create a server connection, innotop asks you for a series of inputs, as +follows: + +=over + +=item DSN + +A DSN is a Data Source Name, which is the initial argument passed to the DBI +module for connecting to a server. It is usually of the form + + DBI:mysql:;mysql_read_default_group=mysql;host=HOSTNAME + +Since this DSN is passed to the DBD::mysql driver, you should read the driver's +documentation at L<"http://search.cpan.org/dist/DBD-mysql/lib/DBD/mysql.pm"> for +the exact details on all the options you can pass the driver in the DSN. You +can read more about DBI at L, and especially at +L. + +The mysql_read_default_group=mysql option lets the DBD driver read your MySQL +options files, such as ~/.my.cnf on UNIX-ish systems. You can use this to avoid +specifying a username or password for the connection. + +=item InnoDB Deadlock Table + +This optional item tells innotop a table name it can use to deliberately create +a small deadlock (see L<"D: InnoDB Deadlocks">). If you specify this option, +you just need to be sure the table doesn't exist, and that innotop can create +and drop the table with the InnoDB storage engine. You can safely omit or just +accept the default if you don't intend to use this. + +=item Username + +innotop will ask you if you want to specify a username. If you say 'y', it will +then prompt you for a user name. If you have a MySQL option file that specifies +your username, you don't have to specify a username. + +The username defaults to your login name on the system you're running innotop on. + +=item Password + +innotop will ask you if you want to specify a password. Like the username, the +password is optional, but there's an additional prompt that asks if you want to +save the password in the innotop configuration file. If you don't save it in +the configuration file, innotop will prompt you for a password each time it +starts. Passwords in the innotop configuration file are saved in plain text, +not encrypted in any way. + +=back + +Once you finish answering these questions, you should be connected to a server. +But innotop isn't limited to monitoring a single server; you can define many +server connections and switch between them by pressing the '@' key. See +L<"SWITCHING BETWEEN CONNECTIONS">. + +To create a new connection, press the '@' key and type the name of the new +connection, then follow the steps given above. + +=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 location is in $HOME/.innotop, but can be +overridden with the L<"--config"> command-line option. You can edit it by hand +safely. innotop reads the configuration file when it starts, and writes it out +again when it exits, so any changes you make 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 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 can be made read-only. 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, +because it would prevent itself from being written to the configuration file. + +=item show_cxn_errors + +Makes innotop print connection errors to STDOUT. See L<"ERROR HANDLING">. + +=item show_cxn_errors_in_tbl + +Makes innotop display connection errors as rows in the first table on screen. +See L<"ERROR HANDLING">. + +=item show_percent + +Adds a '%' character after the value returned by the L<"percent"> +transformation. + +=item show_statusbar + +Controls whether to show the status bar in the display. See L<"INNOTOP +STATUS">. + +=item skip_innodb + +Disables fetching SHOW INNODB STATUS, in case your server(s) do not have InnoDB +enabled and you don't want innotop to try to fetch it. This can also be useful +when you don't have the SUPER privilege, required to run SHOW INNODB STATUS. + +=item status_inc + +Whether to show absolute or incremental values for status variables. +Incremental values are calculated as an offset from the last value innotop saw +for that variable. This is a global setting, but will probably become +mode-specific at some point. Right now it is honored a bit inconsistently; some +modes don't pay attention to it. + +=back + +=item plugins + +This section holds a list of package names of active plugins. If the plugin +exists, innotop will activate it. See L<"PLUGINS"> for more information. + +=item filters + +This section holds user-defined filters (see L<"FILTERS">). Each line is in the +format filter_name=text='filter text' tbls='table list'. + +The filter text is the text of the subroutine's code. The table list is a list +of tables to which the filter can apply. By default, user-defined filters apply +to the table for which they were created, but you can manually override that by +editing the definition in the configuration file. + +=item active_filters + +This section stores which filters are active on each table. Each line is in the +format table_name=filter_list. + +=item tbl_meta + +This section stores user-defined or user-customized columns (see L<"COLUMNS">). +Each line is in the format col_name=properties, where the properties are a +name=quoted-value list. + +=item connections + +This section holds the server connections you have defined. Each line is in the +format name=properties, where the properties are a name=value list. The +properties are self-explanatory, and the only one that is treated specially is +'pass' which is only present if 'savepass' is set. See L<"SERVER CONNECTIONS">. + +=item active_connections + +This section holds a list of which connections are active in each mode. Each +line is in the format mode_name=connection_list. + +=item server_groups + +This section holds server groups. Each line is in the format +name=connection_list. See L<"SERVER GROUPS">. + +=item active_server_groups + +This section holds a list of which server group is active in each mode. Each +line is in the format mode_name=server_group. + +=item max_values_seen + +This section holds the maximum values seen for variables. This is used to scale +the graphs in L<"S: Variables & Status"> mode. Each line is in the format +name=value. + +=item active_columns + +This section holds table column lists. Each line is in the format +tbl_name=column_list. See L<"COLUMNS">. + +=item sort_cols + +This section holds the sort definition. Each line is in the format +tbl_name=column_list. If a column is prefixed with '-', that column sorts +descending. See L<"SORTING">. + +=item visible_tables + +This section defines which tables are visible in each mode. Each line is in the +format mode_name=table_list. See L<"TABLES">. + +=item varsets + +This section defines variable sets for use in L<"S: Status & Variables"> mode. +Each line is in the format name=variable_list. See L<"VARIABLE SETS">. + +=item colors + +This section defines colorization rules. Each line is in the format +tbl_name=property_list. See L<"COLORS">. + +=item stmt_sleep_times + +This section contains statement sleep times. Each line is in the format +statement_name=sleep_time. See L<"S: Statement Sleep Times">. + +=item group_by + +This section contains column lists for table group_by expressions. Each line is +in the format tbl_name=column_list. See L<"GROUPING">. + +=back + +=head1 CUSTOMIZING + +You can customize innotop a great deal. For example, you can: + +=over + +=item * + +Choose which tables to display, and in what order. + +=item * + +Choose which columns are in those tables, and create new columns. + +=item * + +Filter which rows display with built-in filters, user-defined filters, and +quick-filters. + +=item * + +Sort the rows to put important data first or group together related rows. + +=item * + +Highlight rows with color. + +=item * + +Customize the alignment, width, and formatting of columns, and apply +transformations to columns to extract parts of their values or format the values +as you wish (for example, shortening large numbers to familiar units). + +=item * + +Design your own expressions to extract and combine data as you need. This gives +you unlimited flexibility. + +=back + +All these and more are explained in the following sections. + +=head2 TABLES + +A table is what you'd expect: a collection of columns. It also has some other +properties, such as a caption. Filters, sorting rules, and colorization rules +belong to tables and are covered in later sections. + +Internally, table meta-data is defined in a data structure called %tbl_meta. +This hash holds all built-in table definitions, which contain a lot of default +instructions to innotop. The meta-data includes the caption, a list of columns +the user has customized, a list of columns, a list of visible columns, a list of +filters, color rules, a sort-column list, sort direction, and some information +about the table's data sources. Most of this is customizable via the table +editor (see L<"TABLE EDITOR">). + +You can choose which tables to show by pressing the '$' key. See L<"MODES"> and +L<"TABLES">. + +The table life-cycle is as follows: + +=over + +=item * + +Each table begins with a data source, which is an array of hashes. See below +for details on data sources. + +=item * + +Each element of the data source becomes a row in the final table. + +=item * + +For each element in the data source, innotop extracts values from the source and +creates a row. This row is another hash, which later steps will refer to as +$set. The values innotop extracts are determined by the table's columns. Each +column has an extraction subroutine, compiled from an expression (see +L<"EXPRESSIONS">). The resulting row is a hash whose keys are named the same as +the column name. + +=item * + +innotop filters the rows, removing those that don't need to be displayed. See +L<"FILTERS">. + +=item * + +innotop sorts the rows. See L<"SORTING">. + +=item * + +innotop groups the rows together, if specified. See L<"GROUPING">. + +=item * + +innotop colorizes the rows. See L<"COLORS">. + +=item * + +innotop transforms the column values in each row. See L<"TRANSFORMATIONS">. + +=item * + +innotop optionally pivots the rows (see L<"PIVOTING">), then filters and sorts +them. + +=item * + +innotop formats and justifies the rows as a table. During this step, innotop +applies further formatting to the column values, including alignment, maximum +and minimum widths. innotop also does final error checking to ensure there are +no crashes due to undefined values. innotop then adds a caption if specified, +and the table is ready to print. + +=back + +The lifecycle is slightly different if the table is pivoted, as noted above. To +clarify, if the table is pivoted, the process is extract, group, transform, +pivot, filter, sort, create. If it's not pivoted, the process is extract, +filter, sort, group, color, transform, create. This slightly convoluted process +doesn't map all that well to SQL, but pivoting complicates things pretty +thoroughly. Roughly speaking, filtering and sorting happen as late as needed to +effect the final result as you might expect, but as early as possible for +efficiency. + +Each built-in table is described below: + +=over + +=item adaptive_hash_index + +Displays data about InnoDB's adaptive hash index. Data source: +L<"STATUS_VARIABLES">. + +=item buffer_pool + +Displays data about InnoDB's buffer pool. Data source: L<"STATUS_VARIABLES">. + +=item cmd_summary + +Displays weighted status variables. Data source: L<"STATUS_VARIABLES">. + +=item deadlock_locks + +Shows which locks were held and waited for by the last detected deadlock. Data +source: L<"DEADLOCK_LOCKS">. + +=item deadlock_transactions + +Shows transactions involved in the last detected deadlock. Data source: +L<"DEADLOCK_TRANSACTIONS">. + +=item explain + +Shows the output of EXPLAIN. Data source: L<"EXPLAIN">. + +=item file_io_misc + +Displays data about InnoDB's file and I/O operations. Data source: +L<"STATUS_VARIABLES">. + +=item fk_error + +Displays various data about InnoDB's last foreign key error. Data source: +L<"STATUS_VARIABLES">. + +=item innodb_locks + +Displays InnoDB locks. Data source: L<"INNODB_LOCKS">. + +=item innodb_transactions + +Displays data about InnoDB's current transactions. Data source: +L<"INNODB_TRANSACTIONS">. + +=item insert_buffers + +Displays data about InnoDB's insert buffer. Data source: L<"STATUS_VARIABLES">. + +=item io_threads + +Displays data about InnoDB's I/O threads. Data source: L<"IO_THREADS">. + +=item log_statistics + +Displays data about InnoDB's logging system. Data source: L<"STATUS_VARIABLES">. + +=item master_status + +Displays replication master status. Data source: L<"STATUS_VARIABLES">. + +=item open_tables + +Displays open tables. Data source: L<"OPEN_TABLES">. + +=item page_statistics + +Displays InnoDB page statistics. Data source: L<"STATUS_VARIABLES">. + +=item pending_io + +Displays InnoDB pending I/O operations. Data source: L<"STATUS_VARIABLES">. + +=item processlist + +Displays current MySQL processes (threads/connections). Data source: +L<"PROCESSLIST">. + +=item q_header + +Displays various status values. Data source: L<"STATUS_VARIABLES">. + +=item row_operation_misc + +Displays data about InnoDB's row operations. Data source: +L<"STATUS_VARIABLES">. + +=item row_operations + +Displays data about InnoDB's row operations. Data source: +L<"STATUS_VARIABLES">. + +=item semaphores + +Displays data about InnoDB's semaphores and mutexes. Data source: +L<"STATUS_VARIABLES">. + +=item slave_io_status + +Displays data about the slave I/O thread. Data source: +L<"STATUS_VARIABLES">. + +=item slave_sql_status + +Displays data about the slave SQL thread. Data source: L<"STATUS_VARIABLES">. + +=item t_header + +Displays various InnoDB status values. Data source: L<"STATUS_VARIABLES">. + +=item var_status + +Displays user-configurable data. Data source: L<"STATUS_VARIABLES">. + +=item wait_array + +Displays data about InnoDB's OS wait array. Data source: L<"OS_WAIT_ARRAY">. + +=back + +=head2 COLUMNS + +Columns belong to tables. You can choose a table's columns by pressing the '^' +key, which starts the L<"TABLE EDITOR"> and lets you choose and edit columns. +Pressing 'e' from within the table editor lets you edit the column's properties: + +=over + +=item * + +hdr: a column header. This appears in the first row of the table. + +=item * + +just: justification. '-' means left-justified and '' means right-justified, +just as with printf formatting codes (not a coincidence). + +=item * + +dec: whether to further align the column on the decimal point. + +=item * + +num: whether the column is numeric. This affects how values are sorted +(lexically or numerically). + +=item * + +label: a small note about the column, which appears in dialogs that help the +user choose columns. + +=item * + +src: an expression that innotop uses to extract the column's data from its +source (see L<"DATA SOURCES">). See L<"EXPRESSIONS"> for more on expressions. + +=item * + +minw: specifies a minimum display width. This helps stabilize the display, +which makes it easier to read if the data is changing frequently. + +=item * + +maxw: similar to minw. + +=item * + +trans: a list of column transformations. See L<"TRANSFORMATIONS">. + +=item * + +agg: an aggregate function. See L<"GROUPING">. The default is L<"first">. + +=item * + +aggonly: controls whether the column only shows when grouping is enabled on the +table (see L<"GROUPING">). By default, this is disabled. This means columns +will always be shown by default, whether grouping is enabled or not. If a +column's aggonly is set true, the column will appear when you toggle grouping on +the table. Several columns are set this way, such as the count column on +L<"processlist"> and L<"innodb_transactions">, so you don't see a count when the +grouping isn't enabled, but you do when it is. + +=back + +=head2 FILTERS + +Filters remove rows from the display. They behave much like a WHERE clause in +SQL. innotop has several built-in filters, which remove irrelevant information +like inactive queries, but you can define your own as well. innotop also lets +you create quick-filters, which do not get saved to the configuration file, and +are just an easy way to quickly view only some rows. + +You can enable or disable a filter on any table. Press the '%' key (mnemonic: % +looks kind of like a line being filtered between two circles) and choose which +table you want to filter, if asked. You'll then see a list of possible filters +and a list of filters currently enabled for that table. Type the names of +filters you want to apply and press Enter. + +=head3 USER-DEFINED FILTERS + +If you type a name that doesn't exist, innotop will prompt you to create the +filter. Filters are easy to create if you know Perl, and not hard if you don't. +What you're doing is creating a subroutine that returns true if the row should +be displayed. The row is a hash reference passed to your subroutine as $set. + +For example, imagine you want to filter the processlist table so you only see +queries that have been running more than five minutes. Type a new name for your +filter, and when prompted for the subroutine body, press TAB to initiate your +terminal's auto-completion. You'll see the names of the columns in the +L<"processlist"> table (innotop generally tries to help you with auto-completion +lists). You want to filter on the 'time' column. Type the text "$set->{time} > +300" to return true when the query is more than five minutes old. That's all +you need to do. + +In other words, the code you're typing is surrounded by an implicit context, +which looks like this: + + sub filter { + my ( $set ) = @_; + # YOUR CODE HERE + } + +If your filter doesn't work, or if something else suddenly behaves differently, +you might have made an error in your filter, and innotop is silently catching +the error. Try enabling L<"debug"> to make innotop throw an error instead. + +=head3 QUICK-FILTERS + +innotop's quick-filters are a shortcut to create a temporary filter that doesn't +persist when you restart innotop. To create a quick-filter, press the '/' key. +innotop will prompt you for the column name and filter text. Again, you can use +auto-completion on column names. The filter text can be just the text you want +to "search for." For example, to filter the L<"processlist"> table on queries +that refer to the products table, type '/' and then 'info product'. + +The filter text can actually be any Perl regular expression, but of course a +literal string like 'product' works fine as a regular expression. + +Behind the scenes innotop compiles the quick-filter into a specially tagged +filter that is otherwise like any other filter. It just isn't saved to the +configuration file. + +To clear quick-filters, press the '\' key and innotop will clear them all at +once. + +=head2 SORTING + +innotop has sensible built-in defaults to sort the most important rows to the +top of the table. Like anything else in innotop, you can customize how any +table is sorted. + +To start the sort dialog, start the L<"TABLE EDITOR"> with the '^' key, choose a +table if necessary, and press the 's' key. You'll see a list of columns you can +use in the sort expression and the current sort expression, if any. Enter a +list of columns by which you want to sort and press Enter. If you want to +reverse sort, prefix the column name with a minus sign. For example, if you +want to sort by column a ascending, then column b descending, type 'a -b'. You +can also explicitly add a + in front of columns you want to sort ascending, but +it's not required. + +Some modes have keys mapped to open this dialog directly, and to quickly reverse +sort direction. Press '?' as usual to see which keys are mapped in any mode. + +=head2 GROUPING + +innotop can group, or aggregate, rows together (I use the terms +interchangeably). This is quite similar to an SQL GROUP BY clause. You can +specify to group on certain columns, or if you don't specify any, the entire set +of rows is treated as one group. This is quite like SQL so far, but unlike SQL, +you can also select un-grouped columns. innotop actually aggregates every +column. If you don't explicitly specify a grouping function, the default is +'first'. This is basically a convenience so you don't have to specify an +aggregate function for every column you want in the result. + +You can quickly toggle grouping on a table with the '=' key, which toggles its +aggregate property. This property doesn't persist to the config file. + +The columns by which the table is grouped are specified in its group_by +property. When you turn grouping on, innotop places the group_by columns at the +far left of the table, even if they're not supposed to be visible. The rest of +the visible columns appear in order after them. + +Two tables have default group_by lists and a count column built in: +L<"processlist"> and L<"innodb_transactions">. The grouping is by connection +and status, so you can quickly see how many queries or transactions are in a +given status on each server you're monitoring. The time columns are aggregated +as a sum; other columns are left at the default 'first' aggregation. + +By default, the table shown in L<"S: Variables & Status"> mode also uses +grouping so you can monitor variables and status across many servers. The +default aggregation function in this mode is 'avg'. + +Valid grouping functions are defined in the %agg_funcs hash. They include + +=over + +=item first + +Returns the first element in the group. + +=item count + +Returns the number of elements in the group, including undefined elements, much +like SQL's COUNT(*). + +=item avg + +Returns the average of defined elements in the group. + +=item sum + +Returns the sum of elements in the group. + +=back + +Here's an example of grouping at work. Suppose you have a very busy server with +hundreds of open connections, and you want to see how many connections are in +what status. Using the built-in grouping rules, you can press 'Q' to enter +L<"Q: Query List"> mode. Press '=' to toggle grouping (if necessary, select the +L<"processlist"> table when prompted). + +Your display might now look like the following: + + Query List (? for help) localhost, 32:33, 0.11 QPS, 1 thd, 5.0.38-log + + CXN Cmd Cnt ID User Host Time Query + localhost Query 49 12933 webusr localhost 19:38 SELECT * FROM + localhost Sending Da 23 2383 webusr localhost 12:43 SELECT col1, + localhost Sleep 120 140 webusr localhost 5:18:12 + localhost Statistics 12 19213 webusr localhost 01:19 SELECT * FROM + +That's actually quite a worrisome picture. You've got a lot of idle connections +(Sleep), and some connections executing queries (Query and Sending Data). +That's okay, but you also have a lot in Statistics status, collectively spending +over a minute. That means the query optimizer is having a really hard time +optimizing your statements. Something is wrong; it should normally take +milliseconds to optimize queries. You might not have seen this pattern if you +didn't look at your connections in aggregate. (This is a made-up example, but +it can happen in real life). + +=head2 PIVOTING + +innotop can pivot a table for more compact display, similar to a Pivot Table in +a spreadsheet (also known as a crosstab). Pivoting a table makes columns into +rows. Assume you start with this table: + + foo bar + === === + 1 3 + 2 4 + +After pivoting, the table will look like this: + + name set0 set1 + ==== ==== ==== + foo 1 2 + bar 3 4 + +To get reasonable results, you might need to group as well as pivoting. +innotop currently does this for L<"S: Variables & Status"> mode. + +=head2 COLORS + +By default, innotop highlights rows with color so you can see at a glance which +rows are more important. You can customize the colorization rules and add your +own to any table. Open the table editor with the '^' key, choose a table if +needed, and press 'o' to open the color editor dialog. + +The color editor dialog displays the rules applied to the table, in the order +they are evaluated. Each row is evaluated against each rule to see if the rule +matches the row; if it does, the row gets the specified color, and no further +rules are evaluated. The rules look like the following: + + state eq Locked black on_red + cmd eq Sleep white + user eq system user white + cmd eq Connect white + cmd eq Binlog Dump white + time > 600 red + time > 120 yellow + time > 60 green + time > 30 cyan + +This is the default rule set for the L<"processlist"> table. In order of +priority, these rules make locked queries black on a red background, "gray out" +connections from replication and sleeping queries, and make queries turn from +cyan to red as they run longer. + +(For some reason, the ANSI color code "white" is actually a light gray. Your +terminal's display may vary; experiment to find colors you like). + +You can use keystrokes to move the rules up and down, which re-orders their +priority. You can also delete rules and add new ones. If you add a new rule, +innotop prompts you for the column, an operator for the comparison, a value +against which to compare the column, and a color to assign if the rule matches. +There is auto-completion and prompting at each step. + +The value in the third step needs to be correctly quoted. innotop does not try +to quote the value because it doesn't know whether it should treat the value as +a string or a number. If you want to compare the column against a string, as +for example in the first rule above, you should enter 'Locked' surrounded by +quotes. If you get an error message about a bareword, you probably should have +quoted something. + +=head2 EXPRESSIONS + +Expressions are at the core of how innotop works, and are what enables you to +extend innotop as you wish. Recall the table lifecycle explained in +L<"TABLES">. Expressions are used in the earliest step, where it extracts +values from a data source to form rows. + +It does this by calling a subroutine for each column, passing it the source data +set, a set of current values, and a set of previous values. These are all +needed so the subroutine can calculate things like the difference between this +tick and the previous tick. + +The subroutines that extract the data from the set are compiled from +expressions. This gives significantly more power than just naming the values to +fill the columns, because it allows the column's value to be calculated from +whatever data is necessary, but avoids the need to write complicated and lengthy +Perl code. + +innotop begins with a string of text that can look as simple as a value's name +or as complicated as a full-fledged Perl expression. It looks at each +'bareword' token in the string and decides whether it's supposed to be a key +into the $set hash. A bareword is an unquoted value that isn't already +surrounded by code-ish things like dollar signs or curly brackets. If innotop +decides that the bareword isn't a function or other valid Perl code, it converts +it into a hash access. After the whole string is processed, innotop compiles a +subroutine, like this: + + sub compute_column_value { + my ( $set, $cur, $pre ) = @_; + my $val = # EXPANDED STRING GOES HERE + return $val; + } + +Here's a concrete example, taken from the header table L<"q_header"> in L<"Q: +Query List"> mode. This expression calculates the qps, or Queries Per Second, +column's values, from the values returned by SHOW STATUS: + + Questions/Uptime_hires + +innotop decides both words are barewords, and transforms this expression into +the following Perl code: + + $set->{Questions}/$set->{Uptime_hires} + +When surrounded by the rest of the subroutine's code, this is executable Perl +that calculates a high-resolution queries-per-second value. + +The arguments to the subroutine are named $set, $cur, and $pre. In most cases, +$set and $cur will be the same values. However, if L<"status_inc"> is set, $cur +will not be the same as $set, because $set will already contain values that are +the incremental difference between $cur and $pre. + +Every column in innotop is computed by subroutines compiled in the same fashion. +There is no difference between innotop's built-in columns and user-defined +columns. This keeps things consistent and predictable. + +=head2 TRANSFORMATIONS + +Transformations change how a value is rendered. For example, they can take a +number of seconds and display it in H:M:S format. The following transformations +are defined: + +=over + +=item commify + +Adds commas to large numbers every three decimal places. + +=item dulint_to_int + +Accepts two unsigned integers and converts them into a single longlong. This is +useful for certain operations with InnoDB, which uses two integers as +transaction identifiers, for example. + +=item no_ctrl_char + +Removes quoted control characters from the value. This is affected by the +L<"charset"> configuration variable. + +This transformation only operates within quoted strings, for example, values to +a SET clause in an UPDATE statement. It will not alter the UPDATE statement, +but will collapse the quoted string to [BINARY] or [TEXT], depending on the +charset. + +=item percent + +Converts a number to a percentage by multiplying it by two, formatting it with +L<"num_digits"> digits after the decimal point, and optionally adding a percent +sign (see L<"show_percent">). + +=item secs_to_time + +Formats a number of seconds as time in days+hours:minutes:seconds format. + +=item set_precision + +Formats numbers with L<"num_digits"> number of digits after the decimal point. + +=item shorten + +Formats a number as a unit of 1024 (k/M/G/T) and with L<"num_digits"> number of +digits after the decimal point. + +=back + +=head2 TABLE EDITOR + +The innotop table editor lets you customize tables with keystrokes. You start +the table editor with the '^' key. If there's more than one table on the +screen, it will prompt you to choose one of them. Once you do, innotop will +show you something like this: + + Editing table definition for Buffer Pool. Press ? for help, q to quit. + + name hdr label src + cxn CXN Connection from which cxn + buf_pool_size Size Buffer pool size IB_bp_buf_poo + buf_free Free Bufs Buffers free in the b IB_bp_buf_fre + pages_total Pages Pages total IB_bp_pages_t + pages_modified Dirty Pages Pages modified (dirty IB_bp_pages_m + buf_pool_hit_rate Hit Rate Buffer pool hit rate IB_bp_buf_poo + total_mem_alloc Memory Total memory allocate IB_bp_total_m + add_pool_alloc Add'l Pool Additonal pool alloca IB_bp_add_poo + +The first line shows which table you're editing, and reminds you again to press +'?' for a list of key mappings. The rest is a tabular representation of the +table's columns, because that's likely what you're trying to edit. However, you +can edit more than just the table's columns; this screen can start the filter +editor, color rule editor, and more. + +Each row in the display shows a single column in the table you're editing, along +with a couple of its properties such as its header and source expression (see +L<"EXPRESSIONS">). + +The key mappings are Vim-style, as in many other places. Pressing 'j' and 'k' +moves the highlight up or down. You can then (d)elete or (e)dit the highlighted +column. You can also (a)dd a column to the table. This actually just activates +one of the columns already defined for the table; it prompts you to choose from +among the columns available but not currently displayed. Finally, you can +re-order the columns with the '+' and '-' keys. + +You can do more than just edit the columns with the table editor, you can also +edit other properties, such as the table's sort expression and group-by +expression. Press '?' to see the full list, of course. + +If you want to really customize and create your own column, as opposed to just +activating a built-in one that's not currently displayed, press the (n)ew key, +and innotop will prompt you for the information it needs: + +=over + +=item * + +The column name: this needs to be a word without any funny characters, e.g. just +letters, numbers and underscores. + +=item * + +The column header: this is the label that appears at the top of the column, in +the table header. This can have spaces and funny characters, but be careful not +to make it too wide and waste space on-screen. + +=item * + +The column's data source: this is an expression that determines what data from +the source (see L<"TABLES">) innotop will put into the column. This can just be +the name of an item in the source, or it can be a more complex expression, as +described in L<"EXPRESSIONS">. + +=back + +Once you've entered the required data, your table has a new column. There is no +difference between this column and the built-in ones; it can have all the same +properties and behaviors. innotop will write the column's definition to the +configuration file, so it will persist across sessions. + +Here's an example: suppose you want to track how many times your slaves have +retried transactions. According to the MySQL manual, the +Slave_retried_transactions status variable gives you that data: "The total +number of times since startup that the replication slave SQL thread has retried +transactions. This variable was added in version 5.0.4." This is appropriate to +add to the L<"slave_sql_status"> table. + +To add the column, switch to the replication-monitoring mode with the 'M' key, +and press the '^' key to start the table editor. When prompted, choose +slave_sql_status as the table, then press 'n' to create the column. Type +'retries' as the column name, 'Retries' as the column header, and +'Slave_retried_transactions' as the source. Now the column is created, and you +see the table editor screen again. Press 'q' to exit the table editor, and +you'll see your column at the end of the table. + +=head1 VARIABLE SETS + +Variable sets are used in L<"S: Variables & Status"> mode to define more easily +what variables you want to monitor. Behind the scenes they are compiled to a +list of expressions, and then into a column list so they can be treated just +like columns in any other table, in terms of data extraction and +transformations. However, you're protected from the tedious details by a syntax +that ought to feel very natural to you: a SQL SELECT list. + +The data source for variable sets, and indeed the entire S mode, is the +combination of SHOW STATUS, SHOW VARIABLES, and SHOW INNODB STATUS. Imagine +that you had a huge table with one column per variable returned from those +statements. That's the data source for variable sets. You can now query this +data source just like you'd expect. For example: + + Questions, Uptime, Questions/Uptime as QPS + +Behind the scenes innotop will split that variable set into three expressions, +compile them and turn them into a table definition, then extract as usual. This +becomes a "variable set," or a "list of variables you want to monitor." + +innotop lets you name and save your variable sets, and writes them to the +configuration file. You can choose which variable set you want to see with the +'c' key, or activate the next and previous sets with the '>' and '<' keys. +There are many built-in variable sets as well, which should give you a good +start for creating your own. Press 'e' to edit the current variable set, or +just to see how it's defined. To create a new one, just press 'c' and type its +name. + +You may want to use some of the functions listed in L<"TRANSFORMATIONS"> to help +format the results. In particular, L<"set_precision"> is often useful to limit +the number of digits you see. Extending the above example, here's how: + + Questions, Uptime, set_precision(Questions/Uptime) as QPS + +Actually, this still needs a little more work. If your L<"interval"> is less +than one second, you might be dividing by zero because Uptime is incremental in +this mode by default. Instead, use Uptime_hires: + + Questions, Uptime, set_precision(Questions/Uptime_hires) as QPS + +This example is simple, but it shows how easy it is to choose which variables +you want to monitor. + +=head1 PLUGINS + +innotop has a simple but powerful plugin mechanism by which you can extend +or modify its existing functionality, and add new functionality. innotop's +plugin functionality is event-based: plugins register themselves to be called +when events happen. They then have a chance to influence the event. + +An innotop plugin is a Perl module placed in innotop's L<"plugin_dir"> +directory. On UNIX systems, you can place a symbolic link to the module instead +of putting the actual file there. innotop automatically discovers the file. If +there is a corresponding entry in the L<"plugins"> configuration file section, +innotop loads and activates the plugin. + +The module must conform to innotop's plugin interface. Additionally, the source +code of the module must be written in such a way that innotop can inspect the +file and determine the package name and description. + +=head2 Package Source Convention + +innotop inspects the plugin module's source to determine the Perl package name. +It looks for a line of the form "package Foo;" and if found, considers the +plugin's package name to be Foo. Of course the package name can be a valid Perl +package name, with double semicolons and so on. + +It also looks for a description in the source code, to make the plugin editor +more human-friendly. The description is a comment line of the form "# +description: Foo", where "Foo" is the text innotop will consider to be the +plugin's description. + +=head2 Plugin Interface + +The innotop plugin interface is quite simple: innotop expects the plugin to be +an object-oriented module it can call certain methods on. The methods are + +=over + +=item new(%variables) + +This is the plugin's constructor. It is passed a hash of innotop's variables, +which it can manipulate (see L<"Plugin Variables">). It must return a reference +to the newly created plugin object. + +At construction time, innotop has only loaded the general configuration and +created the default built-in variables with their default contents (which is +quite a lot). Therefore, the state of the program is exactly as in the innotop +source code, plus the configuration variables from the L<"general"> section in +the config file. + +If your plugin manipulates the variables, it is changing global data, which is +shared by innotop and all plugins. Plugins are loaded in the order they're +listed in the config file. Your plugin may load before or after another plugin, +so there is a potential for conflict or interaction between plugins if they +modify data other plugins use or modify. + +=item register_for_events() + +This method must return a list of events in which the plugin is interested, if +any. See L<"Plugin Events"> for the defined events. If the plugin returns an +event that's not defined, the event is ignored. + +=item event handlers + +The plugin must implement a method named the same as each event for which it has +registered. In other words, if the plugin returns qw(foo bar) from +register_for_events(), it must have foo() and bar() methods. These methods are +callbacks for the events. See L<"Plugin Events"> for more details about each +event. + +=back + +=head2 Plugin Variables + +The plugin's constructor is passed a hash of innotop's variables, which it can +manipulate. It is probably a good idea if the plugin object saves a copy of it +for later use. The variables are defined in the innotop variable +%pluggable_vars, and are as follows: + +=over + +=item action_for + +A hashref of key mappings. These are innotop's global hot-keys. + +=item agg_funcs + +A hashref of functions that can be used for grouping. See L<"GROUPING">. + +=item config + +The global configuration hash. + +=item connections + +A hashref of connection specifications. These are just specifications of how to +connect to a server. + +=item dbhs + +A hashref of innotop's database connections. These are actual DBI connection +objects. + +=item filters + +A hashref of filters applied to table rows. See L<"FILTERS"> for more. + +=item modes + +A hashref of modes. See L<"MODES"> for more. + +=item server_groups + +A hashref of server groups. See L<"SERVER GROUPS">. + +=item tbl_meta + +A hashref of innotop's table meta-data, with one entry per table (see +L<"TABLES"> for more information). + +=item trans_funcs + +A hashref of transformation functions. See L<"TRANSFORMATIONS">. + +=item var_sets + +A hashref of variable sets. See L<"VARIABLE SETS">. + +=back + +=head2 Plugin Events + +Each event is defined somewhere in the innotop source code. When innotop runs +that code, it executes the callback function for each plugin that expressed its +interest in the event. innotop passes some data for each event. The events are +defined in the %event_listener_for variable, and are as follows: + +=over + +=item extract_values($set, $cur, $pre, $tbl) + +This event occurs inside the function that extracts values from a data source. +The arguments are the set of values, the current values, the previous values, +and the table name. + +=item set_to_tbl + +Events are defined at many places in this subroutine, which is responsible for +turning an arrayref of hashrefs into an arrayref of lines that can be printed to +the screen. The events all pass the same data: an arrayref of rows and the name +of the table being created. The events are set_to_tbl_pre_filter, +set_to_tbl_pre_sort,set_to_tbl_pre_group, set_to_tbl_pre_colorize, +set_to_tbl_pre_transform, set_to_tbl_pre_pivot, set_to_tbl_pre_create, +set_to_tbl_post_create. + +=item draw_screen($lines) + +This event occurs inside the subroutine that prints the lines to the screen. +$lines is an arrayref of strings. + +=back + +=head2 Simple Plugin Example + +The easiest way to explain the plugin functionality is probably with a simple +example. The following module adds a column to the beginning of every table and +sets its value to 1. + + use strict; + use warnings FATAL => 'all'; + + package Innotop::Plugin::Example; + # description: Adds an 'example' column to every table + + sub new { + my ( $class, %vars ) = @_; + # Store reference to innotop's variables in $self + my $self = bless { %vars }, $class; + + # Design the example column + my $col = { + hdr => 'Example', + just => '', + dec => 0, + num => 1, + label => 'Example', + src => 'example', # Get data from this column in the data source + tbl => '', + trans => [], + }; + + # Add the column to every table. + my $tbl_meta = $vars{tbl_meta}; + foreach my $tbl ( values %$tbl_meta ) { + # Add the column to the list of defined columns + $tbl->{cols}->{example} = $col; + # Add the column to the list of visible columns + unshift @{$tbl->{visible}}, 'example'; + } + + # Be sure to return a reference to the object. + return $self; + } + + # I'd like to be called when a data set is being rendered into a table, please. + sub register_for_events { + my ( $self ) = @_; + return qw(set_to_tbl_pre_filter); + } + + # This method will be called when the event fires. + sub set_to_tbl_pre_filter { + my ( $self, $rows, $tbl ) = @_; + # Set the example column's data source to the value 1. + foreach my $row ( @$rows ) { + $row->{example} = 1; + } + } + + 1; + +=head2 Plugin Editor + +The plugin editor lets you view the plugins innotop discovered and activate or +deactivate them. Start the editor by pressing $ to start the configuration +editor from any mode. Press the 'p' key to start the plugin editor. You'll see +a list of plugins innotop discovered. You can use the 'j' and 'k' keys to move +the highlight to the desired one, then press the * key to toggle it active or +inactive. Exit the editor and restart innotop for the changes to take effect. + +=head1 SQL STATEMENTS + +innotop uses a limited set of SQL statements to retrieve data from MySQL for +display. The statements are customized depending on the server version against +which they are executed; for example, on MySQL 5 and newer, INNODB_STATUS +executes "SHOW ENGINE INNODB STATUS", while on earlier versions it executes +"SHOW INNODB STATUS". The statements are as follows: + + Statement SQL executed + =================== =============================== + INNODB_STATUS SHOW [ENGINE] INNODB STATUS + KILL_CONNECTION KILL + KILL_QUERY KILL QUERY + OPEN_TABLES SHOW OPEN TABLES + PROCESSLIST SHOW FULL PROCESSLIST + SHOW_MASTER_LOGS SHOW MASTER LOGS + SHOW_MASTER_STATUS SHOW MASTER STATUS + SHOW_SLAVE_STATUS SHOW SLAVE STATUS + SHOW_STATUS SHOW [GLOBAL] STATUS + SHOW_VARIABLES SHOW [GLOBAL] VARIABLES + +=head1 DATA SOURCES + +Each time innotop extracts values to create a table (see L<"EXPRESSIONS"> and +L<"TABLES">), it does so from a particular data source. Largely because of the +complex data extracted from SHOW INNODB STATUS, this is slightly messy. SHOW +INNODB STATUS contains a mixture of single values and repeated values that form +nested data sets. + +Whenever innotop fetches data from MySQL, it adds two extra bits to each set: +cxn and Uptime_hires. cxn is the name of the connection from which the data +came. Uptime_hires is a high-resolution version of the server's Uptime status +variable, which is important if your L<"interval"> setting is sub-second. + +Here are the kinds of data sources from which data is extracted: + +=over + +=item STATUS_VARIABLES + +This is the broadest category, into which the most kinds of data fall. It +begins with the combination of SHOW STATUS and SHOW VARIABLES, but other sources +may be included as needed, for example, SHOW MASTER STATUS and SHOW SLAVE +STATUS, as well as many of the non-repeated values from SHOW INNODB STATUS. + +=item DEADLOCK_LOCKS + +This data is extracted from the transaction list in the LATEST DETECTED DEADLOCK +section of SHOW INNODB STATUS. It is nested two levels deep: transactions, then +locks. + +=item DEADLOCK_TRANSACTIONS + +This data is from the transaction list in the LATEST DETECTED DEADLOCK +section of SHOW INNODB STATUS. It is nested one level deep. + +=item EXPLAIN + +This data is from the result set returned by EXPLAIN. + +=item INNODB_TRANSACTIONS + +This data is from the TRANSACTIONS section of SHOW INNODB STATUS. + +=item IO_THREADS + +This data is from the list of threads in the the FILE I/O section of SHOW INNODB +STATUS. + +=item INNODB_LOCKS + +This data is from the TRANSACTIONS section of SHOW INNODB STATUS and is nested +two levels deep. + +=item OPEN_TABLES + +This data is from SHOW OPEN TABLES. + +=item PROCESSLIST + +This data is from SHOW FULL PROCESSLIST. + +=item OS_WAIT_ARRAY + +This data is from the SEMAPHORES section of SHOW INNODB STATUS and is nested one +level deep. It comes from the lines that look like this: + + --Thread 1568861104 has waited at btr0cur.c line 424 .... + +=back + +=head1 MYSQL PRIVILEGES + +=over + +=item * + +You must connect to MySQL as a user who has the SUPER privilege for many of the +functions. + +=item * + +If you don't have the SUPER privilege, you can still run some functions, but you +won't necessarily see all the same data. + +=item * + +You need the PROCESS privilege to see the list of currently running queries in Q +mode. + +=item * + +You need special privileges to start and stop slave servers. + +=item * + +You need appropriate privileges to create and drop the deadlock tables if needed +(see L<"SERVER CONNECTIONS">). + +=back + +=head1 SYSTEM REQUIREMENTS + +You need Perl to run innotop, of course. You also need a few Perl modules: DBI, +DBD::mysql, Term::ReadKey, and Time::HiRes. These should be included with most +Perl distributions, but in case they are not, I recommend using versions +distributed with your operating system or Perl distribution, not from CPAN. +Term::ReadKey in particular has been known to cause problems if installed from +CPAN. + +If you have Term::ANSIColor, innotop will use it to format headers more readably +and compactly. (Under Microsoft Windows, you also need Win32::Console::ANSI for +terminal formatting codes to be honored). If you install Term::ReadLine, +preferably Term::ReadLine::Gnu, you'll get nice auto-completion support. + +I run innotop on Gentoo GNU/Linux, Debian and Ubuntu, and I've had feedback from +people successfully running it on Red Hat, CentOS, Solaris, and Mac OSX. I +don't see any reason why it won't work on other UNIX-ish operating systems, but +I don't know for sure. It also runs on Windows under ActivePerl without +problem. + +I use innotop 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 and I hope you +report it. + +=head1 FILES + +$HOMEDIR/.innotop is used to store configuration information. Files include the +configuration file innotop.ini, 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 + +I'm grateful to the following people for various reasons, and hope I haven't +forgotten to include anyone: + +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, +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 I've neglected to include. + +(If I misspelled your name, it's probably because I'm afraid of putting +international characters into this documentation; earlier versions of Perl might +not be able to compile it then). + +=head1 COPYRIGHT, LICENSE AND WARRANTY + +This program is copyright (c) 2006 Baron Schwartz. +Feedback and improvements are welcome. + +THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, version 2; OR the Perl Artistic License. On UNIX and similar +systems, you can issue `man perlgpl' or `man perlartistic' to read these +licenses. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA. + +Execute innotop and press '!' to see this information at any time. + +=head1 AUTHOR + +Baron Schwartz. + +=head1 BUGS + +You can report bugs, ask for improvements, and get other help and support at +L. There are mailing lists, forums, +a bug tracker, etc. Please use these instead of contacting me directly, as it +makes my job easier and benefits others if the discussions are permanent and +public. Of course, if you need to contact me in private, please do. + +=cut --- mysql-dfsg-5.0-5.0.51a.orig/debian/additions/innotop/InnoDBParser.pm +++ mysql-dfsg-5.0-5.0.51a/debian/additions/innotop/InnoDBParser.pm @@ -0,0 +1,1089 @@ +use strict; +use warnings FATAL => 'all'; + +package InnoDBParser; + +# This program is copyright (c) 2006 Baron Schwartz, baron at xaprb dot com. +# Feedback and improvements are gratefully received. +# +# THIS PROGRAM IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, version 2; OR the Perl Artistic License. On UNIX and similar +# systems, you can issue `man perlgpl' or `man perlartistic' to read these + +# You should have received a copy of the GNU General Public License along with +# this program; if not, write to the Free Software Foundation, Inc., 59 Temple +# Place, Suite 330, Boston, MA 02111-1307 USA + +our $VERSION = '1.6.0'; + +use Data::Dumper; +$Data::Dumper::Sortkeys = 1; +use English qw(-no_match_vars); +use List::Util qw(max); + +# Some common patterns +my $d = qr/(\d+)/; # Digit +my $f = qr/(\d+\.\d+)/; # Float +my $t = qr/(\d+ \d+)/; # Transaction ID +my $i = qr/((?:\d{1,3}\.){3}\d+)/; # IP address +my $n = qr/([^`\s]+)/; # MySQL object name +my $w = qr/(\w+)/; # Words +my $fl = qr/([\w\.\/]+) line $d/; # Filename and line number +my $h = qr/((?:0x)?[0-9a-f]*)/; # Hex +my $s = qr/(\d{6} .\d:\d\d:\d\d)/; # InnoDB timestamp + +# If you update this variable, also update the SYNOPSIS in the pod. +my %innodb_section_headers = ( + "TRANSACTIONS" => "tx", + "BUFFER POOL AND MEMORY" => "bp", + "SEMAPHORES" => "sm", + "LOG" => "lg", + "ROW OPERATIONS" => "ro", + "INSERT BUFFER AND ADAPTIVE HASH INDEX" => "ib", + "FILE I/O" => "io", + "LATEST DETECTED DEADLOCK" => "dl", + "LATEST FOREIGN KEY ERROR" => "fk", +); + +my %parser_for = ( + tx => \&parse_tx_section, + bp => \&parse_bp_section, + sm => \&parse_sm_section, + lg => \&parse_lg_section, + ro => \&parse_ro_section, + ib => \&parse_ib_section, + io => \&parse_io_section, + dl => \&parse_dl_section, + fk => \&parse_fk_section, +); + +my %fk_parser_for = ( + Transaction => \&parse_fk_transaction_error, + Error => \&parse_fk_bad_constraint_error, + Cannot => \&parse_fk_cant_drop_parent_error, +); + +# A thread's proc_info can be at least 98 different things I've found in the +# source. Fortunately, most of them begin with a gerunded verb. These are +# the ones that don't. +my %is_proc_info = ( + 'After create' => 1, + 'Execution of init_command' => 1, + 'FULLTEXT initialization' => 1, + 'Reopen tables' => 1, + 'Repair done' => 1, + 'Repair with keycache' => 1, + 'System lock' => 1, + 'Table lock' => 1, + 'Thread initialized' => 1, + 'User lock' => 1, + 'copy to tmp table' => 1, + 'discard_or_import_tablespace' => 1, + 'end' => 1, + 'got handler lock' => 1, + 'got old table' => 1, + 'init' => 1, + 'key cache' => 1, + 'locks' => 1, + 'malloc' => 1, + 'query end' => 1, + 'rename result table' => 1, + 'rename' => 1, + 'setup' => 1, + 'statistics' => 1, + 'status' => 1, + 'table cache' => 1, + 'update' => 1, +); + +sub new { + bless {}, shift; +} + +# Parse the status and return it. +# See srv_printf_innodb_monitor in innobase/srv/srv0srv.c +# Pass in the text to parse, whether to be in debugging mode, which sections +# to parse (hashref; if empty, parse all), and whether to parse full info from +# locks and such (probably shouldn't unless you need to). +sub parse_status_text { + my ( $self, $fulltext, $debug, $sections, $full ) = @_; + + die "I can't parse undef" unless defined $fulltext; + $fulltext =~ s/[\r\n]+/\n/g; + + $sections ||= {}; + die '$sections must be a hashref' unless ref($sections) eq 'HASH'; + + my %innodb_data = ( + got_all => 0, # Whether I was able to get the whole thing + ts => '', # Timestamp the server put on it + last_secs => 0, # Num seconds the averages are over + sections => {}, # Parsed values from each section + ); + + if ( $debug ) { + $innodb_data{'fulltext'} = $fulltext; + } + + # Get the most basic info about the status: beginning and end, and whether + # I got the whole thing (if there has been a big deadlock and there are + # too many locks to print, the output might be truncated) + my ( $time_text ) = $fulltext =~ m/^$s INNODB MONITOR OUTPUT$/m; + $innodb_data{'ts'} = [ parse_innodb_timestamp( $time_text ) ]; + $innodb_data{'timestring'} = ts_to_string($innodb_data{'ts'}); + ( $innodb_data{'last_secs'} ) = $fulltext + =~ m/Per second averages calculated from the last $d seconds/; + + ( my $got_all ) = $fulltext =~ m/END OF INNODB MONITOR OUTPUT/; + $innodb_data{'got_all'} = $got_all || 0; + + # Split it into sections. Each section begins with + # ----- + # LABEL + # ----- + my %innodb_sections; + my @matches = $fulltext + =~ m#\n(---+)\n([A-Z /]+)\n\1\n(.*?)(?=\n(---+)\n[A-Z /]+\n\4\n|$)#gs; + while ( my ( $start, $name, $text, $end ) = splice(@matches, 0, 4) ) { + $innodb_sections{$name} = [ $text, $end ? 1 : 0 ]; + } + # The Row Operations section is a special case, because instead of ending + # with the beginning of another section, it ends with the end of the file. + # So this section is complete if the entire file is complete. + $innodb_sections{'ROW OPERATIONS'}->[1] ||= $innodb_data{'got_all'}; + + # Just for sanity's sake, make sure I understand what to do with each + # section + eval { + foreach my $section ( keys %innodb_sections ) { + my $header = $innodb_section_headers{$section}; + die "Unknown section $section in $fulltext\n" + unless $header; + $innodb_data{'sections'}->{ $header } + ->{'fulltext'} = $innodb_sections{$section}->[0]; + $innodb_data{'sections'}->{ $header } + ->{'complete'} = $innodb_sections{$section}->[1]; + } + }; + if ( $EVAL_ERROR ) { + _debug( $debug, $EVAL_ERROR); + } + + # ################################################################ + # Parse the detailed data out of the sections. + # ################################################################ + eval { + foreach my $section ( keys %parser_for ) { + if ( defined $innodb_data{'sections'}->{$section} + && (!%$sections || (defined($sections->{$section} && $sections->{$section})) )) { + $parser_for{$section}->( + $innodb_data{'sections'}->{$section}, + $innodb_data{'sections'}->{$section}->{'complete'}, + $debug, + $full ) + or delete $innodb_data{'sections'}->{$section}; + } + else { + delete $innodb_data{'sections'}->{$section}; + } + } + }; + if ( $EVAL_ERROR ) { + _debug( $debug, $EVAL_ERROR); + } + + return \%innodb_data; +} + +# Parses the status text and returns it flattened out as a single hash. +sub get_status_hash { + my ( $self, $fulltext, $debug, $sections, $full ) = @_; + + # Parse the status text... + my $innodb_status + = $self->parse_status_text($fulltext, $debug, $sections, $full ); + + # Flatten the hierarchical structure into a single list by grabbing desired + # sections from it. + return + (map { 'IB_' . $_ => $innodb_status->{$_} } qw(timestring last_secs got_all)), + (map { 'IB_bp_' . $_ => $innodb_status->{'sections'}->{'bp'}->{$_} } + qw( writes_pending buf_pool_hit_rate total_mem_alloc buf_pool_reads + awe_mem_alloc pages_modified writes_pending_lru page_creates_sec + reads_pending pages_total buf_pool_hits writes_pending_single_page + page_writes_sec pages_read pages_written page_reads_sec + writes_pending_flush_list buf_pool_size add_pool_alloc + dict_mem_alloc pages_created buf_free complete )), + (map { 'IB_tx_' . $_ => $innodb_status->{'sections'}->{'tx'}->{$_} } + qw( num_lock_structs history_list_len purge_done_for transactions + purge_undo_for is_truncated trx_id_counter complete )), + (map { 'IB_ib_' . $_ => $innodb_status->{'sections'}->{'ib'}->{$_} } + qw( hash_table_size hash_searches_s non_hash_searches_s + bufs_in_node_heap used_cells size free_list_len seg_size inserts + merged_recs merges complete )), + (map { 'IB_lg_' . $_ => $innodb_status->{'sections'}->{'lg'}->{$_} } + qw( log_ios_done pending_chkp_writes last_chkp log_ios_s + log_flushed_to log_seq_no pending_log_writes complete )), + (map { 'IB_sm_' . $_ => $innodb_status->{'sections'}->{'sm'}->{$_} } + qw( wait_array_size rw_shared_spins rw_excl_os_waits mutex_os_waits + mutex_spin_rounds mutex_spin_waits rw_excl_spins rw_shared_os_waits + waits signal_count reservation_count complete )), + (map { 'IB_ro_' . $_ => $innodb_status->{'sections'}->{'ro'}->{$_} } + qw( queries_in_queue n_reserved_extents main_thread_state + main_thread_proc_no main_thread_id read_sec del_sec upd_sec ins_sec + read_views_open num_rows_upd num_rows_ins num_rows_read + queries_inside num_rows_del complete )), + (map { 'IB_fk_' . $_ => $innodb_status->{'sections'}->{'fk'}->{$_} } + qw( trigger parent_table child_index parent_index attempted_op + child_db timestring fk_name records col_name reason txn parent_db + type child_table parent_col complete )), + (map { 'IB_io_' . $_ => $innodb_status->{'sections'}->{'io'}->{$_} } + qw( pending_buffer_pool_flushes pending_pwrites pending_preads + pending_normal_aio_reads fsyncs_s os_file_writes pending_sync_ios + reads_s flush_type avg_bytes_s pending_ibuf_aio_reads writes_s + threads os_file_reads pending_aio_writes pending_log_ios os_fsyncs + pending_log_flushes complete )), + (map { 'IB_dl_' . $_ => $innodb_status->{'sections'}->{'dl'}->{$_} } + qw( timestring rolled_back txns complete )); + +} + +sub ts_to_string { + my $parts = shift; + return sprintf('%02d-%02d-%02d %02d:%02d:%02d', @$parts); +} + +sub parse_innodb_timestamp { + my $text = shift; + my ( $y, $m, $d, $h, $i, $s ) + = $text =~ m/^(\d\d)(\d\d)(\d\d) +(\d+):(\d+):(\d+)$/; + die("Can't get timestamp from $text\n") unless $y; + $y += 2000; + return ( $y, $m, $d, $h, $i, $s ); +} + +sub parse_fk_section { + my ( $section, $complete, $debug, $full ) = @_; + my $fulltext = $section->{'fulltext'}; + + return 0 unless $fulltext; + + my ( $ts, $type ) = $fulltext =~ m/^$s\s+(\w+)/m; + $section->{'ts'} = [ parse_innodb_timestamp( $ts ) ]; + $section->{'timestring'} = ts_to_string($section->{'ts'}); + $section->{'type'} = $type; + + # Decide which type of FK error happened, and dispatch to the right parser. + if ( $type && $fk_parser_for{$type} ) { + $fk_parser_for{$type}->( $section, $complete, $debug, $fulltext, $full ); + } + + delete $section->{'fulltext'} unless $debug; + + return 1; +} + +sub parse_fk_cant_drop_parent_error { + my ( $section, $complete, $debug, $fulltext, $full ) = @_; + + # Parse the parent/child table info out + @{$section}{ qw(attempted_op parent_db parent_table) } = $fulltext + =~ m{Cannot $w table `(.*)/(.*)`}m; + @{$section}{ qw(child_db child_table) } = $fulltext + =~ m{because it is referenced by `(.*)/(.*)`}m; + + ( $section->{'reason'} ) = $fulltext =~ m/(Cannot .*)/s; + $section->{'reason'} =~ s/\n(?:InnoDB: )?/ /gm + if $section->{'reason'}; + + # Certain data may not be present. Make them '' if not present. + map { $section->{$_} ||= "" } + qw(child_index fk_name col_name parent_col); +} + +# See dict/dict0dict.c, function dict_foreign_error_report +# I don't care much about these. There are lots of different messages, and +# they come from someone trying to create a foreign key, or similar +# statements. They aren't indicative of some transaction trying to insert, +# delete or update data. Sometimes it is possible to parse out a lot of +# information about the tables and indexes involved, but often the message +# contains the DDL string the user entered, which is way too much for this +# module to try to handle. +sub parse_fk_bad_constraint_error { + my ( $section, $complete, $debug, $fulltext, $full ) = @_; + + # Parse the parent/child table and index info out + @{$section}{ qw(child_db child_table) } = $fulltext + =~ m{Error in foreign key constraint of table (.*)/(.*):$}m; + $section->{'attempted_op'} = 'DDL'; + + # FK name, parent info... if possible. + @{$section}{ qw(fk_name col_name parent_db parent_table parent_col) } + = $fulltext + =~ m/CONSTRAINT `?$n`? FOREIGN KEY \(`?$n`?\) REFERENCES (?:`?$n`?\.)?`?$n`? \(`?$n`?\)/; + + if ( !defined($section->{'fk_name'}) ) { + # Try to parse SQL a user might have typed in a CREATE statement or such + @{$section}{ qw(col_name parent_db parent_table parent_col) } + = $fulltext + =~ m/FOREIGN\s+KEY\s*\(`?$n`?\)\s+REFERENCES\s+(?:`?$n`?\.)?`?$n`?\s*\(`?$n`?\)/i; + } + $section->{'parent_db'} ||= $section->{'child_db'}; + + # Name of the child index (index in the same table where the FK is, see + # definition of dict_foreign_struct in include/dict0mem.h, where it is + # called foreign_index, as opposed to referenced_index which is in the + # parent table. This may not be possible to find. + @{$section}{ qw(child_index) } = $fulltext + =~ m/^The index in the foreign key in table is $n$/m; + + @{$section}{ qw(reason) } = $fulltext =~ m/:\s*([^:]+)(?= Constraint:|$)/ms; + $section->{'reason'} =~ s/\s+/ /g + if $section->{'reason'}; + + # Certain data may not be present. Make them '' if not present. + map { $section->{$_} ||= "" } + qw(child_index fk_name col_name parent_table parent_col); +} + +# see source file row/row0ins.c +sub parse_fk_transaction_error { + my ( $section, $complete, $debug, $fulltext, $full ) = @_; + + # Parse the txn info out + my ( $txn ) = $fulltext + =~ m/Transaction:\n(TRANSACTION.*)\nForeign key constraint fails/s; + if ( $txn ) { + $section->{'txn'} = parse_tx_text( $txn, $complete, $debug, $full ); + } + + # Parse the parent/child table and index info out. There are two types: an + # update or a delete of a parent record leaves a child orphaned + # (row_ins_foreign_report_err), and an insert or update of a child record has + # no matching parent record (row_ins_foreign_report_add_err). + + @{$section}{ qw(reason child_db child_table) } + = $fulltext =~ m{^(Foreign key constraint fails for table `(.*)/(.*)`:)$}m; + + @{$section}{ qw(fk_name col_name parent_db parent_table parent_col) } + = $fulltext + =~ m/CONSTRAINT `$n` FOREIGN KEY \(`$n`\) REFERENCES (?:`$n`\.)?`$n` \(`$n`\)/; + $section->{'parent_db'} ||= $section->{'child_db'}; + + # Special case, which I don't know how to trigger, but see + # innobase/row/row0ins.c row_ins_check_foreign_constraint + if ( $fulltext =~ m/ibd file does not currently exist!/ ) { + my ( $attempted_op, $index, $records ) + = $fulltext =~ m/^Trying to (add to index) `$n` tuple:\n(.*))?/sm; + $section->{'child_index'} = $index; + $section->{'attempted_op'} = $attempted_op || ''; + if ( $records && $full ) { + ( $section->{'records'} ) + = parse_innodb_record_dump( $records, $complete, $debug ); + } + @{$section}{qw(parent_db parent_table)} + =~ m/^But the parent table `$n`\.`$n`$/m; + } + else { + my ( $attempted_op, $which, $index ) + = $fulltext =~ m/^Trying to ([\w ]*) in (child|parent) table, in index `$n` tuple:$/m; + if ( $which ) { + $section->{$which . '_index'} = $index; + $section->{'attempted_op'} = $attempted_op || ''; + + # Parse out the related records in the other table. + my ( $search_index, $records ); + if ( $which eq 'child' ) { + ( $search_index, $records ) = $fulltext + =~ m/^But in parent table [^,]*, in index `$n`,\nthe closest match we can find is record:\n(.*)/ms; + $section->{'parent_index'} = $search_index; + } + else { + ( $search_index, $records ) = $fulltext + =~ m/^But in child table [^,]*, in index `$n`, (?:the record is not available|there is a record:\n(.*))?/ms; + $section->{'child_index'} = $search_index; + } + if ( $records && $full ) { + $section->{'records'} + = parse_innodb_record_dump( $records, $complete, $debug ); + } + else { + $section->{'records'} = ''; + } + } + } + + # Parse out the tuple trying to be updated, deleted or inserted. + my ( $trigger ) = $fulltext =~ m/^(DATA TUPLE: \d+ fields;\n.*)$/m; + if ( $trigger ) { + $section->{'trigger'} = parse_innodb_record_dump( $trigger, $complete, $debug ); + } + + # Certain data may not be present. Make them '' if not present. + map { $section->{$_} ||= "" } + qw(child_index fk_name col_name parent_table parent_col); +} + +# There are new-style and old-style record formats. See rem/rem0rec.c +# TODO: write some tests for this +sub parse_innodb_record_dump { + my ( $dump, $complete, $debug ) = @_; + return undef unless $dump; + + my $result = {}; + + if ( $dump =~ m/PHYSICAL RECORD/ ) { + my $style = $dump =~ m/compact format/ ? 'new' : 'old'; + $result->{'style'} = $style; + + # This is a new-style record. + if ( $style eq 'new' ) { + @{$result}{qw( heap_no type num_fields info_bits )} + = $dump + =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; compact format; info bits $d$/m; + } + + # OK, it's old-style. Unfortunately there are variations here too. + elsif ( $dump =~ m/-byte offs / ) { + # Older-old style. + @{$result}{qw( heap_no type num_fields byte_offset info_bits )} + = $dump + =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; $d-byte offs [A-Z]+; info bits $d$/m; + if ( $dump !~ m/-byte offs TRUE/ ) { + $result->{'byte_offset'} = 0; + } + } + else { + # Newer-old style. + @{$result}{qw( heap_no type num_fields byte_offset info_bits )} + = $dump + =~ m/^(?:Record lock, heap no $d )?([A-Z ]+): n_fields $d; $d-byte offsets; info bits $d$/m; + } + + } + else { + $result->{'style'} = 'tuple'; + @{$result}{qw( type num_fields )} + = $dump =~ m/^(DATA TUPLE): $d fields;$/m; + } + + # Fill in default values for things that couldn't be parsed. + map { $result->{$_} ||= 0 } + qw(heap_no num_fields byte_offset info_bits); + map { $result->{$_} ||= '' } + qw(style type ); + + my @fields = $dump =~ m/ (\d+:.*?;?);(?=$| \d+:)/gm; + $result->{'fields'} = [ map { parse_field($_, $complete, $debug ) } @fields ]; + + return $result; +} + +# New/old-style applies here. See rem/rem0rec.c +# $text should not include the leading space or the second trailing semicolon. +sub parse_field { + my ( $text, $complete, $debug ) = @_; + + # Sample fields: + # '4: SQL NULL, size 4 ' + # '1: len 6; hex 000000005601; asc V ;' + # '6: SQL NULL' + # '5: len 30; hex 687474703a2f2f7777772e737765657477617465722e636f6d2f73746f72; asc http://www.sweetwater.com/stor;...(truncated)' + my ( $id, $nullsize, $len, $hex, $asc, $truncated ); + ( $id, $nullsize ) = $text =~ m/^$d: SQL NULL, size $d $/; + if ( !defined($id) ) { + ( $id ) = $text =~ m/^$d: SQL NULL$/; + } + if ( !defined($id) ) { + ( $id, $len, $hex, $asc, $truncated ) + = $text =~ m/^$d: len $d; hex $h; asc (.*);(\.\.\.\(truncated\))?$/; + } + + die "Could not parse this field: '$text'" unless defined $id; + return { + id => $id, + len => defined($len) ? $len : defined($nullsize) ? $nullsize : 0, + 'hex' => defined($hex) ? $hex : '', + asc => defined($asc) ? $asc : '', + trunc => $truncated ? 1 : 0, + }; + +} + +sub parse_dl_section { + my ( $dl, $complete, $debug, $full ) = @_; + return unless $dl; + my $fulltext = $dl->{'fulltext'}; + return 0 unless $fulltext; + + my ( $ts ) = $fulltext =~ m/^$s$/m; + return 0 unless $ts; + + $dl->{'ts'} = [ parse_innodb_timestamp( $ts ) ]; + $dl->{'timestring'} = ts_to_string($dl->{'ts'}); + $dl->{'txns'} = {}; + + my @sections + = $fulltext + =~ m{ + ^\*{3}\s([^\n]*) # *** (1) WAITING FOR THIS... + (.*?) # Followed by anything, non-greedy + (?=(?:^\*{3})|\z) # Followed by another three stars or EOF + }gmsx; + + + # Loop through each section. There are no assumptions about how many + # there are, who holds and wants what locks, and who gets rolled back. + while ( my ($header, $body) = splice(@sections, 0, 2) ) { + my ( $txn_id, $what ) = $header =~ m/^\($d\) (.*):$/; + next unless $txn_id; + $dl->{'txns'}->{$txn_id} ||= {}; + my $txn = $dl->{'txns'}->{$txn_id}; + + if ( $what eq 'TRANSACTION' ) { + $txn->{'tx'} = parse_tx_text( $body, $complete, $debug, $full ); + } + else { + push @{$txn->{'locks'}}, parse_innodb_record_locks( $body, $complete, $debug, $full ); + } + } + + @{ $dl }{ qw(rolled_back) } + = $fulltext =~ m/^\*\*\* WE ROLL BACK TRANSACTION \($d\)$/m; + + # Make sure certain values aren't undef + map { $dl->{$_} ||= '' } qw(rolled_back); + + delete $dl->{'fulltext'} unless $debug; + return 1; +} + +sub parse_innodb_record_locks { + my ( $text, $complete, $debug, $full ) = @_; + my @result; + + foreach my $lock ( $text =~ m/(^(?:RECORD|TABLE) LOCKS?.*$)/gm ) { + my $hash = {}; + @{$hash}{ qw(lock_type space_id page_no n_bits index db table txn_id lock_mode) } + = $lock + =~ m{^(RECORD|TABLE) LOCKS? (?:space id $d page no $d n bits $d index `?$n`? of )?table `$n(?:/|`\.`)$n` trx id $t lock.mode (\S+)}m; + ( $hash->{'special'} ) + = $lock =~ m/^(?:RECORD|TABLE) .*? locks (rec but not gap|gap before rec)/m; + $hash->{'insert_intention'} + = $lock =~ m/^(?:RECORD|TABLE) .*? insert intention/m ? 1 : 0; + $hash->{'waiting'} + = $lock =~ m/^(?:RECORD|TABLE) .*? waiting/m ? 1 : 0; + + # Some things may not be in the text, so make sure they are not + # undef. + map { $hash->{$_} ||= 0 } qw(n_bits page_no space_id); + map { $hash->{$_} ||= "" } qw(index special); + push @result, $hash; + } + + return @result; +} + +sub parse_tx_text { + my ( $txn, $complete, $debug, $full ) = @_; + + my ( $txn_id, $txn_status, $active_secs, $proc_no, $os_thread_id ) + = $txn + =~ m/^(?:---)?TRANSACTION $t, (\D*?)(?: $d sec)?, (?:process no $d, )?OS thread id $d/m; + my ( $thread_status, $thread_decl_inside ) + = $txn + =~ m/OS thread id \d+(?: ([^,]+?))?(?:, thread declared inside InnoDB $d)?$/m; + + # Parsing the line that begins 'MySQL thread id' is complicated. The only + # thing always in the line is the thread and query id. See function + # innobase_mysql_print_thd in InnoDB source file sql/ha_innodb.cc. + my ( $thread_line ) = $txn =~ m/^(MySQL thread id .*)$/m; + my ( $mysql_thread_id, $query_id, $hostname, $ip, $user, $query_status ); + + if ( $thread_line ) { + # These parts can always be gotten. + ( $mysql_thread_id, $query_id ) = $thread_line =~ m/^MySQL thread id $d, query id $d/m; + + # If it's a master/slave thread, "Has (read|sent) all" may be the thread's + # proc_info. In these cases, there won't be any host/ip/user info + ( $query_status ) = $thread_line =~ m/(Has (?:read|sent) all .*$)/m; + if ( defined($query_status) ) { + $user = 'system user'; + } + + # It may be the case that the query id is the last thing in the line. + elsif ( $thread_line =~ m/query id \d+ / ) { + # The IP address is the only non-word thing left, so it's the most + # useful marker for where I have to start guessing. + ( $hostname, $ip ) = $thread_line =~ m/query id \d+(?: ([A-Za-z]\S+))? $i/m; + if ( defined $ip ) { + ( $user, $query_status ) = $thread_line =~ m/$ip $w(?: (.*))?$/; + } + else { # OK, there wasn't an IP address. + # There might not be ANYTHING except the query status. + ( $query_status ) = $thread_line =~ m/query id \d+ (.*)$/; + if ( $query_status !~ m/^\w+ing/ && !exists($is_proc_info{$query_status}) ) { + # The remaining tokens are, in order: hostname, user, query_status. + # It's basically impossible to know which is which. + ( $hostname, $user, $query_status ) = $thread_line + =~ m/query id \d+(?: ([A-Za-z]\S+))?(?: $w(?: (.*))?)?$/m; + } + else { + $user = 'system user'; + } + } + } + } + + my ( $lock_wait_status, $lock_structs, $heap_size, $row_locks, $undo_log_entries ) + = $txn + =~ m/^(?:(\D*) )?$d lock struct\(s\), heap size $d(?:, $d row lock\(s\))?(?:, undo log entries $d)?$/m; + my ( $lock_wait_time ) + = $txn + =~ m/^------- TRX HAS BEEN WAITING $d SEC/m; + + my $locks; + # If the transaction has locks, grab the locks. + if ( $txn =~ m/^TABLE LOCK|RECORD LOCKS/ ) { + $locks = [parse_innodb_record_locks($txn, $complete, $debug, $full)]; + } + + my ( $tables_in_use, $tables_locked ) + = $txn + =~ m/^mysql tables in use $d, locked $d$/m; + my ( $txn_doesnt_see_ge, $txn_sees_lt ) + = $txn + =~ m/^Trx read view will not see trx with id >= $t, sees < $t$/m; + my $has_read_view = defined($txn_doesnt_see_ge); + # Only a certain number of bytes of the query text are included here, at least + # under some circumstances. Some versions include 300, some 600. + my ( $query_text ) + = $txn + =~ m{ + ^MySQL\sthread\sid\s[^\n]+\n # This comes before the query text + (.*?) # The query text + (?= # Followed by any of... + ^Trx\sread\sview + |^-------\sTRX\sHAS\sBEEN\sWAITING + |^TABLE\sLOCK + |^RECORD\sLOCKS\sspace\sid + |^(?:---)?TRANSACTION + |^\*\*\*\s\(\d\) + |\Z + ) + }xms; + if ( $query_text ) { + $query_text =~ s/\s+$//; + } + else { + $query_text = ''; + } + + my %stuff = ( + active_secs => $active_secs, + has_read_view => $has_read_view, + heap_size => $heap_size, + hostname => $hostname, + ip => $ip, + lock_structs => $lock_structs, + lock_wait_status => $lock_wait_status, + lock_wait_time => $lock_wait_time, + mysql_thread_id => $mysql_thread_id, + os_thread_id => $os_thread_id, + proc_no => $proc_no, + query_id => $query_id, + query_status => $query_status, + query_text => $query_text, + row_locks => $row_locks, + tables_in_use => $tables_in_use, + tables_locked => $tables_locked, + thread_decl_inside => $thread_decl_inside, + thread_status => $thread_status, + txn_doesnt_see_ge => $txn_doesnt_see_ge, + txn_id => $txn_id, + txn_sees_lt => $txn_sees_lt, + txn_status => $txn_status, + undo_log_entries => $undo_log_entries, + user => $user, + ); + $stuff{'fulltext'} = $txn if $debug; + $stuff{'locks'} = $locks if $locks; + + # Some things may not be in the txn text, so make sure they are not + # undef. + map { $stuff{$_} ||= 0 } qw(active_secs heap_size lock_structs + tables_in_use undo_log_entries tables_locked has_read_view + thread_decl_inside lock_wait_time proc_no row_locks); + map { $stuff{$_} ||= "" } qw(thread_status txn_doesnt_see_ge + txn_sees_lt query_status ip query_text lock_wait_status user); + $stuff{'hostname'} ||= $stuff{'ip'}; + + return \%stuff; +} + +sub parse_tx_section { + my ( $section, $complete, $debug, $full ) = @_; + return unless $section && $section->{'fulltext'}; + my $fulltext = $section->{'fulltext'}; + $section->{'transactions'} = []; + + # Handle the individual transactions + my @transactions = $fulltext =~ m/(---TRANSACTION \d.*?)(?=\n---TRANSACTION|$)/gs; + foreach my $txn ( @transactions ) { + my $stuff = parse_tx_text( $txn, $complete, $debug, $full ); + delete $stuff->{'fulltext'} unless $debug; + push @{$section->{'transactions'}}, $stuff; + } + + # Handle the general info + @{$section}{ 'trx_id_counter' } + = $fulltext =~ m/^Trx id counter $t$/m; + @{$section}{ 'purge_done_for', 'purge_undo_for' } + = $fulltext =~ m/^Purge done for trx's n:o < $t undo n:o < $t$/m; + @{$section}{ 'history_list_len' } # This isn't present in some 4.x versions + = $fulltext =~ m/^History list length $d$/m; + @{$section}{ 'num_lock_structs' } + = $fulltext =~ m/^Total number of lock structs in row lock hash table $d$/m; + @{$section}{ 'is_truncated' } + = $fulltext =~ m/^\.\.\. truncated\.\.\.$/m ? 1 : 0; + + # Fill in things that might not be present + foreach ( qw(history_list_len) ) { + $section->{$_} ||= 0; + } + + delete $section->{'fulltext'} unless $debug; + return 1; +} + +# I've read the source for this section. +sub parse_ro_section { + my ( $section, $complete, $debug, $full ) = @_; + return unless $section && $section->{'fulltext'}; + my $fulltext = $section->{'fulltext'}; + + # Grab the info + @{$section}{ 'queries_inside', 'queries_in_queue' } + = $fulltext =~ m/^$d queries inside InnoDB, $d queries in queue$/m; + ( $section->{ 'read_views_open' } ) + = $fulltext =~ m/^$d read views open inside InnoDB$/m; + ( $section->{ 'n_reserved_extents' } ) + = $fulltext =~ m/^$d tablespace extents now reserved for B-tree/m; + @{$section}{ 'main_thread_proc_no', 'main_thread_id', 'main_thread_state' } + = $fulltext =~ m/^Main thread (?:process no. $d, )?id $d, state: (.*)$/m; + @{$section}{ 'num_rows_ins', 'num_rows_upd', 'num_rows_del', 'num_rows_read' } + = $fulltext =~ m/^Number of rows inserted $d, updated $d, deleted $d, read $d$/m; + @{$section}{ 'ins_sec', 'upd_sec', 'del_sec', 'read_sec' } + = $fulltext =~ m#^$f inserts/s, $f updates/s, $f deletes/s, $f reads/s$#m; + $section->{'main_thread_proc_no'} ||= 0; + + map { $section->{$_} ||= 0 } qw(read_views_open n_reserved_extents); + delete $section->{'fulltext'} unless $debug; + return 1; +} + +sub parse_lg_section { + my ( $section, $complete, $debug, $full ) = @_; + return unless $section; + my $fulltext = $section->{'fulltext'}; + + # Grab the info + ( $section->{ 'log_seq_no' } ) + = $fulltext =~ m/Log sequence number \s*(\d.*)$/m; + ( $section->{ 'log_flushed_to' } ) + = $fulltext =~ m/Log flushed up to \s*(\d.*)$/m; + ( $section->{ 'last_chkp' } ) + = $fulltext =~ m/Last checkpoint at \s*(\d.*)$/m; + @{$section}{ 'pending_log_writes', 'pending_chkp_writes' } + = $fulltext =~ m/$d pending log writes, $d pending chkp writes/; + @{$section}{ 'log_ios_done', 'log_ios_s' } + = $fulltext =~ m#$d log i/o's done, $f log i/o's/second#; + + delete $section->{'fulltext'} unless $debug; + return 1; +} + +sub parse_ib_section { + my ( $section, $complete, $debug, $full ) = @_; + return unless $section && $section->{'fulltext'}; + my $fulltext = $section->{'fulltext'}; + + # Some servers will output ibuf information for tablespace 0, as though there + # might be many tablespaces with insert buffers. (In practice I believe + # the source code shows there will only ever be one). I have to parse both + # cases here, but I assume there will only be one. + @{$section}{ 'size', 'free_list_len', 'seg_size' } + = $fulltext =~ m/^Ibuf(?: for space 0)?: size $d, free list len $d, seg size $d,$/m; + @{$section}{ 'inserts', 'merged_recs', 'merges' } + = $fulltext =~ m/^$d inserts, $d merged recs, $d merges$/m; + + @{$section}{ 'hash_table_size', 'used_cells', 'bufs_in_node_heap' } + = $fulltext =~ m/^Hash table size $d, used cells $d, node heap has $d buffer\(s\)$/m; + @{$section}{ 'hash_searches_s', 'non_hash_searches_s' } + = $fulltext =~ m{^$f hash searches/s, $f non-hash searches/s$}m; + + delete $section->{'fulltext'} unless $debug; + return 1; +} + +sub parse_wait_array { + my ( $text, $complete, $debug, $full ) = @_; + my %result; + + @result{ qw(thread waited_at_filename waited_at_line waited_secs) } + = $text =~ m/^--Thread $d has waited at $fl for $f seconds/m; + + # Depending on whether it's a SYNC_MUTEX,RW_LOCK_EX,RW_LOCK_SHARED, + # there will be different text output + if ( $text =~ m/^Mutex at/m ) { + $result{'request_type'} = 'M'; + @result{ qw( lock_mem_addr lock_cfile_name lock_cline lock_var) } + = $text =~ m/^Mutex at $h created file $fl, lock var $d$/m; + @result{ qw( waiters_flag )} + = $text =~ m/^waiters flag $d$/m; + } + else { + @result{ qw( request_type lock_mem_addr lock_cfile_name lock_cline) } + = $text =~ m/^(.)-lock on RW-latch at $h created in file $fl$/m; + @result{ qw( writer_thread writer_lock_mode ) } + = $text =~ m/^a writer \(thread id $d\) has reserved it in mode (.*)$/m; + @result{ qw( num_readers waiters_flag )} + = $text =~ m/^number of readers $d, waiters flag $d$/m; + @result{ qw(last_s_file_name last_s_line ) } + = $text =~ m/Last time read locked in file $fl$/m; + @result{ qw(last_x_file_name last_x_line ) } + = $text =~ m/Last time write locked in file $fl$/m; + } + + $result{'cell_waiting'} = $text =~ m/^wait has ended$/m ? 0 : 1; + $result{'cell_event_set'} = $text =~ m/^wait is ending$/m ? 1 : 0; + + # Because there are two code paths, some things won't get set. + map { $result{$_} ||= '' } + qw(last_s_file_name last_x_file_name writer_lock_mode); + map { $result{$_} ||= 0 } + qw(num_readers lock_var last_s_line last_x_line writer_thread); + + return \%result; +} + +sub parse_sm_section { + my ( $section, $complete, $debug, $full ) = @_; + return 0 unless $section && $section->{'fulltext'}; + my $fulltext = $section->{'fulltext'}; + + # Grab the info + @{$section}{ 'reservation_count', 'signal_count' } + = $fulltext =~ m/^OS WAIT ARRAY INFO: reservation count $d, signal count $d$/m; + @{$section}{ 'mutex_spin_waits', 'mutex_spin_rounds', 'mutex_os_waits' } + = $fulltext =~ m/^Mutex spin waits $d, rounds $d, OS waits $d$/m; + @{$section}{ 'rw_shared_spins', 'rw_shared_os_waits', 'rw_excl_spins', 'rw_excl_os_waits' } + = $fulltext =~ m/^RW-shared spins $d, OS waits $d; RW-excl spins $d, OS waits $d$/m; + + # Look for info on waits. + my @waits = $fulltext =~ m/^(--Thread.*?)^(?=Mutex spin|--Thread)/gms; + $section->{'waits'} = [ map { parse_wait_array($_, $complete, $debug) } @waits ]; + $section->{'wait_array_size'} = scalar(@waits); + + delete $section->{'fulltext'} unless $debug; + return 1; +} + +# I've read the source for this section. +sub parse_bp_section { + my ( $section, $complete, $debug, $full ) = @_; + return unless $section && $section->{'fulltext'}; + my $fulltext = $section->{'fulltext'}; + + # Grab the info + @{$section}{ 'total_mem_alloc', 'add_pool_alloc' } + = $fulltext =~ m/^Total memory allocated $d; in additional pool allocated $d$/m; + @{$section}{'dict_mem_alloc'} = $fulltext =~ m/Dictionary memory allocated $d/; + @{$section}{'awe_mem_alloc'} = $fulltext =~ m/$d MB of AWE memory/; + @{$section}{'buf_pool_size'} = $fulltext =~ m/^Buffer pool size\s*$d$/m; + @{$section}{'buf_free'} = $fulltext =~ m/^Free buffers\s*$d$/m; + @{$section}{'pages_total'} = $fulltext =~ m/^Database pages\s*$d$/m; + @{$section}{'pages_modified'} = $fulltext =~ m/^Modified db pages\s*$d$/m; + @{$section}{'pages_read', 'pages_created', 'pages_written'} + = $fulltext =~ m/^Pages read $d, created $d, written $d$/m; + @{$section}{'page_reads_sec', 'page_creates_sec', 'page_writes_sec'} + = $fulltext =~ m{^$f reads/s, $f creates/s, $f writes/s$}m; + @{$section}{'buf_pool_hits', 'buf_pool_reads'} + = $fulltext =~ m{Buffer pool hit rate $d / $d$}m; + if ($fulltext =~ m/^No buffer pool page gets since the last printout$/m) { + @{$section}{'buf_pool_hits', 'buf_pool_reads'} = (0, 0); + @{$section}{'buf_pool_hit_rate'} = '--'; + } + else { + @{$section}{'buf_pool_hit_rate'} + = $fulltext =~ m{Buffer pool hit rate (\d+ / \d+)$}m; + } + @{$section}{'reads_pending'} = $fulltext =~ m/^Pending reads $d/m; + @{$section}{'writes_pending_lru', 'writes_pending_flush_list', 'writes_pending_single_page' } + = $fulltext =~ m/^Pending writes: LRU $d, flush list $d, single page $d$/m; + + map { $section->{$_} ||= 0 } + qw(writes_pending_lru writes_pending_flush_list writes_pending_single_page + awe_mem_alloc dict_mem_alloc); + @{$section}{'writes_pending'} = List::Util::sum( + @{$section}{ qw(writes_pending_lru writes_pending_flush_list writes_pending_single_page) }); + + delete $section->{'fulltext'} unless $debug; + return 1; +} + +# I've read the source for this. +sub parse_io_section { + my ( $section, $complete, $debug, $full ) = @_; + return unless $section && $section->{'fulltext'}; + my $fulltext = $section->{'fulltext'}; + $section->{'threads'} = {}; + + # Grab the I/O thread info + my @threads = $fulltext =~ m<^(I/O thread \d+ .*)$>gm; + foreach my $thread (@threads) { + my ( $tid, $state, $purpose, $event_set ) + = $thread =~ m{I/O thread $d state: (.+?) \((.*)\)(?: ev set)?$}m; + if ( defined $tid ) { + $section->{'threads'}->{$tid} = { + thread => $tid, + state => $state, + purpose => $purpose, + event_set => $event_set ? 1 : 0, + }; + } + } + + # Grab the reads/writes/flushes info + @{$section}{ 'pending_normal_aio_reads', 'pending_aio_writes' } + = $fulltext =~ m/^Pending normal aio reads: $d, aio writes: $d,$/m; + @{$section}{ 'pending_ibuf_aio_reads', 'pending_log_ios', 'pending_sync_ios' } + = $fulltext =~ m{^ ibuf aio reads: $d, log i/o's: $d, sync i/o's: $d$}m; + @{$section}{ 'flush_type', 'pending_log_flushes', 'pending_buffer_pool_flushes' } + = $fulltext =~ m/^Pending flushes \($w\) log: $d; buffer pool: $d$/m; + @{$section}{ 'os_file_reads', 'os_file_writes', 'os_fsyncs' } + = $fulltext =~ m/^$d OS file reads, $d OS file writes, $d OS fsyncs$/m; + @{$section}{ 'reads_s', 'avg_bytes_s', 'writes_s', 'fsyncs_s' } + = $fulltext =~ m{^$f reads/s, $d avg bytes/read, $f writes/s, $f fsyncs/s$}m; + @{$section}{ 'pending_preads', 'pending_pwrites' } + = $fulltext =~ m/$d pending preads, $d pending pwrites$/m; + @{$section}{ 'pending_preads', 'pending_pwrites' } = (0, 0) + unless defined($section->{'pending_preads'}); + + delete $section->{'fulltext'} unless $debug; + return 1; +} + +sub _debug { + my ( $debug, $msg ) = @_; + if ( $debug ) { + die $msg; + } + else { + warn $msg; + } + return 1; +} + +1; + +# end_of_package +# ############################################################################ +# Perldoc section. I put this last as per the Dog book. +# ############################################################################ +=pod + +=head1 NAME + +InnoDBParser - Parse InnoDB monitor text. + +=head1 DESCRIPTION + +InnoDBParser tries to parse the output of the InnoDB monitor. One way to get +this output is to connect to a MySQL server and issue the command SHOW ENGINE +INNODB STATUS (omit 'ENGINE' on earlier versions of MySQL). The goal is to +turn text into data that something else (e.g. innotop) can use. + +The output comes from all over, but the place to start in the source is +innobase/srv/srv0srv.c. + +=head1 SYNOPSIS + + use InnoDBParser; + use DBI; + + # Get the status text. + my $dbh = DBI->connect( + "DBI::mysql:test;host=localhost", + 'user', + 'password' + ); + my $query = 'SHOW /*!5 ENGINE */ INNODB STATUS'; + my $text = $dbh->selectcol_arrayref($query)->[0]; + + # 1 or 0 + my $debug = 1; + + # Choose sections of the monitor text you want. Possible values: + # TRANSACTIONS => tx + # BUFFER POOL AND MEMORY => bp + # SEMAPHORES => sm + # LOG => lg + # ROW OPERATIONS => ro + # INSERT BUFFER AND ADAPTIVE HASH INDEX => ib + # FILE I/O => io + # LATEST DETECTED DEADLOCK => dl + # LATEST FOREIGN KEY ERROR => fk + + my $required_sections = { + tx => 1, + }; + + # Parse the status text. + my $parser = InnoDBParser->new; + $innodb_status = $parser->parse_status_text( + $text, + $debug, + # Omit the following parameter to get all sections. + $required_sections, + ); + +=head1 COPYRIGHT, LICENSE AND WARRANTY + +This package is copyright (c) 2006 Baron Schwartz, baron at xaprb dot com. +Feedback and improvements are gratefully received. + +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. + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation, version 2; OR the Perl Artistic License. On UNIX and similar +systems, you can issue `man perlgpl' or `man perlartistic' to read these +licenses. + +You should have received a copy of the GNU General Public License along with +this program; if not, write to the Free Software Foundation, Inc., 59 Temple +Place, Suite 330, Boston, MA 02111-1307 USA + +=head1 AUTHOR + +Baron Schwartz, baron at xaprb dot com. + +=head1 BUGS + +None known, but I bet there are some. The InnoDB monitor text wasn't really +designed to be parsable. + +=head1 SEE ALSO + +innotop - a program that can format the parsed status information for humans +to read and enjoy. + +=cut --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-common.dirs +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-common.dirs @@ -0,0 +1 @@ +etc/mysql/conf.d/ --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.logcheck.ignore.workstation +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.logcheck.ignore.workstation @@ -0,0 +1,32 @@ +/etc/init.d/mysql\[[0-9]+\]: [0-9]+ processes alive and '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ +/etc/init.d/mysql\[[0-9]+\]: Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists\!$ +/etc/init.d/mysql\[[0-9]+\]: '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ +/etc/mysql/debian-start\[[0-9]+\]: Checking for crashed MySQL tables\.$ +mysqld\[[0-9]+\]: ?$ +mysqld\[[0-9]+\]: .*InnoDB: Shutdown completed +mysqld\[[0-9]+\]: .*InnoDB: Started; +mysqld\[[0-9]+\]: .*InnoDB: Starting shutdown\.\.\.$ +mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Normal shutdown$ +mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: ready for connections\.$ +mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Shutdown complete$ +mysqld\[[0-9]+\]: Support MySQL by buying support/licenses at http://shop.mysql.com$ +mysqld\[[0-9]+\]: /usr/sbin/mysqld: ready for connections\.$ +mysqld\[[0-9]+\]: .*/usr/sbin/mysqld: Shutdown Complete$ +mysqld\[[0-9]+\]: Version: .* socket +mysqld\[[0-9]+\]: Warning: Ignoring user change to 'mysql' because the user was set to 'mysql' earlier on the command line$ +mysqld_safe\[[0-9]+\]: ?$ +mysqld_safe\[[0-9]+\]: able to use the new GRANT command!$ +mysqld_safe\[[0-9]+\]: ended$ +mysqld_safe\[[0-9]+\]: http://www.mysql.com$ +mysqld_safe\[[0-9]+\]: NOTE: If you are upgrading from a MySQL <= 3.22.10 you should run$ +mysqld_safe\[[0-9]+\]: PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !$ +mysqld_safe\[[0-9]+\]: Please report any problems with the /usr/bin/mysqlbug script!$ +mysqld_safe\[[0-9]+\]: See the manual for more instructions.$ +mysqld_safe\[[0-9]+\]: started$ +mysqld_safe\[[0-9]+\]: Support MySQL by buying support/licenses at +mysqld_safe\[[0-9]+\]: The latest information about MySQL is available on the web at$ +mysqld_safe\[[0-9]+\]: the /usr/bin/mysql_fix_privilege_tables. Otherwise you will not be$ +mysqld_safe\[[0-9]+\]: To do so, start the server, then issue the following commands:$ +mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root 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'$ --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/01_MAKEFILES__Docs_Images_Makefile.in.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/01_MAKEFILES__Docs_Images_Makefile.in.dpatch @@ -0,0 +1,776 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01_MAKEFILES__Docs_Makefile.in.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Creates Docs/Makefile.in + +@DPATCH@ + +--- old/Docs/Images/Makefile.in 2005-03-01 02:08:01.877429040 +0100 ++++ new/Docs/Images/Makefile.in 2005-02-28 21:21:24.000000000 +0100 +@@ -0,0 +1,765 @@ ++# Makefile.in generated by automake 1.7.9 from Makefile.am. ++# @configure_input@ ++ ++# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 ++# Free Software Foundation, Inc. ++# This Makefile.in is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY, to the extent permitted by law; without ++# even the implied warranty of MERCHANTABILITY or FITNESS FOR A ++# PARTICULAR PURPOSE. ++ ++@SET_MAKE@ ++ ++# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB ++# ++# 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. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ ++# Process this file with automake to create Makefile.in ++ ++srcdir = @srcdir@ ++top_srcdir = @top_srcdir@ ++VPATH = @srcdir@ ++pkgdatadir = $(datadir)/@PACKAGE@ ++pkglibdir = $(libdir)/@PACKAGE@ ++pkgincludedir = $(includedir)/@PACKAGE@ ++top_builddir = . ++ ++am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd ++INSTALL = @INSTALL@ ++install_sh_DATA = $(install_sh) -c -m 644 ++install_sh_PROGRAM = $(install_sh) -c ++install_sh_SCRIPT = $(install_sh) -c ++INSTALL_HEADER = $(INSTALL_DATA) ++transform = $(program_transform_name) ++NORMAL_INSTALL = : ++PRE_INSTALL = : ++POST_INSTALL = : ++NORMAL_UNINSTALL = : ++PRE_UNINSTALL = : ++POST_UNINSTALL = : ++build_triplet = @build@ ++host_triplet = @host@ ++target_triplet = @target@ ++ACLOCAL = @ACLOCAL@ ++ALLOCA = @ALLOCA@ ++AMDEP_FALSE = @AMDEP_FALSE@ ++AMDEP_TRUE = @AMDEP_TRUE@ ++AMTAR = @AMTAR@ ++AR = @AR@ ++AS = @AS@ ++ASSEMBLER_FALSE = @ASSEMBLER_FALSE@ ++ASSEMBLER_TRUE = @ASSEMBLER_TRUE@ ++ASSEMBLER_sparc32_FALSE = @ASSEMBLER_sparc32_FALSE@ ++ASSEMBLER_sparc32_TRUE = @ASSEMBLER_sparc32_TRUE@ ++ASSEMBLER_sparc64_FALSE = @ASSEMBLER_sparc64_FALSE@ ++ASSEMBLER_sparc64_TRUE = @ASSEMBLER_sparc64_TRUE@ ++ASSEMBLER_x86_FALSE = @ASSEMBLER_x86_FALSE@ ++ASSEMBLER_x86_TRUE = @ASSEMBLER_x86_TRUE@ ++AUTOCONF = @AUTOCONF@ ++AUTOHEADER = @AUTOHEADER@ ++AUTOMAKE = @AUTOMAKE@ ++AVAILABLE_LANGUAGES = @AVAILABLE_LANGUAGES@ ++AVAILABLE_LANGUAGES_ERRORS = @AVAILABLE_LANGUAGES_ERRORS@ ++AWK = @AWK@ ++CC = @CC@ ++CCAS = @CCAS@ ++CCASFLAGS = @CCASFLAGS@ ++CCDEPMODE = @CCDEPMODE@ ++CC_VERSION = @CC_VERSION@ ++CFLAGS = @CFLAGS@ ++CHARSETS_NEED_SOURCE = @CHARSETS_NEED_SOURCE@ ++CHARSET_OBJS = @CHARSET_OBJS@ ++CHARSET_SRCS = @CHARSET_SRCS@ ++CHECK_PID = @CHECK_PID@ ++CHMOD = @CHMOD@ ++CLIENT_EXTRA_LDFLAGS = @CLIENT_EXTRA_LDFLAGS@ ++CLIENT_LIBS = @CLIENT_LIBS@ ++CMP = @CMP@ ++COMPILATION_COMMENT = @COMPILATION_COMMENT@ ++COMPILE_PSTACK_FALSE = @COMPILE_PSTACK_FALSE@ ++COMPILE_PSTACK_TRUE = @COMPILE_PSTACK_TRUE@ ++CONF_COMMAND = @CONF_COMMAND@ ++CP = @CP@ ++CPP = @CPP@ ++CPPFLAGS = @CPPFLAGS@ ++CXX = @CXX@ ++CXXCPP = @CXXCPP@ ++CXXDEPMODE = @CXXDEPMODE@ ++CXXFLAGS = @CXXFLAGS@ ++CXXLDFLAGS = @CXXLDFLAGS@ ++CXX_VERSION = @CXX_VERSION@ ++CYGPATH_W = @CYGPATH_W@ ++DEFS = @DEFS@ ++DEPDIR = @DEPDIR@ ++DOT_FRM_VERSION = @DOT_FRM_VERSION@ ++DVIS = @DVIS@ ++ECHO = @ECHO@ ++ECHO_C = @ECHO_C@ ++ECHO_N = @ECHO_N@ ++ECHO_T = @ECHO_T@ ++EGREP = @EGREP@ ++EXEEXT = @EXEEXT@ ++F77 = @F77@ ++FFLAGS = @FFLAGS@ ++FIND_PROC = @FIND_PROC@ ++GETCONF = @GETCONF@ ++GXX = @GXX@ ++HAVE_NETWARE_FALSE = @HAVE_NETWARE_FALSE@ ++HAVE_NETWARE_TRUE = @HAVE_NETWARE_TRUE@ ++HOSTNAME = @HOSTNAME@ ++INSTALL_DATA = @INSTALL_DATA@ ++INSTALL_PROGRAM = @INSTALL_PROGRAM@ ++INSTALL_SCRIPT = @INSTALL_SCRIPT@ ++INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ ++IS_LINUX = @IS_LINUX@ ++KILL = @KILL@ ++LD = @LD@ ++LDFLAGS = @LDFLAGS@ ++LIBDL = @LIBDL@ ++LIBOBJS = @LIBOBJS@ ++LIBS = @LIBS@ ++LIBTOOL = @LIBTOOL@ ++LIB_EXTRA_CCFLAGS = @LIB_EXTRA_CCFLAGS@ ++LM_CFLAGS = @LM_CFLAGS@ ++LN = @LN@ ++LN_CP_F = @LN_CP_F@ ++LN_S = @LN_S@ ++LOCAL_FALSE = @LOCAL_FALSE@ ++LOCAL_TRUE = @LOCAL_TRUE@ ++LTLIBOBJS = @LTLIBOBJS@ ++MACHINE_TYPE = @MACHINE_TYPE@ ++MAINT = @MAINT@ ++MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ ++MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ ++MAKEINFO = @MAKEINFO@ ++MAKE_BINARY_DISTRIBUTION_OPTIONS = @MAKE_BINARY_DISTRIBUTION_OPTIONS@ ++MAKE_SHELL = @MAKE_SHELL@ ++MT_INCLUDES = @MT_INCLUDES@ ++MT_LD_ADD = @MT_LD_ADD@ ++MV = @MV@ ++MYSQLD_DEFAULT_SWITCHES = @MYSQLD_DEFAULT_SWITCHES@ ++MYSQLD_EXTRA_LDFLAGS = @MYSQLD_EXTRA_LDFLAGS@ ++MYSQLD_USER = @MYSQLD_USER@ ++MYSQL_BASE_VERSION = @MYSQL_BASE_VERSION@ ++MYSQL_NO_DASH_VERSION = @MYSQL_NO_DASH_VERSION@ ++MYSQL_SERVER_SUFFIX = @MYSQL_SERVER_SUFFIX@ ++MYSQL_TCP_PORT = @MYSQL_TCP_PORT@ ++MYSQL_TCP_PORT_DEFAULT = @MYSQL_TCP_PORT_DEFAULT@ ++MYSQL_UNIX_ADDR = @MYSQL_UNIX_ADDR@ ++MYSQL_VERSION_ID = @MYSQL_VERSION_ID@ ++NOINST_LDFLAGS = @NOINST_LDFLAGS@ ++OBJEXT = @OBJEXT@ ++PACKAGE = @PACKAGE@ ++PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ ++PACKAGE_NAME = @PACKAGE_NAME@ ++PACKAGE_STRING = @PACKAGE_STRING@ ++PACKAGE_TARNAME = @PACKAGE_TARNAME@ ++PACKAGE_VERSION = @PACKAGE_VERSION@ ++PATH_SEPARATOR = @PATH_SEPARATOR@ ++PDFMANUAL = @PDFMANUAL@ ++PERL = @PERL@ ++PERL5 = @PERL5@ ++PROTOCOL_VERSION = @PROTOCOL_VERSION@ ++PS = @PS@ ++RANLIB = @RANLIB@ ++RM = @RM@ ++SAVE_ASFLAGS = @SAVE_ASFLAGS@ ++SAVE_CFLAGS = @SAVE_CFLAGS@ ++SAVE_CXXFLAGS = @SAVE_CXXFLAGS@ ++SAVE_CXXLDFLAGS = @SAVE_CXXLDFLAGS@ ++SAVE_LDFLAGS = @SAVE_LDFLAGS@ ++SED = @SED@ ++SET_MAKE = @SET_MAKE@ ++SHARED_LIB_VERSION = @SHARED_LIB_VERSION@ ++SHELL = @SHELL@ ++STRIP = @STRIP@ ++SYSTEM_TYPE = @SYSTEM_TYPE@ ++TAR = @TAR@ ++TERMCAP_LIB = @TERMCAP_LIB@ ++THREAD_LOBJECTS = @THREAD_LOBJECTS@ ++THREAD_LPROGRAMS = @THREAD_LPROGRAMS@ ++VERSION = @VERSION@ ++WRAPLIBS = @WRAPLIBS@ ++YACC = @YACC@ ++ac_ct_AR = @ac_ct_AR@ ++ac_ct_CC = @ac_ct_CC@ ++ac_ct_CXX = @ac_ct_CXX@ ++ac_ct_F77 = @ac_ct_F77@ ++ac_ct_GETCONF = @ac_ct_GETCONF@ ++ac_ct_RANLIB = @ac_ct_RANLIB@ ++ac_ct_STRIP = @ac_ct_STRIP@ ++am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ ++am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ ++am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ ++am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ ++am__include = @am__include@ ++am__leading_dot = @am__leading_dot@ ++am__quote = @am__quote@ ++bdb_includes = @bdb_includes@ ++bdb_libs = @bdb_libs@ ++bdb_libs_with_path = @bdb_libs_with_path@ ++bench_dirs = @bench_dirs@ ++bindir = @bindir@ ++build = @build@ ++build_alias = @build_alias@ ++build_cpu = @build_cpu@ ++build_os = @build_os@ ++build_vendor = @build_vendor@ ++datadir = @datadir@ ++default_charset = @default_charset@ ++docs_dirs = @docs_dirs@ ++exec_prefix = @exec_prefix@ ++host = @host@ ++host_alias = @host_alias@ ++host_cpu = @host_cpu@ ++host_os = @host_os@ ++host_vendor = @host_vendor@ ++includedir = @includedir@ ++infodir = @infodir@ ++innodb_includes = @innodb_includes@ ++innodb_libs = @innodb_libs@ ++innodb_system_libs = @innodb_system_libs@ ++install_sh = @install_sh@ ++isam_libs = @isam_libs@ ++libdir = @libdir@ ++libexecdir = @libexecdir@ ++libmysqld_dirs = @libmysqld_dirs@ ++linked_client_targets = @linked_client_targets@ ++linked_netware_sources = @linked_netware_sources@ ++localstatedir = @localstatedir@ ++man_dirs = @man_dirs@ ++mandir = @mandir@ ++netware_dir = @netware_dir@ ++oldincludedir = @oldincludedir@ ++openssl_includes = @openssl_includes@ ++openssl_libs = @openssl_libs@ ++orbit_idl = @orbit_idl@ ++orbit_includes = @orbit_includes@ ++orbit_libs = @orbit_libs@ ++prefix = @prefix@ ++program_transform_name = @program_transform_name@ ++pstack_dirs = @pstack_dirs@ ++pstack_libs = @pstack_libs@ ++readline_dir = @readline_dir@ ++readline_link = @readline_link@ ++sbindir = @sbindir@ ++server_scripts = @server_scripts@ ++sharedstatedir = @sharedstatedir@ ++sql_client_dirs = @sql_client_dirs@ ++sql_server_dirs = @sql_server_dirs@ ++sysconfdir = @sysconfdir@ ++target = @target@ ++target_alias = @target_alias@ ++target_cpu = @target_cpu@ ++target_os = @target_os@ ++target_vendor = @target_vendor@ ++thread_dirs = @thread_dirs@ ++tools_dirs = @tools_dirs@ ++uname_prog = @uname_prog@ ++vio_dir = @vio_dir@ ++vio_libs = @vio_libs@ ++ ++AUTOMAKE_OPTIONS = foreign ++ ++# These are built from source in the Docs directory ++EXTRA_DIST = INSTALL-SOURCE README COPYING EXCEPTIONS-CLIENT ++SUBDIRS = . include @docs_dirs@ @readline_dir@ \ ++ @thread_dirs@ pstack @sql_client_dirs@ \ ++ @sql_server_dirs@ scripts @man_dirs@ tests \ ++ BUILD netware os2 @libmysqld_dirs@ \ ++ @bench_dirs@ support-files @tools_dirs@ ++ ++ ++# Relink after clean ++linked_sources = linked_client_sources linked_server_sources \ ++ linked_libmysql_sources linked_libmysql_r_sources \ ++ linked_libmysqld_sources linked_libmysqldex_sources \ ++ linked_include_sources @linked_netware_sources@ ++ ++ ++CLEANFILES = $(linked_sources) ++subdir = . ++ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ++mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs ++CONFIG_HEADER = config.h ++CONFIG_CLEAN_FILES = bdb/Makefile ++DIST_SOURCES = ++ ++RECURSIVE_TARGETS = info-recursive dvi-recursive pdf-recursive \ ++ ps-recursive install-info-recursive uninstall-info-recursive \ ++ all-recursive install-data-recursive install-exec-recursive \ ++ installdirs-recursive install-recursive uninstall-recursive \ ++ check-recursive installcheck-recursive ++DIST_COMMON = README $(srcdir)/Makefile.in $(srcdir)/configure COPYING \ ++ ChangeLog Makefile.am acconfig.h acinclude.m4 aclocal.m4 \ ++ config.guess config.h.in config.sub configure configure.in \ ++ depcomp install-sh ltconfig ltmain.sh missing mkinstalldirs ++DIST_SUBDIRS = $(SUBDIRS) ++all: config.h ++ $(MAKE) $(AM_MAKEFLAGS) all-recursive ++ ++.SUFFIXES: ++ ++am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ ++ configure.lineno ++$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) ++ cd $(top_srcdir) && \ ++ $(AUTOMAKE) --foreign Makefile ++Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status ++ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe) ++ ++$(top_builddir)/config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) ++ $(SHELL) ./config.status --recheck ++$(srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) ++ cd $(srcdir) && $(AUTOCONF) ++ ++$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in acinclude.m4 ++ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) ++ ++stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status ++ @rm -f stamp-h1 ++ cd $(top_builddir) && $(SHELL) ./config.status config.h ++ ++$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(top_srcdir)/configure.in $(ACLOCAL_M4) $(top_srcdir)/acconfig.h ++ cd $(top_srcdir) && $(AUTOHEADER) ++ touch $(srcdir)/config.h.in ++ ++distclean-hdr: ++ -rm -f config.h stamp-h1 ++bdb/Makefile: $(top_builddir)/config.status $(top_srcdir)/bdb/Makefile.in ++ cd $(top_builddir) && $(SHELL) ./config.status $@ ++ ++mostlyclean-libtool: ++ -rm -f *.lo ++ ++clean-libtool: ++ -rm -rf .libs _libs ++ ++distclean-libtool: ++ -rm -f libtool ++uninstall-info-am: ++ ++# This directory's subdirectories are mostly independent; you can cd ++# into them and run `make' without going through this Makefile. ++# To change the values of `make' variables: instead of editing Makefiles, ++# (1) if the variable is set in `config.status', edit `config.status' ++# (which will cause the Makefiles to be regenerated when you run `make'); ++# (2) otherwise, pass the desired values on the `make' command line. ++$(RECURSIVE_TARGETS): ++ @set fnord $$MAKEFLAGS; amf=$$2; \ ++ dot_seen=no; \ ++ target=`echo $@ | sed s/-recursive//`; \ ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ echo "Making $$target in $$subdir"; \ ++ if test "$$subdir" = "."; then \ ++ dot_seen=yes; \ ++ local_target="$$target-am"; \ ++ else \ ++ local_target="$$target"; \ ++ fi; \ ++ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ ++ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ ++ done; \ ++ if test "$$dot_seen" = "no"; then \ ++ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ ++ fi; test -z "$$fail" ++ ++mostlyclean-recursive clean-recursive distclean-recursive \ ++maintainer-clean-recursive: ++ @set fnord $$MAKEFLAGS; amf=$$2; \ ++ dot_seen=no; \ ++ case "$@" in \ ++ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ ++ *) list='$(SUBDIRS)' ;; \ ++ esac; \ ++ rev=''; for subdir in $$list; do \ ++ if test "$$subdir" = "."; then :; else \ ++ rev="$$subdir $$rev"; \ ++ fi; \ ++ done; \ ++ rev="$$rev ."; \ ++ target=`echo $@ | sed s/-recursive//`; \ ++ for subdir in $$rev; do \ ++ echo "Making $$target in $$subdir"; \ ++ if test "$$subdir" = "."; then \ ++ local_target="$$target-am"; \ ++ else \ ++ local_target="$$target"; \ ++ fi; \ ++ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ ++ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ ++ done && test -z "$$fail" ++tags-recursive: ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ ++ done ++ctags-recursive: ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ ++ done ++ ++ETAGS = etags ++ETAGSFLAGS = ++ ++CTAGS = ctags ++CTAGSFLAGS = ++ ++ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) ++ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) ' { files[$$0] = 1; } \ ++ END { for (i in files) print i; }'`; \ ++ mkid -fID $$unique ++ ++TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ ++ $(TAGS_FILES) $(LISP) ++ tags=; \ ++ here=`pwd`; \ ++ if (etags --etags-include --version) >/dev/null 2>&1; then \ ++ include_option=--etags-include; \ ++ else \ ++ include_option=--include; \ ++ fi; \ ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ if test "$$subdir" = .; then :; else \ ++ test -f $$subdir/TAGS && \ ++ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ ++ fi; \ ++ done; \ ++ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) ' { files[$$0] = 1; } \ ++ END { for (i in files) print i; }'`; \ ++ test -z "$(ETAGS_ARGS)$$tags$$unique" \ ++ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ ++ $$tags $$unique ++ ++ctags: CTAGS ++CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ ++ $(TAGS_FILES) $(LISP) ++ tags=; \ ++ here=`pwd`; \ ++ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) ' { files[$$0] = 1; } \ ++ END { for (i in files) print i; }'`; \ ++ test -z "$(CTAGS_ARGS)$$tags$$unique" \ ++ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ ++ $$tags $$unique ++ ++GTAGS: ++ here=`$(am__cd) $(top_builddir) && pwd` \ ++ && cd $(top_srcdir) \ ++ && gtags -i $(GTAGS_ARGS) $$here ++ ++distclean-tags: ++ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags ++DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ++ ++top_distdir = . ++distdir = $(PACKAGE)-$(VERSION) ++ ++am__remove_distdir = \ ++ { test ! -d $(distdir) \ ++ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ ++ && rm -fr $(distdir); }; } ++ ++GZIP_ENV = --best ++distuninstallcheck_listfiles = find . -type f -print ++distcleancheck_listfiles = find . -type f -print ++ ++distdir: $(DISTFILES) ++ $(am__remove_distdir) ++ mkdir $(distdir) ++ $(mkinstalldirs) $(distdir)/bdb $(distdir)/include ++ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ ++ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ ++ list='$(DISTFILES)'; for file in $$list; do \ ++ case $$file in \ ++ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ ++ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ ++ esac; \ ++ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ ++ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ ++ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ ++ dir="/$$dir"; \ ++ $(mkinstalldirs) "$(distdir)$$dir"; \ ++ else \ ++ dir=''; \ ++ fi; \ ++ if test -d $$d/$$file; then \ ++ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ ++ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ ++ fi; \ ++ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ ++ else \ ++ test -f $(distdir)/$$file \ ++ || cp -p $$d/$$file $(distdir)/$$file \ ++ || exit 1; \ ++ fi; \ ++ done ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ if test "$$subdir" = .; then :; else \ ++ test -d $(distdir)/$$subdir \ ++ || mkdir $(distdir)/$$subdir \ ++ || exit 1; \ ++ (cd $$subdir && \ ++ $(MAKE) $(AM_MAKEFLAGS) \ ++ top_distdir="$(top_distdir)" \ ++ distdir=../$(distdir)/$$subdir \ ++ distdir) \ ++ || exit 1; \ ++ fi; \ ++ done ++ $(MAKE) $(AM_MAKEFLAGS) \ ++ top_distdir="$(top_distdir)" distdir="$(distdir)" \ ++ dist-hook ++ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ++ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ++ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ++ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ ++ || chmod -R a+r $(distdir) ++dist-gzip: distdir ++ $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz ++ $(am__remove_distdir) ++ ++dist dist-all: distdir ++ $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz ++ $(am__remove_distdir) ++ ++# This target untars the dist file and tries a VPATH configuration. Then ++# it guarantees that the distribution is self-contained by making another ++# tarfile. ++distcheck: dist ++ $(am__remove_distdir) ++ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - ++ chmod -R a-w $(distdir); chmod a+w $(distdir) ++ mkdir $(distdir)/_build ++ mkdir $(distdir)/_inst ++ chmod a-w $(distdir) ++ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ ++ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ ++ && cd $(distdir)/_build \ ++ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ ++ $(DISTCHECK_CONFIGURE_FLAGS) \ ++ && $(MAKE) $(AM_MAKEFLAGS) \ ++ && $(MAKE) $(AM_MAKEFLAGS) dvi \ ++ && $(MAKE) $(AM_MAKEFLAGS) check \ ++ && $(MAKE) $(AM_MAKEFLAGS) install \ ++ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ ++ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ ++ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ ++ distuninstallcheck \ ++ && chmod -R a-w "$$dc_install_base" \ ++ && ({ \ ++ (cd ../.. && $(mkinstalldirs) "$$dc_destdir") \ ++ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ ++ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ ++ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ ++ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ ++ } || { rm -rf "$$dc_destdir"; exit 1; }) \ ++ && rm -rf "$$dc_destdir" \ ++ && $(MAKE) $(AM_MAKEFLAGS) dist-gzip \ ++ && rm -f $(distdir).tar.gz \ ++ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck ++ $(am__remove_distdir) ++ @echo "$(distdir).tar.gz is ready for distribution" | \ ++ sed 'h;s/./=/g;p;x;p;x' ++distuninstallcheck: ++ @cd $(distuninstallcheck_dir) \ ++ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ ++ || { echo "ERROR: files left after uninstall:" ; \ ++ if test -n "$(DESTDIR)"; then \ ++ echo " (check DESTDIR support)"; \ ++ fi ; \ ++ $(distuninstallcheck_listfiles) ; \ ++ exit 1; } >&2 ++distcleancheck: distclean ++ @if test '$(srcdir)' = . ; then \ ++ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ ++ exit 1 ; \ ++ fi ++ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ ++ || { echo "ERROR: files left in build directory after distclean:" ; \ ++ $(distcleancheck_listfiles) ; \ ++ exit 1; } >&2 ++check-am: all-am ++check: check-recursive ++all-am: Makefile config.h ++installdirs: installdirs-recursive ++installdirs-am: ++ ++install: install-recursive ++install-exec: install-exec-recursive ++install-data: install-data-recursive ++uninstall: uninstall-recursive ++ ++install-am: all-am ++ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am ++ ++installcheck: installcheck-recursive ++install-strip: ++ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ ++ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ ++ `test -z '$(STRIP)' || \ ++ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install ++mostlyclean-generic: ++ ++clean-generic: ++ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) ++ ++distclean-generic: ++ -rm -f $(CONFIG_CLEAN_FILES) ++ ++maintainer-clean-generic: ++ @echo "This command is intended for maintainers to use" ++ @echo "it deletes files that may require special tools to rebuild." ++clean: clean-recursive ++ ++clean-am: clean-generic clean-libtool mostlyclean-am ++ ++distclean: distclean-recursive ++ -rm -f $(am__CONFIG_DISTCLEAN_FILES) ++ -rm -f Makefile ++distclean-am: clean-am distclean-generic distclean-hdr distclean-libtool \ ++ distclean-tags ++ ++dvi: dvi-recursive ++ ++dvi-am: ++ ++info: info-recursive ++ ++info-am: ++ ++install-data-am: ++ ++install-exec-am: ++ ++install-info: install-info-recursive ++ ++install-man: ++ ++installcheck-am: ++ ++maintainer-clean: maintainer-clean-recursive ++ -rm -f $(am__CONFIG_DISTCLEAN_FILES) ++ -rm -rf $(top_srcdir)/autom4te.cache ++ -rm -f Makefile ++maintainer-clean-am: distclean-am maintainer-clean-generic ++ ++mostlyclean: mostlyclean-recursive ++ ++mostlyclean-am: mostlyclean-generic mostlyclean-libtool ++ ++pdf: pdf-recursive ++ ++pdf-am: ++ ++ps: ps-recursive ++ ++ps-am: ++ ++uninstall-am: uninstall-info-am ++ ++uninstall-info: uninstall-info-recursive ++ ++.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am clean \ ++ clean-generic clean-libtool clean-recursive ctags \ ++ ctags-recursive dist dist-all dist-gzip distcheck distclean \ ++ distclean-generic distclean-hdr distclean-libtool \ ++ distclean-recursive distclean-tags distcleancheck distdir \ ++ distuninstallcheck dvi dvi-am dvi-recursive info info-am \ ++ info-recursive install install-am install-data install-data-am \ ++ install-data-recursive install-exec install-exec-am \ ++ install-exec-recursive install-info install-info-am \ ++ install-info-recursive install-man install-recursive \ ++ install-strip installcheck installcheck-am installdirs \ ++ installdirs-am installdirs-recursive maintainer-clean \ ++ maintainer-clean-generic maintainer-clean-recursive mostlyclean \ ++ mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \ ++ pdf pdf-am pdf-recursive ps ps-am ps-recursive tags \ ++ tags-recursive uninstall uninstall-am uninstall-info-am \ ++ uninstall-info-recursive uninstall-recursive ++ ++ ++# This is just so that the linking is done early. ++config.h: $(linked_sources) ++ ++linked_include_sources: ++ cd include; $(MAKE) link_sources ++ echo timestamp > linked_include_sources ++ ++linked_client_sources: @linked_client_targets@ ++ cd client; $(MAKE) link_sources ++ echo timestamp > linked_client_sources ++ ++linked_libmysql_sources: ++ cd libmysql; $(MAKE) link_sources ++ echo timestamp > linked_libmysql_sources ++ ++linked_libmysql_r_sources: linked_libmysql_sources ++ cd libmysql_r; $(MAKE) link_sources ++ echo timestamp > linked_libmysql_r_sources ++ ++linked_libmysqld_sources: ++ cd libmysqld; $(MAKE) link_sources ++ echo timestamp > linked_libmysqld_sources ++ ++linked_libmysqldex_sources: ++ cd libmysqld/examples; $(MAKE) link_sources ++ echo timestamp > linked_libmysqldex_sources ++ ++linked_netware_sources: ++ cd @netware_dir@; $(MAKE) link_sources ++ echo timestamp > linked_netware_sources ++ ++#avoid recursive make calls in sql directory ++linked_server_sources: ++ cd sql; rm -f mini_client_errors.c;@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c ++ echo timestamp > linked_server_sources ++ ++# Create permission databases ++init-db: all ++ $(top_builddir)/scripts/mysql_install_db ++ ++bin-dist: all ++ $(top_builddir)/scripts/make_binary_distribution @MAKE_BINARY_DISTRIBUTION_OPTIONS@ ++ ++# Remove BK's "SCCS" subdirectories from source distribution ++dist-hook: ++ rm -rf `find $(distdir) -type d -name SCCS` ++ ++tags: ++ support-files/build-tags ++.PHONY: init-db bin-dist ++ ++# Test installation ++ ++test: ++ cd mysql-test ; ./mysql-test-run ++# Tell versions [3.59,3.63) of GNU make to not export all variables. ++# Otherwise a system limit (for SysV at least) may be exceeded. ++.NOEXPORT: --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/56-mysqlhotcopy-invalid-dbtable.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/56-mysqlhotcopy-invalid-dbtable.dpatch @@ -0,0 +1,50 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run + +@DPATCH@ +diff -Naur mysql-dfsg-5.0-5.0.51a.orig/scripts/mysqlhotcopy.sh mysql-dfsg-5.0-5.0.51a/scripts/mysqlhotcopy.sh +--- mysql-dfsg-5.0-5.0.51a.orig/scripts/mysqlhotcopy.sh 2008-01-11 09:43:28.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/scripts/mysqlhotcopy.sh 2008-04-29 15:18:12.000000000 -0400 +@@ -333,7 +333,7 @@ + + $rdb->{files} = [ @db_files ]; + $rdb->{index} = [ @index_files ]; +- my @hc_tables = map { quote_names("$db.$_") } @dbh_tables; ++ my @hc_tables = map { quote_names("$_") } @dbh_tables; + $rdb->{tables} = [ @hc_tables ]; + + $rdb->{raid_dirs} = [ get_raid_dirs( $rdb->{files} ) ]; +@@ -464,13 +464,15 @@ + } + else { + my $start = time; ++ $hc_locks =~ s/\`//g; ++ $hc_locks =~ s/\`//g; + $dbh->do("LOCK TABLES $hc_locks"); + printf "Locked $num_tables tables in %d seconds.\n", time-$start unless $opt{quiet}; + $hc_started = time; # count from time lock is granted + + # flush tables to make on-disk copy uptodate + $start = time; +- $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); ++ $dbh->do("FLUSH TABLES"); + printf "Flushed tables ($hc_tables) in %d seconds.\n", time-$start unless $opt{quiet}; + $dbh->do( "FLUSH LOGS" ) if ( $opt{flushlog} ); + $dbh->do( "RESET MASTER" ) if ( $opt{resetmaster} ); +@@ -478,7 +480,7 @@ + + if ( $opt{record_log_pos} ) { + record_log_pos( $dbh, $opt{record_log_pos} ); +- $dbh->do("FLUSH TABLES /*!32323 $hc_tables */"); ++ $dbh->do("FLUSH TABLES"); + } + } + +@@ -828,7 +830,7 @@ + } || []; + warn "Unable to retrieve list of tables in $db: $@" if $@; + +- return (map { $_->[0] } @$tables); ++ return (map { $db . "." . $_->[0] } @$tables); + } + + sub quote_names { --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/98_CVE-2010-3838.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/98_CVE-2010-3838.dpatch @@ -0,0 +1,59 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via longblob and union or update with subquery. +# Origin: upstream, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3461.1.8 +# Bug: http://bugs.mysql.com/bug.php?id=54461 + +@DPATCH@ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/r/func_misc.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/func_misc.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/func_misc.result 2008-01-11 10:23:34.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/func_misc.result 2010-11-09 11:40:27.000000000 -0500 +@@ -186,3 +186,18 @@ + drop function func_26093_a; + drop function func_26093_b; + End of 5.0 tests ++# ++# Bug #54461: crash with longblob and union or update with subquery ++# ++CREATE TABLE t1 (a INT, b LONGBLOB); ++INSERT INTO t1 VALUES (1, '2'), (2, '3'), (3, '2'); ++SELECT DISTINCT LEAST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1; ++LEAST(a, (SELECT b FROM t1 LIMIT 1)) ++1 ++2 ++SELECT DISTINCT GREATEST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1; ++GREATEST(a, (SELECT b FROM t1 LIMIT 1)) ++2 ++3 ++1 ++DROP TABLE t1; +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/t/func_misc.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/func_misc.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/func_misc.test 2008-01-11 10:23:10.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/func_misc.test 2010-11-09 11:40:47.000000000 -0500 +@@ -190,3 +190,15 @@ + drop function func_26093_b; + + --echo End of 5.0 tests ++--echo # ++--echo # Bug #54461: crash with longblob and union or update with subquery ++--echo # ++ ++CREATE TABLE t1 (a INT, b LONGBLOB); ++INSERT INTO t1 VALUES (1, '2'), (2, '3'), (3, '2'); ++ ++SELECT DISTINCT LEAST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1; ++SELECT DISTINCT GREATEST(a, (SELECT b FROM t1 LIMIT 1)) FROM t1 UNION SELECT 1; ++ ++DROP TABLE t1; ++ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/item_func.cc mysql-dfsg-5.0-5.0.51a/sql/item_func.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/item_func.cc 2010-11-09 11:39:44.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/item_func.cc 2010-11-09 11:44:13.000000000 -0500 +@@ -2243,6 +2243,8 @@ + else if ((cmp_type == DECIMAL_RESULT) || (cmp_type == INT_RESULT)) + max_length= my_decimal_precision_to_length(max_int_part+decimals, decimals, + unsigned_flag); ++ else if (cmp_type == REAL_RESULT) ++ max_length= float_length(decimals); + } + + --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/00list +++ mysql-dfsg-5.0-5.0.51a/debian/patches/00list @@ -0,0 +1,49 @@ +01_MAKEFILES__Docs_Images_Makefile.in.dpatch +01_MAKEFILES__Docs_Makefile.in.dpatch +25_mysys__default.c.dpatch +37_scripts__mysqld_safe.sh__syslog.dpatch +38_scripts__mysqld_safe.sh__signals.dpatch +41_scripts__mysql_install_db.sh__no_test.dpatch +44_scripts__mysql_config__libs.dpatch +45_warn-CLI-passwords.dpatch +50_fix_mysqldump.dpatch +51_incorrect-order.dpatch +52_ndb-gcc-4.2.dpatch +53_integer-gcc-4.2.dpatch +54_ssl-client-support.dpatch +55_testsuite-2008.dpatch +56-mysqlhotcopy-invalid-dbtable.dpatch +57-fix-mysqlslowdump-config.dpatch +58-disable-ndb-backup-print.dpatch +59-fix-mysql-replication-logs.dpatch +#60_raise-max-keylength.dpatch +86_PATH_MAX.dpatch +89_ndb__staticlib.dpatch +90_upstreamdebiandir.dpatch +91_SECURITY_CVE-2007-5925.dpatch +92_fix_order_by32202.dpatch +93_fix_user_setup_on_localhost.dpatch +94_fix_mysqldump_with_old_versions.dpatch +95_SECURITY_CVE-2008-3963 +96_SECURITY_CVE-2008-4098 +97_CVE-2008-4456 +97_CVE-2009-2446 +97_CVE-2009-4019 +97_CVE-2009-4030 +98_CVE-2009-4484 +99_ssl_test_certs +100_CVE-2010-1850 +101_CVE-2010-1849 +102_CVE-2010-1848 +103_CVE-2010-1626 +98_CVE-2010-3677 +98_CVE-2010-3680 +98_CVE-2010-3681 +98_CVE-2010-3682 +98_CVE-2010-3833 +98_CVE-2010-3834 +98_CVE-2010-3835 +98_CVE-2010-3836 +98_CVE-2010-3837 +98_CVE-2010-3838 +98_CVE-2010-3840 --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/98_CVE-2010-3834.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/98_CVE-2010-3834.dpatch @@ -0,0 +1,130 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via derived table materializing. +# Origin: backport, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3461.2.1 +# Origin: backport, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3461.1.26 +# Bug: http://bugs.mysql.com/bug.php?id=55568 + +@DPATCH@ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/r/join.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/join.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/join.result 2008-01-11 10:23:38.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/join.result 2010-11-09 10:56:33.000000000 -0500 +@@ -858,3 +858,19 @@ + Handler_read_rnd_next 5 + drop table t1, t2, t3; + End of 5.0 tests. ++# ++# Bug #54468: crash after item's print() function when ordering/grouping ++# by subquery ++# ++CREATE TABLE t1(a INT, b INT); ++INSERT INTO t1 VALUES (), (); ++SELECT 1 FROM t1 ++GROUP BY ++GREATEST(t1.a, ++(SELECT 1 FROM ++(SELECT t1.b FROM t1,t1 t2 ++ORDER BY t1.a, t1.a LIMIT 1) AS d) ++); ++1 ++1 ++DROP TABLE t1; +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/t/join.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/join.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/join.test 2008-01-11 10:23:13.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/join.test 2010-11-09 10:56:33.000000000 -0500 +@@ -660,3 +660,20 @@ + + + --echo End of 5.0 tests. ++--echo # ++--echo # Bug #54468: crash after item's print() function when ordering/grouping ++--echo # by subquery ++--echo # ++ ++CREATE TABLE t1(a INT, b INT); ++INSERT INTO t1 VALUES (), (); ++ ++SELECT 1 FROM t1 ++GROUP BY ++GREATEST(t1.a, ++ (SELECT 1 FROM ++ (SELECT t1.b FROM t1,t1 t2 ++ ORDER BY t1.a, t1.a LIMIT 1) AS d) ++ ); ++ ++DROP TABLE t1; +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/field.cc mysql-dfsg-5.0-5.0.51a/sql/field.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/field.cc 2008-01-11 09:43:11.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/field.cc 2010-11-09 11:23:49.000000000 -0500 +@@ -1356,15 +1356,25 @@ + + void Field::make_field(Send_field *field) + { +- if (orig_table->s->table_cache_key && *(orig_table->s->table_cache_key)) ++ if (orig_table && orig_table->s->table_cache_key && ++ *(orig_table->s->table_cache_key)) + { + field->org_table_name= orig_table->s->table_name; + field->db_name= orig_table->s->table_cache_key; + } + else + field->org_table_name= field->db_name= ""; +- field->table_name= orig_table->alias; +- field->col_name= field->org_col_name= field_name; ++ if (orig_table && orig_table->alias) ++ { ++ field->table_name= orig_table->alias; ++ field->org_col_name= field_name; ++ } ++ else ++ { ++ field->table_name= ""; ++ field->org_col_name= ""; ++ } ++ field->col_name= field_name; + field->charsetnr= charset()->number; + field->length=field_length; + field->type=type(); +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/sql_select.cc mysql-dfsg-5.0-5.0.51a/sql/sql_select.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/sql_select.cc 2010-11-09 10:56:24.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/sql_select.cc 2010-11-09 11:30:04.000000000 -0500 +@@ -1555,6 +1555,19 @@ + DBUG_RETURN(0); + } + ++ ++void JOIN::cleanup_item_list(List &items) const ++{ ++ if (!items.is_empty()) ++ { ++ List_iterator_fast it(items); ++ Item *item; ++ while ((item= it++)) ++ item->cleanup(); ++ } ++} ++ ++ + /** + @brief Save the original join layout + +@@ -2175,6 +2188,8 @@ + cond_equal= 0; + + cleanup(1); ++ cleanup_item_list(tmp_all_fields1); ++ cleanup_item_list(tmp_all_fields3); + if (exec_tmp_table1) + free_tmp_table(thd, exec_tmp_table1); + if (exec_tmp_table2) +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/sql_select.h mysql-dfsg-5.0-5.0.51a/sql/sql_select.h +--- mysql-dfsg-5.0-5.0.51a~/sql/sql_select.h 2008-01-11 09:43:14.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/sql_select.h 2010-11-09 11:32:32.000000000 -0500 +@@ -472,6 +472,8 @@ + return (unit == &thd->lex->unit && (unit->fake_select_lex == 0 || + select_lex == unit->fake_select_lex)); + } ++private: ++ void cleanup_item_list(List &items) const; + }; + + --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/01_MAKEFILES__Docs_Makefile.in.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/01_MAKEFILES__Docs_Makefile.in.dpatch @@ -0,0 +1,776 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 01_MAKEFILES__Docs_Makefile.in.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Creates Docs/Makefile.in + +@DPATCH@ + +--- old/Docs/Makefile.in 2005-03-01 02:08:01.877429040 +0100 ++++ new/Docs/Makefile.in 2005-02-28 21:21:24.000000000 +0100 +@@ -0,0 +1,765 @@ ++# Makefile.in generated by automake 1.7.9 from Makefile.am. ++# @configure_input@ ++ ++# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 ++# Free Software Foundation, Inc. ++# This Makefile.in is free software; the Free Software Foundation ++# gives unlimited permission to copy and/or distribute it, ++# with or without modifications, as long as this notice is preserved. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY, to the extent permitted by law; without ++# even the implied warranty of MERCHANTABILITY or FITNESS FOR A ++# PARTICULAR PURPOSE. ++ ++@SET_MAKE@ ++ ++# Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB ++# ++# 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. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ ++# Process this file with automake to create Makefile.in ++ ++srcdir = @srcdir@ ++top_srcdir = @top_srcdir@ ++VPATH = @srcdir@ ++pkgdatadir = $(datadir)/@PACKAGE@ ++pkglibdir = $(libdir)/@PACKAGE@ ++pkgincludedir = $(includedir)/@PACKAGE@ ++top_builddir = . ++ ++am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd ++INSTALL = @INSTALL@ ++install_sh_DATA = $(install_sh) -c -m 644 ++install_sh_PROGRAM = $(install_sh) -c ++install_sh_SCRIPT = $(install_sh) -c ++INSTALL_HEADER = $(INSTALL_DATA) ++transform = $(program_transform_name) ++NORMAL_INSTALL = : ++PRE_INSTALL = : ++POST_INSTALL = : ++NORMAL_UNINSTALL = : ++PRE_UNINSTALL = : ++POST_UNINSTALL = : ++build_triplet = @build@ ++host_triplet = @host@ ++target_triplet = @target@ ++ACLOCAL = @ACLOCAL@ ++ALLOCA = @ALLOCA@ ++AMDEP_FALSE = @AMDEP_FALSE@ ++AMDEP_TRUE = @AMDEP_TRUE@ ++AMTAR = @AMTAR@ ++AR = @AR@ ++AS = @AS@ ++ASSEMBLER_FALSE = @ASSEMBLER_FALSE@ ++ASSEMBLER_TRUE = @ASSEMBLER_TRUE@ ++ASSEMBLER_sparc32_FALSE = @ASSEMBLER_sparc32_FALSE@ ++ASSEMBLER_sparc32_TRUE = @ASSEMBLER_sparc32_TRUE@ ++ASSEMBLER_sparc64_FALSE = @ASSEMBLER_sparc64_FALSE@ ++ASSEMBLER_sparc64_TRUE = @ASSEMBLER_sparc64_TRUE@ ++ASSEMBLER_x86_FALSE = @ASSEMBLER_x86_FALSE@ ++ASSEMBLER_x86_TRUE = @ASSEMBLER_x86_TRUE@ ++AUTOCONF = @AUTOCONF@ ++AUTOHEADER = @AUTOHEADER@ ++AUTOMAKE = @AUTOMAKE@ ++AVAILABLE_LANGUAGES = @AVAILABLE_LANGUAGES@ ++AVAILABLE_LANGUAGES_ERRORS = @AVAILABLE_LANGUAGES_ERRORS@ ++AWK = @AWK@ ++CC = @CC@ ++CCAS = @CCAS@ ++CCASFLAGS = @CCASFLAGS@ ++CCDEPMODE = @CCDEPMODE@ ++CC_VERSION = @CC_VERSION@ ++CFLAGS = @CFLAGS@ ++CHARSETS_NEED_SOURCE = @CHARSETS_NEED_SOURCE@ ++CHARSET_OBJS = @CHARSET_OBJS@ ++CHARSET_SRCS = @CHARSET_SRCS@ ++CHECK_PID = @CHECK_PID@ ++CHMOD = @CHMOD@ ++CLIENT_EXTRA_LDFLAGS = @CLIENT_EXTRA_LDFLAGS@ ++CLIENT_LIBS = @CLIENT_LIBS@ ++CMP = @CMP@ ++COMPILATION_COMMENT = @COMPILATION_COMMENT@ ++COMPILE_PSTACK_FALSE = @COMPILE_PSTACK_FALSE@ ++COMPILE_PSTACK_TRUE = @COMPILE_PSTACK_TRUE@ ++CONF_COMMAND = @CONF_COMMAND@ ++CP = @CP@ ++CPP = @CPP@ ++CPPFLAGS = @CPPFLAGS@ ++CXX = @CXX@ ++CXXCPP = @CXXCPP@ ++CXXDEPMODE = @CXXDEPMODE@ ++CXXFLAGS = @CXXFLAGS@ ++CXXLDFLAGS = @CXXLDFLAGS@ ++CXX_VERSION = @CXX_VERSION@ ++CYGPATH_W = @CYGPATH_W@ ++DEFS = @DEFS@ ++DEPDIR = @DEPDIR@ ++DOT_FRM_VERSION = @DOT_FRM_VERSION@ ++DVIS = @DVIS@ ++ECHO = @ECHO@ ++ECHO_C = @ECHO_C@ ++ECHO_N = @ECHO_N@ ++ECHO_T = @ECHO_T@ ++EGREP = @EGREP@ ++EXEEXT = @EXEEXT@ ++F77 = @F77@ ++FFLAGS = @FFLAGS@ ++FIND_PROC = @FIND_PROC@ ++GETCONF = @GETCONF@ ++GXX = @GXX@ ++HAVE_NETWARE_FALSE = @HAVE_NETWARE_FALSE@ ++HAVE_NETWARE_TRUE = @HAVE_NETWARE_TRUE@ ++HOSTNAME = @HOSTNAME@ ++INSTALL_DATA = @INSTALL_DATA@ ++INSTALL_PROGRAM = @INSTALL_PROGRAM@ ++INSTALL_SCRIPT = @INSTALL_SCRIPT@ ++INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ ++IS_LINUX = @IS_LINUX@ ++KILL = @KILL@ ++LD = @LD@ ++LDFLAGS = @LDFLAGS@ ++LIBDL = @LIBDL@ ++LIBOBJS = @LIBOBJS@ ++LIBS = @LIBS@ ++LIBTOOL = @LIBTOOL@ ++LIB_EXTRA_CCFLAGS = @LIB_EXTRA_CCFLAGS@ ++LM_CFLAGS = @LM_CFLAGS@ ++LN = @LN@ ++LN_CP_F = @LN_CP_F@ ++LN_S = @LN_S@ ++LOCAL_FALSE = @LOCAL_FALSE@ ++LOCAL_TRUE = @LOCAL_TRUE@ ++LTLIBOBJS = @LTLIBOBJS@ ++MACHINE_TYPE = @MACHINE_TYPE@ ++MAINT = @MAINT@ ++MAINTAINER_MODE_FALSE = @MAINTAINER_MODE_FALSE@ ++MAINTAINER_MODE_TRUE = @MAINTAINER_MODE_TRUE@ ++MAKEINFO = @MAKEINFO@ ++MAKE_BINARY_DISTRIBUTION_OPTIONS = @MAKE_BINARY_DISTRIBUTION_OPTIONS@ ++MAKE_SHELL = @MAKE_SHELL@ ++MT_INCLUDES = @MT_INCLUDES@ ++MT_LD_ADD = @MT_LD_ADD@ ++MV = @MV@ ++MYSQLD_DEFAULT_SWITCHES = @MYSQLD_DEFAULT_SWITCHES@ ++MYSQLD_EXTRA_LDFLAGS = @MYSQLD_EXTRA_LDFLAGS@ ++MYSQLD_USER = @MYSQLD_USER@ ++MYSQL_BASE_VERSION = @MYSQL_BASE_VERSION@ ++MYSQL_NO_DASH_VERSION = @MYSQL_NO_DASH_VERSION@ ++MYSQL_SERVER_SUFFIX = @MYSQL_SERVER_SUFFIX@ ++MYSQL_TCP_PORT = @MYSQL_TCP_PORT@ ++MYSQL_TCP_PORT_DEFAULT = @MYSQL_TCP_PORT_DEFAULT@ ++MYSQL_UNIX_ADDR = @MYSQL_UNIX_ADDR@ ++MYSQL_VERSION_ID = @MYSQL_VERSION_ID@ ++NOINST_LDFLAGS = @NOINST_LDFLAGS@ ++OBJEXT = @OBJEXT@ ++PACKAGE = @PACKAGE@ ++PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ ++PACKAGE_NAME = @PACKAGE_NAME@ ++PACKAGE_STRING = @PACKAGE_STRING@ ++PACKAGE_TARNAME = @PACKAGE_TARNAME@ ++PACKAGE_VERSION = @PACKAGE_VERSION@ ++PATH_SEPARATOR = @PATH_SEPARATOR@ ++PDFMANUAL = @PDFMANUAL@ ++PERL = @PERL@ ++PERL5 = @PERL5@ ++PROTOCOL_VERSION = @PROTOCOL_VERSION@ ++PS = @PS@ ++RANLIB = @RANLIB@ ++RM = @RM@ ++SAVE_ASFLAGS = @SAVE_ASFLAGS@ ++SAVE_CFLAGS = @SAVE_CFLAGS@ ++SAVE_CXXFLAGS = @SAVE_CXXFLAGS@ ++SAVE_CXXLDFLAGS = @SAVE_CXXLDFLAGS@ ++SAVE_LDFLAGS = @SAVE_LDFLAGS@ ++SED = @SED@ ++SET_MAKE = @SET_MAKE@ ++SHARED_LIB_VERSION = @SHARED_LIB_VERSION@ ++SHELL = @SHELL@ ++STRIP = @STRIP@ ++SYSTEM_TYPE = @SYSTEM_TYPE@ ++TAR = @TAR@ ++TERMCAP_LIB = @TERMCAP_LIB@ ++THREAD_LOBJECTS = @THREAD_LOBJECTS@ ++THREAD_LPROGRAMS = @THREAD_LPROGRAMS@ ++VERSION = @VERSION@ ++WRAPLIBS = @WRAPLIBS@ ++YACC = @YACC@ ++ac_ct_AR = @ac_ct_AR@ ++ac_ct_CC = @ac_ct_CC@ ++ac_ct_CXX = @ac_ct_CXX@ ++ac_ct_F77 = @ac_ct_F77@ ++ac_ct_GETCONF = @ac_ct_GETCONF@ ++ac_ct_RANLIB = @ac_ct_RANLIB@ ++ac_ct_STRIP = @ac_ct_STRIP@ ++am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ ++am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ ++am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ ++am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ ++am__include = @am__include@ ++am__leading_dot = @am__leading_dot@ ++am__quote = @am__quote@ ++bdb_includes = @bdb_includes@ ++bdb_libs = @bdb_libs@ ++bdb_libs_with_path = @bdb_libs_with_path@ ++bench_dirs = @bench_dirs@ ++bindir = @bindir@ ++build = @build@ ++build_alias = @build_alias@ ++build_cpu = @build_cpu@ ++build_os = @build_os@ ++build_vendor = @build_vendor@ ++datadir = @datadir@ ++default_charset = @default_charset@ ++docs_dirs = @docs_dirs@ ++exec_prefix = @exec_prefix@ ++host = @host@ ++host_alias = @host_alias@ ++host_cpu = @host_cpu@ ++host_os = @host_os@ ++host_vendor = @host_vendor@ ++includedir = @includedir@ ++infodir = @infodir@ ++innodb_includes = @innodb_includes@ ++innodb_libs = @innodb_libs@ ++innodb_system_libs = @innodb_system_libs@ ++install_sh = @install_sh@ ++isam_libs = @isam_libs@ ++libdir = @libdir@ ++libexecdir = @libexecdir@ ++libmysqld_dirs = @libmysqld_dirs@ ++linked_client_targets = @linked_client_targets@ ++linked_netware_sources = @linked_netware_sources@ ++localstatedir = @localstatedir@ ++man_dirs = @man_dirs@ ++mandir = @mandir@ ++netware_dir = @netware_dir@ ++oldincludedir = @oldincludedir@ ++openssl_includes = @openssl_includes@ ++openssl_libs = @openssl_libs@ ++orbit_idl = @orbit_idl@ ++orbit_includes = @orbit_includes@ ++orbit_libs = @orbit_libs@ ++prefix = @prefix@ ++program_transform_name = @program_transform_name@ ++pstack_dirs = @pstack_dirs@ ++pstack_libs = @pstack_libs@ ++readline_dir = @readline_dir@ ++readline_link = @readline_link@ ++sbindir = @sbindir@ ++server_scripts = @server_scripts@ ++sharedstatedir = @sharedstatedir@ ++sql_client_dirs = @sql_client_dirs@ ++sql_server_dirs = @sql_server_dirs@ ++sysconfdir = @sysconfdir@ ++target = @target@ ++target_alias = @target_alias@ ++target_cpu = @target_cpu@ ++target_os = @target_os@ ++target_vendor = @target_vendor@ ++thread_dirs = @thread_dirs@ ++tools_dirs = @tools_dirs@ ++uname_prog = @uname_prog@ ++vio_dir = @vio_dir@ ++vio_libs = @vio_libs@ ++ ++AUTOMAKE_OPTIONS = foreign ++ ++# These are built from source in the Docs directory ++EXTRA_DIST = INSTALL-SOURCE README COPYING EXCEPTIONS-CLIENT ++SUBDIRS = . include @docs_dirs@ @readline_dir@ \ ++ @thread_dirs@ pstack @sql_client_dirs@ \ ++ @sql_server_dirs@ scripts @man_dirs@ tests \ ++ BUILD netware os2 @libmysqld_dirs@ \ ++ @bench_dirs@ support-files @tools_dirs@ ++ ++ ++# Relink after clean ++linked_sources = linked_client_sources linked_server_sources \ ++ linked_libmysql_sources linked_libmysql_r_sources \ ++ linked_libmysqld_sources linked_libmysqldex_sources \ ++ linked_include_sources @linked_netware_sources@ ++ ++ ++CLEANFILES = $(linked_sources) ++subdir = . ++ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ++mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs ++CONFIG_HEADER = config.h ++CONFIG_CLEAN_FILES = bdb/Makefile ++DIST_SOURCES = ++ ++RECURSIVE_TARGETS = info-recursive dvi-recursive pdf-recursive \ ++ ps-recursive install-info-recursive uninstall-info-recursive \ ++ all-recursive install-data-recursive install-exec-recursive \ ++ installdirs-recursive install-recursive uninstall-recursive \ ++ check-recursive installcheck-recursive ++DIST_COMMON = README $(srcdir)/Makefile.in $(srcdir)/configure COPYING \ ++ ChangeLog Makefile.am acconfig.h acinclude.m4 aclocal.m4 \ ++ config.guess config.h.in config.sub configure configure.in \ ++ depcomp install-sh ltconfig ltmain.sh missing mkinstalldirs ++DIST_SUBDIRS = $(SUBDIRS) ++all: config.h ++ $(MAKE) $(AM_MAKEFLAGS) all-recursive ++ ++.SUFFIXES: ++ ++am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ ++ configure.lineno ++$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) ++ cd $(top_srcdir) && \ ++ $(AUTOMAKE) --foreign Makefile ++Makefile: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.in $(top_builddir)/config.status ++ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe) ++ ++$(top_builddir)/config.status: $(srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) ++ $(SHELL) ./config.status --recheck ++$(srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENCIES) ++ cd $(srcdir) && $(AUTOCONF) ++ ++$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ configure.in acinclude.m4 ++ cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) ++ ++stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status ++ @rm -f stamp-h1 ++ cd $(top_builddir) && $(SHELL) ./config.status config.h ++ ++$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(top_srcdir)/configure.in $(ACLOCAL_M4) $(top_srcdir)/acconfig.h ++ cd $(top_srcdir) && $(AUTOHEADER) ++ touch $(srcdir)/config.h.in ++ ++distclean-hdr: ++ -rm -f config.h stamp-h1 ++bdb/Makefile: $(top_builddir)/config.status $(top_srcdir)/bdb/Makefile.in ++ cd $(top_builddir) && $(SHELL) ./config.status $@ ++ ++mostlyclean-libtool: ++ -rm -f *.lo ++ ++clean-libtool: ++ -rm -rf .libs _libs ++ ++distclean-libtool: ++ -rm -f libtool ++uninstall-info-am: ++ ++# This directory's subdirectories are mostly independent; you can cd ++# into them and run `make' without going through this Makefile. ++# To change the values of `make' variables: instead of editing Makefiles, ++# (1) if the variable is set in `config.status', edit `config.status' ++# (which will cause the Makefiles to be regenerated when you run `make'); ++# (2) otherwise, pass the desired values on the `make' command line. ++$(RECURSIVE_TARGETS): ++ @set fnord $$MAKEFLAGS; amf=$$2; \ ++ dot_seen=no; \ ++ target=`echo $@ | sed s/-recursive//`; \ ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ echo "Making $$target in $$subdir"; \ ++ if test "$$subdir" = "."; then \ ++ dot_seen=yes; \ ++ local_target="$$target-am"; \ ++ else \ ++ local_target="$$target"; \ ++ fi; \ ++ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ ++ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ ++ done; \ ++ if test "$$dot_seen" = "no"; then \ ++ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ ++ fi; test -z "$$fail" ++ ++mostlyclean-recursive clean-recursive distclean-recursive \ ++maintainer-clean-recursive: ++ @set fnord $$MAKEFLAGS; amf=$$2; \ ++ dot_seen=no; \ ++ case "$@" in \ ++ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ ++ *) list='$(SUBDIRS)' ;; \ ++ esac; \ ++ rev=''; for subdir in $$list; do \ ++ if test "$$subdir" = "."; then :; else \ ++ rev="$$subdir $$rev"; \ ++ fi; \ ++ done; \ ++ rev="$$rev ."; \ ++ target=`echo $@ | sed s/-recursive//`; \ ++ for subdir in $$rev; do \ ++ echo "Making $$target in $$subdir"; \ ++ if test "$$subdir" = "."; then \ ++ local_target="$$target-am"; \ ++ else \ ++ local_target="$$target"; \ ++ fi; \ ++ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ ++ || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ ++ done && test -z "$$fail" ++tags-recursive: ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ ++ done ++ctags-recursive: ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ ++ done ++ ++ETAGS = etags ++ETAGSFLAGS = ++ ++CTAGS = ctags ++CTAGSFLAGS = ++ ++ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) ++ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) ' { files[$$0] = 1; } \ ++ END { for (i in files) print i; }'`; \ ++ mkid -fID $$unique ++ ++TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ ++ $(TAGS_FILES) $(LISP) ++ tags=; \ ++ here=`pwd`; \ ++ if (etags --etags-include --version) >/dev/null 2>&1; then \ ++ include_option=--etags-include; \ ++ else \ ++ include_option=--include; \ ++ fi; \ ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ if test "$$subdir" = .; then :; else \ ++ test -f $$subdir/TAGS && \ ++ tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ ++ fi; \ ++ done; \ ++ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) ' { files[$$0] = 1; } \ ++ END { for (i in files) print i; }'`; \ ++ test -z "$(ETAGS_ARGS)$$tags$$unique" \ ++ || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ ++ $$tags $$unique ++ ++ctags: CTAGS ++CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ ++ $(TAGS_FILES) $(LISP) ++ tags=; \ ++ here=`pwd`; \ ++ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ ++ unique=`for i in $$list; do \ ++ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ ++ done | \ ++ $(AWK) ' { files[$$0] = 1; } \ ++ END { for (i in files) print i; }'`; \ ++ test -z "$(CTAGS_ARGS)$$tags$$unique" \ ++ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ ++ $$tags $$unique ++ ++GTAGS: ++ here=`$(am__cd) $(top_builddir) && pwd` \ ++ && cd $(top_srcdir) \ ++ && gtags -i $(GTAGS_ARGS) $$here ++ ++distclean-tags: ++ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags ++DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ++ ++top_distdir = . ++distdir = $(PACKAGE)-$(VERSION) ++ ++am__remove_distdir = \ ++ { test ! -d $(distdir) \ ++ || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ ++ && rm -fr $(distdir); }; } ++ ++GZIP_ENV = --best ++distuninstallcheck_listfiles = find . -type f -print ++distcleancheck_listfiles = find . -type f -print ++ ++distdir: $(DISTFILES) ++ $(am__remove_distdir) ++ mkdir $(distdir) ++ $(mkinstalldirs) $(distdir)/bdb $(distdir)/include ++ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ ++ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ ++ list='$(DISTFILES)'; for file in $$list; do \ ++ case $$file in \ ++ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ ++ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ ++ esac; \ ++ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ ++ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ ++ if test "$$dir" != "$$file" && test "$$dir" != "."; then \ ++ dir="/$$dir"; \ ++ $(mkinstalldirs) "$(distdir)$$dir"; \ ++ else \ ++ dir=''; \ ++ fi; \ ++ if test -d $$d/$$file; then \ ++ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ ++ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ ++ fi; \ ++ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ ++ else \ ++ test -f $(distdir)/$$file \ ++ || cp -p $$d/$$file $(distdir)/$$file \ ++ || exit 1; \ ++ fi; \ ++ done ++ list='$(SUBDIRS)'; for subdir in $$list; do \ ++ if test "$$subdir" = .; then :; else \ ++ test -d $(distdir)/$$subdir \ ++ || mkdir $(distdir)/$$subdir \ ++ || exit 1; \ ++ (cd $$subdir && \ ++ $(MAKE) $(AM_MAKEFLAGS) \ ++ top_distdir="$(top_distdir)" \ ++ distdir=../$(distdir)/$$subdir \ ++ distdir) \ ++ || exit 1; \ ++ fi; \ ++ done ++ $(MAKE) $(AM_MAKEFLAGS) \ ++ top_distdir="$(top_distdir)" distdir="$(distdir)" \ ++ dist-hook ++ -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ ++ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ++ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ++ ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ ++ || chmod -R a+r $(distdir) ++dist-gzip: distdir ++ $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz ++ $(am__remove_distdir) ++ ++dist dist-all: distdir ++ $(AMTAR) chof - $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz ++ $(am__remove_distdir) ++ ++# This target untars the dist file and tries a VPATH configuration. Then ++# it guarantees that the distribution is self-contained by making another ++# tarfile. ++distcheck: dist ++ $(am__remove_distdir) ++ GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(AMTAR) xf - ++ chmod -R a-w $(distdir); chmod a+w $(distdir) ++ mkdir $(distdir)/_build ++ mkdir $(distdir)/_inst ++ chmod a-w $(distdir) ++ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ ++ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ ++ && cd $(distdir)/_build \ ++ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ ++ $(DISTCHECK_CONFIGURE_FLAGS) \ ++ && $(MAKE) $(AM_MAKEFLAGS) \ ++ && $(MAKE) $(AM_MAKEFLAGS) dvi \ ++ && $(MAKE) $(AM_MAKEFLAGS) check \ ++ && $(MAKE) $(AM_MAKEFLAGS) install \ ++ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ ++ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ ++ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ ++ distuninstallcheck \ ++ && chmod -R a-w "$$dc_install_base" \ ++ && ({ \ ++ (cd ../.. && $(mkinstalldirs) "$$dc_destdir") \ ++ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ ++ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ ++ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ ++ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ ++ } || { rm -rf "$$dc_destdir"; exit 1; }) \ ++ && rm -rf "$$dc_destdir" \ ++ && $(MAKE) $(AM_MAKEFLAGS) dist-gzip \ ++ && rm -f $(distdir).tar.gz \ ++ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck ++ $(am__remove_distdir) ++ @echo "$(distdir).tar.gz is ready for distribution" | \ ++ sed 'h;s/./=/g;p;x;p;x' ++distuninstallcheck: ++ @cd $(distuninstallcheck_dir) \ ++ && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ ++ || { echo "ERROR: files left after uninstall:" ; \ ++ if test -n "$(DESTDIR)"; then \ ++ echo " (check DESTDIR support)"; \ ++ fi ; \ ++ $(distuninstallcheck_listfiles) ; \ ++ exit 1; } >&2 ++distcleancheck: distclean ++ @if test '$(srcdir)' = . ; then \ ++ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ ++ exit 1 ; \ ++ fi ++ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ ++ || { echo "ERROR: files left in build directory after distclean:" ; \ ++ $(distcleancheck_listfiles) ; \ ++ exit 1; } >&2 ++check-am: all-am ++check: check-recursive ++all-am: Makefile config.h ++installdirs: installdirs-recursive ++installdirs-am: ++ ++install: install-recursive ++install-exec: install-exec-recursive ++install-data: install-data-recursive ++uninstall: uninstall-recursive ++ ++install-am: all-am ++ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am ++ ++installcheck: installcheck-recursive ++install-strip: ++ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ ++ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ ++ `test -z '$(STRIP)' || \ ++ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install ++mostlyclean-generic: ++ ++clean-generic: ++ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) ++ ++distclean-generic: ++ -rm -f $(CONFIG_CLEAN_FILES) ++ ++maintainer-clean-generic: ++ @echo "This command is intended for maintainers to use" ++ @echo "it deletes files that may require special tools to rebuild." ++clean: clean-recursive ++ ++clean-am: clean-generic clean-libtool mostlyclean-am ++ ++distclean: distclean-recursive ++ -rm -f $(am__CONFIG_DISTCLEAN_FILES) ++ -rm -f Makefile ++distclean-am: clean-am distclean-generic distclean-hdr distclean-libtool \ ++ distclean-tags ++ ++dvi: dvi-recursive ++ ++dvi-am: ++ ++info: info-recursive ++ ++info-am: ++ ++install-data-am: ++ ++install-exec-am: ++ ++install-info: install-info-recursive ++ ++install-man: ++ ++installcheck-am: ++ ++maintainer-clean: maintainer-clean-recursive ++ -rm -f $(am__CONFIG_DISTCLEAN_FILES) ++ -rm -rf $(top_srcdir)/autom4te.cache ++ -rm -f Makefile ++maintainer-clean-am: distclean-am maintainer-clean-generic ++ ++mostlyclean: mostlyclean-recursive ++ ++mostlyclean-am: mostlyclean-generic mostlyclean-libtool ++ ++pdf: pdf-recursive ++ ++pdf-am: ++ ++ps: ps-recursive ++ ++ps-am: ++ ++uninstall-am: uninstall-info-am ++ ++uninstall-info: uninstall-info-recursive ++ ++.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am clean \ ++ clean-generic clean-libtool clean-recursive ctags \ ++ ctags-recursive dist dist-all dist-gzip distcheck distclean \ ++ distclean-generic distclean-hdr distclean-libtool \ ++ distclean-recursive distclean-tags distcleancheck distdir \ ++ distuninstallcheck dvi dvi-am dvi-recursive info info-am \ ++ info-recursive install install-am install-data install-data-am \ ++ install-data-recursive install-exec install-exec-am \ ++ install-exec-recursive install-info install-info-am \ ++ install-info-recursive install-man install-recursive \ ++ install-strip installcheck installcheck-am installdirs \ ++ installdirs-am installdirs-recursive maintainer-clean \ ++ maintainer-clean-generic maintainer-clean-recursive mostlyclean \ ++ mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \ ++ pdf pdf-am pdf-recursive ps ps-am ps-recursive tags \ ++ tags-recursive uninstall uninstall-am uninstall-info-am \ ++ uninstall-info-recursive uninstall-recursive ++ ++ ++# This is just so that the linking is done early. ++config.h: $(linked_sources) ++ ++linked_include_sources: ++ cd include; $(MAKE) link_sources ++ echo timestamp > linked_include_sources ++ ++linked_client_sources: @linked_client_targets@ ++ cd client; $(MAKE) link_sources ++ echo timestamp > linked_client_sources ++ ++linked_libmysql_sources: ++ cd libmysql; $(MAKE) link_sources ++ echo timestamp > linked_libmysql_sources ++ ++linked_libmysql_r_sources: linked_libmysql_sources ++ cd libmysql_r; $(MAKE) link_sources ++ echo timestamp > linked_libmysql_r_sources ++ ++linked_libmysqld_sources: ++ cd libmysqld; $(MAKE) link_sources ++ echo timestamp > linked_libmysqld_sources ++ ++linked_libmysqldex_sources: ++ cd libmysqld/examples; $(MAKE) link_sources ++ echo timestamp > linked_libmysqldex_sources ++ ++linked_netware_sources: ++ cd @netware_dir@; $(MAKE) link_sources ++ echo timestamp > linked_netware_sources ++ ++#avoid recursive make calls in sql directory ++linked_server_sources: ++ cd sql; rm -f mini_client_errors.c;@LN_CP_F@ ../libmysql/errmsg.c mini_client_errors.c ++ echo timestamp > linked_server_sources ++ ++# Create permission databases ++init-db: all ++ $(top_builddir)/scripts/mysql_install_db ++ ++bin-dist: all ++ $(top_builddir)/scripts/make_binary_distribution @MAKE_BINARY_DISTRIBUTION_OPTIONS@ ++ ++# Remove BK's "SCCS" subdirectories from source distribution ++dist-hook: ++ rm -rf `find $(distdir) -type d -name SCCS` ++ ++tags: ++ support-files/build-tags ++.PHONY: init-db bin-dist ++ ++# Test installation ++ ++test: ++ cd mysql-test ; ./mysql-test-run ++# Tell versions [3.59,3.63) of GNU make to not export all variables. ++# Otherwise a system limit (for SysV at least) may be exceeded. ++.NOEXPORT: --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/91_SECURITY_CVE-2007-5925.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/91_SECURITY_CVE-2007-5925.dpatch @@ -0,0 +1,123 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 91_SECURITY_CVE-2007-5925.dpatch by Norbert Tretkowski +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Fix for CVE-2007-5925: The convert_search_mode_to_innobase function in +## DP: ha_innodb.cc in the InnoDB engine in MySQL 5.1.23-BK and earlier allows +## DP: remote authenticated users to cause a denial of service (database crash) +## DP: via a certain CONTAINS operation on an indexed column, which triggers an +## DP: assertion error. (closes: #451235) + +@DPATCH@ +diff -ru old/innobase/include/db0err.h new/innobase/include/db0err.h +--- old/innobase/include/db0err.h 2007-07-04 16:06:59.000000000 +0300 ++++ new/innobase/include/db0err.h 2007-11-15 10:23:51.000000000 +0200 +@@ -57,6 +57,18 @@ + buffer pool (for big transactions, + InnoDB stores the lock structs in the + buffer pool) */ ++#define DB_FOREIGN_DUPLICATE_KEY 46 /* foreign key constraints ++ activated by the operation would ++ lead to a duplicate key in some ++ table */ ++#define DB_TOO_MANY_CONCURRENT_TRXS 47 /* when InnoDB runs out of the ++ preconfigured undo slots, this can ++ only happen when there are too many ++ concurrent transactions */ ++#define DB_UNSUPPORTED 48 /* when InnoDB sees any artefact or ++ a feature that it can't recoginize or ++ work with e.g., FT indexes created by ++ a later version of the engine. */ + + /* The following are partial failure codes */ + #define DB_FAIL 1000 +diff -ru old/innobase/include/page0cur.h new/innobase/include/page0cur.h +--- old/innobase/include/page0cur.h 2007-07-04 16:06:10.000000000 +0300 ++++ new/innobase/include/page0cur.h 2007-11-15 10:23:51.000000000 +0200 +@@ -22,6 +22,7 @@ + + /* Page cursor search modes; the values must be in this order! */ + ++#define PAGE_CUR_UNSUPP 0 + #define PAGE_CUR_G 1 + #define PAGE_CUR_GE 2 + #define PAGE_CUR_L 3 +diff -ru old/sql/ha_innodb.cc new/sql/ha_innodb.cc +--- old/sql/ha_innodb.cc 2007-07-04 16:06:48.000000000 +0300 ++++ new/sql/ha_innodb.cc 2007-11-15 10:25:55.000000000 +0200 +@@ -526,6 +526,9 @@ + } + + return(HA_ERR_LOCK_TABLE_FULL); ++ } else if (error == DB_UNSUPPORTED) { ++ ++ return(HA_ERR_UNSUPPORTED); + } else { + return(-1); // Unknown error + } +@@ -3689,11 +3692,21 @@ + and comparison of non-latin1 char type fields in + innobase_mysql_cmp() to get PAGE_CUR_LE_OR_EXTENDS to + work correctly. */ +- +- default: assert(0); ++ case HA_READ_MBR_CONTAIN: ++ case HA_READ_MBR_INTERSECT: ++ case HA_READ_MBR_WITHIN: ++ case HA_READ_MBR_DISJOINT: ++ my_error(ER_TABLE_CANT_HANDLE_SPKEYS, MYF(0)); ++ return(PAGE_CUR_UNSUPP); ++ /* do not use "default:" in order to produce a gcc warning: ++ enumeration value '...' not handled in switch ++ (if -Wswitch or -Wall is used) ++ */ + } + +- return(0); ++ my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "this functionality"); ++ ++ return(PAGE_CUR_UNSUPP); + } + + /* +@@ -3831,11 +3844,18 @@ + + last_match_mode = (uint) match_mode; + +- innodb_srv_conc_enter_innodb(prebuilt->trx); ++ if (mode != PAGE_CUR_UNSUPP) { + +- ret = row_search_for_mysql((byte*) buf, mode, prebuilt, match_mode, 0); ++ innodb_srv_conc_enter_innodb(prebuilt->trx); + +- innodb_srv_conc_exit_innodb(prebuilt->trx); ++ ret = row_search_for_mysql((byte*) buf, mode, prebuilt, ++ match_mode, 0); ++ ++ innodb_srv_conc_exit_innodb(prebuilt->trx); ++ } else { ++ ++ ret = DB_UNSUPPORTED; ++ } + + if (ret == DB_SUCCESS) { + error = 0; +@@ -5150,8 +5170,16 @@ + mode2 = convert_search_mode_to_innobase(max_key ? max_key->flag : + HA_READ_KEY_EXACT); + +- n_rows = btr_estimate_n_rows_in_range(index, range_start, +- mode1, range_end, mode2); ++ if (mode1 != PAGE_CUR_UNSUPP && mode2 != PAGE_CUR_UNSUPP) { ++ ++ n_rows = btr_estimate_n_rows_in_range(index, range_start, ++ mode1, range_end, ++ mode2); ++ } else { ++ ++ n_rows = 0; ++ } ++ + dtuple_free_for_mysql(heap1); + dtuple_free_for_mysql(heap2); + --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/58-disable-ndb-backup-print.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/58-disable-ndb-backup-print.dpatch @@ -0,0 +1,16 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 58-disable-ndb-backup-print.dpatch by Mathias Gug +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Disable ndb_backup_print test. +## http://bugs.mysql.com/bug.php?id=32357 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/t/disabled.def mysql-dfsg-5.0-5.0.51a/mysql-test/t/disabled.def +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/disabled.def 2008-03-27 18:53:44.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/disabled.def 2008-03-27 18:56:00.000000000 -0400 +@@ -16,3 +16,4 @@ + im_options_set : Bug#20294: Instance manager tests fail randomly + im_options_unset : Bug#20294: Instance manager tests fail randomly + im_utils : Bug#20294: Instance manager tests fail randomly ++ndb_backup_print : Bug#32357: ndb_backup_print test fails sometimes in pushbuild --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/101_CVE-2010-1849.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/101_CVE-2010-1849.dpatch @@ -0,0 +1,68 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via large packets +# Origin: upstream, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.0-bugteam/revision/2860 +# Bug: http://bugs.mysql.com/bug.php?id=50974 +# Bug: http://bugs.mysql.com/bug.php?id=53908 +# Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=582526 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/include/mysql_com.h mysql-dfsg-5.0-5.0.51a/include/mysql_com.h +--- mysql-dfsg-5.0-5.0.51a~/include/mysql_com.h 2008-01-11 09:43:14.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/include/mysql_com.h 2010-05-26 10:09:21.000000000 -0400 +@@ -219,6 +219,16 @@ + + my_bool report_error; /* We should report error (we have unreported error) */ + my_bool return_errno; ++#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY) ++ /* ++ Controls whether a big packet should be skipped. ++ ++ Initially set to FALSE by default. Unauthenticated sessions must have ++ this set to FALSE so that the server can't be tricked to read packets ++ indefinitely. ++ */ ++ my_bool skip_big_packet; ++#endif + } NET; + + #define packet_error (~(unsigned long) 0) +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/net_serv.cc mysql-dfsg-5.0-5.0.51a/sql/net_serv.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/net_serv.cc 2008-01-11 09:43:28.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/net_serv.cc 2010-05-26 10:09:21.000000000 -0400 +@@ -141,6 +141,9 @@ + net->query_cache_query= 0; + #endif + net->report_error= 0; ++#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY) ++ net->skip_big_packet= FALSE; ++#endif + + if (vio != 0) /* If real connection */ + { +@@ -938,6 +941,7 @@ + { + #if defined(MYSQL_SERVER) && !defined(NO_ALARM) + if (!net->compress && ++ net->skip_big_packet && + !my_net_skip_rest(net, (uint32) len, &alarmed, &alarm_buff)) + net->error= 3; /* Successfully skiped packet */ + #endif +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/sql_parse.cc mysql-dfsg-5.0-5.0.51a/sql/sql_parse.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/sql_parse.cc 2010-05-26 10:09:16.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.51a/sql/sql_parse.cc 2010-05-26 10:09:21.000000000 -0400 +@@ -456,6 +456,15 @@ + } + send_ok(thd); + thd->password= test(passwd_len); // remember for error messages ++ /* ++ Allow the network layer to skip big packets. Although a malicious ++ authenticated session might use this to trick the server to read ++ big packets indefinitely, this is a previously established behavior ++ that needs to be preserved as to not break backwards compatibility. ++ */ ++#if defined(MYSQL_SERVER) && !defined(EMBEDDED_LIBRARY) ++ thd->net.skip_big_packet= TRUE; ++#endif + /* Ready to handle queries */ + DBUG_RETURN(0); + } --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/95_SECURITY_CVE-2008-3963.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/95_SECURITY_CVE-2008-3963.dpatch @@ -0,0 +1,126 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 95_SECURITY_CVE-2008-3963.dpatch by Marc Deslauriers +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Description: Parse an empty bit-string literal as an empty string. +## DP: Upstream: http://bugs.mysql.com/bug.php?id=35658 +## DP: Patch: http://lists.mysql.com/commits/44886 +## DP: Debian: http://bugs.debian.org/498362 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/r/varbinary.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/varbinary.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/varbinary.result 2008-01-11 10:23:42.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/varbinary.result 2008-11-13 14:59:13.000000000 -0500 +@@ -78,3 +78,34 @@ + select length(a) from t1; + length(a) + 6 ++select 0b01000001; ++0b01000001 ++A ++select 0x41; ++0x41 ++A ++select b'01000001'; ++b'01000001' ++A ++select x'41', 0+x'41'; ++x'41' 0+x'41' ++A 65 ++select N'abc', length(N'abc'); ++abc length(N'abc') ++abc 3 ++select N'', length(N''); ++ length(N'') ++ 0 ++select '', length(''); ++ length('') ++ 0 ++select b'', 0+b''; ++b'' 0+b'' ++ 0 ++select x'', 0+x''; ++x'' 0+x'' ++ 0 ++select 0x; ++ERROR 42S22: Unknown column '0x' in 'field list' ++select 0b; ++ERROR 42S22: Unknown column '0b' in 'field list' +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/t/varbinary.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/varbinary.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/varbinary.test 2008-01-11 10:23:27.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/varbinary.test 2008-11-13 14:59:13.000000000 -0500 +@@ -84,3 +84,31 @@ + alter table t1 modify a varchar(255); + select length(a) from t1; + ++# ++# Bug#35658 (An empty binary value leads to mysqld crash) ++# ++ ++select 0b01000001; ++ ++select 0x41; ++ ++select b'01000001'; ++ ++select x'41', 0+x'41'; ++ ++select N'abc', length(N'abc'); ++ ++select N'', length(N''); ++ ++select '', length(''); ++ ++select b'', 0+b''; ++ ++select x'', 0+x''; ++ ++--error ER_BAD_FIELD_ERROR ++select 0x; ++ ++--error ER_BAD_FIELD_ERROR ++select 0b; ++ +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/item.cc mysql-dfsg-5.0-5.0.51a/sql/item.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/item.cc 2008-01-11 09:43:12.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/item.cc 2008-11-13 14:59:13.000000000 -0500 +@@ -4811,21 +4811,28 @@ + if (!ptr) + return; + str_value.set(ptr, max_length, &my_charset_bin); +- ptr+= max_length - 1; +- ptr[1]= 0; // Set end null for string +- for (; end >= str; end--) ++ ++ if (max_length > 0) + { +- if (power == 256) ++ ptr+= max_length - 1; ++ ptr[1]= 0; // Set end null for string ++ for (; end >= str; end--) + { +- power= 1; +- *ptr--= bits; +- bits= 0; ++ if (power == 256) ++ { ++ power= 1; ++ *ptr--= bits; ++ bits= 0; ++ } ++ if (*end == '1') ++ bits|= power; ++ power<<= 1; + } +- if (*end == '1') +- bits|= power; +- power<<= 1; ++ *ptr= (char) bits; + } +- *ptr= (char) bits; ++ else ++ ptr[0]= 0; ++ + collation.set(&my_charset_bin, DERIVATION_COERCIBLE); + fixed= 1; + } --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/89_ndb__staticlib.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/89_ndb__staticlib.dpatch @@ -0,0 +1,43 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 85_ndb__staticlib.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Patch to remove any dynamic link dependencies to libndbclient.so.0.0.0 + +@DPATCH@ +diff -Nur mysql-dfsg-5.0-5.0.50.orig/ndb/src/cw/cpcd/Makefile.in mysql-dfsg-5.0-5.0.50/ndb/src/cw/cpcd/Makefile.in +--- mysql-dfsg-5.0-5.0.50.orig/ndb/src/cw/cpcd/Makefile.in 2007-10-19 17:18:18.000000000 +0200 ++++ mysql-dfsg-5.0-5.0.50/ndb/src/cw/cpcd/Makefile.in 2007-11-26 20:09:02.000000000 +0100 +@@ -404,7 +404,7 @@ + zlib_dir = @zlib_dir@ + ndb_cpcd_SOURCES = main.cpp CPCD.cpp Process.cpp APIService.cpp Monitor.cpp common.cpp + LDADD_LOC = \ +- $(top_builddir)/ndb/src/libndbclient.la \ ++ $(top_builddir)/ndb/src/.libs/libndbclient.a \ + $(top_builddir)/dbug/libdbug.a \ + $(top_builddir)/mysys/libmysys.a \ + $(top_builddir)/strings/libmystrings.a @NDB_SCI_LIBS@ +diff -Nur mysql-dfsg-5.0-5.0.50.orig/ndb/src/mgmsrv/Makefile.in mysql-dfsg-5.0-5.0.50/ndb/src/mgmsrv/Makefile.in +--- mysql-dfsg-5.0-5.0.50.orig/ndb/src/mgmsrv/Makefile.in 2007-10-19 17:18:25.000000000 +0200 ++++ mysql-dfsg-5.0-5.0.50/ndb/src/mgmsrv/Makefile.in 2007-11-26 20:09:23.000000000 +0100 +@@ -431,7 +431,7 @@ + -I$(top_srcdir)/ndb/src/mgmclient + + LDADD_LOC = $(top_builddir)/ndb/src/mgmclient/CommandInterpreter.lo \ +- $(top_builddir)/ndb/src/libndbclient.la \ ++ $(top_builddir)/ndb/src/.libs/libndbclient.a \ + $(top_builddir)/dbug/libdbug.a \ + $(top_builddir)/mysys/libmysys.a \ + $(top_builddir)/strings/libmystrings.a \ +diff -Nur mysql-dfsg-5.0-5.0.50.orig/ndb/tools/Makefile.in mysql-dfsg-5.0-5.0.50/ndb/tools/Makefile.in +--- mysql-dfsg-5.0-5.0.50.orig/ndb/tools/Makefile.in 2007-10-19 17:18:29.000000000 +0200 ++++ mysql-dfsg-5.0-5.0.50/ndb/tools/Makefile.in 2007-11-26 20:10:03.000000000 +0100 +@@ -559,7 +559,7 @@ + -I$(top_srcdir)/ndb/test/include \ + -I$(top_srcdir)/ndb/include/mgmapi \ + -I$(top_srcdir)/ndb/include/kernel +-LDADD = $(LDADD_LOC) $(top_builddir)/ndb/src/libndbclient.la \ ++LDADD = $(LDADD_LOC) $(top_builddir)/ndb/src/.libs/libndbclient.a \ + $(top_builddir)/dbug/libdbug.a \ + $(top_builddir)/mysys/libmysys.a \ + $(top_builddir)/strings/libmystrings.a @NDB_SCI_LIBS@ --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/54_ssl-client-support.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/54_ssl-client-support.dpatch @@ -0,0 +1,80 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 54_ssl-client-support.dpatch by Norbert Tretkowski +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: http://bugs.mysql.com/bug.php?id=33292 + +@DPATCH@ + +diff -Nrup a/vio/viossl.c b/vio/viossl.c +--- a/vio/viossl.c 2007-08-28 11:34:42 +02:00 ++++ b/vio/viossl.c 2008-02-07 08:48:27 +01:00 +@@ -172,20 +172,15 @@ void vio_ssl_delete(Vio *vio) + vio_delete(vio); + } + +-int sslaccept(struct st_VioSSLFd *ptr, Vio *vio, long timeout) +-{ +- DBUG_ENTER("sslaccept"); +- DBUG_RETURN(sslconnect(ptr, vio, timeout)); +-} +- + +-int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout) ++static int ssl_do(struct st_VioSSLFd *ptr, Vio *vio, long timeout, ++ int (*connect_accept_func)(SSL*)) + { + SSL *ssl; + my_bool unused; + my_bool was_blocking; + +- DBUG_ENTER("sslconnect"); ++ DBUG_ENTER("ssl_do"); + DBUG_PRINT("enter", ("ptr: 0x%lx, sd: %d ctx: 0x%lx", + (long) ptr, vio->sd, (long) ptr->ssl_context)); + +@@ -204,13 +199,9 @@ int sslconnect(struct st_VioSSLFd *ptr, + SSL_SESSION_set_timeout(SSL_get_session(ssl), timeout); + SSL_set_fd(ssl, vio->sd); + +- /* +- SSL_do_handshake will select between SSL_connect +- or SSL_accept depending on server or client side +- */ +- if (SSL_do_handshake(ssl) < 1) ++ if (connect_accept_func(ssl) < 1) + { +- DBUG_PRINT("error", ("SSL_do_handshake failure")); ++ DBUG_PRINT("error", ("SSL_connect/accept failure")); + report_errors(ssl); + SSL_free(ssl); + vio_blocking(vio, was_blocking, &unused); +@@ -259,6 +250,20 @@ int sslconnect(struct st_VioSSLFd *ptr, + } + + ++int sslaccept(struct st_VioSSLFd *ptr, Vio *vio, long timeout) ++{ ++ DBUG_ENTER("sslaccept"); ++ DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_accept)); ++} ++ ++ ++int sslconnect(struct st_VioSSLFd *ptr, Vio *vio, long timeout) ++{ ++ DBUG_ENTER("sslconnect"); ++ DBUG_RETURN(ssl_do(ptr, vio, timeout, SSL_connect)); ++} ++ ++ + int vio_ssl_blocking(Vio *vio __attribute__((unused)), + my_bool set_blocking_mode, + my_bool *old_mode) +@@ -268,5 +273,7 @@ int vio_ssl_blocking(Vio *vio __attribut + /* Return error if we try to change to non_blocking mode */ + return (set_blocking_mode ? 0 : 1); + } ++ ++ + + #endif /* HAVE_OPENSSL */ --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/103_CVE-2010-1626.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/103_CVE-2010-1626.dpatch @@ -0,0 +1,66 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix DROP TABLE privilege bypass via symlink attack +# Origin: backport, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1-bugteam/revision/3351.37.1 +# Bug: http://bugs.mysql.com/bug.php?id=40980 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/myisam/mi_delete_table.c mysql-dfsg-5.0-5.0.51a/myisam/mi_delete_table.c +--- mysql-dfsg-5.0-5.0.51a~/myisam/mi_delete_table.c 2008-01-11 09:43:12.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/myisam/mi_delete_table.c 2010-05-27 15:20:45.000000000 -0400 +@@ -19,6 +19,41 @@ + + #include "fulltext.h" + ++ ++/** ++ Remove MyISAM data/index file safely ++ ++ @details ++ If name is a symlink and file it is pointing to is not in ++ data directory, file is also removed. ++ ++ @param name file to remove ++ ++ @returns ++ 0 on success or my_errno on failure ++*/ ++ ++static int _mi_safe_delete_file(const char *name) ++{ ++ DBUG_ENTER("_mi_safe_delete_file"); ++ if (my_is_symlink(name) && (*myisam_test_invalid_symlink)(name)) ++ { ++ /* ++ Symlink is pointing to file in data directory. ++ Remove symlink, keep file. ++ */ ++ if (my_delete(name, MYF(MY_WME))) ++ DBUG_RETURN(my_errno); ++ } ++ else ++ { ++ if (my_delete_with_symlink(name, MYF(MY_WME))) ++ DBUG_RETURN(my_errno); ++ } ++ DBUG_RETURN(0); ++} ++ ++ + int mi_delete_table(const char *name) + { + char from[FN_REFLEN]; +@@ -58,12 +93,12 @@ + #endif /* USE_RAID */ + + fn_format(from,name,"",MI_NAME_IEXT,4); +- if (my_delete_with_symlink(from, MYF(MY_WME))) ++ if (_mi_safe_delete_file(from)) + DBUG_RETURN(my_errno); + fn_format(from,name,"",MI_NAME_DEXT,4); + #ifdef USE_RAID + if (raid_type) + DBUG_RETURN(my_raid_delete(from, raid_chunks, MYF(MY_WME)) ? my_errno : 0); + #endif +- DBUG_RETURN(my_delete_with_symlink(from, MYF(MY_WME)) ? my_errno : 0); ++ DBUG_RETURN(_mi_safe_delete_file(from)); + } --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/92_fix_order_by32202.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/92_fix_order_by32202.dpatch @@ -0,0 +1,147 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 92_fix_order_by32202.dpatch by Jamie Strandboge +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/r/group_by.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/group_by.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/group_by.result 2008-01-11 10:23:35.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/group_by.result 2008-03-17 07:41:43.000000000 -0400 +@@ -1113,3 +1113,68 @@ + 3 1 + 3 2 + DROP TABLE t1; ++CREATE TABLE t1( ++id INT AUTO_INCREMENT PRIMARY KEY, ++c1 INT NOT NULL, ++c2 INT NOT NULL, ++UNIQUE KEY (c2,c1)); ++INSERT INTO t1(c1,c2) VALUES (5,1), (4,1), (3,5), (2,3), (1,3); ++SELECT * FROM t1 ORDER BY c1; ++id c1 c2 ++5 1 3 ++4 2 3 ++3 3 5 ++2 4 1 ++1 5 1 ++SELECT * FROM t1 GROUP BY id ORDER BY c1; ++id c1 c2 ++5 1 3 ++4 2 3 ++3 3 5 ++2 4 1 ++1 5 1 ++SELECT * FROM t1 GROUP BY id ORDER BY id DESC; ++id c1 c2 ++5 1 3 ++4 2 3 ++3 3 5 ++2 4 1 ++1 5 1 ++SELECT * FROM t1 GROUP BY c2 ,c1, id ORDER BY c2, c1; ++id c1 c2 ++2 4 1 ++1 5 1 ++5 1 3 ++4 2 3 ++3 3 5 ++SELECT * FROM t1 GROUP BY c2, c1, id ORDER BY c2 DESC, c1; ++id c1 c2 ++3 3 5 ++5 1 3 ++4 2 3 ++2 4 1 ++1 5 1 ++SELECT * FROM t1 GROUP BY c2, c1, id ORDER BY c2 DESC, c1 DESC; ++id c1 c2 ++3 3 5 ++4 2 3 ++5 1 3 ++1 5 1 ++2 4 1 ++SELECT * FROM t1 GROUP BY c2 ORDER BY c2, c1; ++id c1 c2 ++1 5 1 ++4 2 3 ++3 3 5 ++SELECT * FROM t1 GROUP BY c2 ORDER BY c2 DESC, c1; ++id c1 c2 ++3 3 5 ++4 2 3 ++1 5 1 ++SELECT * FROM t1 GROUP BY c2 ORDER BY c2 DESC, c1 DESC; ++id c1 c2 ++3 3 5 ++4 2 3 ++1 5 1 ++DROP TABLE t1; ++End of 5.0 tests +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/t/group_by.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/group_by.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/group_by.test 2008-01-11 10:23:11.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/group_by.test 2008-03-17 07:41:43.000000000 -0400 +@@ -815,3 +815,38 @@ + SELECT c,b FROM t1 GROUP BY c,b; + + DROP TABLE t1; ++ ++# ++# Bug #32202: ORDER BY not working with GROUP BY ++# ++ ++CREATE TABLE t1( ++ id INT AUTO_INCREMENT PRIMARY KEY, ++ c1 INT NOT NULL, ++ c2 INT NOT NULL, ++ UNIQUE KEY (c2,c1)); ++ ++INSERT INTO t1(c1,c2) VALUES (5,1), (4,1), (3,5), (2,3), (1,3); ++ ++# Show that the test cases from the bug report pass ++SELECT * FROM t1 ORDER BY c1; ++SELECT * FROM t1 GROUP BY id ORDER BY c1; ++ ++# Show that DESC is handled correctly ++SELECT * FROM t1 GROUP BY id ORDER BY id DESC; ++ ++# Show that results are correctly ordered when ORDER BY fields ++# are a subset of GROUP BY ones ++SELECT * FROM t1 GROUP BY c2 ,c1, id ORDER BY c2, c1; ++SELECT * FROM t1 GROUP BY c2, c1, id ORDER BY c2 DESC, c1; ++SELECT * FROM t1 GROUP BY c2, c1, id ORDER BY c2 DESC, c1 DESC; ++ ++# Show that results are correctly ordered when GROUP BY fields ++# are a subset of ORDER BY ones ++SELECT * FROM t1 GROUP BY c2 ORDER BY c2, c1; ++SELECT * FROM t1 GROUP BY c2 ORDER BY c2 DESC, c1; ++SELECT * FROM t1 GROUP BY c2 ORDER BY c2 DESC, c1 DESC; ++ ++DROP TABLE t1; ++ ++--echo End of 5.0 tests +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/sql_select.cc mysql-dfsg-5.0-5.0.51a/sql/sql_select.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/sql_select.cc 2008-03-17 07:41:25.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.51a/sql/sql_select.cc 2008-03-17 07:41:43.000000000 -0400 +@@ -1065,10 +1065,19 @@ + We have found that grouping can be removed since groups correspond to + only one row anyway, but we still have to guarantee correct result + order. The line below effectively rewrites the query from GROUP BY +- to ORDER BY . One exception is if skip_sort_order is +- set (see above), then we can simply skip GROUP BY. ++ to ORDER BY . There are two exceptions: ++ - if skip_sort_order is set (see above), then we can simply skip ++ GROUP BY; ++ - we can only rewrite ORDER BY if the ORDER BY fields are 'compatible' ++ with the GROUP BY ones, i.e. either one is a prefix of another. ++ We only check if the ORDER BY is a prefix of GROUP BY. In this case ++ test_if_subpart() copies the ASC/DESC attributes from the original ++ ORDER BY fields. ++ If GROUP BY is a prefix of ORDER BY, then it is safe to leave ++ 'order' as is. + */ +- order= skip_sort_order ? 0 : group_list; ++ if (!order || test_if_subpart(group_list, order)) ++ order= skip_sort_order ? 0 : group_list; + group_list= 0; + group= 0; + } --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/53_integer-gcc-4.2.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/53_integer-gcc-4.2.dpatch @@ -0,0 +1,303 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 53_integer-gcc-4.2.dpatch by Norbert Tretkowski +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: http://bugs.mysql.com/bug.php?id=31799 + +@DPATCH@ +--- 1.9/strings/int2str.c 2007-10-24 09:26:32 +02:00 ++++ 1.10/strings/int2str.c 2007-10-24 09:26:32 +02:00 +@@ -57,6 +57,7 @@ int2str(register long int val, register + register char *p; + long int new_val; + char *dig_vec= upcase ? _dig_vec_upper : _dig_vec_lower; ++ ulong uval= (ulong) val; + + if (radix < 0) + { +@@ -65,7 +66,8 @@ int2str(register long int val, register + if (val < 0) + { + *dst++ = '-'; +- val = -val; ++ /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ ++ uval = (ulong)0 - uval; + } + radix = -radix; + } +@@ -86,8 +88,8 @@ int2str(register long int val, register + */ + p = &buffer[sizeof(buffer)-1]; + *p = '\0'; +- new_val=(ulong) val / (ulong) radix; +- *--p = dig_vec[(uchar) ((ulong) val- (ulong) new_val*(ulong) radix)]; ++ new_val= uval / (ulong) radix; ++ *--p = dig_vec[(uchar) (uval- (ulong) new_val*(ulong) radix)]; + val = new_val; + #ifdef HAVE_LDIV + while (val != 0) +@@ -133,20 +135,22 @@ char *int10_to_str(long int val,char *ds + char buffer[65]; + register char *p; + long int new_val; ++ unsigned long int uval = (unsigned long int) val; + + if (radix < 0) /* -10 */ + { + if (val < 0) + { + *dst++ = '-'; +- val = -val; ++ /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ ++ uval = (unsigned long int)0 - uval; + } + } + + p = &buffer[sizeof(buffer)-1]; + *p = '\0'; +- new_val= (long) ((unsigned long int) val / 10); +- *--p = '0'+ (char) ((unsigned long int) val - (unsigned long) new_val * 10); ++ new_val= (long) (uval / 10); ++ *--p = '0'+ (char) (uval - (unsigned long) new_val * 10); + val = new_val; + + while (val != 0) + +--- 1.9/strings/longlong2str.c 2007-10-24 09:26:32 +02:00 ++++ 1.10/strings/longlong2str.c 2007-10-24 09:26:32 +02:00 +@@ -51,13 +51,15 @@ char *longlong2str(longlong val,char *ds + char buffer[65]; + register char *p; + long long_val; ++ ulonglong uval= (ulonglong) val; + + if (radix < 0) + { + if (radix < -36 || radix > -2) return (char*) 0; + if (val < 0) { + *dst++ = '-'; +- val = -val; ++ /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ ++ uval = (ulonglong)0 - uval; + } + radix = -radix; + } +@@ -65,7 +67,7 @@ char *longlong2str(longlong val,char *ds + { + if (radix > 36 || radix < 2) return (char*) 0; + } +- if (val == 0) ++ if (uval == 0) + { + *dst++='0'; + *dst='\0'; +@@ -74,14 +76,14 @@ char *longlong2str(longlong val,char *ds + p = &buffer[sizeof(buffer)-1]; + *p = '\0'; + +- while ((ulonglong) val > (ulonglong) LONG_MAX) ++ while (uval > (ulonglong) LONG_MAX) + { +- ulonglong quo=(ulonglong) val/(uint) radix; +- uint rem= (uint) (val- quo* (uint) radix); ++ ulonglong quo= uval/(uint) radix; ++ uint rem= (uint) (uval- quo* (uint) radix); + *--p = _dig_vec_upper[rem]; +- val= quo; ++ uval= quo; + } +- long_val= (long) val; ++ long_val= (long) uval; + while (long_val != 0) + { + long quo= long_val/radix; +@@ -100,17 +102,19 @@ char *longlong10_to_str(longlong val,cha + char buffer[65]; + register char *p; + long long_val; ++ ulonglong uval= (ulonglong) val; + + if (radix < 0) + { + if (val < 0) + { + *dst++ = '-'; +- val = -val; ++ /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ ++ uval = (ulonglong)0 - uval; + } + } + +- if (val == 0) ++ if (uval == 0) + { + *dst++='0'; + *dst='\0'; +@@ -119,14 +123,14 @@ char *longlong10_to_str(longlong val,cha + p = &buffer[sizeof(buffer)-1]; + *p = '\0'; + +- while ((ulonglong) val > (ulonglong) LONG_MAX) ++ while (uval > (ulonglong) LONG_MAX) + { +- ulonglong quo=(ulonglong) val/(uint) 10; +- uint rem= (uint) (val- quo* (uint) 10); ++ ulonglong quo= uval/(uint) 10; ++ uint rem= (uint) (uval- quo* (uint) 10); + *--p = _dig_vec_upper[rem]; +- val= quo; ++ uval= quo; + } +- long_val= (long) val; ++ long_val= (long) uval; + while (long_val != 0) + { + long quo= long_val/10; + +--- 1.65/strings/ctype-ucs2.c 2007-10-24 09:26:32 +02:00 ++++ 1.66/strings/ctype-ucs2.c 2007-10-24 09:26:32 +02:00 +@@ -1018,6 +1018,7 @@ int my_l10tostr_ucs2(CHARSET_INFO *cs, + register char *p, *db, *de; + long int new_val; + int sl=0; ++ unsigned long int uval = (unsigned long int) val; + + p = &buffer[sizeof(buffer)-1]; + *p='\0'; +@@ -1027,12 +1028,13 @@ int my_l10tostr_ucs2(CHARSET_INFO *cs, + if (val < 0) + { + sl = 1; +- val = -val; ++ /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ ++ uval = (unsigned long int)0 - uval; + } + } + +- new_val = (long) ((unsigned long int) val / 10); +- *--p = '0'+ (char) ((unsigned long int) val - (unsigned long) new_val * 10); ++ new_val = (long) (uval / 10); ++ *--p = '0'+ (char) (uval - (unsigned long) new_val * 10); + val = new_val; + + while (val != 0) +@@ -1065,34 +1067,36 @@ int my_ll10tostr_ucs2(CHARSET_INFO *cs _ + register char *p, *db, *de; + long long_val; + int sl=0; ++ ulonglong uval= (ulonglong) val; + + if (radix < 0) + { + if (val < 0) + { + sl=1; +- val = -val; ++ /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ ++ uval = (ulonglong)0 - uval; + } + } + + p = &buffer[sizeof(buffer)-1]; + *p='\0'; + +- if (val == 0) ++ if (uval == 0) + { + *--p='0'; + goto cnv; + } + +- while ((ulonglong) val > (ulonglong) LONG_MAX) ++ while (uval > (ulonglong) LONG_MAX) + { +- ulonglong quo=(ulonglong) val/(uint) 10; +- uint rem= (uint) (val- quo* (uint) 10); ++ ulonglong quo= uval/(uint) 10; ++ uint rem= (uint) (uval- quo* (uint) 10); + *--p = '0' + rem; +- val= quo; ++ uval= quo; + } + +- long_val= (long) val; ++ long_val= (long) uval; + while (long_val != 0) + { + long quo= long_val/10; + +--- 1.82/strings/ctype-simple.c 2007-10-24 09:26:32 +02:00 ++++ 1.83/strings/ctype-simple.c 2007-10-24 09:26:32 +02:00 +@@ -837,6 +837,7 @@ int my_long10_to_str_8bit(CHARSET_INFO * + register char *p, *e; + long int new_val; + uint sign=0; ++ unsigned long int uval = (unsigned long int) val; + + e = p = &buffer[sizeof(buffer)-1]; + *p= 0; +@@ -845,15 +846,16 @@ int my_long10_to_str_8bit(CHARSET_INFO * + { + if (val < 0) + { +- val= -val; ++ /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ ++ uval= (unsigned long int)0 - uval; + *dst++= '-'; + len--; + sign= 1; + } + } + +- new_val = (long) ((unsigned long int) val / 10); +- *--p = '0'+ (char) ((unsigned long int) val - (unsigned long) new_val * 10); ++ new_val = (long) (uval / 10); ++ *--p = '0'+ (char) (uval - (unsigned long) new_val * 10); + val = new_val; + + while (val != 0) +@@ -876,12 +878,14 @@ int my_longlong10_to_str_8bit(CHARSET_IN + register char *p, *e; + long long_val; + uint sign= 0; ++ ulonglong uval = (ulonglong)val; + + if (radix < 0) + { + if (val < 0) + { +- val = -val; ++ /* Avoid integer overflow in (-val) for LONGLONG_MIN (BUG#31799). */ ++ uval = (ulonglong)0 - uval; + *dst++= '-'; + len--; + sign= 1; +@@ -891,22 +895,22 @@ int my_longlong10_to_str_8bit(CHARSET_IN + e = p = &buffer[sizeof(buffer)-1]; + *p= 0; + +- if (val == 0) ++ if (uval == 0) + { + *--p= '0'; + len= 1; + goto cnv; + } + +- while ((ulonglong) val > (ulonglong) LONG_MAX) ++ while (uval > (ulonglong) LONG_MAX) + { +- ulonglong quo=(ulonglong) val/(uint) 10; +- uint rem= (uint) (val- quo* (uint) 10); ++ ulonglong quo= uval/(uint) 10; ++ uint rem= (uint) (uval- quo* (uint) 10); + *--p = '0' + rem; +- val= quo; ++ uval= quo; + } + +- long_val= (long) val; ++ long_val= (long) uval; + while (long_val != 0) + { + long quo= long_val/10; --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/97_CVE-2009-4019.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/97_CVE-2009-4019.dpatch @@ -0,0 +1,161 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via certain SELECT statements with +# subqueries and statements that use the GeomFromWKB function +# Origin: upstream, http://lists.mysql.com/commits/88069 +# Origin: upstream, http://lists.mysql.com/commits/88742 +# Bug: http://bugs.mysql.com/47780 +# Bug: http://bugs.mysql.com/48291 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/r/gis.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/gis.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/gis.result 2008-01-11 10:23:35.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/gis.result 2010-01-21 17:00:52.000000000 -0500 +@@ -888,4 +888,16 @@ + SELECT 1; + 1 + 1 ++# ++# Bug #47780: crash when comparing GIS items from subquery ++# ++CREATE TABLE t1(a INT, b MULTIPOLYGON); ++INSERT INTO t1 VALUES ++(0, ++GEOMFROMTEXT( ++'multipolygon(((1 2,3 4,5 6,7 8,9 8),(7 6,5 4,3 2,1 2,3 4)))')); ++# must not crash ++SELECT 1 FROM t1 WHERE a <> (SELECT GEOMETRYCOLLECTIONFROMWKB(b) FROM t1); ++1 ++DROP TABLE t1; + End of 5.0 tests +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/r/select.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/select.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/select.result 2010-01-21 17:00:04.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/select.result 2010-01-21 17:01:10.000000000 -0500 +@@ -4135,4 +4135,16 @@ + 1 + 1 + DROP TABLE t1, t2, t3; ++# ++# Bug #48291 : crash with row() operator,select into @var, and ++# subquery returning multiple rows ++# ++CREATE TABLE t1(a INT); ++INSERT INTO t1 VALUES (2),(3); ++# Should not crash ++SELECT 1 FROM t1 WHERE a <> 1 AND NOT ++ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1)) ++INTO @var0; ++ERROR 21000: Subquery returns more than 1 row ++DROP TABLE t1; + End of 5.0 tests +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/t/gis.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/gis.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/gis.test 2008-01-11 10:23:11.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/gis.test 2010-01-21 17:00:15.000000000 -0500 +@@ -590,4 +590,20 @@ + --enable_query_log + SELECT 1; + ++--echo # ++--echo # Bug #47780: crash when comparing GIS items from subquery ++--echo # ++ ++CREATE TABLE t1(a INT, b MULTIPOLYGON); ++INSERT INTO t1 VALUES ++ (0, ++ GEOMFROMTEXT( ++ 'multipolygon(((1 2,3 4,5 6,7 8,9 8),(7 6,5 4,3 2,1 2,3 4)))')); ++ ++--echo # must not crash ++SELECT 1 FROM t1 WHERE a <> (SELECT GEOMETRYCOLLECTIONFROMWKB(b) FROM t1); ++ ++DROP TABLE t1; ++ ++ + --echo End of 5.0 tests +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/t/select.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/select.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/select.test 2010-01-21 17:00:04.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/select.test 2010-01-21 17:00:15.000000000 -0500 +@@ -3520,4 +3520,22 @@ + + DROP TABLE t1, t2, t3; + ++ ++--echo # ++--echo # Bug #48291 : crash with row() operator,select into @var, and ++--echo # subquery returning multiple rows ++--echo # ++ ++CREATE TABLE t1(a INT); ++INSERT INTO t1 VALUES (2),(3); ++ ++--echo # Should not crash ++--error ER_SUBQUERY_NO_1_ROW ++SELECT 1 FROM t1 WHERE a <> 1 AND NOT ++ROW(a,a) <=> ROW((SELECT 1 FROM t1 WHERE 1=2),(SELECT 1 FROM t1)) ++INTO @var0; ++ ++DROP TABLE t1; ++ ++ + --echo End of 5.0 tests +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/item_geofunc.cc mysql-dfsg-5.0-5.0.51a/sql/item_geofunc.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/item_geofunc.cc 2008-01-11 09:43:19.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/item_geofunc.cc 2010-01-21 17:00:15.000000000 -0500 +@@ -83,7 +83,10 @@ + + str->set_charset(&my_charset_bin); + if (str->reserve(SRID_SIZE, 512)) +- return 0; ++ { ++ null_value= TRUE; /* purecov: inspected */ ++ return 0; /* purecov: inspected */ ++ } + str->length(0); + str->q_append(srid); + if ((null_value= +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/sql_class.cc mysql-dfsg-5.0-5.0.51a/sql/sql_class.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/sql_class.cc 2008-01-11 09:43:38.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/sql_class.cc 2010-01-21 17:00:15.000000000 -0500 +@@ -1987,9 +1987,11 @@ + else + { + Item_func_set_user_var *suv= new Item_func_set_user_var(mv->s, item); +- suv->fix_fields(thd, 0); ++ if (suv->fix_fields(thd, 0)) ++ DBUG_RETURN (1); + suv->check(0); +- suv->update(); ++ if (suv->update()) ++ DBUG_RETURN (1); + } + } + DBUG_RETURN(0); +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/sql_select.cc mysql-dfsg-5.0-5.0.51a/sql/sql_select.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/sql_select.cc 2010-01-21 17:00:04.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/sql_select.cc 2010-01-21 17:00:15.000000000 -0500 +@@ -10649,6 +10649,7 @@ + bool not_used_in_distinct=join_tab->not_used_in_distinct; + ha_rows found_records=join->found_records; + COND *select_cond= join_tab->select_cond; ++ bool select_cond_result= TRUE; + + if (error > 0 || (*report_error)) // Fatal error + return NESTED_LOOP_ERROR; +@@ -10660,7 +10661,17 @@ + return NESTED_LOOP_KILLED; /* purecov: inspected */ + } + DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond)); +- if (!select_cond || select_cond->val_int()) ++ ++ if (select_cond) ++ { ++ select_cond_result= test(select_cond->val_int()); ++ ++ /* check for errors evaluating the condition */ ++ if (join->thd->net.report_error) ++ return NESTED_LOOP_ERROR; ++ } ++ ++ if (!select_cond || select_cond_result) + { + /* + There is no select condition or the attached pushed down --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/94_fix_mysqldump_with_old_versions.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/94_fix_mysqldump_with_old_versions.dpatch @@ -0,0 +1,61 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run + +@DPATCH@ +diff -Naur mysql-dfsg-5.0-5.0.51a.orig/client/mysqldump.c mysql-dfsg-5.0-5.0.51a/client/mysqldump.c +--- mysql-dfsg-5.0-5.0.51a.orig/client/mysqldump.c 2008-01-11 14:43:27.000000000 +0000 ++++ mysql-dfsg-5.0-5.0.51a/client/mysqldump.c 2008-09-08 15:25:34.000000000 +0000 +@@ -109,6 +109,8 @@ + *log_error_file= NULL; + static char **defaults_argv= 0; + static char compatible_mode_normal_str[255]; ++/* Server supports character_set_results session variable? */ ++static my_bool server_supports_switching_charsets= TRUE; + static ulong opt_compatible_mode= 0; + #define MYSQL_OPT_MASTER_DATA_EFFECTIVE_SQL 1 + #define MYSQL_OPT_MASTER_DATA_COMMENTED_SQL 2 +@@ -992,12 +994,27 @@ + return 0; + } + ++/** ++ Switch charset for results to some specified charset. If the server does not ++ support character_set_results variable, nothing can be done here. As for ++ whether something should be done here, future new callers of this function ++ should be aware that the server lacking the facility of switching charsets is ++ treated as success. + ++ @note If the server lacks support, then nothing is changed and no error ++ condition is returned. ++ ++ @returns whether there was an error or not ++*/ + static int switch_character_set_results(MYSQL *mysql, const char *cs_name) + { + char query_buffer[QUERY_LENGTH]; + size_t query_length; + ++ /* Server lacks facility. This is not an error, by arbitrary decision . */ ++ if (!server_supports_switching_charsets) ++ return FALSE; ++ + query_length= my_snprintf(query_buffer, + sizeof (query_buffer), + "SET SESSION character_set_results = '%s'", +@@ -1093,11 +1110,14 @@ + DB_error(&mysql_connection, "when trying to connect"); + DBUG_RETURN(1); + } +- /* +- Don't dump SET NAMES with a pre-4.1 server (bug#7997). +- */ + if (mysql_get_server_version(&mysql_connection) < 40100) ++ { ++ /* Don't dump SET NAMES with a pre-4.1 server (bug#7997). */ + opt_set_charset= 0; ++ ++ /* Don't switch charsets for 4.1 and earlier. (bug#34192). */ ++ server_supports_switching_charsets= FALSE; ++ } + /* + As we're going to set SQL_MODE, it would be lost on reconnect, so we + cannot reconnect. --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/93_fix_user_setup_on_localhost.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/93_fix_user_setup_on_localhost.dpatch @@ -0,0 +1,18 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 93_fix_user_setup_on_localhost.dpatch by Daniel Hahler +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/scripts/mysql_system_tables_data.sql mysql-dfsg-5.0-5.0.51a/scripts/mysql_system_tables_data.sql +--- mysql-dfsg-5.0-5.0.51a~/scripts/mysql_system_tables_data.sql 2008-01-11 15:43:26.000000000 +0100 ++++ mysql-dfsg-5.0-5.0.51a/scripts/mysql_system_tables_data.sql 2008-04-28 20:57:08.084428731 +0200 +@@ -18,6 +18,6 @@ + REPLACE INTO tmp_user VALUES (@@hostname,'root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0); + REPLACE INTO tmp_user VALUES ('127.0.0.1','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y','','','','',0,0,0,0); + INSERT INTO tmp_user (host,user) VALUES ('localhost',''); +-INSERT INTO tmp_user (host,user) VALUES (@@hostname,''); ++REPLACE INTO tmp_user (host,user) VALUES (@@hostname,''); + INSERT INTO user SELECT * FROM tmp_user WHERE @had_user_table=0; + DROP TABLE tmp_user; --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/98_CVE-2010-3837.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/98_CVE-2010-3837.dpatch @@ -0,0 +1,102 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via use of GROUP_CONCAT() and +# WITH ROLLUP together +# Origin: upstream, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3461.1.7 +# Bug: http://bugs.mysql.com/bug.php?id=54476 + +@DPATCH@ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/r/func_gconcat.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/func_gconcat.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/func_gconcat.result 2008-01-11 10:23:34.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/func_gconcat.result 2010-11-09 11:39:34.000000000 -0500 +@@ -820,3 +820,22 @@ + 2 ra,ra + drop table t1; + End of 5.0 tests ++# ++# Bug #54476: crash when group_concat and 'with rollup' in prepared statements ++# ++CREATE TABLE t1 (a INT); ++INSERT INTO t1 VALUES (1), (2); ++PREPARE stmt FROM "SELECT GROUP_CONCAT(t1.a ORDER BY t1.a) FROM t1 JOIN t1 t2 GROUP BY t1.a WITH ROLLUP"; ++EXECUTE stmt; ++GROUP_CONCAT(t1.a ORDER BY t1.a) ++1,1 ++2,2 ++1,1,2,2 ++EXECUTE stmt; ++GROUP_CONCAT(t1.a ORDER BY t1.a) ++1,1 ++2,2 ++1,1,2,2 ++DEALLOCATE PREPARE stmt; ++DROP TABLE t1; ++End of 5.1 tests +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/t/func_gconcat.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/func_gconcat.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/func_gconcat.test 2008-01-11 10:23:10.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/func_gconcat.test 2010-11-09 11:39:34.000000000 -0500 +@@ -563,3 +563,18 @@ + drop table t1; + + --echo End of 5.0 tests ++--echo # ++--echo # Bug #54476: crash when group_concat and 'with rollup' in prepared statements ++--echo # ++ ++CREATE TABLE t1 (a INT); ++INSERT INTO t1 VALUES (1), (2); ++ ++PREPARE stmt FROM "SELECT GROUP_CONCAT(t1.a ORDER BY t1.a) FROM t1 JOIN t1 t2 GROUP BY t1.a WITH ROLLUP"; ++EXECUTE stmt; ++EXECUTE stmt; ++ ++DEALLOCATE PREPARE stmt; ++DROP TABLE t1; ++ ++--echo End of 5.1 tests +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/item_sum.cc mysql-dfsg-5.0-5.0.51a/sql/item_sum.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/item_sum.cc 2008-01-11 09:43:39.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/item_sum.cc 2010-11-09 11:39:34.000000000 -0500 +@@ -3073,7 +3073,6 @@ + separator(item->separator), + tree(item->tree), + table(item->table), +- order(item->order), + context(item->context), + arg_count_order(item->arg_count_order), + arg_count_field(item->arg_count_field), +@@ -3086,6 +3085,24 @@ + { + quick_group= item->quick_group; + result.set_charset(collation.collation); ++ ++ /* ++ Since the ORDER structures pointed to by the elements of the 'order' array ++ may be modified in find_order_in_list() called from ++ Item_func_group_concat::setup(), create a copy of those structures so that ++ such modifications done in this object would not have any effect on the ++ object being copied. ++ */ ++ ORDER *tmp; ++ if (!(order= (ORDER **) thd->alloc(sizeof(ORDER *) * arg_count_order + ++ sizeof(ORDER) * arg_count_order))) ++ return; ++ tmp= (ORDER *)(order + arg_count_order); ++ for (uint i= 0; i < arg_count_order; i++, tmp++) ++ { ++ memcpy(tmp, item->order[i], sizeof(ORDER)); ++ order[i]= tmp; ++ } + } + + +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/table.h mysql-dfsg-5.0-5.0.51a/sql/table.h +--- mysql-dfsg-5.0-5.0.51a~/sql/table.h 2008-01-11 09:43:26.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/table.h 2010-11-09 11:39:34.000000000 -0500 +@@ -30,7 +30,6 @@ + struct st_order *next; + Item **item; /* Point at item in select fields */ + Item *item_ptr; /* Storage for initial item */ +- Item **item_copy; /* For SPs; the original item ptr */ + int counter; /* position in SELECT list, correct + only if counter_used is true*/ + bool asc; /* true if ascending */ --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/102_CVE-2010-1848.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/102_CVE-2010-1848.dpatch @@ -0,0 +1,94 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix privilege check bypass via crafted table name argument +# to COM_FIELD_LIST +# Origin: backport, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.0-bugteam/revision/2861 +# Bug: http://bugs.mysql.com/bug.php?id=53371 +# Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=582526 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/sql_parse.cc mysql-dfsg-5.0-5.0.51a/sql/sql_parse.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/sql_parse.cc 2010-05-26 10:40:20.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.51a/sql/sql_parse.cc 2010-05-26 10:40:44.000000000 -0400 +@@ -1886,6 +1886,13 @@ + } + thd->convert_string(&conv_name, system_charset_info, + packet, arg_length, thd->charset()); ++ if (check_table_name (conv_name.str, conv_name.length)) ++ { ++ /* this is OK due to convert_string() null-terminating the string */ ++ my_error(ER_WRONG_TABLE_NAME, MYF(0), conv_name.str); ++ break; ++ } ++ + table_list.alias= table_list.table_name= conv_name.str; + packet= pend+1; + +diff -urNad mysql-dfsg-5.0-5.0.51a~/tests/mysql_client_test.c mysql-dfsg-5.0-5.0.51a/tests/mysql_client_test.c +--- mysql-dfsg-5.0-5.0.51a~/tests/mysql_client_test.c 2010-05-26 10:40:20.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.51a/tests/mysql_client_test.c 2010-05-26 10:41:08.000000000 -0400 +@@ -115,6 +115,8 @@ + + #define DIE_UNLESS(expr) \ + ((void) ((expr) ? 0 : (die(__FILE__, __LINE__, #expr), 0))) ++#define DIE_IF(expr) \ ++ ((void) ((expr) ? (die(__FILE__, __LINE__, #expr), 0) : 0)) + #define DIE(expr) \ + die(__FILE__, __LINE__, #expr) + +@@ -15878,6 +15880,48 @@ + DBUG_VOID_RETURN; + } + ++ ++static void test_bug53371() ++{ ++ int rc; ++ MYSQL_RES *result; ++ ++ myheader("test_bug53371"); ++ ++ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1"); ++ myquery(rc); ++ rc= mysql_query(mysql, "DROP DATABASE IF EXISTS bug53371"); ++ myquery(rc); ++ rc= mysql_query(mysql, "DROP USER 'testbug'@localhost"); ++ ++ rc= mysql_query(mysql, "CREATE TABLE t1 (a INT)"); ++ myquery(rc); ++ rc= mysql_query(mysql, "CREATE DATABASE bug53371"); ++ myquery(rc); ++ rc= mysql_query(mysql, "GRANT SELECT ON bug53371.* to 'testbug'@localhost"); ++ myquery(rc); ++ ++ rc= mysql_change_user(mysql, "testbug", NULL, "bug53371"); ++ myquery(rc); ++ ++ rc= mysql_query(mysql, "SHOW COLUMNS FROM client_test_db.t1"); ++ DIE_UNLESS(rc); ++ DIE_UNLESS(mysql_errno(mysql) == 1142); ++ ++ result= mysql_list_fields(mysql, "../client_test_db/t1", NULL); ++ DIE_IF(result); ++ ++ rc= mysql_change_user(mysql, opt_user, opt_password, current_db); ++ myquery(rc); ++ rc= mysql_query(mysql, "DROP TABLE t1"); ++ myquery(rc); ++ rc= mysql_query(mysql, "DROP DATABASE bug53371"); ++ myquery(rc); ++ rc= mysql_query(mysql, "DROP USER 'testbug'@localhost"); ++ myquery(rc); ++} ++ ++ + /* + Read and parse arguments and MySQL options from my.cnf + */ +@@ -16165,6 +16209,7 @@ + { "test_bug27592", test_bug27592 }, + { "test_bug29948", test_bug29948 }, + { "test_bug29306", test_bug29306 }, ++ { "test_bug53371", test_bug53371 }, + { 0, 0 } + }; + --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/98_CVE-2010-3835.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/98_CVE-2010-3835.dpatch @@ -0,0 +1,84 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via user-variable assignment expression. +# Origin: upstream, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3461.1.18 +# Bug: http://bugs.mysql.com/bug.php?id=55564 + +@DPATCH@ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/r/user_var.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/user_var.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/user_var.result 2008-01-11 10:23:42.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/user_var.result 2010-11-09 11:35:42.000000000 -0500 +@@ -353,3 +353,20 @@ + 2.6 1 + 1.6 4 + drop table t1; ++CREATE TABLE t1(a INT); ++INSERT INTO t1 VALUES (0),(0); ++# BUG#55615 : should not crash ++SELECT (@a:=(SELECT @a:=1 FROM t1 LIMIT 1)) AND COUNT(1) FROM t1 GROUP BY @a; ++(@a:=(SELECT @a:=1 FROM t1 LIMIT 1)) AND COUNT(1) ++1 ++1 ++# BUG#55564 : should not crash ++SELECT IF( ++@v:=LEAST((SELECT 1 FROM t1 t2 LEFT JOIN t1 ON (@v) GROUP BY t1.a), a), ++count(*), 1) ++FROM t1 GROUP BY a LIMIT 1; ++IF( ++@v:=LEAST((SELECT 1 FROM t1 t2 LEFT JOIN t1 ON (@v) GROUP BY t1.a), a), ++count(*), 1) ++1 ++DROP TABLE t1; +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/t/user_var.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/user_var.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/user_var.test 2008-01-11 10:23:27.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/user_var.test 2010-11-09 11:36:07.000000000 -0500 +@@ -237,3 +237,21 @@ + select @a:=f3, count(f3) from t1 group by 1 desc; + select @a:=f4, count(f4) from t1 group by 1 desc; + drop table t1; ++# ++# Bug #55615: debug assertion after using variable in assignment and ++# referred to ++# Bug #55564: crash with user variables, assignments, joins... ++# ++ ++CREATE TABLE t1(a INT); ++INSERT INTO t1 VALUES (0),(0); ++--echo # BUG#55615 : should not crash ++SELECT (@a:=(SELECT @a:=1 FROM t1 LIMIT 1)) AND COUNT(1) FROM t1 GROUP BY @a; ++--echo # BUG#55564 : should not crash ++SELECT IF( ++ @v:=LEAST((SELECT 1 FROM t1 t2 LEFT JOIN t1 ON (@v) GROUP BY t1.a), a), ++ count(*), 1) ++FROM t1 GROUP BY a LIMIT 1; ++ ++DROP TABLE t1; ++ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/item_func.cc mysql-dfsg-5.0-5.0.51a/sql/item_func.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/item_func.cc 2010-11-09 11:35:00.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/item_func.cc 2010-11-09 11:35:08.000000000 -0500 +@@ -4254,6 +4254,14 @@ + return entry->val_int(&null_value); + } + ++bool Item_func_set_user_var::val_bool_result() ++{ ++ DBUG_ASSERT(fixed == 1); ++ check(TRUE); ++ update(); // Store expression ++ return entry->val_int(&null_value) != 0; ++} ++ + String *Item_func_set_user_var::str_result(String *str) + { + DBUG_ASSERT(fixed == 1); +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/item_func.h mysql-dfsg-5.0-5.0.51a/sql/item_func.h +--- mysql-dfsg-5.0-5.0.51a~/sql/item_func.h 2008-01-11 09:43:28.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/item_func.h 2010-11-09 11:35:08.000000000 -0500 +@@ -1210,6 +1210,7 @@ + my_decimal *val_decimal(my_decimal *); + double val_result(); + longlong val_int_result(); ++ bool val_bool_result(); + String *str_result(String *str); + my_decimal *val_decimal_result(my_decimal *); + bool update_hash(void *ptr, uint length, enum Item_result type, --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/97_CVE-2008-4456.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/97_CVE-2008-4456.dpatch @@ -0,0 +1,58 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix cross-site scripting in the command-line client +# Origin: upstream, http://lists.mysql.com/commits/91358 +# Bug: http://bugs.mysql.com/bug.php?id=27884 +# Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=526254 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/client/mysql.cc mysql-dfsg-5.0-5.0.51a/client/mysql.cc +--- mysql-dfsg-5.0-5.0.51a~/client/mysql.cc 2010-01-21 16:58:57.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/client/mysql.cc 2010-01-21 16:59:05.000000000 -0500 +@@ -2533,9 +2533,12 @@ + { + while((field = mysql_fetch_field(result))) + { +- tee_fprintf(PAGER, "%s", (field->name ? +- (field->name[0] ? field->name : +- "   ") : "NULL")); ++ tee_fputs("", PAGER); ++ if (field->name && field->name[0]) ++ xmlencode_print(field->name, field->name_length); ++ else ++ tee_fputs(field->name ? "   " : "NULL", PAGER); ++ tee_fputs("", PAGER); + } + (void) tee_fputs("", PAGER); + } +@@ -2546,7 +2549,7 @@ + for (uint i=0; i < mysql_num_fields(result); i++) + { + (void) tee_fputs("", PAGER); +- safe_put_field(cur[i],lengths[i]); ++ xmlencode_print(cur[i], lengths[i]); + (void) tee_fputs("", PAGER); + } + (void) tee_fputs("", PAGER); +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/r/mysql.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/mysql.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/mysql.result 2008-01-11 10:23:39.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/mysql.result 2010-01-21 16:59:28.000000000 -0500 +@@ -178,4 +178,5 @@ + 1 + 1 + 1 ++
<
< & >
+ End of 5.0 tests +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/t/mysql.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/mysql.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/mysql.test 2008-01-11 10:23:15.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/mysql.test 2010-01-21 16:59:05.000000000 -0500 +@@ -281,4 +281,10 @@ + # + --exec $MYSQL test -e "/*! \C latin1 */ select 1;" + ++# ++# Bug #27884: mysql --html does not quote HTML special characters in output ++# ++--exec $MYSQL --html test -e "select '< & >' as \`<\`" ++--echo ++ + --echo End of 5.0 tests --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/38_scripts__mysqld_safe.sh__signals.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/38_scripts__mysqld_safe.sh__signals.dpatch @@ -0,0 +1,45 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 38_scripts__mysqld_safe.sh__signals.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Executes /etc/init.d/mysql on signals + +@DPATCH@ + +--- old/scripts/mysqld_safe.sh 2005-02-15 14:43:48.000000000 -0800 ++++ new/scripts/mysqld_safe.sh 2005-02-21 13:02:55.000000000 -0800 +@@ -10,8 +10,6 @@ + # mysql.server works by first doing a cd to the base directory and from there + # executing mysqld_safe + +-trap '' 1 2 3 15 # we shouldn't let anyone kill us +- + umask 007 + + KILL_MYSQLD=1; +@@ -274,6 +272,13 @@ + fi + + # ++# From now on, we catch signals to do a proper shutdown of mysqld ++# when signalled to do so. ++# ++trap '/usr/bin/mysqladmin --defaults-extra-file=/etc/mysql/debian.cnf refresh' 1 # HUP ++trap '/usr/bin/mysqladmin --defaults-extra-file=/etc/mysql/debian.cnf shutdown' 2 3 15 # INT QUIT and TERM ++ ++# + # Uncomment the following lines if you want all tables to be automatically + # checked and repaired during startup. You should add sensible key_buffer + # and sort_buffer values to my.cnf to improve check performance or require +@@ -299,9 +304,9 @@ + rm -f $safe_mysql_unix_port $pid_file # Some extra safety + if test -z "$args" + then +- $NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file @MYSQLD_DEFAULT_SWITCHES@ 2>&1 | $ERR_LOGGER -t mysqld ++ $NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file @MYSQLD_DEFAULT_SWITCHES@ 2>&1 | $ERR_LOGGER -t mysqld & wait + else +- eval "$NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file @MYSQLD_DEFAULT_SWITCHES@ $args 2>&1 | $ERR_LOGGER -t mysqld" ++ eval "$NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file @MYSQLD_DEFAULT_SWITCHES@ $args 2>&1 | $ERR_LOGGER -t mysqld & wait" + fi + if test ! -f $pid_file # This is removed if normal shutdown + then --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/99_ssl_test_certs.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/99_ssl_test_certs.dpatch @@ -0,0 +1,688 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: update certificates in test suite as they are expired +# Origin: upstream, http://lists.mysql.com/commits/98623 +# Bug: http://bugs.mysql.com/bug.php?id=50642 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/r/openssl_1.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/openssl_1.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/openssl_1.result 2008-01-11 10:23:39.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/openssl_1.result 2010-01-29 12:35:16.000000000 -0500 +@@ -3,8 +3,8 @@ + insert into t1 values (5); + grant select on test.* to ssl_user1@localhost require SSL; + grant select on test.* to ssl_user2@localhost require cipher "DHE-RSA-AES256-SHA"; +-grant select on test.* to ssl_user3@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "/C=SE/ST=Uppsala/L=Uppsala/O=MySQL AB/emailAddress=abstract.mysql.developer@mysql.com"; +-grant select on test.* to ssl_user4@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "/C=SE/ST=Uppsala/L=Uppsala/O=MySQL AB/emailAddress=abstract.mysql.developer@mysql.com" ISSUER "/C=SE/ST=Uppsala/L=Uppsala/O=MySQL AB"; ++grant select on test.* to ssl_user3@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "/C=SE/ST=Uppsala/O=MySQL AB"; ++grant select on test.* to ssl_user4@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "/C=SE/ST=Uppsala/O=MySQL AB" ISSUER "/C=SE/ST=Uppsala/L=Uppsala/O=MySQL AB"; + grant select on test.* to ssl_user5@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "xxx"; + flush privileges; + connect(localhost,ssl_user5,,test,MASTER_PORT,MASTER_SOCKET); +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/cacert.pem mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/cacert.pem +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/cacert.pem 2008-01-11 10:23:44.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/cacert.pem 2010-01-29 12:35:16.000000000 -0500 +@@ -1,17 +1,17 @@ + -----BEGIN CERTIFICATE----- +-MIICrTCCAhagAwIBAgIJAIAO/Ybiptv1MA0GCSqGSIb3DQEBBAUAMEQxCzAJBgNV ++MIICrTCCAhagAwIBAgIJAMI7xZKjhrDbMA0GCSqGSIb3DQEBBAUAMEQxCzAJBgNV + BAYTAlNFMRAwDgYDVQQIEwdVcHBzYWxhMRAwDgYDVQQHEwdVcHBzYWxhMREwDwYD +-VQQKEwhNeVNRTCBBQjAeFw0wNjA1MDMwODQ4NTRaFw0wOTAxMjcwODQ4NTRaMEQx ++VQQKEwhNeVNRTCBBQjAeFw0xMDAxMjkxMTQ3MTBaFw0xNTAxMjgxMTQ3MTBaMEQx + CzAJBgNVBAYTAlNFMRAwDgYDVQQIEwdVcHBzYWxhMRAwDgYDVQQHEwdVcHBzYWxh + MREwDwYDVQQKEwhNeVNRTCBBQjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +-+C46EQl1u7tQ6gb9eqc8V079gr8YmDPCEqtjO8bCIbchpjOpDITx0WZz36Sn9E72 +-GPJwNip4FxLaPRIA3xNQHM5cE5U53qznlRx1Fc4O3hcWCvyCqNDl/vzPAh3pI6Bl +-Ku9hfHXpp93W812smVPe9haShEXGgbEPYGzvOfVdu/MCAwEAAaOBpjCBozAdBgNV +-HQ4EFgQUjIy/6OCTmqtPHBFha6/qzVk3yTcwdAYDVR0jBG0wa4AUjIy/6OCTmqtP +-HBFha6/qzVk3yTehSKRGMEQxCzAJBgNVBAYTAlNFMRAwDgYDVQQIEwdVcHBzYWxh +-MRAwDgYDVQQHEwdVcHBzYWxhMREwDwYDVQQKEwhNeVNRTCBBQoIJAIAO/Ybiptv1 +-MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEEBQADgYEA8lD9zyB820Oq1aj7ZafX +-De/hbdt9RIl2tzgw2K3r1KZGdXJVL0vSt5fZ51Nq9lg7OPJy3iXf+caBJEp0IJpB +-uf4Gfr6zfXw+UlY6ZthRtHQHoXKcbskECjH5/ps/Uaa+dpVQ9O+Ii1rPzmgo6ztM +-s+xZ46ESBt4WiHXm8kwbU9Y= ++wQYsOEfrN4ESP3FjsI8cghE+tZVuyK2gck61lwieVxjgFMtBd65mI5a1y9pmlOI1 ++yM4SB2Ppqcuw7/e1CdV1y7lvHrGNt5yqEHbN4QX1gvsN8TQauP/2WILturk4R4Hq ++rKg0ZySu7f1Xhl0ed9a48LpaEHD17IcxWEGMMJwAxF0CAwEAAaOBpjCBozAMBgNV ++HRMEBTADAQH/MB0GA1UdDgQWBBSvktYQ0ahLnyxyVKqty+WpBbBrDTB0BgNVHSME ++bTBrgBSvktYQ0ahLnyxyVKqty+WpBbBrDaFIpEYwRDELMAkGA1UEBhMCU0UxEDAO ++BgNVBAgTB1VwcHNhbGExEDAOBgNVBAcTB1VwcHNhbGExETAPBgNVBAoTCE15U1FM ++IEFCggkAwjvFkqOGsNswDQYJKoZIhvcNAQEEBQADgYEAdKN1PjwMHAKG2Ww1145g ++JQGBnKxSFOUaoSvkBi/4ntTM+ysnViWh7WvxyWjR9zU9arfr7aqsDeQxm0XDOqzj ++AQ/cQIla2/Li8tXyfc06bisH/IHRaSc2zWqioTKbEwMdVOdrvq4a8V8ic3xYyIWn ++7F4WeS07J8LKardSvM0+hOA= + -----END CERTIFICATE----- +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/client-cert.pem mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/client-cert.pem +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/client-cert.pem 2008-01-11 10:23:44.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/client-cert.pem 2010-01-29 12:35:16.000000000 -0500 +@@ -1,42 +1,46 @@ + Certificate: + Data: + Version: 1 (0x0) +- Serial Number: 1 (0x1) ++ Serial Number: 1048577 (0x100001) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=SE, ST=Uppsala, L=Uppsala, O=MySQL AB + Validity +- Not Before: May 3 08:55:39 2006 GMT +- Not After : Jan 27 08:55:39 2009 GMT +- Subject: C=SE, ST=Uppsala, L=Uppsala, O=MySQL AB/emailAddress=abstract.mysql.developer@mysql.com ++ Not Before: Jan 29 11:50:22 2010 GMT ++ Not After : Jan 28 11:50:22 2015 GMT ++ Subject: C=SE, ST=Uppsala, O=MySQL AB + Subject Public Key Info: + Public Key Algorithm: rsaEncryption +- RSA Public Key: (512 bit) +- Modulus (512 bit): +- 00:d8:db:68:28:49:84:4d:d6:0f:5c:bc:3d:9a:ab: +- 70:d5:3e:f5:b5:17:ba:ef:e1:f8:87:54:30:22:1f: +- 81:07:bf:f9:24:7f:8a:54:10:e9:5f:e6:99:50:04: +- d4:3b:55:a9:f1:52:ad:12:2b:5a:da:5c:be:8c:3e: +- 5b:9e:b0:5a:19 ++ Public-Key: (1024 bit) ++ Modulus: ++ 00:cc:9a:37:49:13:66:dc:cf:e3:0b:13:a1:23:ed: ++ 78:db:4e:bd:11:f6:8c:0d:76:f9:a3:32:56:9a:f8: ++ a1:21:6a:55:4e:4d:3f:e6:67:9d:26:99:b2:cd:a4: ++ 9a:d2:2b:59:5c:d7:8a:d3:60:68:f8:18:bd:c5:be: ++ 15:e1:2a:3c:a3:d4:61:cb:f5:11:94:17:81:81:f7: ++ 87:8c:f6:6a:d2:ee:d8:e6:77:f6:62:66:4d:2e:16: ++ 8d:08:81:4a:c9:c6:4b:31:e5:b9:c7:8a:84:96:48: ++ a7:47:8c:0d:26:90:56:4e:e6:a5:6e:8c:b3:f2:9f: ++ fc:3d:78:9b:49:6e:86:83:77 + Exponent: 65537 (0x10001) + Signature Algorithm: md5WithRSAEncryption +- 07:57:bf:07:92:c2:8e:86:24:6b:0a:bf:e5:31:21:44:c3:60: +- 02:a6:ac:9e:f7:db:7a:6e:fc:4f:d4:7b:54:18:80:47:d2:4a: +- 63:0e:e3:f8:af:6e:58:e3:97:5a:2b:82:5d:76:20:d1:33:a0: +- f5:43:a1:d1:51:f4:ca:c8:b3:1a:66:4e:0e:55:df:d2:e8:fa: +- 83:18:42:f5:ec:66:40:f0:39:e8:f9:d7:cf:f6:dd:e4:7b:69: +- dd:0c:92:d8:52:95:43:6f:29:3d:f0:8d:4c:dd:52:ea:6b:a0: +- 39:0f:dc:59:a7:5c:37:6b:8b:05:44:b7:69:ea:a3:58:e0:4e: +- ce:d6 ++ 5e:1f:a3:53:5f:24:13:1c:f8:28:32:b0:7f:69:69:f3:0e:c0: ++ 34:87:10:03:7d:da:15:8b:bd:19:b8:1a:56:31:e7:85:49:81: ++ c9:7f:45:20:74:3e:89:c0:e0:26:84:51:cc:04:16:ce:69:99: ++ 01:e1:26:99:b3:e3:f5:bd:ec:5f:a0:84:e4:38:da:75:78:7b: ++ 89:9c:d2:cd:60:95:20:ba:8e:e3:7c:e6:df:76:3a:7c:89:77: ++ 02:94:86:11:3a:c4:61:7d:6f:71:83:21:8a:17:fb:17:e2:ee: ++ 02:6b:61:c1:b4:52:63:d7:d8:46:b2:c5:9c:6f:38:91:8a:35: ++ 32:0b + -----BEGIN CERTIFICATE----- +-MIIB5jCCAU8CAQEwDQYJKoZIhvcNAQEEBQAwRDELMAkGA1UEBhMCU0UxEDAOBgNV +-BAgTB1VwcHNhbGExEDAOBgNVBAcTB1VwcHNhbGExETAPBgNVBAoTCE15U1FMIEFC +-MB4XDTA2MDUwMzA4NTUzOVoXDTA5MDEyNzA4NTUzOVowdzELMAkGA1UEBhMCU0Ux +-EDAOBgNVBAgTB1VwcHNhbGExEDAOBgNVBAcTB1VwcHNhbGExETAPBgNVBAoTCE15 +-U1FMIEFCMTEwLwYJKoZIhvcNAQkBFiJhYnN0cmFjdC5teXNxbC5kZXZlbG9wZXJA +-bXlzcWwuY29tMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANjbaChJhE3WD1y8PZqr +-cNU+9bUXuu/h+IdUMCIfgQe/+SR/ilQQ6V/mmVAE1DtVqfFSrRIrWtpcvow+W56w +-WhkCAwEAATANBgkqhkiG9w0BAQQFAAOBgQAHV78HksKOhiRrCr/lMSFEw2ACpqye +-99t6bvxP1HtUGIBH0kpjDuP4r25Y45daK4JddiDRM6D1Q6HRUfTKyLMaZk4OVd/S +-6PqDGEL17GZA8Dno+dfP9t3ke2ndDJLYUpVDbyk98I1M3VLqa6A5D9xZp1w3a4sF +-RLdp6qNY4E7O1g== ++MIIB5zCCAVACAxAAATANBgkqhkiG9w0BAQQFADBEMQswCQYDVQQGEwJTRTEQMA4G ++A1UECBMHVXBwc2FsYTEQMA4GA1UEBxMHVXBwc2FsYTERMA8GA1UEChMITXlTUUwg ++QUIwHhcNMTAwMTI5MTE1MDIyWhcNMTUwMTI4MTE1MDIyWjAyMQswCQYDVQQGEwJT ++RTEQMA4GA1UECBMHVXBwc2FsYTERMA8GA1UEChMITXlTUUwgQUIwgZ8wDQYJKoZI ++hvcNAQEBBQADgY0AMIGJAoGBAMyaN0kTZtzP4wsToSPteNtOvRH2jA12+aMyVpr4 ++oSFqVU5NP+ZnnSaZss2kmtIrWVzXitNgaPgYvcW+FeEqPKPUYcv1EZQXgYH3h4z2 ++atLu2OZ39mJmTS4WjQiBSsnGSzHluceKhJZIp0eMDSaQVk7mpW6Ms/Kf/D14m0lu ++hoN3AgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAXh+jU18kExz4KDKwf2lp8w7ANIcQ ++A33aFYu9GbgaVjHnhUmByX9FIHQ+icDgJoRRzAQWzmmZAeEmmbPj9b3sX6CE5Dja ++dXh7iZzSzWCVILqO43zm33Y6fIl3ApSGETrEYX1vcYMhihf7F+LuAmthwbRSY9fY ++RrLFnG84kYo1Mgs= + -----END CERTIFICATE----- +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/client-key.pem mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/client-key.pem +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/client-key.pem 2008-01-11 10:23:44.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/client-key.pem 2010-01-29 12:35:16.000000000 -0500 +@@ -1,9 +1,15 @@ + -----BEGIN RSA PRIVATE KEY----- +-MIIBOgIBAAJBANjbaChJhE3WD1y8PZqrcNU+9bUXuu/h+IdUMCIfgQe/+SR/ilQQ +-6V/mmVAE1DtVqfFSrRIrWtpcvow+W56wWhkCAwEAAQJAK27WT6tZylUjQomZNQ89 +-TBiOEbUtBbqWklQ0R8FTkH9uKV+8KYQ+k+tMkoAEGFfChB0YfofNQ2KZYWWw4yOB +-WQIhAPXXDQt73aou10s+cmKM3C3WzLmIZtrvm9wNBXWDGxgTAiEA4dG4cXrZfa1M +-TTbjzNU1/Jf50/M8SvZDWMPQWxJ8oqMCIH6zBpYUkHlVCsBMvsbrsc4uFfTIx7mu +-I7WVQGr/1sbhAiBf4uFirjtztgZUMx5/d3k5DH80lG/hlLf8FQl/4lWx6QIhAPHw +-CXfPUbUFl4r/i9Br5+exGol50qX4F3aP5Sh5EnZT ++MIICXQIBAAKBgQDMmjdJE2bcz+MLE6Ej7XjbTr0R9owNdvmjMlaa+KEhalVOTT/m ++Z50mmbLNpJrSK1lc14rTYGj4GL3FvhXhKjyj1GHL9RGUF4GB94eM9mrS7tjmd/Zi ++Zk0uFo0IgUrJxksx5bnHioSWSKdHjA0mkFZO5qVujLPyn/w9eJtJboaDdwIDAQAB ++AoGASqk/4We2En+93y3jkIO4pXafIe3w/3zZ7caRue1ehx4RUQh5d+95djuB9u7J ++HEZ7TpjM7QNyao5EueL6gvbxt0LXFvqAMni7yM9tt/HUYtHHPqYiRtUny9bKYFTm ++l8szCCMal/wD9GZU9ByHDNHm7tHUMyMhARNTYSgx+SERFmECQQD/6jJocC4SXf6f ++T3LqimWR02lbJ7qCoDgRglsUXh0zjrG+IIiAyE+QOCCx1GMe3Uw6bsIuYwdHT6as ++WcdPs04xAkEAzKulvEvLVvN5zfa/DTYRTV7jh6aDleOxjsD5oN/oJXoACnPzVuUL ++qQQMNtuAXm6Q1QItrRxpQsSKbY0UQka6JwJBAOSgoNoG5lIIYTKIMvzwGV+XBLeo ++HYsXgh+6Wo4uql3mLErUG78ZtWL9kc/tE4R+ZdyKGLaCR/1gXmH5bwN4B/ECQEBb ++uUH8k3REG4kojesZlVc+/00ojzgS4UKCa/yqa9VdB6ZBz8MDQydinnShkTwgiGpy ++xOoqhO753o2UT0qH8wECQQC99IEJWUnwvExVMkLaZH5NjAFJkb22sjkmuT11tAgU ++RQgOMoDOm6driojnOnDWOkx1r1Gy9NgMLooduja4v6cx + -----END RSA PRIVATE KEY----- +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/server-cert-des.pem mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/server-cert-des.pem +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/server-cert-des.pem 2008-01-11 10:23:44.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/server-cert-des.pem 1969-12-31 19:00:00.000000000 -0500 +@@ -1,16 +0,0 @@ +------BEGIN CERTIFICATE----- +-MIICljCCAX4CAQEwDQYJKoZIhvcNAQEEBQAwUTELMAkGA1UEBhMCU0UxEDAOBgNV +-BAgTB1VwcHNhbGExETAPBgNVBAoTCE15U1FMIEFCMRAwDgYDVQQLEwdTdXBwb3J0 +-MQswCQYDVQQDEwJDQTAeFw0wNjA4MjgxMTA4NTlaFw0wOTA1MjQxMTA4NTlaMFUx +-CzAJBgNVBAYTAlNFMRAwDgYDVQQIEwdVcHBzYWxhMREwDwYDVQQKEwhNeVNRTCBB +-QjEQMA4GA1UECxMHU3VwcG9ydDEPMA0GA1UEAxMGc2VydmVyMIGfMA0GCSqGSIb3 +-DQEBAQUAA4GNADCBiQKBgQDEiOVZcWYzZe7I8xhhUwCzvmkZifAXeMTH+8XKGLHX +-NWF3FLduAmeAad9oOZgBKb+oWTdRDWXqwu6nYYUBfrUpaY27/wLkgWRgewL3LZnw +-W2FjhNsjx3gI2NK+Pix47q9d+a+5T4AW5+lK499l0K0k2cvyFdIerhDW8R0t8Uru +-twIDAQABMA0GCSqGSIb3DQEBBAUAA4IBAQC2LQcqLg52RbelWrKutlJ5E6rzugnJ +-ZAlbN9sM98O2xFiIGDA3tb5j9LAEjE0E+RqdptEYnvy9b3szhLYXtIILZTkClf9r +-Uwu1nUYPTyp+9ZYCa4fovOU5h1Ogv+9UZPds/LPDwWEn8K+lvscB4X57wJyuoEck +-1Mu41OA6h77181MydSdgZo0oquJDWhdCsYHXVFVs0F6naMm2uPMCTDiQVlhHJuTO +-VQMNIwxRFtvsv2tpsXsaP/8sT32d5CFebfxxSVnqQvJ4ZdIrphl6L43XU01rsEcE +-K8KYujZQ6SKws+HVcGqsr7TPgJfJE6D+5RazvvIQISPvx4eduebqzqdC +------END CERTIFICATE----- +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/server-cert.pem mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/server-cert.pem +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/server-cert.pem 2008-01-11 10:23:44.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/server-cert.pem 2010-01-29 12:35:16.000000000 -0500 +@@ -1,42 +1,41 @@ + Certificate: + Data: + Version: 1 (0x0) +- Serial Number: 1 (0x1) ++ Serial Number: 1048578 (0x100002) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=SE, ST=Uppsala, L=Uppsala, O=MySQL AB + Validity +- Not Before: May 3 08:54:13 2006 GMT +- Not After : Jan 27 08:54:13 2009 GMT +- Subject: C=SE, ST=Uppsala, L=Uppsala, O=MySQL AB, CN=localhost/emailAddress=abstract.mysql.developer@mysql.com ++ Not Before: Jan 29 11:56:49 2010 GMT ++ Not After : Jan 28 11:56:49 2015 GMT ++ Subject: C=SE, ST=Uppsala, O=MySQL AB, CN=localhost + Subject Public Key Info: + Public Key Algorithm: rsaEncryption +- RSA Public Key: (512 bit) +- Modulus (512 bit): +- 00:d9:fd:da:b3:fb:7c:e0:b0:03:be:97:c6:a4:36: +- ac:71:af:bb:2d:e5:84:ed:f3:8f:2b:eb:11:e5:aa: +- 66:ed:bf:62:6b:e3:ce:fa:80:ed:90:ff:b9:4a:39: +- 20:40:b6:f2:99:bf:2f:33:b5:f2:ec:3a:90:60:1d: +- 9e:94:7e:a4:1b ++ Public-Key: (512 bit) ++ Modulus: ++ 00:cd:e4:87:51:9d:72:11:a0:d1:fa:f3:92:8b:13: ++ 1c:eb:f7:e2:9a:2f:72:a8:d6:65:48:d1:69:af:1b: ++ c0:4c:13:e5:60:60:51:41:e9:ab:a6:bc:13:bb:0c: ++ 5e:32:7c:d9:6c:9e:cd:05:24:84:78:db:80:91:2e: ++ d8:88:2b:c2:ed + Exponent: 65537 (0x10001) + Signature Algorithm: md5WithRSAEncryption +- de:5e:35:cd:7b:11:e6:7c:c5:7c:d6:27:4e:72:12:49:42:eb: +- 6f:2c:96:f3:f4:00:78:a7:4f:9f:2d:7b:d7:30:39:af:49:4d: +- df:b1:55:0d:30:be:23:6f:06:67:fd:dd:ba:98:66:36:c6:32: +- b7:ed:63:fc:aa:49:cd:4f:72:98:3b:13:0e:f6:28:d7:d4:eb: +- 04:6b:dc:e8:c7:04:80:92:e4:04:86:0b:ed:32:25:76:1d:a9: +- 5c:a9:2c:18:2c:bd:bc:15:ed:e1:76:96:4d:bb:0d:41:44:06: +- 2c:ad:45:bb:db:61:ad:17:11:cb:49:70:67:eb:c6:27:d3:91: +- c8:f2 ++ 73:ce:9c:6e:39:46:b4:14:be:da:3f:f3:1b:ba:90:bc:23:43: ++ d7:82:2a:70:4e:a6:d9:5a:65:5c:b7:df:71:df:75:77:c5:80: ++ a4:af:fa:d2:59:e2:fd:c9:9c:f0:98:95:8e:69:a9:8c:7c:d8: ++ 6f:48:d2:e3:36:e0:cd:ff:3f:d1:a5:e6:ab:75:09:c4:50:10: ++ c4:96:dd:bf:3b:de:32:46:da:ca:4a:f1:d6:52:8a:33:2f:ab: ++ f5:2e:70:3f:d4:9c:be:00:c8:03:f9:39:8a:df:5b:70:3c:40: ++ ef:03:be:7c:3d:1d:32:32:f3:51:81:e2:83:30:6e:3d:38:9b: ++ fb:3c + -----BEGIN CERTIFICATE----- +-MIIB+zCCAWQCAQEwDQYJKoZIhvcNAQEEBQAwRDELMAkGA1UEBhMCU0UxEDAOBgNV +-BAgTB1VwcHNhbGExEDAOBgNVBAcTB1VwcHNhbGExETAPBgNVBAoTCE15U1FMIEFC +-MB4XDTA2MDUwMzA4NTQxM1oXDTA5MDEyNzA4NTQxM1owgYsxCzAJBgNVBAYTAlNF +-MRAwDgYDVQQIEwdVcHBzYWxhMRAwDgYDVQQHEwdVcHBzYWxhMREwDwYDVQQKEwhN +-eVNRTCBBQjESMBAGA1UEAxMJbG9jYWxob3N0MTEwLwYJKoZIhvcNAQkBFiJhYnN0 +-cmFjdC5teXNxbC5kZXZlbG9wZXJAbXlzcWwuY29tMFwwDQYJKoZIhvcNAQEBBQAD +-SwAwSAJBANn92rP7fOCwA76XxqQ2rHGvuy3lhO3zjyvrEeWqZu2/YmvjzvqA7ZD/ +-uUo5IEC28pm/LzO18uw6kGAdnpR+pBsCAwEAATANBgkqhkiG9w0BAQQFAAOBgQDe +-XjXNexHmfMV81idOchJJQutvLJbz9AB4p0+fLXvXMDmvSU3fsVUNML4jbwZn/d26 +-mGY2xjK37WP8qknNT3KYOxMO9ijX1OsEa9zoxwSAkuQEhgvtMiV2HalcqSwYLL28 +-Fe3hdpZNuw1BRAYsrUW722GtFxHLSXBn68Yn05HI8g== ++MIIBtzCCASACAxAAAjANBgkqhkiG9w0BAQQFADBEMQswCQYDVQQGEwJTRTEQMA4G ++A1UECBMHVXBwc2FsYTEQMA4GA1UEBxMHVXBwc2FsYTERMA8GA1UEChMITXlTUUwg ++QUIwHhcNMTAwMTI5MTE1NjQ5WhcNMTUwMTI4MTE1NjQ5WjBGMQswCQYDVQQGEwJT ++RTEQMA4GA1UECBMHVXBwc2FsYTERMA8GA1UEChMITXlTUUwgQUIxEjAQBgNVBAMT ++CWxvY2FsaG9zdDBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDN5IdRnXIRoNH685KL ++Exzr9+KaL3Ko1mVI0WmvG8BME+VgYFFB6aumvBO7DF4yfNlsns0FJIR424CRLtiI ++K8LtAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAc86cbjlGtBS+2j/zG7qQvCND14Iq ++cE6m2VplXLffcd91d8WApK/60lni/cmc8JiVjmmpjHzYb0jS4zbgzf8/0aXmq3UJ ++xFAQxJbdvzveMkbaykrx1lKKMy+r9S5wP9ScvgDIA/k5it9bcDxA7wO+fD0dMjLz ++UYHigzBuPTib+zw= + -----END CERTIFICATE----- +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/server-key-des.pem mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/server-key-des.pem +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/server-key-des.pem 2008-01-11 10:23:44.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/server-key-des.pem 1969-12-31 19:00:00.000000000 -0500 +@@ -1,18 +0,0 @@ +------BEGIN RSA PRIVATE KEY----- +-Proc-Type: 4,ENCRYPTED +-DEK-Info: DES-EDE3-CBC,D2BE7598C7E3BDA5 +- +-1W3qPgw5ut80OhaAGVZZe/tfFiBAlwpX1SohdApWj+QYP+dK/mdEBhgI3BXTFNLW +-pJqDTzGlKtft7hHN6QDFEdZMKxej5+2iLu14V62o+5yQgUoqswoXcmmqJCJ7AvyJ +-yMBmGAzxRFlQsT8lf6o5TS1/efBvjvWhh3NG2Zq2LpyhWRRqA3kNhzktzt2WjDZe +-ZkKmZJJnArr/Aw7jEBC4sH+nmgxoR18GzDddRG12hv1AWyHc3+VisTBpyNzeBy17 +-rxuQtqLzkAJmId723ddw83RVNSvBUUS3G0rx5O3HPobvZK89UqVxcXtIgc11WTVU +-N3DbcJq5it43Loo0W3gAngtESDm2E3rTadrmdUSDGv2wQ5dNFl6cQ1f397Sdd/WC +-A0grn1tKjJ6COp80Ymdyvn+stjv/+Rl1/KHSeG0lNeZxqjPPOJ7NHaKv7qjYsJ6W +-LT35/Xc3oCo5qk9FOlq/0tGjHxf6RcFr5U7k5ILKZs+RmvJ4Sv/VYShLfLTcfGbJ +-wBNfRKvcHZBQJQBb1+s/kRrjFFtvhrUwLz4+c9kskp+t4qRVYywUAnGGGsMs/GPm +-wYsLQZO6Bs5/taaVUyaJQW015J7FGGv+/7/A1dIhu73S/Xl/YcFbX/CMEVq2Lxxd +-hZdFIuaZ7LE+0MDQWsvYMYPDPLDH11diczb/jeKBdLPOzk/FUqVx3Fin1PpcaBxY +-b+7oZJhYdg/rAWDeQ/nji9qnEG8waK6x1hdkYPOrqqWQPfgM/LPsSrgWeuTSdx2B +-Ixi01UlBb5UP4K7UrjyddPobmcVjXaQLNe7zaq0+OS3UnIG85GtHrQ== +------END RSA PRIVATE KEY----- +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/server-key.pem mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/server-key.pem +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/server-key.pem 2008-01-11 10:23:44.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/server-key.pem 2010-01-29 12:35:16.000000000 -0500 +@@ -1,9 +1,9 @@ + -----BEGIN RSA PRIVATE KEY----- +-MIIBOgIBAAJBANn92rP7fOCwA76XxqQ2rHGvuy3lhO3zjyvrEeWqZu2/YmvjzvqA +-7ZD/uUo5IEC28pm/LzO18uw6kGAdnpR+pBsCAwEAAQJBAMieYdpmRoUaODf9wqh6 +-ULXH/sG8i1vaXRcUHcJ50oRVfVK8/tGGvUuTDu6MeINTdahNDlYfjwOjKWVXys1w +-h6ECIQDs6s7DfczK2bKCLt0zqg24mZL3rOpGmDU+TatwN1yVgwIhAOuMzdVTX39p +-328+5WxJvBOFfxmSmqdDhIFpnRMvgguJAiByvKjT/km+970+1OllyvaIL0AA2OpA +-tBgdC0p6tyUMdwIgKuHAWzTJbu28UolVxQgLaFZmVCZ/ZzIAfnrWsLZ2a1kCIBq/ +-ywJ2cpyFlgazu8AH6KCQa0ok9s70ElaB6FEC85Al ++MIIBOwIBAAJBAM3kh1GdchGg0frzkosTHOv34povcqjWZUjRaa8bwEwT5WBgUUHp ++q6a8E7sMXjJ82WyezQUkhHjbgJEu2Igrwu0CAwEAAQJBAJuwhFbF3NzRpBbEmnqJ ++4GPa1UJMQMLFJF+04tqj/HxJcAIVhOJhGmmtYNw1yjz/ZsPnfJCMz4eFOtdjvGtf ++peECIQDmFFg2WLvYo+2m9w9V7z4ZIkg7ixYkI/ObUUctfZkPOQIhAOUWnrvjFrAX ++bIvYT/YR50+3ZDLEc51XxNgJnWqWYl1VAiEAnTOFWgyivFC1DgF8PvDp8u5TgCt2 ++A1d1GMgd490O+TECIC/WMl0/hTxOF9930vKqOGf//o9PUGkZq8QE9fcM4gtlAiAE ++iOcFpnLjtWj57jrhuw214ucnB5rklkQQe+AtcARNkg== + -----END RSA PRIVATE KEY----- +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/server8k-cert.pem mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/server8k-cert.pem +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/server8k-cert.pem 2008-01-11 10:23:44.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/server8k-cert.pem 2010-01-29 12:35:16.000000000 -0500 +@@ -1,51 +1,125 @@ ++Certificate: ++ Data: ++ Version: 1 (0x0) ++ Serial Number: 1048579 (0x100003) ++ Signature Algorithm: md5WithRSAEncryption ++ Issuer: C=SE, ST=Uppsala, L=Uppsala, O=MySQL AB ++ Validity ++ Not Before: Jan 29 12:01:53 2010 GMT ++ Not After : Jan 28 12:01:53 2015 GMT ++ Subject: C=SE, ST=Uppsala, O=MySQL AB, CN=server ++ Subject Public Key Info: ++ Public Key Algorithm: rsaEncryption ++ Public-Key: (8192 bit) ++ Modulus: ++ 00:ca:aa:1d:c4:11:ec:91:f0:c7:ff:5f:90:92:fc: ++ 40:0c:5e:b7:3d:00:c5:20:d5:0f:89:31:07:d7:41: ++ 4c:8b:60:80:aa:38:14:de:93:6b:9c:74:88:41:68: ++ b5:02:41:01:2d:86:a2:7a:95:53:5e:7b:67:2f:6c: ++ 1e:29:51:f9:44:fd:4a:80:be:b2:23:a1:3e:1b:38: ++ cf:88:c4:71:ee:f8:6b:41:c5:2d:c0:c3:52:ac:59: ++ 7d:81:34:19:95:32:b8:9a:51:b6:41:36:d4:c4:a1: ++ ae:84:e6:38:b9:e8:bf:96:be:19:7a:6b:77:4d:e0: ++ de:e6:b3:b6:6b:bc:3d:dd:68:bc:4b:c4:eb:f5:36: ++ 93:ed:56:a2:15:50:8a:10:e8:d6:22:ed:6c:b1:cd: ++ c3:18:c9:f6:0a:e1:de:61:65:62:d6:14:41:8c:b5: ++ fb:14:68:c1:cf:12:5d:41:21:9d:57:11:43:7d:bb: ++ 43:2c:21:bb:c3:44:7d:a8:cf:1f:c3:71:75:b5:47: ++ c2:7d:ce:38:3c:73:64:9e:15:d8:a7:27:cf:bd:40: ++ c8:45:08:e3:c8:39:a8:0b:8e:c2:5b:7b:f1:47:91: ++ 12:91:cc:e1:00:e0:94:5b:bd:32:e4:0c:8d:c3:be: ++ cc:76:32:52:12:69:b0:18:e0:b0:c2:76:34:5a:5f: ++ 79:d9:f6:81:9d:02:0a:61:69:1c:33:ce:49:fa:76: ++ 03:1e:07:5b:27:0b:bf:34:9e:34:96:b8:03:9b:50: ++ 3a:6a:2f:17:7a:14:cf:65:63:00:37:52:a8:73:ce: ++ 4b:14:40:f4:d2:9a:56:54:33:b8:77:2e:42:5b:8f: ++ ec:1f:18:f4:ad:ab:8a:4a:8d:6d:70:25:f3:58:e7: ++ cb:66:51:14:7d:16:f4:eb:6d:56:76:76:51:6e:d6: ++ 1d:da:d3:8d:c0:64:5a:67:4e:af:e2:bf:33:d1:b8: ++ f6:2a:fc:57:87:a7:35:5e:80:c9:ac:fc:87:c9:71: ++ 17:91:bf:b7:4d:a3:ed:3c:1b:27:f4:66:a0:f9:46: ++ 03:27:cc:ea:80:f6:4b:40:f6:41:94:cd:bd:0a:b3: ++ ef:26:be:de:6f:69:ae:0f:3f:1c:55:63:33:90:9b: ++ ed:ca:5a:12:4d:de:4b:06:c2:a2:92:b0:42:3d:31: ++ af:a4:15:12:15:f8:8a:e9:88:8d:cf:fd:85:66:50: ++ 6f:11:f1:9f:48:f3:b5:ba:9d:86:68:24:a2:5d:a8: ++ 7c:54:42:fa:d8:b5:c5:f2:dd:0e:0f:d0:68:e4:54: ++ 7e:c5:b9:a0:9b:65:2d:77:f4:8f:b9:30:0a:d5:86: ++ 5c:ed:c9:7c:d1:da:9d:0d:63:50:ee:e5:1e:92:63: ++ cc:a2:0c:e8:4a:96:02:4d:dc:8f:df:7c:8f:08:18: ++ a8:30:88:d7:af:89:ad:fc:57:4b:10:f9:f1:cb:48: ++ e8:b6:3b:c8:3f:fc:c2:d3:d1:4a:10:3c:1b:6b:64: ++ dc:e5:65:1e:5b:b2:da:b1:e2:24:97:8f:ee:c0:4b: ++ 8e:18:83:7c:17:a6:3c:45:b3:60:06:23:f2:2f:18: ++ 13:9e:17:8a:c6:72:79:8c:4d:04:f3:9d:ea:e0:25: ++ d3:33:8c:1e:11:47:63:1f:a5:45:3f:bd:85:b3:fe: ++ a5:68:ee:48:b7:0c:a4:c9:7f:72:d0:75:66:9b:6a: ++ f9:a0:50:f3:a8:59:6d:a3:dd:38:4f:70:2b:bb:ff: ++ 92:2e:71:ab:ef:e9:00:ed:0d:d1:b4:6f:f0:8e:b2: ++ 09:fb:4d:61:0d:d9:10:d5:54:11:cd:03:94:84:fd: ++ a8:68:e4:45:6e:1e:6a:1e:2f:85:a1:6d:f5:b6:c0: ++ f1:ee:f7:36:e9:fe:c2:f7:ad:cc:13:46:5b:88:42: ++ f0:2d:1f:b5:0e:7e:b5:2b:e4:8d:ab:b9:87:30:6a: ++ 3d:12:f4:ad:f3:1c:ac:cc:1a:48:29:2a:96:7b:80: ++ 00:0b:6e:59:87:bf:a3:ca:70:99:1b:1c:fd:72:3d: ++ b2:d3:94:4a:cf:55:75:be:1f:40:ec:55:35:48:2d: ++ 55:f0:00:da:3c:b0:60:ba:11:32:66:54:0b:be:06: ++ a4:5e:b7:c9:59:bb:4d:f4:92:06:26:48:6e:c2:12: ++ d4:7c:f0:20:b8:a2:e1:bc:6a:b6:19:0e:37:47:55: ++ c9:f2:49:0d:96:75:a2:84:64:bf:34:fc:be:b2:41: ++ e4:f5:88:eb:e1:b7:26:a5:e5:41:c2:20:0c:f6:e2: ++ a8:a5:e7:76:54:a5:fb:4b:80:05:7d:18:85:7a:ba: ++ bc:b7:ad:c0:2f:60:85:cc:15:12:1c:2f:0a:9e:f3: ++ 7c:40:cf:f4:3e:23:d2:95:ca:d0:06:58:52:f0:84: ++ d8:0f:3d:eb:ff:12:68:94:79:8f:be:40:29:5f:98: ++ c8:90:6c:05:2f:99:8c:2a:63:78:1f:23:b1:29:c5: ++ e7:49:c9:b2:92:0f:53:0b:d5:71:28:17:c2:19:bf: ++ 60:bf:7c:87:a8:ab:c1:f4:0a:c1:b8:d2:68:ee:c1: ++ ce:a7:13:13:17:6d:24:5d:a2:37:a6:d7:7d:48:8b: ++ 2b:74:2d:40:2e:ca:19:d5:b6:3e:6c:42:71:fa:cf: ++ 85:87:f9:de:80:73:8b:89:f4:70:f0:d8:d7:ff:40: ++ 41:9c:c7:15:6d:9b:6e:4c:b5:52:02:99:79:32:73: ++ ca:26:a0:ac:31:6f:c4:b0:f5:da:bb:c2:1f:e0:9f: ++ 44:ba:25:f7:9f ++ Exponent: 65537 (0x10001) ++ Signature Algorithm: md5WithRSAEncryption ++ 08:75:dc:b9:3f:aa:b6:7e:81:7a:39:d1:ee:ed:44:b6:ce:1b: ++ 37:c4:4c:19:d0:66:e6:eb:b5:4f:2a:ef:95:58:64:21:55:01: ++ 12:30:ac:8a:95:d1:06:de:29:46:a4:f1:7d:7f:b0:1e:d2:4e: ++ fb:f6:fa:9a:74:be:85:62:db:0b:82:90:58:62:c5:5f:f1:80: ++ 02:9f:c5:fb:f3:6b:b0:b4:3b:04:b1:e5:53:c2:d0:00:a1:1a: ++ 9d:65:60:6f:73:98:67:e0:9c:c8:12:94:79:59:bf:43:7b:f5: ++ 77:c8:8f:df:b1:cd:11:1c:01:19:99:c2:22:42:f7:41:ae:b4: ++ b8:1a + -----BEGIN CERTIFICATE----- +-MIIJHDCCBQQCAQEwDQYJKoZIhvcNAQEEBQAwTjELMAkGA1UEBhMCU0UxEDAOBgNV +-BAgTB1VwcHNhbGExETAPBgNVBAoTCE15U1FMIEFCMQ0wCwYDVQQLEwRUZXN0MQsw +-CQYDVQQDEwJDQTAeFw0wNzA3MTMwNzU2MjVaFw0xMDA0MDgwNzU2MjVaMFoxCzAJ +-BgNVBAYTAlNFMRAwDgYDVQQIEwdVcHBzYWxhMRkwFwYDVQQKFBBNeVNRTCAgIAog +-ICAgIEFCMQ0wCwYDVQQLEwRUZXN0MQ8wDQYDVQQDEwZzZXJ2ZXIwggQiMA0GCSqG +-SIb3DQEBAQUAA4IEDwAwggQKAoIEAQDUFlh/3mwov5YaICFXOdJXgHV/uDkTjXB6 +-9oxlipshQaYPX8LDT5vhI3gPciS1Z1sRE2dTcC4Mk2K4LDUIjp3WkeTfFAHZPV3E +-Y+3OH/ftH4N6SEIBTKE4EY6ah0nJtU98M0JhxOh5zHje6zQp1SkBnhEOQYexYRqj +-OtGloZ9RyF0iFAXcyu2Ap14u37l5Yla0cyPzvZqP4mFYlcXwaRfAacJmqMM1vuQv +-Fx1JITUTBugMF3VGZ1F0tw63EIUH/FW/WWncPqvG18na40qlv9ZkBw0FhZeKS8cK +-JIY5y4J30jn/eV8p1lTO7K+ASTuGZWmdRDgjUG0Y9OGuKsPPoaE6ml0HTnMBsBSQ +-fXUq9XkwGt8DTgPioAKHBHjLbILEy4FMYWrlTZlPTzNqyhayec/2T15oDladNSt7 +-JpDLpX70UECXFhdEGxsGxtXdKbIBvNm2yT4X2nxW9ItsECjSSgD+94TgGoa8QKDw +-rpmgq+Wqpm54CZ1vN1oqyMUw1sjNEX/iLByHAjSALby2Kffk5cl5mnsR6d/k4jsi +-c3Qsciwkd+rQt/8VMhS2ns3nkez/BK3FvQA2Ms8xJhFLfszVrBhnjcFRTNT2+/KM +-lr1oT5Q1XZKL7qVXTpabPL51JlVBL5CSHl1QRkffsqfqcgJkcHBq+kKjUiFs4lad +-hTrvNBCXYa5+NkA2QqIfdOpNwl62/gdE7/7zU1uh40vkVKyzL+APkLPywPEXBOpQ +-yIDNkgoXmS10+JMD44K7uZyUmxZL7W7Xbi30NuEFrVOzoUmVXhapPbpQnkQHxn8n +-tqKPYXdBcvXcCKyJ6i79H2Vk9fM6rBYiwNcE7QyWqfd2QMjzr76veF04sXkPR+tG +-5Y1lrF9Zp3vabFXQg2RJuGA3rV6MR2GFNXuChIYu410vhIhPNtmdKEVoIVZsFsug +-+dtn0PDCFrR8VEd/sshp0naNa9Ad1lY+marJkOJOVpPgCs2yJDPAUB/YdvSJ4avW +-6ZdvNTwhBL8fEJMS2DSqkaa6A3+i/SqITpU8ToJxsMGagBsLieXgvJALFysSRfR/ +-2dmEu9/J0PPc28inHXwjiLb99VKlkuEz8wX9UkuoqFl0pLa8jrlM8hzdPQ9QHb3k +-9c5knfgPCYkOIWwGXH+NwANHdQRK7CmGAFV24k9+P3q0g5ikabVHr+4ZQ3WPd+1H +-K0+Msbb/vv53vFJWa+pYeNeFcwNCyW2kJBTMiI6qmlL4IWCcX+QDzpRLalbAWWHj +-l5Zk39QEaCL024DYK948IDXCqDg6utEs7YnMdaIF0meYMKjehZFp0fVQ8e8Od+rp +-bbjdj/w60wMgBpSOeYxVrs3QKNZd/if4Az3LggoVHB09SjXKiWpvAgMBAAEwDQYJ +-KoZIhvcNAQEEBQADggQBABncOBW0wQwJdEB6W3d9CrhFp40q1OM54GPfX0/0aUfP +-aOQPxS1uCKcFhxAmR4OT9RiJx+0bhDctekkuMkj5yy3u0a/4PxHIhnVxXTyB0/Hj +-N1gLz6cQricunl6Q4Ldi54gR5/KUehKLBWnqsfxhgzWBHosvhlJC0xh/uio7JTqz +-ns60djyL7R4wGbSqiGdhT9L2HfpJo3dmmWLDxe02jaHkbL1Z6NQMxrRgs3+gctp/ +-Wd5UxNl4BHbNsSbzaK9V9gXUcj4TjZGGSqVki0+pEZ3dmksGZdoW9cSKtzKvgUQ6 +-vhhqO4dcopxkY2zYeVOpspgTm0XLZSbNPXv5rSFwa4cpWSfD7u8o8KhHvkkSMahw +-cMuH17W4voHHFDtWP8Oq9rA7uE/4/LKCl0JmJl2RWM+G6PMH8w4X4auHPssgRvb/ +-Ge1AvgqQJrvi7zWx3XYKKJ0ISBy7fi5Jo/wYgLagRYcG3mwdm1+gAdw+77C/ZGmG +-FbWFIPB1+Mc6azhhk9m/vqP7o/Wuncc99mp2zPMzdAEzuzp/IJ9UJNat0edA7jiC +-bQ7JSRJ1DSzdJZSWWHdardLNKipPfrEHVm7f5QvL5DQLnGpt+rCWL361KsGtvETC +-o+Ph7+kDJsJLokUYfs/BEZopzspNPy/NQ2ECwQp7T4Yq/PBE6Ce/dFaoZysMUOrG +-TcALtJW6It98dRmTJPiqjlrlHNTrfoV3Aiy+tK4rpyGuApSHc+1Y+t7YvWotRlQ4 +-GEboBqR8evjDPJ1xAaUZqwLkebf3mlpl4MzHM9uNWBkQdJilkQs/IrAaApG3Ayt0 +-nIymNHmDslBEdrRGmT4aNWAWYvVYzyKDy3H0fzYdWwuA9goJUL4tj3eMJa8pgEU/ +-rG3HfflVi+xuwm1UnLXPSIE8hixgV8ebnwcCnEjlUBvwpl7f5Ub40jKcdycdGvVu +-gcTUzuRl1+Ikfk/MXKPbdi4A5Pjtz6AG4Ez9q5j7X77JqskTI5Z/f1RPiKwFBJHg +-cN4+BPnEuSWGcjiNDOfQxhk5exlWRf/gpEhnQpGHe3a7tZgfxHUb/pWU9BYpf8OH +-vtV3WSDXlUqsEEH6/bmvj8lmFWJLmeZv+qLy1wHxcXR9/GJ6TwCF8niQIl3MrBAL +-sKPLft1drmpqdIQpZQIJxtN/AQuD9mxEdW7XA6rkvFySKcswJpS1QjkSWpafCBWE +-wu+SPxZL8oFrnNMTU3JloUjcRp70FkNXLLm/Dy+MjW2qFBtIoBgNptVGp94L1uZS +-amd2XJMcOQ+X9fcH3wAdM3IHGn3NiLf6eTW92JNNA0IN6aNtyVaJKmFJ1JfXOl9r +-ujr4SorRSesaerjIcuzW1u1YE5RlgeI4kizV2/D5kYc= ++MIIFfDCCBOUCAxAAAzANBgkqhkiG9w0BAQQFADBEMQswCQYDVQQGEwJTRTEQMA4G ++A1UECBMHVXBwc2FsYTEQMA4GA1UEBxMHVXBwc2FsYTERMA8GA1UEChMITXlTUUwg ++QUIwHhcNMTAwMTI5MTIwMTUzWhcNMTUwMTI4MTIwMTUzWjBDMQswCQYDVQQGEwJT ++RTEQMA4GA1UECBMHVXBwc2FsYTERMA8GA1UEChMITXlTUUwgQUIxDzANBgNVBAMT ++BnNlcnZlcjCCBCIwDQYJKoZIhvcNAQEBBQADggQPADCCBAoCggQBAMqqHcQR7JHw ++x/9fkJL8QAxetz0AxSDVD4kxB9dBTItggKo4FN6Ta5x0iEFotQJBAS2GonqVU157 ++Zy9sHilR+UT9SoC+siOhPhs4z4jEce74a0HFLcDDUqxZfYE0GZUyuJpRtkE21MSh ++roTmOLnov5a+GXprd03g3uaztmu8Pd1ovEvE6/U2k+1WohVQihDo1iLtbLHNwxjJ ++9grh3mFlYtYUQYy1+xRowc8SXUEhnVcRQ327Qywhu8NEfajPH8NxdbVHwn3OODxz ++ZJ4V2Kcnz71AyEUI48g5qAuOwlt78UeREpHM4QDglFu9MuQMjcO+zHYyUhJpsBjg ++sMJ2NFpfedn2gZ0CCmFpHDPOSfp2Ax4HWycLvzSeNJa4A5tQOmovF3oUz2VjADdS ++qHPOSxRA9NKaVlQzuHcuQluP7B8Y9K2rikqNbXAl81jny2ZRFH0W9OttVnZ2UW7W ++HdrTjcBkWmdOr+K/M9G49ir8V4enNV6Ayaz8h8lxF5G/t02j7TwbJ/RmoPlGAyfM ++6oD2S0D2QZTNvQqz7ya+3m9prg8/HFVjM5Cb7cpaEk3eSwbCopKwQj0xr6QVEhX4 ++iumIjc/9hWZQbxHxn0jztbqdhmgkol2ofFRC+ti1xfLdDg/QaORUfsW5oJtlLXf0 ++j7kwCtWGXO3JfNHanQ1jUO7lHpJjzKIM6EqWAk3cj998jwgYqDCI16+JrfxXSxD5 ++8ctI6LY7yD/8wtPRShA8G2tk3OVlHluy2rHiJJeP7sBLjhiDfBemPEWzYAYj8i8Y ++E54XisZyeYxNBPOd6uAl0zOMHhFHYx+lRT+9hbP+pWjuSLcMpMl/ctB1Zptq+aBQ ++86hZbaPdOE9wK7v/ki5xq+/pAO0N0bRv8I6yCftNYQ3ZENVUEc0DlIT9qGjkRW4e ++ah4vhaFt9bbA8e73Nun+wvetzBNGW4hC8C0ftQ5+tSvkjau5hzBqPRL0rfMcrMwa ++SCkqlnuAAAtuWYe/o8pwmRsc/XI9stOUSs9Vdb4fQOxVNUgtVfAA2jywYLoRMmZU ++C74GpF63yVm7TfSSBiZIbsIS1HzwILii4bxqthkON0dVyfJJDZZ1ooRkvzT8vrJB ++5PWI6+G3JqXlQcIgDPbiqKXndlSl+0uABX0YhXq6vLetwC9ghcwVEhwvCp7zfEDP ++9D4j0pXK0AZYUvCE2A896/8SaJR5j75AKV+YyJBsBS+ZjCpjeB8jsSnF50nJspIP ++UwvVcSgXwhm/YL98h6irwfQKwbjSaO7BzqcTExdtJF2iN6bXfUiLK3QtQC7KGdW2 ++PmxCcfrPhYf53oBzi4n0cPDY1/9AQZzHFW2bbky1UgKZeTJzyiagrDFvxLD12rvC ++H+CfRLol958CAwEAATANBgkqhkiG9w0BAQQFAAOBgQAIddy5P6q2foF6OdHu7US2 ++zhs3xEwZ0Gbm67VPKu+VWGQhVQESMKyKldEG3ilGpPF9f7Ae0k779vqadL6FYtsL ++gpBYYsVf8YACn8X782uwtDsEseVTwtAAoRqdZWBvc5hn4JzIEpR5Wb9De/V3yI/f ++sc0RHAEZmcIiQvdBrrS4Gg== + -----END CERTIFICATE----- +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/server8k-key.pem mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/server8k-key.pem +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/std_data/server8k-key.pem 2008-01-11 10:23:44.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/std_data/server8k-key.pem 2010-01-29 12:35:16.000000000 -0500 +@@ -1,99 +1,99 @@ + -----BEGIN RSA PRIVATE KEY----- +-MIISKQIBAAKCBAEA1BZYf95sKL+WGiAhVznSV4B1f7g5E41wevaMZYqbIUGmD1/C +-w0+b4SN4D3IktWdbERNnU3AuDJNiuCw1CI6d1pHk3xQB2T1dxGPtzh/37R+DekhC +-AUyhOBGOmodJybVPfDNCYcToecx43us0KdUpAZ4RDkGHsWEaozrRpaGfUchdIhQF +-3MrtgKdeLt+5eWJWtHMj872aj+JhWJXF8GkXwGnCZqjDNb7kLxcdSSE1EwboDBd1 +-RmdRdLcOtxCFB/xVv1lp3D6rxtfJ2uNKpb/WZAcNBYWXikvHCiSGOcuCd9I5/3lf +-KdZUzuyvgEk7hmVpnUQ4I1BtGPThrirDz6GhOppdB05zAbAUkH11KvV5MBrfA04D +-4qAChwR4y2yCxMuBTGFq5U2ZT08zasoWsnnP9k9eaA5WnTUreyaQy6V+9FBAlxYX +-RBsbBsbV3SmyAbzZtsk+F9p8VvSLbBAo0koA/veE4BqGvECg8K6ZoKvlqqZueAmd +-bzdaKsjFMNbIzRF/4iwchwI0gC28tin35OXJeZp7Eenf5OI7InN0LHIsJHfq0Lf/ +-FTIUtp7N55Hs/wStxb0ANjLPMSYRS37M1awYZ43BUUzU9vvyjJa9aE+UNV2Si+6l +-V06Wmzy+dSZVQS+Qkh5dUEZH37Kn6nICZHBwavpCo1IhbOJWnYU67zQQl2GufjZA +-NkKiH3TqTcJetv4HRO/+81NboeNL5FSssy/gD5Cz8sDxFwTqUMiAzZIKF5ktdPiT +-A+OCu7mclJsWS+1u124t9DbhBa1Ts6FJlV4WqT26UJ5EB8Z/J7aij2F3QXL13Ais +-ieou/R9lZPXzOqwWIsDXBO0Mlqn3dkDI86++r3hdOLF5D0frRuWNZaxfWad72mxV +-0INkSbhgN61ejEdhhTV7goSGLuNdL4SITzbZnShFaCFWbBbLoPnbZ9Dwwha0fFRH +-f7LIadJ2jWvQHdZWPpmqyZDiTlaT4ArNsiQzwFAf2Hb0ieGr1umXbzU8IQS/HxCT +-Etg0qpGmugN/ov0qiE6VPE6CcbDBmoAbC4nl4LyQCxcrEkX0f9nZhLvfydDz3NvI +-px18I4i2/fVSpZLhM/MF/VJLqKhZdKS2vI65TPIc3T0PUB295PXOZJ34DwmJDiFs +-Blx/jcADR3UESuwphgBVduJPfj96tIOYpGm1R6/uGUN1j3ftRytPjLG2/77+d7xS +-VmvqWHjXhXMDQsltpCQUzIiOqppS+CFgnF/kA86US2pWwFlh45eWZN/UBGgi9NuA +-2CvePCA1wqg4OrrRLO2JzHWiBdJnmDCo3oWRadH1UPHvDnfq6W243Y/8OtMDIAaU +-jnmMVa7N0CjWXf4n+AM9y4IKFRwdPUo1yolqbwIDAQABAoIEAQDI3u0tFoWMRoCs +-99d8HLiaxYED2YC9gw2QeKjal198LQhRsVnu0ByMLKLOxkX8RgrbbmxDe5Exufob +-A0urciAOFJoXqoRhs5x2oEqgGmkf/ePx0jQptOFREFfnBdGeKIpC0O3DWdLxYPbt +-8wixwkEXVhVDUk9pcdXf2ZqsbBpQRBvpZdtzlgNCAcLTVHP/gmMqf48CkIauVjPq +-ydfybibfx4sm3hodclH+Q78p/zicb8MhiKo7ZymgCKz4N743pQe1tsLrpbPeHY0C +-MpoFyF8O2Bq+KxwvELxQX+19GcHVKJhj3hmCr4wde9BxCWtGTBCusekVkVvy8iQ5 +-aCmTIrtonMEVZXjJlXK0sw5hBKOmKx0jrSVC5FfgdxzNVlW4fCJXLEEpMsjMc+/3 +-6bV7jqGn4N5CYaopNS2ccxdaucE3NjcmofahO6bqUTJHSPFecfYmCA42W2m+ldjj +-HZ78JLkyw03nT1hjPjbwHf5FTem1KfKg4EJrDprowMT7D8KZb0SW+z59pFoDOM5u +-Heu6sOSUtvpvKfozdw2ZAI58dhpW4/jTfCEtewRhPqE3/V7g3haTnQFxU8gm/a4N +-uefZTCjFE16QWNuvnUrJWw/DlvOBY8GjpQCWY0mDeBHPNOI0Xg9oRTgOCrKSLUya +-YSbg6BmhSKwKsYQU834jrQb3fXFlXZVIxlcNePOWMhHFFNAHucHF822Nr7u/3FOT +-twcbBIOXCGfDT6ed8d4dNum1L7k9Blju16CWkfuciL8PGXY4mGAmF4nZMXGZgK8B +-Cz9cxhtvFLe8gz5615DtBAsuVm7Q4AAHiULAMg6t6auyxCb8pXbAL0Ec5X4zS3+f +-I2riODYiyHCh/qTtjawOzUZZEtjZRMSDi+jk8wjjDdkFU8McOaYoPyqT3TDy2v6m +-NiPJs8GWQ2NCNo9CNoGbEIIFFP5iSz18XLFAOF+2dN/KHHl9nKyi7kOhYbbzoNku +-2wQV40yVsrS4E/hd/7+2IB2Muduxiu7NxCUSUXsw6p0hZTYMpIoduEfRSk1al0lS +-862GD8JgJ4RhJ0uIOTDJS52MQmO8zFIL86emdjjV1CzVvadYSQLTX7ZgR0i8g46A +-y0muCFAC8EJpnEtHzqtQ/z22zB8TCJShFuUK9KF6K8nOlbc6ShcUXU2J6r1sc8aT +-Dx0yzRXfCL15fpCJBP49EYaKhArTNmFRa2GaLiJP0OYkTrrwVOGuS6x2+kRVoP/8 +-BcNMZ5x8mXP1LgotHCztgMKX30Hn5CLxbH8QfcWKemGva1jBmhCWxS17Gh3Ld9T3 +-/WKkBa6JDq83rlO84x/iF3mB3tYkZPfcYtYURn5wwm/BmVV/9G1VwAatJdxmfCSy +-5JwC9WDBAoICAQD7xStPk3lq+qYHAtLZidujmzSNv7XG+E8UC9yvMRFuBwSM5ZE4 +-YGD2LDev2nghB+7OSR8KJIkxeaNjP91Zf3s8wjCuxLg/cLGI6mf6uWy9+zypFg3i +-J+ylDKa6NBuqYyY75W7Pj63xvGQlw5kX5+mB3ulQbActT4cUiVdEkyDytzubqLzY +-s15QGFrL9gqLow+C+7LKQKdeXq8OavFV1PWkMDAJUki6cIir9m+f5Mqr2cQCLKgx +-38aX8c9UWJv6pI5zQQuBjpaBOwz07WnyTXiFpc71x/8i85uLGDM0e3VO5ZPGeRBj +-jZ0ucHatOHJ3i/nPRG16rsPR+q97QiDHoLF0quHEG+ND+rwTBzNGIwzYRE16p1o3 +-UdzFk1RzlDCfOX7QgszCwK6mf8TbCK9f/FxJ5e6TCkt3iHXSrlLS4op6k9nEpKFH +-KHf4nPtCy9GriP+A8+dA6K1s+DgejoIojBMBTsnl4TEf+m8BaenTXGuU7KYyc8dR +-JqmpmDggDRT/ImHRhXirY7lIIYXnI7tRjN5gmnKpEiHScT1r848zpQ4gWH1Dx/ks +-mKT6NZ8nF45saQCYbKEYc0RH9Kw0O7vr1kVtNPc2dEZtVgt4bC5fnl7xX1/YTk3m +-+h1qfzbku/+MX5rRjHLR2l8a71UltlnnnpP5NKBBgtxll6aCIkk6CdH8YQKCAgEA +-16aBaVa0cOZmiOQwPQkpuXIbV7msz1ttWEAHElCy6waniOCON89PYFCb7F0NjV3Q +-i+pGaRgG1iZGbjjHwyqTrHhMloFm+IsSWZqOZzrHgSJgA4bgTJFgp+5b31sQXGfJ +-14QQSqMJLC61/M+CnrNtiuI3IVHx6BFRxI42uE7PfTyUMaFhL9F0/SLl0Mw0oMPj +-S5kmarduuKpRn1tN9WO+ywEvYwopvH3e9PBssZzPpttlLiE/Wulb0iEtlVXYB9DS +-Vzc94N2dzFMIvWUDF9BQ+IBMRzXRm15Psy6LfzoK+9S6w38Dx3BVV8ykSMKeW1UR +-ZwTajjdnIBLdE3onD5XMmrSOPw/WtV5zXEYY4DObhIPoN2iD8GJP0IubPb6fonH5 +-VHmuVZoXrroFEe7rdt2wgmBdPPl6fqvBKVhjJOpYQctrFLgWh63bXZKaBWqbQM9W +-fECq8We1VN3fzqwfwJQit3z5R/DjQNk8eQx7SnnkOzAY6ZgpysHCwaoPOnPVuiYF +-ZU0+X3iwfsdeefWmGEDIzoZk6nYaljs61lOhhEoWHngZHDkMOp5kg0n9f8BUP02+ +-WJ4QhwzZ73hr4FPBuPHHXECw9TCAgCBHBFrnrXg5QalDhRXz4F+3tCY7UUpD/ikZ +-L6Daxm5zGJ5u3rXs6WwKy2EHVVS9zfqs4Q259pQdWM8CggIAcIKpGzOVM+h033c0 +-kIBZxeAq+Rlt+0+lzxiJ80RjPJ8oOmqwndf8HKaf8BcaTfCEmGz20QqIwLJSAJ1e +-posgoINLTB6fE8Kho8TU2KeaX7/xWMKBS8p5pzxjGZ0Fq/wI7wVVoq3blsaQnout +-U5CQujfKXeUYw/fhLp09gWiadbzKh4I9ej2V7QclNDZsegBRg0BForqH0NVRN4k0 +-9h1n9IqQPOonlCGMAgTr1zFgHLIBNNOOClOtJOOruk6qzbRR8FFl+eyld3TTEnUy +-PlS+gkMZnJ5WduEUZnFXGKH/R1Wy1yPs3gA/+KvLbRdnl+LWrPgwUH3fBmwXlWZ0 +-zaETDEb9Ay1PP2bCO2KhWDt7lv3W/fPhjg0oMqbnO4tCuzTvZfC93l5K7h708skL +-zkIxX9i/57fXB8DUnmTGoHUaWzLNQ2IqrGj6TACjDDOXLCfZvl/AvTH9pk+6jHU0 +-1zfZmmECOpeK43Z/ussA8jI/5Vpn3u38aVh0w1RB6JjQBD/yJLaXuUekWgaZFzTR +-ldz014jNqp5uvONcBmzeVr7w9CV3PR4VTQed2i6yQ770J6A44uTQjOOd5OYDOohj +-Lz4e4nGj9BK8Eko8cAEwLAzS8tyjMT+08n5dPOVCu68DwVBMGE7CVONYUuoXS/YU +-cTxddiU9ZGk9Yq0FfOwjeys+SqECggIAdn3M2b6Egwx2Bn2ra74fKQBjub4SEBWi +-bT0xJYUl6jHL2E/alRvZ94gTRLqUebq0nkxpx9El4IFDbcjRKpG4dqnbG0+a7rIr +-sQRVfq8zc+cZbparpCa1P1CfNojo4n080KiF8xzGK3q3EGRM1zqr1AYcWLiX/PWX +-QjMKKhdTtvKUUvjjV8z1RSnpsOKjgDpiJ+XM0BJeSiV7l94pZc4axZyvFvI8oI9g +-9KEueCE7j+k5HTGziBZ1F26Xh1iVzSWWjcmSvH3I+L4fLUHVgz45X3HPd8lAlOgr +-Tr8icxPHeTwYKtcdknZMzmNpWXlmXbTOTRbDqCUVCvCSfOM/lzauJ8tR5aCkTx/I +-r0js3jQ9HYEFFXzeEjVSubob4L9fI3kQkLQTcIGsxZr8si/fPX7uP5UHZjuGbRee +-mUMxptUFDZHiEo5cAs0qna2x54v+JoxGbxtxUhez8R/Am+TDxaMfuEZ5Cmh31egH +-bFPJYtC68TKqXZ/4RqpUgukYWPvQ0emWSWU6AmdkQyT06nppeyYNsDz0MkgWr7l3 +-yNBHDVNP+Anxcip+Z68kd2cuXQWmxOnIzxR67FnJXeWDEM20whRHgI8jLHYsBTq3 +-CtOQPSaz/zosGXJIgF7Xp6riKPZvibW3Ww49Z47EuyBCtyirNk7hV4LG7sITUJyO +-ZVKPfcdAoM0CggIBANz3EBZGyt3af2UjFFKbazV01KcHF8OxqdQzsLqHCXWb98V6 +-PggQnrF76U7DvqOWho9djDBPrbQU55HG5nXq+eZKPwhsOdwQ8bxOhaVxQcATZOI7 +-FtJYnjM1/+zMzzS0iPR5DA2pbB3AKH2Z+wODmF23CK2XTwoJyPKxvlyGKrIqq3gN +-kOmocNu2Qm5bJf+D/hYPm5Ust2wzD52NnvJU536bZ0ZMo1/kaK2idqSAzqo4TkR1 +-j9U0fdW2rIBDo/qFmBBdJhYVjYLj4qR8CEEoIjshD4Nztf1xRM5C8irE/gJcT5+r +-4bPJJ5TjAtHxPiQqZruSprSEUbMsPqBap64ow0SmbNNWSgyaz2ha1rG0p52NBzH4 +-XM52LBqS9QHPHvB0ooYfBTfPpDM3CePuuNyzjPAw86ncUo38FKXuc2oViJJ6C5I7 +-v2sKhLK5gu3uPBB2ludDEXSpWBqiraynolOT/o52r+taYp9YY2WU3GrhOiV/A1FV +-Nl118xiF6FOFpEeTbhHvy27A8kZEKXgeSs+f4aC0XG9kLVD1CiCbQiqHTDcDS4nV +-O1N1eQxhP81X+YKE4Lgufh07REqYVwtCj2lQcMp73WDyfBLKTEFlmHusoqmT5JCH +-X0BWNjk5Dn1g5h63/lQb+EjNRILBhDFYhrDRDQtw5p0/7IY3AcNKDUHv+XGn ++MIISKgIBAAKCBAEAyqodxBHskfDH/1+QkvxADF63PQDFINUPiTEH10FMi2CAqjgU ++3pNrnHSIQWi1AkEBLYaiepVTXntnL2weKVH5RP1KgL6yI6E+GzjPiMRx7vhrQcUt ++wMNSrFl9gTQZlTK4mlG2QTbUxKGuhOY4uei/lr4Zemt3TeDe5rO2a7w93Wi8S8Tr ++9TaT7VaiFVCKEOjWIu1ssc3DGMn2CuHeYWVi1hRBjLX7FGjBzxJdQSGdVxFDfbtD ++LCG7w0R9qM8fw3F1tUfCfc44PHNknhXYpyfPvUDIRQjjyDmoC47CW3vxR5ESkczh ++AOCUW70y5AyNw77MdjJSEmmwGOCwwnY0Wl952faBnQIKYWkcM85J+nYDHgdbJwu/ ++NJ40lrgDm1A6ai8XehTPZWMAN1Koc85LFED00ppWVDO4dy5CW4/sHxj0rauKSo1t ++cCXzWOfLZlEUfRb0621WdnZRbtYd2tONwGRaZ06v4r8z0bj2KvxXh6c1XoDJrPyH ++yXEXkb+3TaPtPBsn9Gag+UYDJ8zqgPZLQPZBlM29CrPvJr7eb2muDz8cVWMzkJvt ++yloSTd5LBsKikrBCPTGvpBUSFfiK6YiNz/2FZlBvEfGfSPO1up2GaCSiXah8VEL6 ++2LXF8t0OD9Bo5FR+xbmgm2Utd/SPuTAK1YZc7cl80dqdDWNQ7uUekmPMogzoSpYC ++TdyP33yPCBioMIjXr4mt/FdLEPnxy0jotjvIP/zC09FKEDwba2Tc5WUeW7LaseIk ++l4/uwEuOGIN8F6Y8RbNgBiPyLxgTnheKxnJ5jE0E853q4CXTM4weEUdjH6VFP72F ++s/6laO5ItwykyX9y0HVmm2r5oFDzqFlto904T3Aru/+SLnGr7+kA7Q3RtG/wjrIJ +++01hDdkQ1VQRzQOUhP2oaORFbh5qHi+FoW31tsDx7vc26f7C963ME0ZbiELwLR+1 ++Dn61K+SNq7mHMGo9EvSt8xyszBpIKSqWe4AAC25Zh7+jynCZGxz9cj2y05RKz1V1 ++vh9A7FU1SC1V8ADaPLBguhEyZlQLvgakXrfJWbtN9JIGJkhuwhLUfPAguKLhvGq2 ++GQ43R1XJ8kkNlnWihGS/NPy+skHk9Yjr4bcmpeVBwiAM9uKoped2VKX7S4AFfRiF ++erq8t63AL2CFzBUSHC8KnvN8QM/0PiPSlcrQBlhS8ITYDz3r/xJolHmPvkApX5jI ++kGwFL5mMKmN4HyOxKcXnScmykg9TC9VxKBfCGb9gv3yHqKvB9ArBuNJo7sHOpxMT ++F20kXaI3ptd9SIsrdC1ALsoZ1bY+bEJx+s+Fh/negHOLifRw8NjX/0BBnMcVbZtu ++TLVSApl5MnPKJqCsMW/EsPXau8If4J9EuiX3nwIDAQABAoIEAElnTjqq502AsV+c ++hGfId4ZDdAjjU4LtyJ+/I4DihM/ilxeQEnb/XDWhu4w9WXpEgyGzJvxRQ43wElKJ ++zW7X4voK58Yzy5++EhmX/QsjY8TTMz3yJf0wgawtCZkXfsCcS2KRf/qk2nGRwf0e ++yaMEWwhFOEMv01lgvjs/Ei55Usrz2Wd0HqaFKxUGkNQ5hJhVTOH/rqPDzAsZc0VD ++w+Dw8NhrI8bMTvF4c+IFW8NwYmWbuh87CTxdx30VPJI82ttWJ/UN1bLtU08J2IKt ++lPgOIl8ArMjcTGxD/cqZ3Wl3Pc/XCqvGUiSYMwP7Rgh1R4+DdtjEpxdGMmMAVuVI ++HPQyqpa4gv+UMqBPish0yjSuM7jXnztINOvg9Vk1sxC5AT9eaRltmiS1s+lVxe+T ++43ulf0ccYXJD/WclWSGCwloNFuokPIV+Lgo1pKsp4XDgoxQfkXwH8Q4dEqebY9rT ++Tv9FGb1bMbdl22X1oSu2lBltBZaB/QnruV7L2GaQ0tqLKizgBRuvZFSE+DWdMb6d ++9mnEB8LWtca/nzogXb5qv4GEMUX4FUAmSf1FnGWZwwDi1DFfJ860RVKf0xokGGQ3 ++cm3H/F4veds88Z1hsAu0bG8h/bEAim+Whvag995cFHDD4on41KXW8wX1on9VFA1W ++CkaGUPhLRytXDBVCSJkOYYFSJlb2wqONiWe4Tn5hsantCfliTj/GVkgDq2h7dAGR ++WyoqTntJAv/xJsUOV9WmGXnWNeZX8BSO3P5dnXnMzhCWQGoprXmWFyJ3TYCJ2+CO ++rzkZbtuKvTvGc3sDJgrSVmmg0BrOkH+GyYVlJdTDBmfzoORludDCFHECa8oK7NwY ++t3o0eNlG6IqTxl2HIoPneW9nXFQtCXv6tpJjljwjlz5WpJG+kBW6bDedcxZu7olZ ++fqtnyZTB2SjzzbGdQ4JvFup8MxNyPvYiqumQXJgkyXFVDl/UFhjWuGe04i8NBJgJ ++xORcjfgLrKH1XKVBWPJdh/2YeUKIIvQ9RB4WVqXgGmD/21tgv1bVEMYabh23e/HE ++Fe1U2XQPJKxGCEtG6b4zhFP+PeZACS+Vk5IVJYK9n4SepPBPgX/wbJLOcKGpsKjp ++yx5WjopMO6T+VUV8HIduuZ+E8+uAILHDmo2Bq+LHblaxd4SkM0+hL2H36imK5CUO ++5fLuvHW88LvFtQw6xhP20s+BnmgzE5ZvNG4Iedkjvwe9HmdNDew0UYT5vNJN0ehh ++OlraBC++JYwEclrBD9SRvprT63XKDG735pPvzLQi7WKDCBn1/JEgxDIO8nkMewOZ ++FU48Mdmkn9wqPeIigQciwl62fuAQCGRG+RXMQqra4A1apqMZQEauTK50VhHDGdbc ++ye9LHaECggIBAO9lAzoYS/Lu0ticMt24P8BSbGdxSNIpEyIlTTs+7A0UjpfXsoK9 ++4EJWZ7lhgbQh+SCTS662SeC+s8M6bT+3mELxUC5S/N3aCPyfjcM3JaoACkI9+VMn ++9otJZjAEwH7cNpMN0Xa8fHCEma3l3XKiVxEJbuJC86S5mpkjeXVnDajAidBtevBd ++LWJ9n2yXk+ZKUyI0mjpqItwUxOgQ/MOIvqAu66xyjg08/I1QQTuIrReAA+oaVKhp ++c42Ufn26hUhNrQCBAtMAO3VC/chciet6vEMNEM13GqLp4+PcPhRX90gO4+bNrScD ++WgiW/jc24CGan8gAenBWC/3l/C6JUsMp+ZYmPozsa0zo6edgiO/f2KXe5nP87wZT ++MxaYJgnyXJxMefI79kUHPrhpXZxuiSCEWLhCBN34Lhpr2L491i2g/FJj9i6N3EzE ++N3ic5Q63o4QFusjqIm3taQQFoGP2Cgg9owz5WJ0uRz/gtOE3XQiQA7+ozoAXOlTw ++pJK5MMtVrEoOLIbVJIpxfDcKDp3yorR8QCQLHgDBmFeNCDmk+7YP33dRIc/AVNLF ++q7cecqEc7D8AkXX8Q53GfCEg+uqbdeMQXK4BUE9iwRK9RiFhas/RJe73+Iio3S0L ++ekLpnnOfvk744ws+JWsLpsfC/ZE7OxBLPtq2xvGl/RT2G7tCjmpX3CbPAoICAQDY ++uOEJks2T105EcMPJjzNHCCqjK6S7qZaWkF3KT1Z0Mu5oUZwwHamsMg4BQJ2mjMrL ++fRBKfXQLA6vgE7zysw3F300RDxE1RVow5+JLDQ4bqupp27/M0a8fuwksyOdKHqCV ++YHzuTCxbVIFZawTjfOxJVXDHKCFCilfY1LsA+V+oFe3Ej8YYxWXkXA9ZLigpmt3s ++Wu6eFcZgF3utzIGjI6eP6lL5bWp6Bh9Avp2xrOvpFwE2m02Y7/Zom6MT4DXvByY2 ++KHHQLsasEMpeLuxQXjLeTocwcxBwBFKhX95yFuv31k00VydT+NExtaZeUYi9l19J ++WmM4GjFjAqa3uUwMNVv5JfWtKMyk4FOox2XftLvMiIhV95B8hAGxtYr3hPkGg80O ++AWPq6OKUD332COXRaHkmL5aQdN3gP5zh9+rH6icLrrZbrQidVRyDw03doRoGrH7i ++ixXLyYoW80PHgqUDPohd5bFkZpi2vwXMl1YQ2TfN9TvYFSGme9YCm9ZuypnqauW/ ++aAf0FI1MNwS+XDREtzPdFi0me6WxpKL4a2Z3GGNxIFuBjQ/uydWpjxkny9qI3KAp ++SgjI3kBUDGq3gf0R+Xo/d4d/4asK9Nv2Fi0X+RfGqioFaTbQl/1zhNdvhP9IcwEJ ++DLVQ3UhMdfg285RarC2Sihui0M8Smi9od9Dj6rdWMQKCAgEAiQVRFoRnnDGz/wVQ ++W/Wkj6jdoUuG+btG10lwbhOyuj3k6+Yqp4iUfoPENKgpu/eiB1InhGWT3Y5ph7m+ ++ZDTqco56bTlUwIqWkDmmw3CiHy6MsKOWPFFoXQry8VMW9sWGex7yoDp8I07SQ2WJ ++HZ7rpLW4gMr/d25AnZxfXaJRgCBMAT9YmZFLc88hW99aaPproO1oxTyQnVVJ6uYm ++NqjjKv4QKJEc21jn2N5xp+iv4f6Evw65G/fXitbOm5oRxXOoLNyqyCie35wrc+37 ++hwumC97DmkasuUiUBoy9/5jl0ZmsOiPJEsZpVvdNpD7FhJZjE++qJPgrPvTPJbe1 ++5jz1PUrAjJqZQ9kgYC2x01JVR4NQdlz0VrNyT2FgjFrrRQ7E0bAeYh4meRjd2rat ++yC3YNgabkI0HnlnSIfl0yIMXSPUsKDNMP6gjc+aheI4FioBZC7xvXmn/rKynw+9E ++iLj2xWtGnBir8VTlUu8EUe1UJ/Qv1cL1wT5HhC95TTjJN03rkHUYyCDyjvIzsZX6 ++KMHhWIAAeUBVuO7hIVVcOTXWmw2WA7o7ErTPdy13QN40Hk9t8pEkBn9f9vpQg83d ++aMypr3LTC80jY11wcZS3tSEpzCCkYVv91FV4cioTZmytWbg9A+dbNWzi1f22ctTr ++FoVrAXaSYie2trOy5bjPmPCW8qMCggIBALQUKymBSkDmTqqf6I+65ajIKGWdBizJ ++Jc/F9aj9c6DqER+tcFKq0ym6DdkMj/KsWnXrXXYH+DyOuGpg/EfOcEtS2P6rvmi9 ++T8wDYg1qs6ZZxp5fcmgGc7Wx/FWyOj1kZZq5qhV4RgM9nJ1oR4+fZdcpn6RcvAZG ++XehWG20byVgpoIAL11cN7zRpKne32rd3b5/NjyjcfxGpcaNgovej0L/MvVV0jV0H ++aUCrIu1X+k6cRu3Q7hF+kwkpCcCiNS6AikfGI4wQ0hR3fy/zXXkKTMpcBglEEwyB ++Cwf8WSID2d79uvka0hr8TRc5ERyeMzkWZp7U9EzRtufGdDGFTqN2Uw4bdKCFnkYC ++AIHl7ciMrN+vM1n7c5uDNMUtTGOPojy/l8tjbFrtWBgfJ1Mg4ZW3cbNBJ6Kw+Qw0 ++z28USYoEDp2uduiGRvo0lpUF29Wk37Nb8bLcTygeNxgK2u8Up3iipT0gdt4uQgbX ++g0IVHfayB6SjeS57oJJto85XHz7AKlSWroD1OGagDSifLtneU7AlanryymGHrI6H ++dsNkuqeLJFYDxQVI6UxJebiCpyxiPxwp9wtX8SS3SEyOZL5GzLn6ypGiCH1CTpW0 ++EHHSy3V4DUGOc4w7eMirAnbSkxCfOmBA70NNw/uFY2XlQHKow0T0fImfKIeJagbT ++B0GPDYvUpLKBAoICAQCzYnq8xupXK7lvTLaj936qGSe54OC2sj9+UpsFiPxglNY2 ++sO5zKWKyY7+rjK6zG2ciGfPEDsZNIqKw1W/KBfR2kRLqkt4bC3fSCvUztx0vtGUe ++veXlqiwETdE7RJXoaGJrgJArYJvpOd8PtWGeM+sSJNNrUlGlJnSiZ0CcypqUZgZL ++WzGFfLOQYAXCykdB1iZkBqU2C5wktvCb9sVz6G3TmAwSKTENOWWZWmh+W0J4pZFV ++ZEyvsxViJRQbwxa0kC0F5J/UtWZknO79/ZFj1H4jiAR45EjWHE+UZAkFwG8BSl54 ++EKOx7GDanuRILr0dtbyi4d31nCYXdjs3x2+1N3exw4oKQIvNuF54WoowbNPu0kEb ++G+7/kLwcJqRnSV4AiLuMz5aOte7JJSw5tzgZZlAQwJO7IDfrLqodivcXF5yirwiF ++dyBpzSDmupy/aTHnCpT+l0H96jRU2awxaeRHZUqZog8gMHsslNVZEFvUFDJ7AUN/ ++yyfUzJYjH18pZt0hS7jNb1O7KxZCkWGMiEcxHkgF/UINab5qruNBVKOkJ5vqGhYi ++uNkgeGsQtXJcpqMRRiVXJE0kE+26gk+iaYnBJN9jnwy8OEAlYFUHsbCPObe/vPMQ ++3RLl+ZoKdFkN/gTiy70wUTRVw+tWk+iAZc7GPX1CqDFOqGZ2t+xdF8hpsMtEww== + -----END RSA PRIVATE KEY----- +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/t/openssl_1.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/openssl_1.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/openssl_1.test 2008-01-11 10:23:16.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/openssl_1.test 2010-01-29 12:35:16.000000000 -0500 +@@ -11,8 +11,8 @@ + + grant select on test.* to ssl_user1@localhost require SSL; + grant select on test.* to ssl_user2@localhost require cipher "DHE-RSA-AES256-SHA"; +-grant select on test.* to ssl_user3@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "/C=SE/ST=Uppsala/L=Uppsala/O=MySQL AB/emailAddress=abstract.mysql.developer@mysql.com"; +-grant select on test.* to ssl_user4@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "/C=SE/ST=Uppsala/L=Uppsala/O=MySQL AB/emailAddress=abstract.mysql.developer@mysql.com" ISSUER "/C=SE/ST=Uppsala/L=Uppsala/O=MySQL AB"; ++grant select on test.* to ssl_user3@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "/C=SE/ST=Uppsala/O=MySQL AB"; ++grant select on test.* to ssl_user4@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "/C=SE/ST=Uppsala/O=MySQL AB" ISSUER "/C=SE/ST=Uppsala/L=Uppsala/O=MySQL AB"; + grant select on test.* to ssl_user5@localhost require cipher "DHE-RSA-AES256-SHA" AND SUBJECT "xxx"; + flush privileges; + --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/98_CVE-2010-3833.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/98_CVE-2010-3833.dpatch @@ -0,0 +1,81 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via incorrect propagation of type errors. +# Origin: backport, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3461.1.20 +# Bug: http://bugs.mysql.com/bug.php?id=55826 + +@DPATCH@ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/suite/innodb/r/innodb_mysql.result mysql-dfsg-5.0-5.0.51a/mysql-test/suite/innodb/r/innodb_mysql.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/suite/innodb/r/innodb_mysql.result 1969-12-31 19:00:00.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/suite/innodb/r/innodb_mysql.result 2010-11-09 10:51:54.000000000 -0500 +@@ -0,0 +1,12 @@ ++# ++# Bug#55826: create table .. select crashes with when KILL_BAD_DATA ++# is returned ++# ++CREATE TABLE t1(a INT) ENGINE=innodb; ++INSERT INTO t1 VALUES (0); ++SET SQL_MODE='STRICT_ALL_TABLES'; ++CREATE TABLE t2 ++SELECT LEAST((SELECT '' FROM t1),NOW()) FROM `t1`; ++ERROR 22007: Incorrect datetime value: '' for column 'NOW()' at row 1 ++DROP TABLE t1; ++SET SQL_MODE=DEFAULT; +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/suite/innodb/t/innodb_mysql.test mysql-dfsg-5.0-5.0.51a/mysql-test/suite/innodb/t/innodb_mysql.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/suite/innodb/t/innodb_mysql.test 1969-12-31 19:00:00.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/suite/innodb/t/innodb_mysql.test 2010-11-09 10:51:54.000000000 -0500 +@@ -0,0 +1,15 @@ ++--echo # ++--echo # Bug#55826: create table .. select crashes with when KILL_BAD_DATA ++--echo # is returned ++--echo # ++-- source include/have_innodb.inc ++CREATE TABLE t1(a INT) ENGINE=innodb; ++INSERT INTO t1 VALUES (0); ++SET SQL_MODE='STRICT_ALL_TABLES'; ++--error ER_TRUNCATED_WRONG_VALUE ++CREATE TABLE t2 ++ SELECT LEAST((SELECT '' FROM t1),NOW()) FROM `t1`; ++DROP TABLE t1; ++SET SQL_MODE=DEFAULT; ++ ++ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/item_func.cc mysql-dfsg-5.0-5.0.51a/sql/item_func.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/item_func.cc 2008-01-11 09:43:40.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/item_func.cc 2010-11-09 10:54:25.000000000 -0500 +@@ -2260,7 +2260,7 @@ + stored to the value pointer, if latter is provided. + + RETURN +- 0 If one of arguments is NULL ++ 0 If one of arguments is NULL or there was a execution error + # index of the least/greatest argument + */ + +@@ -2275,6 +2275,14 @@ + Item **arg= args + i; + bool is_null; + ulonglong res= get_datetime_value(thd, &arg, 0, datetime_item, &is_null); ++ ++ /* Check if we need to stop (because of error or KILL) and stop the loop */ ++ if (thd->net.report_error) ++ { ++ null_value= 1; ++ return 0; ++ } ++ + if ((null_value= args[i]->null_value)) + return 0; + if (i == 0 || (res < min_max ? cmp_sign : -cmp_sign) > 0) +@@ -2303,6 +2311,12 @@ + if (null_value) + return 0; + str_res= args[min_max_idx]->val_str(str); ++ if (args[min_max_idx]->null_value) ++ { ++ // check if the call to val_str() above returns a NULL value ++ null_value= 1; ++ return NULL; ++ } + str_res->set_charset(collation.collation); + return str_res; + } --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/98_CVE-2010-3682.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/98_CVE-2010-3682.dpatch @@ -0,0 +1,82 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via use of EXPLAIN with certain queries +# Origin: backport, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3351.52.1 +# Origin: backport, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3299 +# Bug: http://bugs.mysql.com/bug.php?id=52711 + +@DPATCH@ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/r/subselect.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/subselect.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/subselect.result 2008-01-11 10:23:41.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/subselect.result 2010-11-09 10:42:53.000000000 -0500 +@@ -4140,3 +4140,19 @@ + 3 + DROP TABLE t1,t2; + End of 5.0 tests. ++# ++# Bug #52711: Segfault when doing EXPLAIN SELECT with ++# union...order by (select... where...) ++# ++CREATE TABLE t1 (a VARCHAR(10), FULLTEXT KEY a (a)); ++INSERT INTO t1 VALUES (1),(2); ++CREATE TABLE t2 (b INT); ++INSERT INTO t2 VALUES (1),(2); ++# Should not crash ++EXPLAIN ++SELECT * FROM t2 UNION SELECT * FROM t2 ++ORDER BY (SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE)); ++# Should not crash ++SELECT * FROM t2 UNION SELECT * FROM t2 ++ORDER BY (SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE)); ++DROP TABLE t1,t2; +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/t/subselect.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/subselect.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/subselect.test 2008-01-11 10:23:24.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/subselect.test 2010-11-09 10:43:20.000000000 -0500 +@@ -2988,3 +2988,26 @@ + DROP TABLE t1,t2; + + --echo End of 5.0 tests. ++ ++--echo # ++--echo # Bug #52711: Segfault when doing EXPLAIN SELECT with ++--echo # union...order by (select... where...) ++--echo # ++ ++CREATE TABLE t1 (a VARCHAR(10), FULLTEXT KEY a (a)); ++INSERT INTO t1 VALUES (1),(2); ++CREATE TABLE t2 (b INT); ++INSERT INTO t2 VALUES (1),(2); ++ ++--echo # Should not crash ++--disable_result_log ++EXPLAIN ++SELECT * FROM t2 UNION SELECT * FROM t2 ++ ORDER BY (SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE)); ++ ++--echo # Should not crash ++SELECT * FROM t2 UNION SELECT * FROM t2 ++ ORDER BY (SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abc' IN BOOLEAN MODE)); ++DROP TABLE t1,t2; ++--enable_result_log ++ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/sql_select.cc mysql-dfsg-5.0-5.0.51a/sql/sql_select.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/sql_select.cc 2010-11-09 10:41:48.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/sql_select.cc 2010-11-09 10:41:54.000000000 -0500 +@@ -490,7 +490,7 @@ + thd->lex->allow_sum_func= save_allow_sum_func; + } + +- if (!thd->lex->view_prepare_mode) ++ if (!thd->lex->view_prepare_mode && !(select_options & SELECT_DESCRIBE)) + { + Item_subselect *subselect; + /* Is it subselect? */ +@@ -6688,7 +6688,8 @@ + *simple_order=0; // Must do a temp table to sort + else if (!(order_tables & not_const_tables)) + { +- if (order->item[0]->with_subselect) ++ if (order->item[0]->with_subselect && ++ !(join->select_lex->options & SELECT_DESCRIBE)) + order->item[0]->val_str(&order->item[0]->str_value); + DBUG_PRINT("info",("removing: %s", order->item[0]->full_name())); + continue; // skip const item --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/86_PATH_MAX.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/86_PATH_MAX.dpatch @@ -0,0 +1,139 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 86_PATH_MAX.dpatch by and Cyril Brulebois +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Patch to define PATH_MAX on systems which do not. +## DP: http://bugs.mysql.com/16574 and Debian bug #378949, #348182. + +@DPATCH@ + +--- old/ndb/src/common/logger/FileLogHandler.cpp ++++ new/ndb/src/common/logger/FileLogHandler.cpp +@@ -18,6 +18,10 @@ + #include + #include + ++#ifndef PATH_MAX ++#define PATH_MAX 4096 ++#endif ++ + // + // PUBLIC + // +--- old/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp ++++ new/ndb/src/kernel/blocks/ndbfs/AsyncFile.cpp +@@ -64,6 +64,10 @@ + #define WRITEBUFFERSIZE 262144 + #endif + ++#ifndef PATH_MAX ++#define PATH_MAX 4096 ++#endif ++ + const char *actionName[] = { + "open", + "close", +--- old/ndb/src/kernel/blocks/ndbfs/Filename.cpp ++++ new/ndb/src/kernel/blocks/ndbfs/Filename.cpp +@@ -25,6 +25,10 @@ + + #include + ++#ifndef PATH_MAX ++#define PATH_MAX 4096 ++#endif ++ + static const char* fileExtension[] = { + ".Data", + ".FragLog", +--- old/ndb/src/kernel/blocks/ndbfs/Filename.hpp ++++ new/ndb/src/kernel/blocks/ndbfs/Filename.hpp +@@ -17,6 +17,10 @@ + #ifndef Filename_H + #define Filename_H + ++#ifndef PATH_MAX ++#define PATH_MAX 4096 ++#endif ++ + //=========================================================================== + // + // .DESCRIPTION +--- old/ndb/src/kernel/vm/Configuration.cpp ++++ new/ndb/src/kernel/vm/Configuration.cpp +@@ -39,6 +39,10 @@ + #include + #include + ++#ifndef PATH_MAX ++#define PATH_MAX 4096 ++#endif ++ + extern "C" { + void ndbSetOwnVersion(); + } +--- old/ndb/src/cw/cpcd/CPCD.cpp ++++ new/ndb/src/cw/cpcd/CPCD.cpp +@@ -24,6 +24,10 @@ + + #include "common.hpp" + ++#ifndef PATH_MAX ++#define PATH_MAX 4096 ++#endif ++ + extern const ParserRow commands[]; + + +--- old/ndb/src/cw/cpcd/Process.cpp ++++ new/ndb/src/cw/cpcd/Process.cpp +@@ -27,6 +27,10 @@ + #include + #endif + ++#ifndef PATH_MAX ++#define PATH_MAX 4096 ++#endif ++ + void + CPCD::Process::print(FILE * f){ + fprintf(f, "define process\n"); +--- old/ndb/tools/restore/Restore.hpp 2007-04-06 00:41:47.000000000 +0200 ++++ new/ndb/tools/restore/Restore.hpp 2007-04-06 00:42:22.000000000 +0200 +@@ -25,6 +25,10 @@ + #include + #include + ++#ifndef PATH_MAX ++#define PATH_MAX 4096 ++#endif ++ + const int FileNameLenC = 256; + const int TableNameLenC = 256; + const int AttrNameLenC = 256; +--- old/ndb/include/util/File.hpp ++++ new/ndb/include/util/File.hpp +@@ -19,6 +19,10 @@ + + #include + ++#ifndef PATH_MAX ++#define PATH_MAX 4096 ++#endif ++ + /** + * This class provides a file abstraction . It has operations + * to create, read, write and delete a file. +--- old/ndb/src/common/portlib/NdbConfig.c ++++ new/ndb/src/common/portlib/NdbConfig.c +@@ -20,6 +20,10 @@ + #include + #include + ++#ifndef PATH_MAX ++#define PATH_MAX 4096 ++#endif ++ + static const char *datadir_path= 0; + + const char * --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/55_testsuite-2008.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/55_testsuite-2008.dpatch @@ -0,0 +1,67 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 55_testsuite-2008.dpatch by Norbert Tretkowski +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: http://bugs.mysql.com/bug.php?id=33623 + +@DPATCH@ +diff -Nrup a/mysql-test/r/view.result b/mysql-test/r/view.result +--- a/mysql-test/r/view.result 2007-09-24 17:34:09 +05:00 ++++ b/mysql-test/r/view.result 2007-10-10 12:16:12 +05:00 +@@ -2706,18 +2706,19 @@ CREATE TABLE t1( + fName varchar(25) NOT NULL, + lName varchar(25) NOT NULL, + DOB date NOT NULL, ++test_date date NOT NULL, + uID int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY); +-INSERT INTO t1(fName, lName, DOB) VALUES +-('Hank', 'Hill', '1964-09-29'), +-('Tom', 'Adams', '1908-02-14'), +-('Homer', 'Simpson', '1968-03-05'); ++INSERT INTO t1(fName, lName, DOB, test_date) VALUES ++('Hank', 'Hill', '1964-09-29', '2007-01-01'), ++('Tom', 'Adams', '1908-02-14', '2007-01-01'), ++('Homer', 'Simpson', '1968-03-05', '2007-01-01'); + CREATE VIEW v1 AS +-SELECT (year(now())-year(DOB)) AS Age ++SELECT (year(test_date)-year(DOB)) AS Age + FROM t1 HAVING Age < 75; + SHOW CREATE VIEW v1; + View Create View +-v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select (year(now()) - year(`t1`.`DOB`)) AS `Age` from `t1` having (`Age` < 75) +-SELECT (year(now())-year(DOB)) AS Age FROM t1 HAVING Age < 75; ++v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select (year(`t1`.`test_date`) - year(`t1`.`DOB`)) AS `Age` from `t1` having (`Age` < 75) ++SELECT (year(test_date)-year(DOB)) AS Age FROM t1 HAVING Age < 75; + Age + 43 + 39 +diff -Nrup a/mysql-test/t/view.test b/mysql-test/t/view.test +--- a/mysql-test/t/view.test 2007-09-24 17:34:09 +05:00 ++++ b/mysql-test/t/view.test 2007-10-10 12:16:12 +05:00 +@@ -2548,19 +2548,20 @@ CREATE TABLE t1( + fName varchar(25) NOT NULL, + lName varchar(25) NOT NULL, + DOB date NOT NULL, ++ test_date date NOT NULL, + uID int unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY); + +-INSERT INTO t1(fName, lName, DOB) VALUES +- ('Hank', 'Hill', '1964-09-29'), +- ('Tom', 'Adams', '1908-02-14'), +- ('Homer', 'Simpson', '1968-03-05'); ++INSERT INTO t1(fName, lName, DOB, test_date) VALUES ++ ('Hank', 'Hill', '1964-09-29', '2007-01-01'), ++ ('Tom', 'Adams', '1908-02-14', '2007-01-01'), ++ ('Homer', 'Simpson', '1968-03-05', '2007-01-01'); + + CREATE VIEW v1 AS +- SELECT (year(now())-year(DOB)) AS Age ++ SELECT (year(test_date)-year(DOB)) AS Age + FROM t1 HAVING Age < 75; + SHOW CREATE VIEW v1; + +-SELECT (year(now())-year(DOB)) AS Age FROM t1 HAVING Age < 75; ++SELECT (year(test_date)-year(DOB)) AS Age FROM t1 HAVING Age < 75; + SELECT * FROM v1; + + DROP VIEW v1; --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/57-fix-mysqlslowdump-config.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/57-fix-mysqlslowdump-config.dpatch @@ -0,0 +1,23 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run + +@DPATCH@ +diff -Naur mysql-dfsg-5.0-5.0.45.orig/scripts/mysqldumpslow.sh mysql-dfsg-5.0-5.0.45/scripts/mysqldumpslow.sh +--- mysql-dfsg-5.0-5.0.45.orig/scripts/mysqldumpslow.sh 2007-07-04 09:06:41.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.45/scripts/mysqldumpslow.sh 2008-02-04 08:04:14.000000000 -0500 +@@ -34,13 +34,13 @@ + $opt{'help'} and usage(); + + unless (@ARGV) { +- my $defaults = `my_print_defaults mysqld`; ++ my $defaults = `my_print_defaults mysqld -c -c /etc/mysql/my.cnf`; + my $basedir = ($defaults =~ m/--basedir=(.*)/)[0] +- or die "Can't determine basedir from 'my_print_defaults mysqld' output: $defaults"; ++ or die "Can't determine basedir from 'my_print_defaults mysqld' -c -c /etc/mysql/my.cnf output: $defaults"; + warn "basedir=$basedir\n" if $opt{v}; + + my $datadir = ($defaults =~ m/--datadir=(.*)/)[0]; +- my $slowlog = ($defaults =~ m/--log-slow-queries=(.*)/)[0]; ++ my $slowlog = ($defaults =~ m/--log[-_]slow[-_]queries=(.*)/)[0]; + if (!$datadir or $opt{i}) { + # determine the datadir from the instances section of /etc/my.cnf, if any + my $instances = `my_print_defaults instances`; --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/41_scripts__mysql_install_db.sh__no_test.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/41_scripts__mysql_install_db.sh__no_test.dpatch @@ -0,0 +1,19 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 41_scripts__mysql_install_db.sh__no_test.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: scripts__mysql_install_db.sh__no_test +## DP: http://bugs.mysql.com/bug.php?id=6901 + +@DPATCH@ +--- mysql-dfsg-5.0-5.0.50.orig/scripts/mysql_install_db.sh 2007-10-19 17:17:12.000000000 +0200 ++++ mysql-dfsg-5.0-5.0.50/scripts/mysql_install_db.sh 2007-11-26 19:48:30.000000000 +0100 +@@ -311,7 +311,7 @@ + fi + + # Create database directories mysql & test +-for dir in $ldata $ldata/mysql $ldata/test ++for dir in $ldata $ldata/mysql + do + if test ! -d $dir + then --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/98_CVE-2010-3680.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/98_CVE-2010-3680.dpatch @@ -0,0 +1,102 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via TEMPORARY InnoDB tables with +# nullable columns +# Origin: backport, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3436.2.2 +# Bug: http://bugs.mysql.com/bug.php?id=54044 + +@DPATCH@ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/suite/innodb/r/innodb_bug54044.result mysql-dfsg-5.0-5.0.51a/mysql-test/suite/innodb/r/innodb_bug54044.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/suite/innodb/r/innodb_bug54044.result 1969-12-31 19:00:00.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/suite/innodb/r/innodb_bug54044.result 2010-11-09 10:29:01.000000000 -0500 +@@ -0,0 +1,3 @@ ++CREATE TEMPORARY TABLE TABLE_54044 ENGINE = INNODB ++AS SELECT IF(NULL IS NOT NULL, NULL, NULL); ++ERROR HY000: Can't create table 'test.TABLE_54044' (errno: -1) +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/suite/innodb/t/innodb_bug54044.test mysql-dfsg-5.0-5.0.51a/mysql-test/suite/innodb/t/innodb_bug54044.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/suite/innodb/t/innodb_bug54044.test 1969-12-31 19:00:00.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/suite/innodb/t/innodb_bug54044.test 2010-11-09 10:29:01.000000000 -0500 +@@ -0,0 +1,11 @@ ++# This is the test for bug #54044. Special handle MYSQL_TYPE_NULL type ++# during create table, so it will not trigger assertion failure. ++ ++--source include/have_innodb.inc ++ ++# This 'create table' operation should fail because of ++# using NULL datatype ++--error ER_CANT_CREATE_TABLE ++CREATE TEMPORARY TABLE TABLE_54044 ENGINE = INNODB ++ AS SELECT IF(NULL IS NOT NULL, NULL, NULL); ++ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/suite/innodb_plugin/r/innodb_bug54044.result mysql-dfsg-5.0-5.0.51a/mysql-test/suite/innodb_plugin/r/innodb_bug54044.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/suite/innodb_plugin/r/innodb_bug54044.result 1969-12-31 19:00:00.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/suite/innodb_plugin/r/innodb_bug54044.result 2010-11-09 10:29:02.000000000 -0500 +@@ -0,0 +1,3 @@ ++CREATE TEMPORARY TABLE TABLE_54044 ENGINE = INNODB ++AS SELECT IF(NULL IS NOT NULL, NULL, NULL); ++ERROR HY000: Can't create table 'test.TABLE_54044' (errno: -1) +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/suite/innodb_plugin/t/innodb_bug54044.test mysql-dfsg-5.0-5.0.51a/mysql-test/suite/innodb_plugin/t/innodb_bug54044.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/suite/innodb_plugin/t/innodb_bug54044.test 1969-12-31 19:00:00.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/suite/innodb_plugin/t/innodb_bug54044.test 2010-11-09 10:29:02.000000000 -0500 +@@ -0,0 +1,11 @@ ++# This is the test for bug #54044. Special handle MYSQL_TYPE_NULL type ++# during create table, so it will not trigger assertion failure. ++ ++--source include/have_innodb_plugin.inc ++ ++# This 'create table' operation should fail because of ++# using NULL datatype ++--error ER_CANT_CREATE_TABLE ++CREATE TEMPORARY TABLE TABLE_54044 ENGINE = INNODB ++ AS SELECT IF(NULL IS NOT NULL, NULL, NULL); ++ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/ha_innodb.cc mysql-dfsg-5.0-5.0.51a/sql/ha_innodb.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/ha_innodb.cc 2010-11-09 10:28:53.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/ha_innodb.cc 2010-11-09 10:34:56.000000000 -0500 +@@ -2577,6 +2577,11 @@ + case FIELD_TYPE_BLOB: + case FIELD_TYPE_LONG_BLOB: + return(DATA_BLOB); ++ case MYSQL_TYPE_NULL: ++ /* MySQL currently accepts "NULL" datatype, but will ++ reject such datatype in the next release. We will cope ++ with it and not trigger assertion failure in 5.1 */ ++ break; + default: + assert(0); + } +@@ -4379,7 +4384,26 @@ + field = form->field[i]; + + col_type = get_innobase_type_from_mysql_type(&unsigned_type, +- field); ++ field); ++ ++ if (!col_type) { ++ push_warning_printf( ++ (THD*) trx->mysql_thd, ++ MYSQL_ERROR::WARN_LEVEL_WARN, ++ ER_CANT_CREATE_TABLE, ++ "Error creating table '%s' with " ++ "column '%s'. Please check its " ++ "column type and try to re-create " ++ "the table with an appropriate " ++ "column type.", ++ table->name, (char*) field->field_name); ++ dict_mem_table_free(table); ++ trx_commit_for_mysql(trx); ++ ++ error = DB_ERROR; ++ goto error_ret; ++ } ++ + if (field->null_ptr) { + nulls_allowed = 0; + } else { +@@ -4436,6 +4460,7 @@ + + error = row_create_table_for_mysql(table, trx); + ++error_ret: + error = convert_error_code_to_mysql(error, NULL); + + DBUG_RETURN(error); --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/90_upstreamdebiandir.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/90_upstreamdebiandir.dpatch @@ -0,0 +1,29 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 90_upstreamdebiandir.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: No description. + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.45~/configure mysql-dfsg-5.0-5.0.45/configure +--- mysql-dfsg-5.0-5.0.45~/configure 2007-07-04 15:10:10.000000000 +0200 ++++ mysql-dfsg-5.0-5.0.45/configure 2007-07-17 14:55:49.000000000 +0200 +@@ -41876,7 +41876,7 @@ + + + # Output results +- ac_config_files="$ac_config_files Makefile extra/Makefile mysys/Makefile strings/Makefile regex/Makefile heap/Makefile myisam/Makefile myisammrg/Makefile os2/Makefile os2/include/Makefile os2/include/sys/Makefile man/Makefile BUILD/Makefile vio/Makefile libmysql/Makefile client/Makefile pstack/Makefile pstack/aout/Makefile sql/Makefile sql/share/Makefile sql-common/Makefile SSL/Makefile dbug/Makefile scripts/Makefile include/Makefile sql-bench/Makefile server-tools/Makefile server-tools/instance-manager/Makefile tests/Makefile Docs/Makefile support-files/Makefile support-files/MacOSX/Makefile support-files/RHEL4-SElinux/Makefile mysql-test/Makefile netware/Makefile include/mysql_version.h cmd-line-utils/Makefile cmd-line-utils/libedit/Makefile win/Makefile zlib/Makefile debian/Makefile debian/defs.mk debian/control cmd-line-utils/readline/Makefile" ++ ac_config_files="$ac_config_files Makefile extra/Makefile mysys/Makefile strings/Makefile regex/Makefile heap/Makefile myisam/Makefile myisammrg/Makefile os2/Makefile os2/include/Makefile os2/include/sys/Makefile man/Makefile BUILD/Makefile vio/Makefile libmysql/Makefile client/Makefile pstack/Makefile pstack/aout/Makefile sql/Makefile sql/share/Makefile sql-common/Makefile SSL/Makefile dbug/Makefile scripts/Makefile include/Makefile sql-bench/Makefile server-tools/Makefile server-tools/instance-manager/Makefile tests/Makefile Docs/Makefile support-files/Makefile support-files/MacOSX/Makefile support-files/RHEL4-SElinux/Makefile mysql-test/Makefile netware/Makefile include/mysql_version.h cmd-line-utils/Makefile cmd-line-utils/libedit/Makefile win/Makefile zlib/Makefile cmd-line-utils/readline/Makefile" + + ac_config_commands="$ac_config_commands default" + +@@ -42602,9 +42602,6 @@ + "cmd-line-utils/libedit/Makefile" ) CONFIG_FILES="$CONFIG_FILES cmd-line-utils/libedit/Makefile" ;; + "win/Makefile" ) CONFIG_FILES="$CONFIG_FILES win/Makefile" ;; + "zlib/Makefile" ) CONFIG_FILES="$CONFIG_FILES zlib/Makefile" ;; +- "debian/Makefile" ) CONFIG_FILES="$CONFIG_FILES debian/Makefile" ;; +- "debian/defs.mk" ) CONFIG_FILES="$CONFIG_FILES debian/defs.mk" ;; +- "debian/control" ) CONFIG_FILES="$CONFIG_FILES debian/control" ;; + "cmd-line-utils/readline/Makefile" ) CONFIG_FILES="$CONFIG_FILES cmd-line-utils/readline/Makefile" ;; + "depfiles" ) CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "default" ) CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;; --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/100_CVE-2010-1850.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/100_CVE-2010-1850.dpatch @@ -0,0 +1,29 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: arbitrary code execution via crafted table name argument +# to COM_FIELD_LIST +# Origin: upstream, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.0-bugteam/revision/2859 +# Bug: http://bugs.mysql.com/bug.php?id=53237 +# Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=582526 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/sql_parse.cc mysql-dfsg-5.0-5.0.51a/sql/sql_parse.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/sql_parse.cc 2010-05-26 10:08:38.000000000 -0400 ++++ mysql-dfsg-5.0-5.0.51a/sql/sql_parse.cc 2010-05-26 10:08:59.000000000 -0400 +@@ -1867,8 +1867,16 @@ + if (thd->copy_db_to(&table_list.db, &table_list.db_length)) + break; + pend= strend(packet); ++ uint arg_length= pend - packet; ++ ++ /* Check given table name length. */ ++ if (arg_length >= packet_length || arg_length > NAME_LEN) ++ { ++ my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0)); ++ break; ++ } + thd->convert_string(&conv_name, system_charset_info, +- packet, (uint) (pend-packet), thd->charset()); ++ packet, arg_length, thd->charset()); + table_list.alias= table_list.table_name= conv_name.str; + packet= pend+1; + --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/98_CVE-2010-3677.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/98_CVE-2010-3677.dpatch @@ -0,0 +1,74 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via joins involving a table with a +# unique SET column +# Origin: upstream, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3436.1.1 +# Bug: http://bugs.mysql.com/bug.php?id=54575 + +@DPATCH@ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/r/func_like.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/func_like.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/func_like.result 2008-01-11 10:23:34.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/func_like.result 2010-11-09 10:19:36.000000000 -0500 +@@ -165,3 +165,17 @@ + select _cp1251'andre%' like convert('andre%' using cp1251) escape ''; + _cp1251'andre%' like convert('andre%' using cp1251) escape '' + 1 ++End of 4.1 tests ++# ++# Bug #54575: crash when joining tables with unique set column ++# ++CREATE TABLE t1(a SET('a') NOT NULL, UNIQUE KEY(a)); ++CREATE TABLE t2(b INT PRIMARY KEY); ++INSERT INTO t1 VALUES (); ++Warnings: ++Warning 1364 Field 'a' doesn't have a default value ++INSERT INTO t2 VALUES (1), (2), (3); ++SELECT 1 FROM t2 JOIN t1 ON 1 LIKE a GROUP BY a; ++1 ++DROP TABLE t1, t2; ++End of 5.1 tests +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/t/func_like.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/func_like.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/func_like.test 2008-01-11 10:23:10.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/func_like.test 2010-11-09 10:19:36.000000000 -0500 +@@ -112,5 +112,19 @@ + # + select _cp1251'andre%' like convert('andre%' using cp1251) escape ''; + +-# +-# End of 4.1 tests ++ ++--echo End of 4.1 tests ++ ++ ++--echo # ++--echo # Bug #54575: crash when joining tables with unique set column ++--echo # ++CREATE TABLE t1(a SET('a') NOT NULL, UNIQUE KEY(a)); ++CREATE TABLE t2(b INT PRIMARY KEY); ++INSERT INTO t1 VALUES (); ++INSERT INTO t2 VALUES (1), (2), (3); ++SELECT 1 FROM t2 JOIN t1 ON 1 LIKE a GROUP BY a; ++DROP TABLE t1, t2; ++ ++ ++--echo End of 5.1 tests +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/item_cmpfunc.cc mysql-dfsg-5.0-5.0.51a/sql/item_cmpfunc.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/item_cmpfunc.cc 2008-01-11 09:43:38.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/item_cmpfunc.cc 2010-11-09 10:19:36.000000000 -0500 +@@ -4093,13 +4093,14 @@ + if (args[1]->const_item()) + { + String* res2= args[1]->val_str((String *)&tmp_value2); ++ const char *ptr2; + +- if (!res2) ++ if (!res2 || !(ptr2= res2->ptr())) + return OPTIMIZE_NONE; + +- if (*res2->ptr() != wild_many) ++ if (*ptr2 != wild_many) + { +- if (args[0]->result_type() != STRING_RESULT || *res2->ptr() != wild_one) ++ if (args[0]->result_type() != STRING_RESULT || *ptr2 != wild_one) + return OPTIMIZE_OP; + } + } --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/50_fix_mysqldump.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/50_fix_mysqldump.dpatch @@ -0,0 +1,55 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 50_fix_mysqldump.dpatch by Norbert Tretkowski +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: SHOW FIELDS FROM a view with no valid definer was possible (since fix +## DP: for Bug#26817), but gave NULL as a field-type. This led to mysqldump-ing +## DP: of such views being successful, but loading such a dump with the client +## DP: failing. Patch allows SHOW FIELDS to give data-type of field in underlying +## DP: table. + +@DPATCH@ +diff -Nrup a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result +--- a/mysql-test/r/information_schema_db.result 2007-08-20 08:23:06 +02:00 ++++ b/mysql-test/r/information_schema_db.result 2007-10-26 09:01:28 +02:00 +@@ -130,7 +130,7 @@ Warnings: + Warning 1356 View 'testdb_1.v7' references invalid table(s) or column(s) or function(s) or definer/invoker of view lack rights to use them + show fields from testdb_1.v7; + Field Type Null Key Default Extra +-f1 null YES NULL ++f1 char(4) YES NULL + Warnings: + Note 1449 There is no 'no_such_user'@'no_such_host' registered + create table t3 (f1 char(4), f2 char(4)); +@@ -150,7 +150,7 @@ View Create View + v6 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `testdb_1`.`v6` AS select `testdb_1`.`t1`.`f1` AS `f1` from `testdb_1`.`t1` + show fields from testdb_1.v7; + Field Type Null Key Default Extra +-f1 null YES NULL ++f1 char(4) YES NULL + Warnings: + Note 1449 There is no 'no_such_user'@'no_such_host' registered + show create view testdb_1.v7; +@@ -178,7 +178,7 @@ show create view v4; + ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table + show fields from v4; + Field Type Null Key Default Extra +-f1 null YES NULL ++f1 char(4) YES NULL + f2 char(4) YES NULL + show fields from v2; + Field Type Null Key Default Extra +diff -Nrup a/sql/sql_base.cc b/sql/sql_base.cc +--- a/sql/sql_base.cc 2007-09-27 11:17:13 +02:00 ++++ b/sql/sql_base.cc 2007-10-26 09:01:28 +02:00 +@@ -3958,7 +3958,9 @@ find_field_in_tables(THD *thd, Item_iden + { + Field *cur_field= find_field_in_table_ref(thd, cur_table, name, length, + item->name, db, table_name, ref, +- check_privileges, ++ (thd->lex->sql_command == ++ SQLCOM_SHOW_FIELDS) ++ ? false : check_privileges, + allow_rowid, + &(item->cached_field_index), + register_tree_change, --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/59-fix-mysql-replication-logs.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/59-fix-mysql-replication-logs.dpatch @@ -0,0 +1,54 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 59-fix-mysql-replication-logs.dpatch by Mathias Gug +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Fix mysql replication logs. +## http://bugs.mysql.com/bug.php?id=28597 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/t/rpl_dual_pos_advance.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/rpl_dual_pos_advance.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/rpl_dual_pos_advance.test 2008-01-11 10:23:19.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/rpl_dual_pos_advance.test 2008-03-27 19:01:08.000000000 -0400 +@@ -106,9 +106,3 @@ + sync_with_master; + + # End of 4.1 tests +- +-# Cleanup +-# The A->B->A replication causes the master to start writing relay logs +-# in var/run, remove them +-remove_file $MYSQLTEST_VARDIR/run/master-relay-bin.000001; +-remove_file $MYSQLTEST_VARDIR/run/master-relay-bin.index; +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/t/rpl_temporary.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/rpl_temporary.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/rpl_temporary.test 2008-01-11 10:23:22.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/rpl_temporary.test 2008-03-27 19:01:08.000000000 -0400 +@@ -211,6 +211,8 @@ + connection master; + drop table t1; + ++--remove_file $MYSQLTEST_VARDIR/tmp/bug14157.sql ++ + # Delete the anonymous users + source include/delete_anonymous_users.inc; + +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/log.cc mysql-dfsg-5.0-5.0.51a/sql/log.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/log.cc 2008-01-11 09:43:40.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/log.cc 2008-03-27 19:01:08.000000000 -0400 +@@ -448,13 +448,10 @@ + { + if (!log_name || !log_name[0]) + { +- /* +- TODO: The following should be using fn_format(); We just need to +- first change fn_format() to cut the file name if it's too long. +- */ +- strmake(buff, pidfile_name,FN_REFLEN-5); +- strmov(fn_ext(buff),suffix); +- return (const char *)buff; ++ strmake(buff, pidfile_name, FN_REFLEN - strlen(suffix) - 1); ++ return (const char *) ++ fn_format(buff, buff, "", suffix, MYF(MY_REPLACE_EXT|MY_REPLACE_DIR)); ++ + } + // get rid of extension if the log is binary to avoid problems + if (strip_ext) --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/97_CVE-2009-4030.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/97_CVE-2009-4030.dpatch @@ -0,0 +1,32 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix privilege restriction bypass via incorrect calculation +# of the mysql_unpacked_real_data_home value +# Origin: upstream, http://lists.mysql.com/commits/89940 +# Bug: http://bugs.mysql.com/bug.php?id=32167 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/mysqld.cc mysql-dfsg-5.0-5.0.51a/sql/mysqld.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/mysqld.cc 2010-01-21 17:01:35.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/mysqld.cc 2010-01-21 17:05:39.000000000 -0500 +@@ -7566,16 +7566,17 @@ + pos[0]= FN_LIBCHAR; + pos[1]= 0; + } +- convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); + convert_dirname(language,language,NullS); ++ convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); + (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir ++ (void) my_load_path(pidfile_name,pidfile_name,mysql_real_data_home); ++ + my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0)); +- mysql_unpacked_real_data_home_len= strlen(mysql_unpacked_real_data_home); ++ mysql_unpacked_real_data_home_len= ++ (int) strlen(mysql_unpacked_real_data_home); + if (mysql_unpacked_real_data_home[mysql_unpacked_real_data_home_len-1] == FN_LIBCHAR) + --mysql_unpacked_real_data_home_len; + +- (void) my_load_path(pidfile_name,pidfile_name,mysql_real_data_home); +- + char *sharedir=get_relative_path(SHAREDIR); + if (test_if_hard_path(sharedir)) + strmake(buff,sharedir,sizeof(buff)-1); /* purecov: tested */ --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/52_ndb-gcc-4.2.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/52_ndb-gcc-4.2.dpatch @@ -0,0 +1,153 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 52_ndb-gcc-4.2.dpatch by Norbert Tretkowski +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: http://bugs.mysql.com/bug.php?id=31761 + +@DPATCH@ +--- 1.8/ndb/include/kernel/AttributeHeader.hpp 2007-10-23 16:46:03 +02:00 ++++ 1.9/ndb/include/kernel/AttributeHeader.hpp 2007-10-23 16:46:03 +02:00 +@@ -41,8 +41,7 @@ public: + STATIC_CONST( FRAGMENT_MEMORY= 0xFFF9 ); + + /** Initialize AttributeHeader at location aHeaderPtr */ +- static AttributeHeader& init(void* aHeaderPtr, Uint32 anAttributeId, +- Uint32 aDataSize); ++ static void init(Uint32* aHeaderPtr, Uint32 anAttributeId, Uint32 aDataSize); + + /** Returns size of AttributeHeader (usually one or two words) */ + Uint32 getHeaderSize() const; // In 32-bit words +@@ -100,10 +99,11 @@ public: + */ + + inline +-AttributeHeader& AttributeHeader::init(void* aHeaderPtr, Uint32 anAttributeId, +- Uint32 aDataSize) ++void AttributeHeader::init(Uint32* aHeaderPtr, Uint32 anAttributeId, ++ Uint32 aDataSize) + { +- return * new (aHeaderPtr) AttributeHeader(anAttributeId, aDataSize); ++ AttributeHeader ah(anAttributeId, aDataSize); ++ *aHeaderPtr = ah.m_value; + } + + inline + +--- 1.25/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp 2007-10-23 16:46:03 +02:00 ++++ 1.26/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp 2007-10-23 16:46:03 +02:00 +@@ -1577,8 +1577,8 @@ int Dbtup::interpreterNextLab(Signal* si + Uint32 TdataForUpdate[3]; + Uint32 Tlen; + +- AttributeHeader& ah = AttributeHeader::init(&TdataForUpdate[0], +- TattrId, TattrNoOfWords); ++ AttributeHeader ah(TattrId, TattrNoOfWords); ++ TdataForUpdate[0] = ah.m_value; + TdataForUpdate[1] = TregMemBuffer[theRegister + 2]; + TdataForUpdate[2] = TregMemBuffer[theRegister + 3]; + Tlen = TattrNoOfWords + 1; +@@ -1594,6 +1594,7 @@ int Dbtup::interpreterNextLab(Signal* si + // Write a NULL value into the attribute + /* --------------------------------------------------------- */ + ah.setNULL(); ++ TdataForUpdate[0] = ah.m_value; + Tlen = 1; + }//if + int TnoDataRW= updateAttributes(pagePtr, + +--- 1.20/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp 2007-10-23 16:46:03 +02:00 ++++ 1.21/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp 2007-10-23 16:46:03 +02:00 +@@ -676,8 +676,6 @@ bool + Dbtup::checkUpdateOfPrimaryKey(Uint32* updateBuffer, Tablerec* const regTabPtr) + { + Uint32 keyReadBuffer[MAX_KEY_SIZE_IN_WORDS]; +- Uint32 attributeHeader; +- AttributeHeader* ahOut = (AttributeHeader*)&attributeHeader; + AttributeHeader ahIn(*updateBuffer); + Uint32 attributeId = ahIn.getAttributeId(); + Uint32 attrDescriptorIndex = regTabPtr->tabDescriptor + (attributeId << ZAD_LOG_SIZE); +@@ -700,16 +698,17 @@ Dbtup::checkUpdateOfPrimaryKey(Uint32* u + + ReadFunction f = regTabPtr->readFunctionArray[attributeId]; + +- AttributeHeader::init(&attributeHeader, attributeId, 0); ++ AttributeHeader attributeHeader(attributeId, 0); + tOutBufIndex = 0; + tMaxRead = MAX_KEY_SIZE_IN_WORDS; + + bool tmp = tXfrmFlag; + tXfrmFlag = true; +- ndbrequire((this->*f)(&keyReadBuffer[0], ahOut, attrDescriptor, attributeOffset)); ++ ndbrequire((this->*f)(&keyReadBuffer[0], &attributeHeader, attrDescriptor, ++ attributeOffset)); + tXfrmFlag = tmp; +- ndbrequire(tOutBufIndex == ahOut->getDataSize()); +- if (ahIn.getDataSize() != ahOut->getDataSize()) { ++ ndbrequire(tOutBufIndex == attributeHeader.getDataSize()); ++ if (ahIn.getDataSize() != attributeHeader.getDataSize()) { + ljam(); + return true; + }//if + +--- 1.13/ndb/src/kernel/blocks/dbutil/DbUtil.cpp 2007-10-23 16:46:03 +02:00 ++++ 1.14/ndb/src/kernel/blocks/dbutil/DbUtil.cpp 2007-10-23 16:46:03 +02:00 +@@ -1168,9 +1168,7 @@ DbUtil::prepareOperation(Signal* signal, + /************************************************************** + * Attribute found - store in mapping (AttributeId, Position) + **************************************************************/ +- AttributeHeader & attrMap = +- AttributeHeader::init(attrMappingIt.data, +- attrDesc.AttributeId, // 1. Store AttrId ++ AttributeHeader attrMap(attrDesc.AttributeId, // 1. Store AttrId + 0); + + if (attrDesc.AttributeKeyFlag) { +@@ -1199,6 +1197,7 @@ DbUtil::prepareOperation(Signal* signal, + return; + } + } ++ *(attrMappingIt.data) = attrMap.m_value; + #if 0 + ndbout << "BEFORE: attrLength: " << attrLength << endl; + #endif + +--- 1.24/ndb/src/ndbapi/NdbOperationDefine.cpp 2007-10-23 16:46:03 +02:00 ++++ 1.25/ndb/src/ndbapi/NdbOperationDefine.cpp 2007-10-23 16:46:03 +02:00 +@@ -392,9 +392,8 @@ NdbOperation::getValue_impl(const NdbCol + return NULL; + }//if + }//if +- Uint32 ah; +- AttributeHeader::init(&ah, tAttrInfo->m_attrId, 0); +- if (insertATTRINFO(ah) != -1) { ++ AttributeHeader ah(tAttrInfo->m_attrId, 0); ++ if (insertATTRINFO(ah.m_value) != -1) { + // Insert Attribute Id into ATTRINFO part. + + /************************************************************************ +@@ -525,12 +524,11 @@ NdbOperation::setValue( const NdbColumnI + + tAttrId = tAttrInfo->m_attrId; + const char *aValue = aValuePassed; +- Uint32 ahValue; + if (aValue == NULL) { + if (tAttrInfo->m_nullable) { +- AttributeHeader& ah = AttributeHeader::init(&ahValue, tAttrId, 0); ++ AttributeHeader ah(tAttrId, 0); + ah.setNULL(); +- insertATTRINFO(ahValue); ++ insertATTRINFO(ah.m_value); + // Insert Attribute Id with the value + // NULL into ATTRINFO part. + DBUG_RETURN(0); +@@ -563,8 +561,8 @@ NdbOperation::setValue( const NdbColumnI + }//if + const Uint32 totalSizeInWords = (sizeInBytes + 3)/4; // Including bits in last word + const Uint32 sizeInWords = sizeInBytes / 4; // Excluding bits in last word +- (void) AttributeHeader::init(&ahValue, tAttrId, totalSizeInWords); +- insertATTRINFO( ahValue ); ++ AttributeHeader ah(tAttrId, totalSizeInWords); ++ insertATTRINFO( ah.m_value ); + + /*********************************************************************** + * Check if the pointer of the value passed is aligned on a 4 byte boundary. --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/98_CVE-2010-3681.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/98_CVE-2010-3681.dpatch @@ -0,0 +1,210 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via alternate reads from two indexes +# on a table using the HANDLER interface +# Origin: upstream, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3422.1.1 +# Bug: http://bugs.mysql.com/bug.php?id=54007 + +@DPATCH@ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/r/handler.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/handler.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/handler.result 2008-01-11 10:23:36.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/handler.result 2010-11-09 10:40:00.000000000 -0500 +@@ -502,3 +502,96 @@ + ERROR 42S22: Unknown column 'inexistent' in 'field list' + handler t1_alias close; + drop table t1; ++# ++# Bug #54007: assert in ha_myisam::index_next , HANDLER ++# ++CREATE TABLE t1(a INT, b INT, PRIMARY KEY(a), KEY b(b), KEY ab(a, b)); ++HANDLER t1 OPEN; ++HANDLER t1 READ FIRST; ++a b ++HANDLER t1 READ `PRIMARY` NEXT; ++a b ++HANDLER t1 READ ab NEXT; ++a b ++HANDLER t1 READ b NEXT; ++a b ++HANDLER t1 READ NEXT; ++a b ++HANDLER t1 CLOSE; ++INSERT INTO t1 VALUES (2, 20), (1, 10), (4, 40), (3, 30); ++HANDLER t1 OPEN; ++HANDLER t1 READ FIRST; ++a b ++2 20 ++HANDLER t1 READ NEXT; ++a b ++1 10 ++HANDLER t1 READ `PRIMARY` NEXT; ++a b ++1 10 ++HANDLER t1 READ `PRIMARY` NEXT; ++a b ++2 20 ++HANDLER t1 READ ab NEXT; ++a b ++1 10 ++HANDLER t1 READ ab NEXT; ++a b ++2 20 ++HANDLER t1 READ b NEXT; ++a b ++1 10 ++HANDLER t1 READ b NEXT; ++a b ++2 20 ++HANDLER t1 READ b NEXT; ++a b ++3 30 ++HANDLER t1 READ b NEXT; ++a b ++4 40 ++HANDLER t1 READ b NEXT; ++a b ++HANDLER t1 READ NEXT; ++a b ++4 40 ++HANDLER t1 READ NEXT; ++a b ++3 30 ++HANDLER t1 READ NEXT; ++a b ++HANDLER t1 CLOSE; ++HANDLER t1 OPEN; ++HANDLER t1 READ FIRST; ++a b ++2 20 ++HANDLER t1 READ `PRIMARY` PREV; ++a b ++4 40 ++HANDLER t1 READ `PRIMARY` PREV; ++a b ++3 30 ++HANDLER t1 READ b PREV; ++a b ++4 40 ++HANDLER t1 READ b PREV; ++a b ++3 30 ++HANDLER t1 CLOSE; ++HANDLER t1 OPEN; ++HANDLER t1 READ FIRST; ++a b ++2 20 ++HANDLER t1 READ `PRIMARY` PREV LIMIT 3; ++a b ++4 40 ++3 30 ++2 20 ++HANDLER t1 READ b NEXT LIMIT 5; ++a b ++1 10 ++2 20 ++3 30 ++4 40 ++HANDLER t1 CLOSE; ++DROP TABLE t1; +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/t/handler.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/handler.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/handler.test 2008-01-11 10:23:11.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/handler.test 2010-11-09 10:40:49.000000000 -0500 +@@ -460,3 +460,52 @@ + handler t1_alias READ a next where inexistent > 0; + handler t1_alias close; + drop table t1; ++ ++--echo # ++--echo # Bug #54007: assert in ha_myisam::index_next , HANDLER ++--echo # ++CREATE TABLE t1(a INT, b INT, PRIMARY KEY(a), KEY b(b), KEY ab(a, b)); ++ ++HANDLER t1 OPEN; ++HANDLER t1 READ FIRST; ++HANDLER t1 READ `PRIMARY` NEXT; ++HANDLER t1 READ ab NEXT; ++HANDLER t1 READ b NEXT; ++HANDLER t1 READ NEXT; ++HANDLER t1 CLOSE; ++ ++INSERT INTO t1 VALUES (2, 20), (1, 10), (4, 40), (3, 30); ++HANDLER t1 OPEN; ++HANDLER t1 READ FIRST; ++HANDLER t1 READ NEXT; ++HANDLER t1 READ `PRIMARY` NEXT; ++HANDLER t1 READ `PRIMARY` NEXT; ++HANDLER t1 READ ab NEXT; ++HANDLER t1 READ ab NEXT; ++HANDLER t1 READ b NEXT; ++HANDLER t1 READ b NEXT; ++HANDLER t1 READ b NEXT; ++HANDLER t1 READ b NEXT; ++HANDLER t1 READ b NEXT; ++HANDLER t1 READ NEXT; ++HANDLER t1 READ NEXT; ++HANDLER t1 READ NEXT; ++HANDLER t1 CLOSE; ++ ++HANDLER t1 OPEN; ++HANDLER t1 READ FIRST; ++HANDLER t1 READ `PRIMARY` PREV; ++HANDLER t1 READ `PRIMARY` PREV; ++HANDLER t1 READ b PREV; ++HANDLER t1 READ b PREV; ++HANDLER t1 CLOSE; ++ ++HANDLER t1 OPEN; ++HANDLER t1 READ FIRST; ++HANDLER t1 READ `PRIMARY` PREV LIMIT 3; ++HANDLER t1 READ b NEXT LIMIT 5; ++HANDLER t1 CLOSE; ++ ++DROP TABLE t1; ++ ++ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/sql_handler.cc mysql-dfsg-5.0-5.0.51a/sql/sql_handler.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/sql_handler.cc 2008-01-11 09:43:25.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/sql_handler.cc 2010-11-09 10:38:23.000000000 -0500 +@@ -450,6 +450,14 @@ + my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), keyname, tables->alias); + goto err; + } ++ /* Check if the same index involved. */ ++ if ((uint) keyno != table->file->get_index()) ++ { ++ if (mode == RNEXT) ++ mode= RFIRST; ++ else if (mode == RPREV) ++ mode= RLAST; ++ } + } + + if (insert_fields(thd, &thd->lex->select_lex.context, +@@ -472,9 +480,16 @@ + case RNEXT: + if (table->file->inited != handler::NONE) + { +- error=keyname ? +- table->file->index_next(table->record[0]) : +- table->file->rnd_next(table->record[0]); ++ if (keyname) ++ { ++ /* Check if we read from the same index. */ ++ DBUG_ASSERT((uint) keyno == table->file->get_index()); ++ error= table->file->index_next(table->record[0]); ++ } ++ else ++ { ++ error= table->file->rnd_next(table->record[0]); ++ } + break; + } + /* else fall through */ +@@ -495,6 +510,8 @@ + break; + case RPREV: + DBUG_ASSERT(keyname != 0); ++ /* Check if we read from the same index. */ ++ DBUG_ASSERT((uint) keyno == table->file->get_index()); + if (table->file->inited != handler::NONE) + { + error=table->file->index_prev(table->record[0]); --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/60_raise-max-keylength.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/60_raise-max-keylength.dpatch @@ -0,0 +1,495 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 60_raise-max-keylength.dpatch by Norbert Tretkowski +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Raises the maximum key length to 4005 bytes or 1335 UTF-8 characters, +## DP: which is the maximum raise possible without changing other parameters. + +@DPATCH@ +diff -Nrup a/include/myisam.h b/include/myisam.h +--- a/include/myisam.h 2006-12-23 20:04:05 +01:00 ++++ b/include/myisam.h 2008-01-30 18:26:56 +01:00 +@@ -48,15 +48,27 @@ extern "C" { + #define MI_MAX_KEY MAX_INDEXES /* Max allowed keys */ + #endif + +-#define MI_MAX_POSSIBLE_KEY_BUFF (1024+6+6) /* For myisam_chk */ + /* + The following defines can be increased if necessary. + But beware the dependency of MI_MAX_POSSIBLE_KEY_BUFF and MI_MAX_KEY_LENGTH. + */ +-#define MI_MAX_KEY_LENGTH 1000 /* Max length in bytes */ + #define MI_MAX_KEY_SEG 16 /* Max segments for key */ ++ /* ++ Max key length computes from max key block. At least 4 keys should ++ go into a key block. Each key has a length (1 or 3 bytes), a data ++ file pointer (max 8 bytes), optionally a key file pointer (max 8 ++ bytes), optional length per key segment (max 3 bytes), and an ++ optional null byte per key segment. The key_length computation in ++ mi_create() adds another data pointer per key (max 8 bytes). A block ++ has a 2 byte length and optionally a key file pointer. See ++ myisamdef.h:MI_BLOCK_SIZE() and mi_create(). With ++ MI_MAX_KEY_BLOCK_LENGTH = 16384 and MI_MAX_KEY_SEG = 16 we have ++ (16384-2-8)/4-8-8-(8+(3+1)*16) = 4005 bytes. ++ */ ++#define MI_MAX_KEY_LENGTH 4005 /* Max key length in bytes */ + + #define MI_MAX_KEY_BUFF (MI_MAX_KEY_LENGTH+MI_MAX_KEY_SEG*6+8+8) ++#define MI_MAX_POSSIBLE_KEY_BUFF (MI_MAX_KEY_LENGTH+24+6+6) /* For myisam_chk */ + #define MI_MAX_MSG_BUF 1024 /* used in CHECK TABLE, REPAIR TABLE */ + #define MI_NAME_IEXT ".MYI" + #define MI_NAME_DEXT ".MYD" +diff -Nrup a/mysql-test/r/ctype_utf8.result b/mysql-test/r/ctype_utf8.result +--- a/mysql-test/r/ctype_utf8.result 2007-10-30 09:20:28 +01:00 ++++ b/mysql-test/r/ctype_utf8.result 2008-01-30 18:26:56 +01:00 +@@ -240,8 +240,10 @@ select hex(s1) from t1; + hex(s1) + 41 + drop table t1; +-create table t1 (a text character set utf8, primary key(a(360))); +-ERROR 42000: Specified key was too long; max key length is 1000 bytes ++create table t1 (a text character set utf8, primary key(a(1336))); ++ERROR 42000: Specified key was too long; max key length is 4005 bytes ++create table t1 (a text character set utf8, primary key(a(1335))); ++drop table t1; + CREATE TABLE t1 ( a varchar(10) ) CHARACTER SET utf8; + INSERT INTO t1 VALUES ( 'test' ); + SELECT a.a, b.a FROM t1 a, t1 b WHERE a.a = b.a; +diff -Nrup a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result +--- a/mysql-test/r/innodb.result 2007-12-13 11:49:11 +01:00 ++++ b/mysql-test/r/innodb.result 2008-01-30 18:26:56 +01:00 +@@ -2773,7 +2773,7 @@ c varchar(255) character set utf8, + d varchar(255) character set utf8, + e varchar(255) character set utf8, + key (a,b,c,d,e)) engine=innodb; +-ERROR 42000: Specified key was too long; max key length is 3072 bytes ++ERROR 42000: Specified key was too long; max key length is 3500 bytes + create table t1 (s1 varbinary(2),primary key (s1)) engine=innodb; + create table t2 (s1 binary(2),primary key (s1)) engine=innodb; + create table t3 (s1 varchar(2) binary,primary key (s1)) engine=innodb; +diff -Nrup a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result +--- a/mysql-test/r/myisam.result 2008-01-16 12:15:56 +01:00 ++++ b/mysql-test/r/myisam.result 2008-01-30 18:26:56 +01:00 +@@ -322,11 +322,34 @@ CHECK TABLE t1; + Table Op Msg_type Msg_text + test.t1 check status OK + drop table t1; +-CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), d varchar(255), e varchar(255), KEY t1 (a, b, c, d, e)); +-ERROR 42000: Specified key was too long; max key length is 1000 bytes +-CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), d varchar(255), e varchar(255)); +-ALTER TABLE t1 ADD INDEX t1 (a, b, c, d, e); +-ERROR 42000: Specified key was too long; max key length is 1000 bytes ++CREATE TABLE t1 ( ++a varchar(255), b varchar(255), c varchar(255), d varchar(255), ++e varchar(255), f varchar(255), g varchar(255), h varchar(255), ++i varchar(255), j varchar(255), k varchar(255), l varchar(255), ++m varchar(255), n varchar(255), o varchar(255), p varchar(181), ++KEY t1 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)); ++ERROR 42000: Specified key was too long; max key length is 4005 bytes ++CREATE TABLE t1 ( ++a varchar(255), b varchar(255), c varchar(255), d varchar(255), ++e varchar(255), f varchar(255), g varchar(255), h varchar(255), ++i varchar(255), j varchar(255), k varchar(255), l varchar(255), ++m varchar(255), n varchar(255), o varchar(255), p varchar(181)); ++ALTER TABLE t1 ADD INDEX t1 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); ++ERROR 42000: Specified key was too long; max key length is 4005 bytes ++DROP TABLE t1; ++CREATE TABLE t1 ( ++a varchar(255), b varchar(255), c varchar(255), d varchar(255), ++e varchar(255), f varchar(255), g varchar(255), h varchar(255), ++i varchar(255), j varchar(255), k varchar(255), l varchar(255), ++m varchar(255), n varchar(255), o varchar(255), p varchar(180), ++KEY t1 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)); ++DROP TABLE t1; ++CREATE TABLE t1 ( ++a varchar(255), b varchar(255), c varchar(255), d varchar(255), ++e varchar(255), f varchar(255), g varchar(255), h varchar(255), ++i varchar(255), j varchar(255), k varchar(255), l varchar(255), ++m varchar(255), n varchar(255), o varchar(255), p varchar(180)); ++ALTER TABLE t1 ADD INDEX t1 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); + DROP TABLE t1; + CREATE TABLE t1 (a int not null, b int, c int, key(b), key(c), key(a,b), key(c,a)); + INSERT into t1 values (0, null, 0), (0, null, 1), (0, null, 2), (0, null,3), (1,1,4); +@@ -1093,6 +1116,186 @@ length(c1) c1 + 2 A + 2 B + DROP TABLE t1; ++CREATE TABLE t1 ( ++c1 VARCHAR(255) NOT NULL, ++c2 VARCHAR(255) NOT NULL, ++c3 VARCHAR(255) NOT NULL, ++c4 VARCHAR(255) NOT NULL, ++c5 VARCHAR(255) NOT NULL, ++c6 VARCHAR(61), ++KEY i1 (c1, c2, c3, c4, c5, c6)) DEFAULT CHARSET=UTF8; ++ERROR 42000: Specified key was too long; max key length is 4005 bytes ++CREATE TABLE t1 ( ++c1 VARCHAR(255) NOT NULL, ++c2 VARCHAR(255) NOT NULL, ++c3 VARCHAR(255) NOT NULL, ++c4 VARCHAR(255) NOT NULL, ++c5 VARCHAR(255) NOT NULL, ++c6 VARCHAR(60), ++KEY i1 (c1, c2, c3, c4, c5, c6)) DEFAULT CHARSET=UTF8; ++INSERT INTO t1 VALUES ++(REPEAT('0', 255), REPEAT('0', 255), REPEAT('0', 255), ++REPEAT('0', 255), REPEAT('0', 255), CONCAT(REPEAT('M', 59), '1')), ++(REPEAT('0', 255), REPEAT('0', 255), REPEAT('0', 255), ++REPEAT('0', 255), REPEAT('0', 255), CONCAT(REPEAT('M', 59), '7')), ++(REPEAT('0', 255), REPEAT('0', 255), REPEAT('0', 255), ++REPEAT('0', 255), REPEAT('0', 255), CONCAT(REPEAT('M', 59), '5')), ++(REPEAT('0', 255), REPEAT('0', 255), REPEAT('0', 255), ++REPEAT('0', 255), REPEAT('0', 255), CONCAT(REPEAT('M', 59), '8')), ++(REPEAT('0', 255), REPEAT('0', 255), REPEAT('0', 255), ++REPEAT('0', 255), REPEAT('0', 255), CONCAT(REPEAT('M', 59), '6')), ++(REPEAT('0', 255), REPEAT('0', 255), REPEAT('0', 255), ++REPEAT('0', 255), REPEAT('0', 255), CONCAT(REPEAT('M', 59), '5')); ++CHECK TABLE t1 EXTENDED; ++Table Op Msg_type Msg_text ++test.t1 check status OK ++OPTIMIZE TABLE t1; ++Table test.t1 ++Op optimize ++Msg_type status ++Msg_text OK ++SHOW CREATE TABLE t1; ++Table t1 ++Create Table CREATE TABLE `t1` ( ++ `c1` varchar(255) NOT NULL, ++ `c2` varchar(255) NOT NULL, ++ `c3` varchar(255) NOT NULL, ++ `c4` varchar(255) NOT NULL, ++ `c5` varchar(255) NOT NULL, ++ `c6` varchar(60) default NULL, ++ KEY `i1` (`c1`,`c2`,`c3`,`c4`,`c5`,`c6`) ++) ENGINE=MyISAM DEFAULT CHARSET=utf8 ++SHOW TABLE STATUS LIKE 't1'; ++Name t1 ++Engine MyISAM ++Version 10 ++Row_format Dynamic ++Rows 6 ++Avg_row_length # ++Data_length # ++Max_data_length # ++Index_length # ++Data_free 0 ++Auto_increment NULL ++Create_time # ++Update_time # ++Check_time # ++Collation utf8_general_ci ++Checksum NULL ++Create_options ++Comment ++SHOW INDEX FROM t1; ++Table t1 ++Non_unique 1 ++Key_name i1 ++Seq_in_index 1 ++Column_name c1 ++Collation A ++Cardinality 1 ++Sub_part NULL ++Packed NULL ++Null ++Index_type BTREE ++Comment ++Table t1 ++Non_unique 1 ++Key_name i1 ++Seq_in_index 2 ++Column_name c2 ++Collation A ++Cardinality 1 ++Sub_part NULL ++Packed NULL ++Null ++Index_type BTREE ++Comment ++Table t1 ++Non_unique 1 ++Key_name i1 ++Seq_in_index 3 ++Column_name c3 ++Collation A ++Cardinality 1 ++Sub_part NULL ++Packed NULL ++Null ++Index_type BTREE ++Comment ++Table t1 ++Non_unique 1 ++Key_name i1 ++Seq_in_index 4 ++Column_name c4 ++Collation A ++Cardinality 1 ++Sub_part NULL ++Packed NULL ++Null ++Index_type BTREE ++Comment ++Table t1 ++Non_unique 1 ++Key_name i1 ++Seq_in_index 5 ++Column_name c5 ++Collation A ++Cardinality 1 ++Sub_part NULL ++Packed NULL ++Null ++Index_type BTREE ++Comment ++Table t1 ++Non_unique 1 ++Key_name i1 ++Seq_in_index 6 ++Column_name c6 ++Collation A ++Cardinality 6 ++Sub_part NULL ++Packed NULL ++Null YES ++Index_type BTREE ++Comment ++EXPLAIN SELECT SUBSTR(c6, 50) FROM t1 ++ORDER BY c1, c2, c3, c4, c5, c6; ++id 1 ++select_type SIMPLE ++table t1 ++type index ++possible_keys NULL ++key i1 ++key_len 4018 ++ref NULL ++rows 6 ++Extra Using index ++SELECT SUBSTR(c6, 50) FROM t1 ORDER BY c1, c2, c3, c4, c5, c6; ++SUBSTR(c6, 50) ++MMMMMMMMMM1 ++MMMMMMMMMM5 ++MMMMMMMMMM5 ++MMMMMMMMMM6 ++MMMMMMMMMM7 ++MMMMMMMMMM8 ++DELETE FROM t1 WHERE c6 LIKE '%5' LIMIT 1; ++UPDATE t1 SET c6 = CONCAT(REPEAT('M', 59), '9') WHERE c6 LIKE '%1'; ++SELECT SUBSTR(c6, 50) FROM t1 ORDER BY c1, c2, c3, c4, c5, c6; ++SUBSTR(c6, 50) ++MMMMMMMMMM5 ++MMMMMMMMMM6 ++MMMMMMMMMM7 ++MMMMMMMMMM8 ++MMMMMMMMMM9 ++CHECK TABLE t1 EXTENDED; ++Table Op Msg_type Msg_text ++test.t1 check status OK ++REPAIR TABLE t1 EXTENDED; ++Table Op Msg_type Msg_text ++test.t1 repair status OK ++CHECK TABLE t1 EXTENDED; ++Table Op Msg_type Msg_text ++test.t1 check status OK ++DROP TABLE t1; + End of 4.1 tests + set storage_engine=MyISAM; + drop table if exists t1,t2,t3; +@@ -1668,7 +1871,7 @@ a b + drop table t1; + create table t1 (v varchar(65530), key(v)); + Warnings: +-Warning 1071 Specified key was too long; max key length is 1000 bytes ++Warning 1071 Specified key was too long; max key length is 4005 bytes + drop table if exists t1; + create table t1 (v varchar(65536)); + Warnings: +diff -Nrup a/mysql-test/r/type_blob.result b/mysql-test/r/type_blob.result +--- a/mysql-test/r/type_blob.result 2007-11-19 18:34:12 +01:00 ++++ b/mysql-test/r/type_blob.result 2008-01-30 18:26:56 +01:00 +@@ -356,16 +356,24 @@ HELLO MY 1 + a 1 + hello 1 + drop table t1; +-create table t1 (a text, unique (a(2100))); +-ERROR 42000: Specified key was too long; max key length is 1000 bytes +-create table t1 (a text, key (a(2100))); ++create table t1 (a text, unique (a(4006))); ++ERROR 42000: Specified key was too long; max key length is 4005 bytes ++create table t1 (a text, unique (a(4005))); ++show create table t1; ++Table Create Table ++t1 CREATE TABLE `t1` ( ++ `a` text, ++ UNIQUE KEY `a` (`a`(4005)) ++) ENGINE=MyISAM DEFAULT CHARSET=latin1 ++drop table t1; ++create table t1 (a text, key (a(4006))); + Warnings: +-Warning 1071 Specified key was too long; max key length is 1000 bytes ++Warning 1071 Specified key was too long; max key length is 4005 bytes + show create table t1; + Table Create Table + t1 CREATE TABLE `t1` ( + `a` text, +- KEY `a` (`a`(1000)) ++ KEY `a` (`a`(4005)) + ) ENGINE=MyISAM DEFAULT CHARSET=latin1 + drop table t1; + CREATE TABLE t1 ( +diff -Nrup a/mysql-test/t/ctype_utf8.test b/mysql-test/t/ctype_utf8.test +--- a/mysql-test/t/ctype_utf8.test 2007-10-30 09:20:28 +01:00 ++++ b/mysql-test/t/ctype_utf8.test 2008-01-30 18:26:56 +01:00 +@@ -162,9 +162,12 @@ drop table t1; + # + # Bug 2699 + # UTF8 breaks primary keys for cols > 333 characters ++# Limit raised to 1335 UTF-8 chars by fix for Bug#4541. See myisam.test. + # + --error 1071 +-create table t1 (a text character set utf8, primary key(a(360))); ++create table t1 (a text character set utf8, primary key(a(1336))); ++create table t1 (a text character set utf8, primary key(a(1335))); ++drop table t1; + + + # +diff -Nrup a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test +--- a/mysql-test/t/myisam.test 2008-01-16 12:15:56 +01:00 ++++ b/mysql-test/t/myisam.test 2008-01-30 18:26:56 +01:00 +@@ -334,13 +334,36 @@ drop table t1; + + # + # Test of creating table with too long key ++# Limit raised to 4005 bytes by fix for Bug#4541. See myisam.test. + # +- + --error 1071 +-CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), d varchar(255), e varchar(255), KEY t1 (a, b, c, d, e)); +-CREATE TABLE t1 (a varchar(255), b varchar(255), c varchar(255), d varchar(255), e varchar(255)); ++CREATE TABLE t1 ( ++ a varchar(255), b varchar(255), c varchar(255), d varchar(255), ++ e varchar(255), f varchar(255), g varchar(255), h varchar(255), ++ i varchar(255), j varchar(255), k varchar(255), l varchar(255), ++ m varchar(255), n varchar(255), o varchar(255), p varchar(181), ++ KEY t1 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)); ++CREATE TABLE t1 ( ++ a varchar(255), b varchar(255), c varchar(255), d varchar(255), ++ e varchar(255), f varchar(255), g varchar(255), h varchar(255), ++ i varchar(255), j varchar(255), k varchar(255), l varchar(255), ++ m varchar(255), n varchar(255), o varchar(255), p varchar(181)); + --error 1071 +-ALTER TABLE t1 ADD INDEX t1 (a, b, c, d, e); ++ALTER TABLE t1 ADD INDEX t1 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); ++DROP TABLE t1; ++CREATE TABLE t1 ( ++ a varchar(255), b varchar(255), c varchar(255), d varchar(255), ++ e varchar(255), f varchar(255), g varchar(255), h varchar(255), ++ i varchar(255), j varchar(255), k varchar(255), l varchar(255), ++ m varchar(255), n varchar(255), o varchar(255), p varchar(180), ++ KEY t1 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)); ++DROP TABLE t1; ++CREATE TABLE t1 ( ++ a varchar(255), b varchar(255), c varchar(255), d varchar(255), ++ e varchar(255), f varchar(255), g varchar(255), h varchar(255), ++ i varchar(255), j varchar(255), k varchar(255), l varchar(255), ++ m varchar(255), n varchar(255), o varchar(255), p varchar(180)); ++ALTER TABLE t1 ADD INDEX t1 (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p); + DROP TABLE t1; + + # +@@ -1016,6 +1039,59 @@ SELECT DISTINCT length(c1), c1 FROM t1 W + SELECT DISTINCT COUNT(*) FROM t1 IGNORE INDEX (c1) WHERE c1 = ''; + SELECT DISTINCT length(c1), c1 FROM t1 IGNORE INDEX (c1) WHERE c1 = ''; + SELECT DISTINCT length(c1), c1 FROM t1 ORDER BY c1; ++DROP TABLE t1; ++ ++# ++# Bug#4541 - "Specified key was too long; max key length is 1000 bytes" ++# with utf8 ++# Raised limit for max key length from 1000 to 4005 bytes. ++# This is maximum without changing other limits (e.g. MI_MAX_KEY_BLOCK_LENGTH) ++# ++--error 1071 ++CREATE TABLE t1 ( ++ c1 VARCHAR(255) NOT NULL, ++ c2 VARCHAR(255) NOT NULL, ++ c3 VARCHAR(255) NOT NULL, ++ c4 VARCHAR(255) NOT NULL, ++ c5 VARCHAR(255) NOT NULL, ++ c6 VARCHAR(61), ++ KEY i1 (c1, c2, c3, c4, c5, c6)) DEFAULT CHARSET=UTF8; ++CREATE TABLE t1 ( ++ c1 VARCHAR(255) NOT NULL, ++ c2 VARCHAR(255) NOT NULL, ++ c3 VARCHAR(255) NOT NULL, ++ c4 VARCHAR(255) NOT NULL, ++ c5 VARCHAR(255) NOT NULL, ++ c6 VARCHAR(60), ++ KEY i1 (c1, c2, c3, c4, c5, c6)) DEFAULT CHARSET=UTF8; ++INSERT INTO t1 VALUES ++ (REPEAT('0', 255), REPEAT('0', 255), REPEAT('0', 255), ++ REPEAT('0', 255), REPEAT('0', 255), CONCAT(REPEAT('M', 59), '1')), ++ (REPEAT('0', 255), REPEAT('0', 255), REPEAT('0', 255), ++ REPEAT('0', 255), REPEAT('0', 255), CONCAT(REPEAT('M', 59), '7')), ++ (REPEAT('0', 255), REPEAT('0', 255), REPEAT('0', 255), ++ REPEAT('0', 255), REPEAT('0', 255), CONCAT(REPEAT('M', 59), '5')), ++ (REPEAT('0', 255), REPEAT('0', 255), REPEAT('0', 255), ++ REPEAT('0', 255), REPEAT('0', 255), CONCAT(REPEAT('M', 59), '8')), ++ (REPEAT('0', 255), REPEAT('0', 255), REPEAT('0', 255), ++ REPEAT('0', 255), REPEAT('0', 255), CONCAT(REPEAT('M', 59), '6')), ++ (REPEAT('0', 255), REPEAT('0', 255), REPEAT('0', 255), ++ REPEAT('0', 255), REPEAT('0', 255), CONCAT(REPEAT('M', 59), '5')); ++CHECK TABLE t1 EXTENDED; ++query_vertical OPTIMIZE TABLE t1; ++query_vertical SHOW CREATE TABLE t1; ++--replace_column 6 # 7 # 8 # 9 # 12 # 13 # 14 # ++query_vertical SHOW TABLE STATUS LIKE 't1'; ++query_vertical SHOW INDEX FROM t1; ++query_vertical EXPLAIN SELECT SUBSTR(c6, 50) FROM t1 ++ ORDER BY c1, c2, c3, c4, c5, c6; ++SELECT SUBSTR(c6, 50) FROM t1 ORDER BY c1, c2, c3, c4, c5, c6; ++DELETE FROM t1 WHERE c6 LIKE '%5' LIMIT 1; ++UPDATE t1 SET c6 = CONCAT(REPEAT('M', 59), '9') WHERE c6 LIKE '%1'; ++SELECT SUBSTR(c6, 50) FROM t1 ORDER BY c1, c2, c3, c4, c5, c6; ++CHECK TABLE t1 EXTENDED; ++REPAIR TABLE t1 EXTENDED; ++CHECK TABLE t1 EXTENDED; + DROP TABLE t1; + + --echo End of 4.1 tests +diff -Nrup a/mysql-test/t/type_blob.test b/mysql-test/t/type_blob.test +--- a/mysql-test/t/type_blob.test 2007-11-19 18:34:12 +01:00 ++++ b/mysql-test/t/type_blob.test 2008-01-30 18:26:56 +01:00 +@@ -131,9 +131,15 @@ select c,count(*) from t1 group by c; + select d,count(*) from t1 group by d; + drop table t1; + ++# ++# Limit raised to 4005 bytes by fix for Bug#4541. See myisam.test. ++# + -- error 1071 +-create table t1 (a text, unique (a(2100))); # should give an error +-create table t1 (a text, key (a(2100))); # key is auto-truncated ++create table t1 (a text, unique (a(4006))); # should give an error ++create table t1 (a text, unique (a(4005))); # should give an error ++show create table t1; ++drop table t1; ++create table t1 (a text, key (a(4006))); # key is auto-truncated + show create table t1; + drop table t1; + +diff -Nrup a/sql/unireg.h b/sql/unireg.h +--- a/sql/unireg.h 2007-08-02 22:57:41 +02:00 ++++ b/sql/unireg.h 2008-01-30 18:26:56 +01:00 +@@ -49,7 +49,7 @@ + #define MAX_SYS_VAR_LENGTH 32 + #define MAX_KEY MAX_INDEXES /* Max used keys */ + #define MAX_REF_PARTS 16 /* Max parts used as ref */ +-#define MAX_KEY_LENGTH 3072 /* max possible key */ ++#define MAX_KEY_LENGTH 4005 /* myisamdef.h */ /* max possible key */ + #if SIZEOF_OFF_T > 4 + #define MAX_REFLENGTH 8 /* Max length for record ref */ + #else --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/51_incorrect-order.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/51_incorrect-order.dpatch @@ -0,0 +1,115 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 51_incorrect-order.dpatch by Norbert Tretkowski +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: http://lists.mysql.com/commits/37246 + +@DPATCH@ +diff -Nrup a/mysql-test/r/select.result b/mysql-test/r/select.result +--- a/mysql-test/r/select.result 2007-09-13 17:31:07 +04:00 ++++ b/mysql-test/r/select.result 2007-11-07 14:00:41 +03:00 +@@ -4096,4 +4096,43 @@ SELECT `x` FROM v3; + x + 1 + DROP VIEW v1, v2, v3; ++CREATE TABLE t1 (c11 INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY); ++CREATE TABLE t2 (c21 INT UNSIGNED NOT NULL, ++c22 INT DEFAULT NULL, ++KEY(c21, c22)); ++CREATE TABLE t3 (c31 INT UNSIGNED NOT NULL DEFAULT 0, ++c32 INT DEFAULT NULL, ++c33 INT NOT NULL, ++c34 INT UNSIGNED DEFAULT 0, ++KEY (c33, c34, c32)); ++INSERT INTO t1 values (),(),(),(),(); ++INSERT INTO t2 SELECT a.c11, b.c11 FROM t1 a, t1 b; ++INSERT INTO t3 VALUES (1, 1, 1, 0), ++(2, 2, 0, 0), ++(3, 3, 1, 0), ++(4, 4, 0, 0), ++(5, 5, 1, 0); ++SELECT c32 FROM t1, t2, t3 WHERE t1.c11 IN (1, 3, 5) AND ++t3.c31 = t1.c11 AND t2.c21 = t1.c11 AND ++t3.c33 = 1 AND t2.c22 in (1, 3) ++ORDER BY c32; ++c32 ++1 ++1 ++3 ++3 ++5 ++5 ++SELECT c32 FROM t1, t2, t3 WHERE t1.c11 IN (1, 3, 5) AND ++t3.c31 = t1.c11 AND t2.c21 = t1.c11 AND ++t3.c33 = 1 AND t2.c22 in (1, 3) ++ORDER BY c32 DESC; ++c32 ++5 ++5 ++3 ++3 ++1 ++1 ++DROP TABLE t1, t2, t3; + End of 5.0 tests +diff -Nrup a/mysql-test/t/select.test b/mysql-test/t/select.test +--- a/mysql-test/t/select.test 2007-09-15 09:02:02 +04:00 ++++ b/mysql-test/t/select.test 2007-11-07 14:00:41 +03:00 +@@ -3484,4 +3484,40 @@ DROP VIEW v1, v2, v3; + + --enable_ps_protocol + ++# ++# Bug #30666: Incorrect order when using range conditions on 2 tables or more ++# ++ ++CREATE TABLE t1 (c11 INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY); ++CREATE TABLE t2 (c21 INT UNSIGNED NOT NULL, ++ c22 INT DEFAULT NULL, ++ KEY(c21, c22)); ++CREATE TABLE t3 (c31 INT UNSIGNED NOT NULL DEFAULT 0, ++ c32 INT DEFAULT NULL, ++ c33 INT NOT NULL, ++ c34 INT UNSIGNED DEFAULT 0, ++ KEY (c33, c34, c32)); ++ ++INSERT INTO t1 values (),(),(),(),(); ++INSERT INTO t2 SELECT a.c11, b.c11 FROM t1 a, t1 b; ++INSERT INTO t3 VALUES (1, 1, 1, 0), ++ (2, 2, 0, 0), ++ (3, 3, 1, 0), ++ (4, 4, 0, 0), ++ (5, 5, 1, 0); ++ ++# Show that ORDER BY produces the correct results order ++SELECT c32 FROM t1, t2, t3 WHERE t1.c11 IN (1, 3, 5) AND ++ t3.c31 = t1.c11 AND t2.c21 = t1.c11 AND ++ t3.c33 = 1 AND t2.c22 in (1, 3) ++ ORDER BY c32; ++ ++# Show that ORDER BY DESC produces the correct results order ++SELECT c32 FROM t1, t2, t3 WHERE t1.c11 IN (1, 3, 5) AND ++ t3.c31 = t1.c11 AND t2.c21 = t1.c11 AND ++ t3.c33 = 1 AND t2.c22 in (1, 3) ++ ORDER BY c32 DESC; ++ ++DROP TABLE t1, t2, t3; ++ + --echo End of 5.0 tests +diff -Nrup a/sql/sql_select.cc b/sql/sql_select.cc +--- a/sql/sql_select.cc 2007-10-02 18:45:48 +04:00 ++++ b/sql/sql_select.cc 2007-11-07 14:00:42 +03:00 +@@ -6071,10 +6071,9 @@ make_join_readinfo(JOIN *join, ulonglong + ordered. If there is a temp table the ordering is done as a last + operation and doesn't prevent join cache usage. + */ +- if (!ordered_set && !join->need_tmp && +- ((table == join->sort_by_table && +- (!join->order || join->skip_sort_order)) || +- (join->sort_by_table == (TABLE *) 1 && i != join->const_tables))) ++ if (!ordered_set && !join->need_tmp && ++ (table == join->sort_by_table || ++ (join->sort_by_table == (TABLE *) 1 && i != join->const_tables))) + ordered_set= 1; + + switch (tab->type) { --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/45_warn-CLI-passwords.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/45_warn-CLI-passwords.dpatch @@ -0,0 +1,191 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 45_warn-CLI-passwords.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: warn-CLI-passwords + +@DPATCH@ + +--- old/client/mysqladmin.cc.orig 2005-11-15 01:12:30.000000000 +0100 ++++ new/client/mysqladmin.cc 2005-11-22 00:17:41.327082273 +0100 +@@ -154,7 +154,7 @@ + {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR, + REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, + {"password", 'p', +- "Password to use when connecting to server. If password is not given it's asked from the tty.", ++ "Password to use when connecting to server. If password is not given it's asked from the tty. WARNING: Providing a password on command line is insecure as it is visible through /proc to anyone for a short time.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + #ifdef __WIN__ + {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, +--- old/client/mysql.cc.orig 2005-11-15 01:12:45.000000000 +0100 ++++ new/client/mysql.cc 2005-11-22 00:17:41.329082230 +0100 +@@ -621,7 +621,7 @@ + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + #endif + {"password", 'p', +- "Password to use when connecting to server. If password is not given it's asked from the tty.", ++ "Password to use when connecting to server. If password is not given it's asked from the tty. WARNING: This is insecure as the password is visible for anyone through /proc for a short time.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + #ifdef __WIN__ + {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, +--- old/client/mysqldump.c.orig 2005-11-15 01:12:38.000000000 +0100 ++++ new/client/mysqldump.c 2005-11-22 00:17:41.332082165 +0100 +@@ -323,7 +323,7 @@ + "Sorts each table's rows by primary key, or first unique key, if such a key exists. Useful when dumping a MyISAM table to be loaded into an InnoDB table, but will make the dump itself take considerably longer.", + (gptr*) &opt_order_by_primary, (gptr*) &opt_order_by_primary, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"password", 'p', +- "Password to use when connecting to server. If password is not given it's solicited on the tty.", ++ "Password to use when connecting to server. If password is not given it's solicited on the tty. WARNING: Providing a password on command line is insecure as it is visible through /proc to anyone for a short time.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + #ifdef __WIN__ + {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, +--- old/client/mysqlshow.c.orig 2005-11-15 01:12:47.000000000 +0100 ++++ new/client/mysqlshow.c 2005-11-22 00:17:41.333082144 +0100 +@@ -185,7 +185,7 @@ + {"keys", 'k', "Show keys for table.", (gptr*) &opt_show_keys, + (gptr*) &opt_show_keys, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, + {"password", 'p', +- "Password to use when connecting to server. If password is not given it's asked from the tty.", ++ "Password to use when connecting to server. If password is not given it's asked from the tty. WARNING: Providing a password on command line is insecure as it is visible through /proc to anyone for a short time.", + 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, + {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, + (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, +--- old/scripts/mysqlaccess.sh.orig 2005-11-15 01:12:32.000000000 +0100 ++++ new/scripts/mysqlaccess.sh 2005-11-22 00:17:41.352081736 +0100 +@@ -74,11 +74,17 @@ + + -u, --user=# username for logging in to the db + -p, --password=# validate password for user ++ WARNING: Providing a password on command line is ++ insecure as it is visible through /proc to anyone ++ for a short time. + -h, --host=# name or IP-number of the host + -d, --db=# name of the database + + -U, --superuser=# connect as superuser + -P, --spassword=# password for superuser ++ WARNING: Providing a password on command line is ++ insecure as it is visible through /proc to anyone ++ for a short time. + -H, --rhost=# remote MySQL-server to connect to + --old_server connect to old MySQL-server (before v3.21) which + does not yet know how to handle full where clauses. +--- old/scripts/mysql_convert_table_format.sh.orig 2005-11-15 01:12:45.000000000 +0100 ++++ new/scripts/mysql_convert_table_format.sh 2005-11-22 00:17:41.353081714 +0100 +@@ -107,6 +107,8 @@ + + --password='password' + Password for the current user. ++ WARNING: Providing a password on command line is insecure as it is visible ++ through /proc to anyone for a short time. + + --port=port + TCP/IP port to connect to if host is not "localhost". +--- old/scripts/mysqld_multi.sh.orig 2005-11-15 01:12:46.000000000 +0100 ++++ new/scripts/mysqld_multi.sh 2005-11-22 00:17:41.355081671 +0100 +@@ -730,6 +730,9 @@ + mysqladmin = /path/to/mysqladmin/mysqladmin + socket = /tmp/mysql.sock3 + port = 3308 ++ WARNING: Providing a password on command line is ++ insecure as it is visible through /proc to anyone ++ for a short time. + pid-file = @localstatedir@3/hostname.pid3 + datadir = @localstatedir@3 + language = @datadir@/mysql/swedish +--- old/scripts/mysql_fix_privilege_tables.sh.orig 2005-11-15 01:12:47.000000000 +0100 ++++ new/scripts/mysql_fix_privilege_tables.sh 2005-11-22 00:17:41.357081628 +0100 +@@ -33,6 +33,10 @@ + + case "$1" in + --no-defaults|--defaults-file=*|--defaults-extra-file=*) ++# ++# WARNING: Providing a password on command line is insecure as it is visible ++# through /proc to anyone for a short time. ++# + defaults="$1"; shift + ;; + esac +--- old/scripts/mysqlhotcopy.sh.orig 2005-11-15 01:12:47.000000000 +0100 ++++ new/scripts/mysqlhotcopy.sh 2005-11-22 00:17:41.358081607 +0100 +@@ -32,6 +32,7 @@ + + mysqlhotcopy --method='scp -Bq -i /usr/home/foo/.ssh/identity' --user=root --password=secretpassword \ + db_1./^nice_table/ user@some.system.dom:~/path/to/new_directory ++ (INSECURE) + + WARNING: THIS PROGRAM IS STILL IN BETA. Comments/patches welcome. + +@@ -53,6 +54,9 @@ + -u, --user=# user for database login if not current user + -p, --password=# password to use when connecting to server (if not set + in my.cnf, which is recommended) ++ WARNING: Providing a password on command line is ++ insecure as it is visible through /proc to anyone ++ for a short time. + -h, --host=# Hostname for local server when connecting over TCP/IP + -P, --port=# port to use when connecting to local server with TCP/IP + -S, --socket=# socket to use when connecting to local server +@@ -1025,6 +1029,9 @@ + one of the config files, normally /etc/my.cnf or your personal ~/.my.cnf. + (See the chapter 'my.cnf Option Files' in the manual) + ++WARNING: Providing a password on command line is insecure as it is visible ++through /proc to anyone for a short time. ++ + =item -h, -h, --host=# + + Hostname for local server when connecting over TCP/IP. By specifying this +--- old/scripts/mysql_setpermission.sh.orig 2005-11-15 01:12:30.000000000 +0100 ++++ new/scripts/mysql_setpermission.sh 2005-11-22 00:17:41.359081585 +0100 +@@ -647,6 +647,9 @@ + + --user : is the username to connect with. + --password : the password of the username. ++ WARNING: Providing a password on command line is ++ insecure as it is visible through /proc to anyone ++ for a short time. + --host : the host to connect to. + --socket : the socket to connect to. + --port : the port number of the host to connect to. +--- old/scripts/mysql_tableinfo.sh.orig 2005-11-15 01:12:32.000000000 +0100 ++++ new/scripts/mysql_tableinfo.sh 2005-11-22 00:17:41.360081564 +0100 +@@ -462,6 +462,8 @@ + =item -p, --password=# + + password to use when connecting to server ++WARNING: Providing a password on command line is insecure as it is visible ++through /proc to anyone for a short time. + + =item -h, --host=# + +--- old/scripts/mysql_explain_log.sh 2007-02-20 18:49:37.000000000 +0100 ++++ new/scripts/mysql_explain_log.sh 2007-03-22 22:32:26.000000000 +0100 +@@ -341,6 +341,9 @@ + The MySQL username to use when connecting to the server + --password=PASSWORD, -p=PASSWORD + The password to use when connecting to the server ++ WARNING: Providing a password on command line is ++ insecure as it is visible through /proc to anyone ++ for a short time. + --socket=SOCKET, -s=SOCKET + The socket file to use when connecting to the server + --printerror=1, -e 1 +@@ -379,7 +382,7 @@ + + =head1 USAGE + +-mysql_explain_log [--date=YYMMDD] --host=dbhost] [--user=dbuser] [--password=dbpw] [--socket=/path/to/socket] [--printerror=1] < logfile ++mysql_explain_log [--date=YYMMDD] --host=dbhost] [--user=dbuser] [--password=dbpw (INSECURE)] [--socket=/path/to/socket] [--printerror=1] < logfile + + --help, -h + Display this help message +@@ -391,6 +394,8 @@ + The MySQL username to use when connecting to the server + --password=PASSWORD, -p=PASSWORD + The password to use when connecting to the server ++ WARNING: Providing a password on command line is insecure ++ as it is visible through /proc to anyone for a short time. + --socket=SOCKET, -s=SOCKET + The socket file to use when connecting to the server + --printerror=1, -e 1 --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/98_CVE-2010-3836.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/98_CVE-2010-3836.dpatch @@ -0,0 +1,62 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via pre-evaluation of LIKE +# predicates during view preparation. +# Origin: upstream, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3452.1.22 +# Bug: http://bugs.mysql.com/bug.php?id=54568 + +@DPATCH@ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/r/subselect3.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/subselect3.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/subselect3.result 2008-01-11 10:23:41.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/subselect3.result 2010-11-09 11:37:53.000000000 -0500 +@@ -760,3 +760,21 @@ + 2 DEPENDENT SUBQUERY t2 unique_subquery PRIMARY PRIMARY 4 func 1 Using index + DROP TABLE t1; + End of 5.0 tests ++# ++# Bug#54568: create view cause Assertion failed: 0, ++# file .\item_subselect.cc, line 836 ++# ++EXPLAIN SELECT 1 LIKE ( 1 IN ( SELECT 1 ) ); ++id select_type table type possible_keys key key_len ref rows Extra ++1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used ++Warnings: ++Note 1249 Select 2 was reduced during optimization ++DESCRIBE SELECT 1 LIKE ( 1 IN ( SELECT 1 ) ); ++id select_type table type possible_keys key key_len ref rows Extra ++1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used ++Warnings: ++Note 1249 Select 2 was reduced during optimization ++# None of the below should crash ++CREATE VIEW v1 AS SELECT 1 LIKE ( 1 IN ( SELECT 1 ) ); ++CREATE VIEW v2 AS SELECT 1 LIKE '%' ESCAPE ( 1 IN ( SELECT 1 ) ); ++DROP VIEW v1, v2; +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/t/subselect3.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/subselect3.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/subselect3.test 2008-01-11 10:23:24.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/subselect3.test 2010-11-09 11:38:18.000000000 -0500 +@@ -589,3 +589,14 @@ + DROP TABLE t1; + + --echo End of 5.0 tests ++ ++--echo # ++--echo # Bug#54568: create view cause Assertion failed: 0, ++--echo # file .\item_subselect.cc, line 836 ++--echo # ++EXPLAIN SELECT 1 LIKE ( 1 IN ( SELECT 1 ) ); ++DESCRIBE SELECT 1 LIKE ( 1 IN ( SELECT 1 ) ); ++--echo # None of the below should crash ++CREATE VIEW v1 AS SELECT 1 LIKE ( 1 IN ( SELECT 1 ) ); ++CREATE VIEW v2 AS SELECT 1 LIKE '%' ESCAPE ( 1 IN ( SELECT 1 ) ); ++DROP VIEW v1, v2; +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/item_cmpfunc.cc mysql-dfsg-5.0-5.0.51a/sql/item_cmpfunc.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/item_cmpfunc.cc 2010-11-09 11:37:05.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/item_cmpfunc.cc 2010-11-09 11:37:12.000000000 -0500 +@@ -4121,7 +4121,7 @@ + return TRUE; + } + +- if (escape_item->const_item()) ++ if (escape_item->const_item() && !thd->lex->view_prepare_mode) + { + /* If we are on execution stage */ + String *escape_str= escape_item->val_str(&tmp_value1); --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/37_scripts__mysqld_safe.sh__syslog.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/37_scripts__mysqld_safe.sh__syslog.dpatch @@ -0,0 +1,124 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 37_scripts__mysqld_safe.sh__syslog.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: scripts__mysqld_safe.sh__syslog + +@DPATCH@ + +--- old/scripts/mysqld_safe.sh.orig 2005-11-15 01:12:47.000000000 +0100 ++++ new/scripts/mysqld_safe.sh 2005-11-22 00:01:38.913802923 +0100 +@@ -13,6 +13,9 @@ + KILL_MYSQLD=1; + MYSQLD= + ++# This command can be used as pipe to syslog. With "-s" it also logs to stderr. ++ERR_LOGGER="logger -p daemon.err -t mysqld_safe -i" ++ + trap '' 1 2 3 15 # we shouldn't let anyone kill us + + umask 007 +@@ -76,7 +79,6 @@ + + # mysqld_safe-specific options - must be set in my.cnf ([mysqld_safe])! + --ledir=*) ledir=`echo "$arg" | sed -e "s;--ledir=;;"` ;; +- --log-error=*) err_log=`echo "$arg" | sed -e "s;--log-error=;;"` ;; + --open-files-limit=*) open_files=`echo "$arg" | sed -e "s;--open-files-limit=;;"` ;; + --core-file-size=*) core_file_size=`echo "$arg" | sed -e "s;--core-file-size=;;"` ;; + --timezone=*) TZ=`echo "$arg" | sed -e "s;--timezone=;;"` ; export TZ; ;; +@@ -177,7 +179,6 @@ + + # these rely on $DATADIR by default, so we'll set them later on + pid_file= +-err_log= + + # Get first arguments from the my.cnf file, groups [mysqld] and [mysqld_safe] + # and then merge with the command line arguments +@@ -244,7 +245,6 @@ + * ) pid_file="$DATADIR/$pid_file" ;; + esac + fi +-test -z "$err_log" && err_log=$DATADIR/`@HOSTNAME@`.err + + if test -n "$mysql_unix_port" + then +@@ -314,8 +314,6 @@ + then + USER_OPTION="--user=$user" + fi +- # If we are root, change the err log to the right user. +- touch $err_log; chown $user $err_log + if test -n "$open_files" + then + ulimit -n $open_files +@@ -337,18 +335,16 @@ + then + if @FIND_PROC@ + then # The pid contains a mysqld process +- echo "A mysqld process already exists" +- echo "A mysqld process already exists at " `date` >> $err_log ++ echo "A mysqld process already exists" | $ERR_LOGGER -s + exit 1 + fi + fi + rm -f $pid_file + if test -f $pid_file + then +- echo "Fatal error: Can't remove the pid file: $pid_file" +- echo "Fatal error: Can't remove the pid file: $pid_file at " `date` >> $err_log +- echo "Please remove it manually and start $0 again" +- echo "mysqld daemon not started" ++ echo "Fatal error: Can't remove the pid file: $pid_file" | $ERR_LOGGER -s ++ echo "Please remove it manually and start $0 again" | $ERR_LOGGER -s ++ echo "mysqld daemon not started" | $ERR_LOGGER -s + exit 1 + fi + fi +@@ -373,15 +369,15 @@ + # ulimit -n 256 > /dev/null 2>&1 # Fix for BSD and FreeBSD systems + #fi + +-echo "`date +'%y%m%d %H:%M:%S mysqld started'`" >> $err_log ++echo "started" | $ERR_LOGGER -s + while true + do + rm -f $safe_mysql_unix_port $pid_file # Some extra safety + if test -z "$args" + then +- $NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file @MYSQLD_DEFAULT_SWITCHES@ >> $err_log 2>&1 ++ $NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file @MYSQLD_DEFAULT_SWITCHES@ 2>&1 | $ERR_LOGGER -t mysqld + else +- eval "$NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file @MYSQLD_DEFAULT_SWITCHES@ $args >> $err_log 2>&1" ++ eval "$NOHUP_NICENESS $ledir/$MYSQLD $defaults --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR $USER_OPTION --pid-file=$pid_file @MYSQLD_DEFAULT_SWITCHES@ $args 2>&1 | $ERR_LOGGER -t mysqld" + fi + if test ! -f $pid_file # This is removed if normal shutdown + then +@@ -398,7 +394,7 @@ + # kill -9 is used or the process won't react on the kill. + numofproces=`ps xaww | grep -v "grep" | grep "$ledir/$MYSQLD\>" | grep -c "pid-file=$pid_file"` + +- echo -e "\nNumber of processes running now: $numofproces" | tee -a $err_log ++ echo "Number of processes running now: $numofproces" | $ERR_LOGGER -s + I=1 + while test "$I" -le "$numofproces" + do +@@ -411,16 +407,14 @@ + # echo "TEST $I - $T **" + if kill -9 $T + then +- echo "$MYSQLD process hanging, pid $T - killed" | tee -a $err_log ++ echo "$MYSQLD process hanging, pid $T - killed" | $ERR_LOGGER -s + else + break + fi + I=`expr $I + 1` + done + fi +- echo "`date +'%y%m%d %H:%M:%S'` mysqld restarted" | tee -a $err_log ++ echo "restarted" | $ERR_LOGGER -s + done + +-echo "`date +'%y%m%d %H:%M:%S'` mysqld ended" | tee -a $err_log +-echo "" | tee -a $err_log +- ++echo "ended" | $ERR_LOGGER -s --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/25_mysys__default.c.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/25_mysys__default.c.dpatch @@ -0,0 +1,19 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 25_mysys__default.c.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: mysys__default.c + +@DPATCH@ + +--- old/mysys/default.c 2005-05-26 15:26:56.000000000 +0200 ++++ new/mysys/default.c 2005-06-08 19:54:26.434959920 +0200 +@@ -866,7 +866,7 @@ + if ((env= getenv("ETC"))) + *ptr++= env; + #endif +- *ptr++= "/etc/"; ++ *ptr++= "/etc/mysql/"; + #endif + if ((env= getenv(STRINGIFY_ARG(DEFAULT_HOME_ENV)))) + *ptr++= env; --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/98_CVE-2009-4484.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/98_CVE-2009-4484.dpatch @@ -0,0 +1,179 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix arbitrary code execution via yassl stack overflow +# Origin: upstream, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.0/revision/2837.1.1 +# Bug: http://bugs.mysql.com/bug.php?id=50227 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/extra/yassl/taocrypt/include/asn.hpp mysql-dfsg-5.0-5.0.51a/extra/yassl/taocrypt/include/asn.hpp +--- mysql-dfsg-5.0-5.0.51a~/extra/yassl/taocrypt/include/asn.hpp 2008-01-11 09:43:14.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/extra/yassl/taocrypt/include/asn.hpp 2010-01-29 12:34:55.000000000 -0500 +@@ -305,6 +305,7 @@ + bool ValidateSignature(SignerList*); + bool ConfirmSignature(Source&); + void GetKey(); ++ char* AddTag(char*, const char*, const char*, word32, word32); + void GetName(NameType); + void GetValidity(); + void GetDate(DateType); +diff -urNad mysql-dfsg-5.0-5.0.51a~/extra/yassl/taocrypt/src/asn.cpp mysql-dfsg-5.0-5.0.51a/extra/yassl/taocrypt/src/asn.cpp +--- mysql-dfsg-5.0-5.0.51a~/extra/yassl/taocrypt/src/asn.cpp 2008-01-11 09:43:28.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/extra/yassl/taocrypt/src/asn.cpp 2010-01-29 12:34:55.000000000 -0500 +@@ -652,6 +652,23 @@ + } + + ++char *CertDecoder::AddTag(char *ptr, const char *buf_end, ++ const char *tag_name, word32 tag_name_length, ++ word32 tag_value_length) ++{ ++ if (ptr + tag_name_length + tag_value_length > buf_end) ++ return 0; ++ ++ memcpy(ptr, tag_name, tag_name_length); ++ ptr+= tag_name_length; ++ ++ memcpy(ptr, source_.get_current(), tag_value_length); ++ ptr+= tag_value_length; ++ ++ return ptr; ++} ++ ++ + // process NAME, either issuer or subject + void CertDecoder::GetName(NameType nt) + { +@@ -659,11 +676,21 @@ + + SHA sha; + word32 length = GetSequence(); // length of all distinguished names +- assert (length < ASN_NAME_MAX); ++ ++ if (length >= ASN_NAME_MAX) ++ goto err; + length += source_.get_index(); + +- char* ptr = (nt == ISSUER) ? issuer_ : subject_; +- word32 idx = 0; ++ char *ptr, *buf_end; ++ ++ if (nt == ISSUER) { ++ ptr= issuer_; ++ buf_end= ptr + sizeof(issuer_) - 1; // 1 byte for trailing 0 ++ } ++ else { ++ ptr= subject_; ++ buf_end= ptr + sizeof(subject_) - 1; // 1 byte for trailing 0 ++ } + + while (source_.get_index() < length) { + GetSet(); +@@ -685,47 +712,36 @@ + byte id = source_.next(); + b = source_.next(); // strType + word32 strLen = GetLength(source_); +- bool copy = false; + +- if (id == COMMON_NAME) { +- memcpy(&ptr[idx], "/CN=", 4); +- idx += 4; +- copy = true; +- } +- else if (id == SUR_NAME) { +- memcpy(&ptr[idx], "/SN=", 4); +- idx += 4; +- copy = true; +- } +- else if (id == COUNTRY_NAME) { +- memcpy(&ptr[idx], "/C=", 3); +- idx += 3; +- copy = true; +- } +- else if (id == LOCALITY_NAME) { +- memcpy(&ptr[idx], "/L=", 3); +- idx += 3; +- copy = true; +- } +- else if (id == STATE_NAME) { +- memcpy(&ptr[idx], "/ST=", 4); +- idx += 4; +- copy = true; +- } +- else if (id == ORG_NAME) { +- memcpy(&ptr[idx], "/O=", 3); +- idx += 3; +- copy = true; +- } +- else if (id == ORGUNIT_NAME) { +- memcpy(&ptr[idx], "/OU=", 4); +- idx += 4; +- copy = true; +- } +- +- if (copy) { +- memcpy(&ptr[idx], source_.get_current(), strLen); +- idx += strLen; ++ switch (id) { ++ case COMMON_NAME: ++ if (!(ptr= AddTag(ptr, buf_end, "/CN=", 4, strLen))) ++ goto err; ++ break; ++ case SUR_NAME: ++ if (!(ptr= AddTag(ptr, buf_end, "/SN=", 4, strLen))) ++ goto err; ++ break; ++ case COUNTRY_NAME: ++ if (!(ptr= AddTag(ptr, buf_end, "/C=", 3, strLen))) ++ goto err; ++ break; ++ case LOCALITY_NAME: ++ if (!(ptr= AddTag(ptr, buf_end, "/L=", 3, strLen))) ++ goto err; ++ break; ++ case STATE_NAME: ++ if (!(ptr= AddTag(ptr, buf_end, "/ST=", 4, strLen))) ++ goto err; ++ break; ++ case ORG_NAME: ++ if (!(ptr= AddTag(ptr, buf_end, "/O=", 3, strLen))) ++ goto err; ++ break; ++ case ORGUNIT_NAME: ++ if (!(ptr= AddTag(ptr, buf_end, "/OU=", 4, strLen))) ++ goto err; ++ break; + } + + sha.Update(source_.get_current(), strLen); +@@ -739,23 +755,20 @@ + source_.advance(oidSz + 1); + word32 length = GetLength(source_); + +- if (email) { +- memcpy(&ptr[idx], "/emailAddress=", 14); +- idx += 14; +- +- memcpy(&ptr[idx], source_.get_current(), length); +- idx += length; +- } ++ if (email && !(ptr= AddTag(ptr, buf_end, "/emailAddress=", 14, length))) ++ goto err; + + source_.advance(length); + } + } +- ptr[idx++] = 0; ++ *ptr= 0; + +- if (nt == ISSUER) +- sha.Final(issuerHash_); +- else +- sha.Final(subjectHash_); ++ sha.Final(nt == ISSUER ? issuerHash_ : subjectHash_); ++ ++ return; ++ ++err: ++ source_.SetError(CONTENT_E); + } + + --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/44_scripts__mysql_config__libs.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/44_scripts__mysql_config__libs.dpatch @@ -0,0 +1,24 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 99-unnamed.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Removes unnecessary library dependencies. See #390692 + +@DPATCH@ + +--- old/scripts/mysql_config.sh 2006-08-25 23:12:10.000000000 +0200 ++++ new/scripts/mysql_config.sh 2006-10-02 21:05:52.000000000 +0200 +@@ -98,10 +98,10 @@ + + # Create options + # We intentionally add a space to the beginning and end of lib strings, simplifies replace later +-libs=" $ldflags -L$pkglibdir -lmysqlclient @ZLIB_DEPS@ @NON_THREADED_LIBS@" ++libs=" $ldflags -L$pkglibdir -lmysqlclient" + libs="$libs @openssl_libs@ @STATIC_NSS_FLAGS@ " +-libs_r=" $ldflags -L$pkglibdir -lmysqlclient_r @ZLIB_DEPS@ @LIBS@ @openssl_libs@ " +-embedded_libs=" $ldflags -L$pkglibdir -lmysqld @ZLIB_DEPS@ @LIBS@ @WRAPLIBS@ @innodb_system_libs@ @openssl_libs@ " ++libs_r=" $ldflags -L$pkglibdir -lmysqlclient_r @openssl_libs@ " ++embedded_libs=" $ldflags -L$pkglibdir -lmysqld @WRAPLIBS@ @innodb_system_libs@ @openssl_libs@ " + + cflags="-I$pkgincludedir @CFLAGS@ " #note: end space! + include="-I$pkgincludedir" --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/96_SECURITY_CVE-2008-4098.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/96_SECURITY_CVE-2008-4098.dpatch @@ -0,0 +1,606 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 96_SECURITY_CVE-2008-4098.dpatch by Marc Deslauriers +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Description: Disallow use of MySQL data directory in DATA DIRECTORY +## DP: and INDEX DIRECTORY options. +## DP: Ubuntu: https://bugs.launchpad.net/bugs/254129 +## DP: Upstream: http://bugs.mysql.com/bug.php?id=32167 +## DP: Patch: http://lists.mysql.com/commits/52326 +## DP: Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=480292 +## DP: Debian Patch: http://security.debian.org/pool/updates/main/m/mysql-dfsg-5.0/mysql-dfsg-5.0_5.0.32-7etch8.diff.gz + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/include/my_sys.h mysql-dfsg-5.0-5.0.51a/include/my_sys.h +--- mysql-dfsg-5.0-5.0.51a~/include/my_sys.h 2008-01-11 09:43:37.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/include/my_sys.h 2008-11-13 17:15:20.000000000 -0500 +@@ -568,6 +568,7 @@ + extern File my_dup(File file, myf MyFlags); + extern int my_mkdir(const char *dir, int Flags, myf MyFlags); + extern int my_readlink(char *to, const char *filename, myf MyFlags); ++extern int my_is_symlink(const char *filename); + extern int my_realpath(char *to, const char *filename, myf MyFlags); + extern File my_create_with_symlink(const char *linkname, const char *filename, + int createflags, int access_flags, +diff -urNad mysql-dfsg-5.0-5.0.51a~/include/myisam.h mysql-dfsg-5.0-5.0.51a/include/myisam.h +--- mysql-dfsg-5.0-5.0.51a~/include/myisam.h 2008-01-11 09:43:14.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/include/myisam.h 2008-11-13 17:15:20.000000000 -0500 +@@ -267,6 +267,10 @@ + extern my_off_t myisam_max_temp_length; + extern ulong myisam_bulk_insert_tree_size, myisam_data_pointer_size; + ++/* usually used to check if a symlink points into the mysql data home */ ++/* which is normally forbidden */ ++extern int (*myisam_test_invalid_symlink)(const char *filename); ++ + /* Prototypes for myisam-functions */ + + extern int mi_close(struct st_myisam_info *file); +diff -urNad mysql-dfsg-5.0-5.0.51a~/myisam/mi_check.c mysql-dfsg-5.0-5.0.51a/myisam/mi_check.c +--- mysql-dfsg-5.0-5.0.51a~/myisam/mi_check.c 2008-01-11 09:43:38.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/myisam/mi_check.c 2008-11-13 17:15:20.000000000 -0500 +@@ -1616,7 +1616,7 @@ + DATA_TMP_EXT, share->base.raid_chunks, + (param->testflag & T_BACKUP_DATA ? + MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || +- mi_open_datafile(info,share,-1)) ++ mi_open_datafile(info,share,name,-1)) + got_error=1; + } + } +@@ -2404,7 +2404,7 @@ + DATA_TMP_EXT, share->base.raid_chunks, + (param->testflag & T_BACKUP_DATA ? + MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || +- mi_open_datafile(info,share,-1)) ++ mi_open_datafile(info,share,name,-1)) + got_error=1; + } + } +@@ -2936,7 +2936,7 @@ + DATA_TMP_EXT, share->base.raid_chunks, + (param->testflag & T_BACKUP_DATA ? + MYF(MY_REDEL_MAKE_BACKUP): MYF(0))) || +- mi_open_datafile(info,share,-1)) ++ mi_open_datafile(info,share,name,-1)) + got_error=1; + } + } +diff -urNad mysql-dfsg-5.0-5.0.51a~/myisam/mi_open.c mysql-dfsg-5.0-5.0.51a/myisam/mi_open.c +--- mysql-dfsg-5.0-5.0.51a~/myisam/mi_open.c 2008-01-11 09:43:24.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/myisam/mi_open.c 2008-11-13 17:15:20.000000000 -0500 +@@ -74,7 +74,7 @@ + + MI_INFO *mi_open(const char *name, int mode, uint open_flags) + { +- int lock_error,kfile,open_mode,save_errno,have_rtree=0; ++ int lock_error,kfile,open_mode,save_errno,have_rtree=0, realpath_err; + uint i,j,len,errpos,head_length,base_pos,offset,info_length,keys, + key_parts,unique_key_parts,fulltext_keys,uniques; + char name_buff[FN_REFLEN], org_name[FN_REFLEN], index_name[FN_REFLEN], +@@ -95,6 +95,15 @@ + bzero((byte*) &info,sizeof(info)); + + my_realpath(name_buff, fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0)); ++ realpath_err= my_realpath(name_buff, ++ fn_format(org_name,name,"",MI_NAME_IEXT,4),MYF(0)); ++ if (my_is_symlink(org_name) && ++ (realpath_err || (*myisam_test_invalid_symlink)(name_buff))) ++ { ++ my_errno= HA_WRONG_CREATE_OPTION; ++ DBUG_RETURN (NULL); ++ } ++ + pthread_mutex_lock(&THR_LOCK_myisam); + if (!(old_info=test_if_reopen(name_buff))) + { +@@ -460,7 +469,7 @@ + lock_error=1; /* Database unlocked */ + } + +- if (mi_open_datafile(&info, share, -1)) ++ if (mi_open_datafile(&info, share, name, -1)) + goto err; + errpos=5; + +@@ -531,7 +540,7 @@ + my_errno=EACCES; /* Can't open in write mode */ + goto err; + } +- if (mi_open_datafile(&info, share, old_info->dfile)) ++ if (mi_open_datafile(&info, share, name, old_info->dfile)) + goto err; + errpos=5; + have_rtree= old_info->rtree_recursion_state != NULL; +@@ -1176,12 +1185,29 @@ + exist a dup()-like call that would give us two different file descriptors. + *************************************************************************/ + +-int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup __attribute__((unused))) ++int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, const char *org_name, File file_to_dup __attribute__((unused))) + { ++ char *data_name= share->data_file_name; ++ char real_data_name[FN_REFLEN]; ++ ++ if (org_name) ++ { ++ fn_format(real_data_name,org_name,"",MI_NAME_DEXT,4); ++ if (my_is_symlink(real_data_name)) ++ { ++ if (my_realpath(real_data_name, real_data_name, MYF(0)) || ++ (*myisam_test_invalid_symlink)(real_data_name)) ++ { ++ my_errno= HA_WRONG_CREATE_OPTION; ++ return 1; ++ } ++ data_name= real_data_name; ++ } ++ } + #ifdef USE_RAID + if (share->base.raid_type) + { +- info->dfile=my_raid_open(share->data_file_name, ++ info->dfile=my_raid_open(data_name, + share->mode | O_SHARE, + share->base.raid_type, + share->base.raid_chunks, +@@ -1190,7 +1216,7 @@ + } + else + #endif +- info->dfile=my_open(share->data_file_name, share->mode | O_SHARE, ++ info->dfile=my_open(data_name, share->mode | O_SHARE, + MYF(MY_WME)); + return info->dfile >= 0 ? 0 : 1; + } +diff -urNad mysql-dfsg-5.0-5.0.51a~/myisam/mi_static.c mysql-dfsg-5.0-5.0.51a/myisam/mi_static.c +--- mysql-dfsg-5.0-5.0.51a~/myisam/mi_static.c 2008-01-11 09:43:12.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/myisam/mi_static.c 2008-11-13 17:15:20.000000000 -0500 +@@ -41,6 +41,15 @@ + ulong myisam_bulk_insert_tree_size=8192*1024; + ulong myisam_data_pointer_size=4; + ++ ++static int always_valid(const char *filename) ++{ ++ return 0; ++} ++ ++int (*myisam_test_invalid_symlink)(const char *filename)= always_valid; ++ ++ + /* + read_vec[] is used for converting between P_READ_KEY.. and SEARCH_ + Position is , == , >= , <= , > , < +diff -urNad mysql-dfsg-5.0-5.0.51a~/myisam/myisamchk.c mysql-dfsg-5.0-5.0.51a/myisam/myisamchk.c +--- mysql-dfsg-5.0-5.0.51a~/myisam/myisamchk.c 2008-01-11 09:43:29.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/myisam/myisamchk.c 2008-11-13 17:15:20.000000000 -0500 +@@ -1039,7 +1039,7 @@ + error|=change_to_newfile(filename,MI_NAME_DEXT,DATA_TMP_EXT, + raid_chunks, + MYF(0)); +- if (mi_open_datafile(info,info->s, -1)) ++ if (mi_open_datafile(info,info->s, NULL, -1)) + error=1; + param->out_flag&= ~O_NEW_DATA; /* We are using new datafile */ + param->read_cache.file=info->dfile; +diff -urNad mysql-dfsg-5.0-5.0.51a~/myisam/myisamdef.h mysql-dfsg-5.0-5.0.51a/myisam/myisamdef.h +--- mysql-dfsg-5.0-5.0.51a~/myisam/myisamdef.h 2008-01-11 09:43:18.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/myisam/myisamdef.h 2008-11-13 17:15:20.000000000 -0500 +@@ -739,7 +739,8 @@ + + extern MI_INFO *test_if_reopen(char *filename); + my_bool check_table_is_closed(const char *name, const char *where); +-int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, File file_to_dup); ++int mi_open_datafile(MI_INFO *info, MYISAM_SHARE *share, const char *orn_name, ++ File file_to_dup); + int mi_open_keyfile(MYISAM_SHARE *share); + void mi_setup_functions(register MYISAM_SHARE *share); + +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/r/symlink.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/symlink.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/symlink.result 2008-01-11 10:23:41.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/symlink.result 2008-11-13 17:21:02.000000000 -0500 +@@ -100,23 +100,27 @@ + ) ENGINE=MyISAM DEFAULT CHARSET=latin1 + drop table t1; + CREATE TABLE t1(a INT) +-DATA DIRECTORY='TEST_DIR/master-data/mysql' +-INDEX DIRECTORY='TEST_DIR/master-data/mysql'; +-RENAME TABLE t1 TO user; +-ERROR HY000: Can't create/write to file 'TEST_DIR/master-data/mysql/user.MYI' (Errcode: 17) +-DROP TABLE t1; +-show create table t1; +-Table Create Table +-t1 CREATE TABLE `t1` ( +- `i` int(11) default NULL +-) ENGINE=MyISAM DEFAULT CHARSET=latin1 +-drop table t1; +-show create table t1; +-Table Create Table +-t1 CREATE TABLE `t1` ( +- `i` int(11) default NULL +-) ENGINE=MyISAM DEFAULT CHARSET=latin1 +-drop table t1; ++DATA DIRECTORY='TEST_DIR/tmp' ++INDEX DIRECTORY='TEST_DIR/tmp'; ++ERROR HY000: Can't create/write to file 'TEST_DIR/tmp/t1.MYI' (Errcode: 17) ++CREATE TABLE t2(a INT) ++DATA DIRECTORY='TEST_DIR/tmp' ++INDEX DIRECTORY='TEST_DIR/tmp'; ++RENAME TABLE t2 TO t1; ++ERROR HY000: Can't create/write to file 'TEST_DIR/tmp/t1.MYI' (Errcode: 17) ++DROP TABLE t2; ++CREATE TABLE t1(a INT) ++DATA DIRECTORY='TEST_DIR/var/master-data/test'; ++Got one of the listed errors ++CREATE TABLE t1(a INT) ++DATA DIRECTORY='TEST_DIR/var/master-data/'; ++Got one of the listed errors ++CREATE TABLE t1(a INT) ++INDEX DIRECTORY='TEST_DIR/var/master-data'; ++Got one of the listed errors ++CREATE TABLE t1(a INT) ++INDEX DIRECTORY='TEST_DIR/var/master-data_var'; ++Got one of the listed errors + show create table t1; + Table Create Table + t1 CREATE TEMPORARY TABLE `t1` ( +@@ -139,26 +143,10 @@ + 42 + drop table t1; + End of 4.1 tests +-CREATE DATABASE db1; +-CREATE DATABASE db2; +-USE db2; +-INSERT INTO db2.t1 VALUES (1); +-SELECT * FROM db2.t1; +-b +-1 +-RESET QUERY CACHE; +-USE db1; + SET SESSION keep_files_on_create = TRUE; + CREATE TABLE t1 (a INT) ENGINE MYISAM; +-ERROR HY000: Can't create/write to file './db1/t1.MYD' (Errcode: 17) +-CREATE TABLE t3 (a INT) Engine=MyISAM; +-INSERT INTO t3 VALUES (1),(2),(3); +-TRUNCATE TABLE t3; +-SELECT * from t3; +-a +-SET SESSION keep_files_on_create = DEFAULT; +-DROP TABLE db2.t1, db1.t3; +-DROP DATABASE db1; +-DROP DATABASE db2; +-USE test; ++ERROR HY000: Can't create/write to file './test/t1.MYD' (Errcode: 17) ++SET SESSION keep_files_on_create = FALSE; ++CREATE TABLE t1 (a INT) ENGINE MYISAM; ++DROP TABLE t1; + End of 5.0 tests +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysql-test/t/symlink.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/symlink.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/symlink.test 2008-01-11 10:23:24.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/symlink.test 2008-11-13 17:18:10.000000000 -0500 +@@ -71,7 +71,7 @@ + SHOW CREATE TABLE t9; + + disable_query_log; +---error 1103,1103 ++--error 1210,1210 + create table t1 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam data directory="tmp"; + + # Check that we cannot link over a table from another database. +@@ -81,7 +81,7 @@ + --error 1,1 + create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="/this-dir-does-not-exist"; + +---error 1103,1103 ++--error 1210,1210 + create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) engine=myisam index directory="not-hard-path"; + + # Should fail becasue the file t9.MYI already exist in 'run' +@@ -127,29 +127,42 @@ + # + # BUG#32111 - Security Breach via DATA/INDEX DIRECORY and RENAME TABLE + # ++--write_file $MYSQLTEST_VARDIR/tmp/t1.MYI ++EOF + --replace_result $MYSQLTEST_VARDIR TEST_DIR ++--error 1 + eval CREATE TABLE t1(a INT) +-DATA DIRECTORY='$MYSQLTEST_VARDIR/master-data/mysql' +-INDEX DIRECTORY='$MYSQLTEST_VARDIR/master-data/mysql'; ++DATA DIRECTORY='$MYSQLTEST_VARDIR/tmp' ++INDEX DIRECTORY='$MYSQLTEST_VARDIR/tmp'; ++--replace_result $MYSQLTEST_VARDIR TEST_DIR ++eval CREATE TABLE t2(a INT) ++DATA DIRECTORY='$MYSQLTEST_VARDIR/tmp' ++INDEX DIRECTORY='$MYSQLTEST_VARDIR/tmp'; + --replace_result $MYSQLTEST_VARDIR TEST_DIR + --error 1 +-RENAME TABLE t1 TO user; +-DROP TABLE t1; ++RENAME TABLE t2 TO t1; ++DROP TABLE t2; ++--remove_file $MYSQLTEST_VARDIR/tmp/t1.MYI + + # +-# Test specifying DATA DIRECTORY that is the same as what would normally +-# have been chosen. (Bug #8707) ++# Bug#32167 another privilege bypass with DATA/INDEX DIRECORY + # +-disable_query_log; +-eval create table t1 (i int) data directory = "$MYSQLTEST_VARDIR/master-data/test/"; +-enable_query_log; +-show create table t1; +-drop table t1; +-disable_query_log; +-eval create table t1 (i int) index directory = "$MYSQLTEST_VARDIR/master-data/test/"; +-enable_query_log; +-show create table t1; +-drop table t1; ++--replace_result $MYSQL_TEST_DIR TEST_DIR ++--error 1,1210 ++eval CREATE TABLE t1(a INT) ++DATA DIRECTORY='$MYSQL_TEST_DIR/var/master-data/test'; ++--replace_result $MYSQL_TEST_DIR TEST_DIR ++--error 1,1210 ++eval CREATE TABLE t1(a INT) ++DATA DIRECTORY='$MYSQL_TEST_DIR/var/master-data/'; ++--replace_result $MYSQL_TEST_DIR TEST_DIR ++--error 1,1210 ++eval CREATE TABLE t1(a INT) ++INDEX DIRECTORY='$MYSQL_TEST_DIR/var/master-data'; ++--replace_result $MYSQL_TEST_DIR TEST_DIR ++--error 1,1210 ++eval CREATE TABLE t1(a INT) ++INDEX DIRECTORY='$MYSQL_TEST_DIR/var/master-data_var'; + + # + # Bug#8706 - temporary table with data directory option fails +@@ -194,38 +207,17 @@ + # Bug #29325: create table overwrites .MYD file of other table (datadir) + # + +-CREATE DATABASE db1; +-CREATE DATABASE db2; +- +-USE db2; +---disable_query_log +-eval CREATE TABLE t1 (b INT) ENGINE MYISAM +-DATA DIRECTORY = '$MYSQLTEST_VARDIR/master-data/db1/'; +---enable_query_log +- +-INSERT INTO db2.t1 VALUES (1); +-SELECT * FROM db2.t1; +-RESET QUERY CACHE; +- +-USE db1; +- +-#no warning from create table + SET SESSION keep_files_on_create = TRUE; ++--write_file $MYSQLTEST_VARDIR/master-data/test/t1.MYD ++EOF + --disable_abort_on_error ++--error 1 + CREATE TABLE t1 (a INT) ENGINE MYISAM; ++--error 0,1 ++--remove_file $MYSQLTEST_VARDIR/master-data/test/t1.MYD; + --enable_abort_on_error +- +-CREATE TABLE t3 (a INT) Engine=MyISAM; +-INSERT INTO t3 VALUES (1),(2),(3); +-TRUNCATE TABLE t3; +-SELECT * from t3; +- +-SET SESSION keep_files_on_create = DEFAULT; +- +-DROP TABLE db2.t1, db1.t3; +-DROP DATABASE db1; +-DROP DATABASE db2; +-USE test; +- ++SET SESSION keep_files_on_create = FALSE; ++CREATE TABLE t1 (a INT) ENGINE MYISAM; ++DROP TABLE t1; + + --echo End of 5.0 tests +diff -urNad mysql-dfsg-5.0-5.0.51a~/mysys/my_symlink.c mysql-dfsg-5.0-5.0.51a/mysys/my_symlink.c +--- mysql-dfsg-5.0-5.0.51a~/mysys/my_symlink.c 2008-01-11 09:43:14.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysys/my_symlink.c 2008-11-13 17:15:20.000000000 -0500 +@@ -106,38 +106,38 @@ + #define BUFF_LEN FN_LEN + #endif + ++int my_is_symlink(const char *filename __attribute__((unused))) ++{ ++ struct stat stat_buff; ++ return !lstat(filename, &stat_buff) && S_ISLNK(stat_buff.st_mode); ++} ++ ++ + int my_realpath(char *to, const char *filename, + myf MyFlags __attribute__((unused))) + { + #if defined(HAVE_REALPATH) && !defined(HAVE_purify) && !defined(HAVE_BROKEN_REALPATH) + int result=0; + char buff[BUFF_LEN]; +- struct stat stat_buff; ++ char *ptr; + DBUG_ENTER("my_realpath"); + +- if (!(MyFlags & MY_RESOLVE_LINK) || +- (!lstat(filename,&stat_buff) && S_ISLNK(stat_buff.st_mode))) +- { +- char *ptr; +- DBUG_PRINT("info",("executing realpath")); +- if ((ptr=realpath(filename,buff))) +- { ++ DBUG_PRINT("info",("executing realpath")); ++ if ((ptr=realpath(filename,buff))) + strmake(to,ptr,FN_REFLEN-1); +- } +- else +- { +- /* +- Realpath didn't work; Use my_load_path() which is a poor substitute +- original name but will at least be able to resolve paths that starts +- with '.'. +- */ +- DBUG_PRINT("error",("realpath failed with errno: %d", errno)); +- my_errno=errno; +- if (MyFlags & MY_WME) +- my_error(EE_REALPATH, MYF(0), filename, my_errno); +- my_load_path(to, filename, NullS); +- result= -1; +- } ++ else ++ { ++ /* ++ Realpath didn't work; Use my_load_path() which is a poor substitute ++ original name but will at least be able to resolve paths that starts ++ with '.'. ++ */ ++ DBUG_PRINT("error",("realpath failed with errno: %d", errno)); ++ my_errno=errno; ++ if (MyFlags & MY_WME) ++ my_error(EE_REALPATH, MYF(0), filename, my_errno); ++ my_load_path(to, filename, NullS); ++ result= -1; + } + DBUG_RETURN(result); + #else +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/mysql_priv.h mysql-dfsg-5.0-5.0.51a/sql/mysql_priv.h +--- mysql-dfsg-5.0-5.0.51a~/sql/mysql_priv.h 2008-01-11 09:43:38.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/mysql_priv.h 2008-11-13 17:15:20.000000000 -0500 +@@ -1255,7 +1255,9 @@ + extern time_t server_start_time, flush_status_time; + extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], + mysql_real_data_home[], *opt_mysql_tmpdir, mysql_charsets_dir[], ++ mysql_unpacked_real_data_home[], + def_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; ++extern int mysql_unpacked_real_data_home_len; + #define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list)) + extern MY_TMPDIR mysql_tmpdir_list; + extern const char *command_name[]; +@@ -1756,6 +1758,8 @@ + #define check_stack_overrun(A, B, C) 0 + #endif + ++extern "C" int test_if_data_home_dir(const char *dir); ++ + #endif /* MYSQL_CLIENT */ + + #endif +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/mysqld.cc mysql-dfsg-5.0-5.0.51a/sql/mysqld.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/mysqld.cc 2008-01-11 09:43:18.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/mysqld.cc 2008-11-13 17:15:20.000000000 -0500 +@@ -453,8 +453,9 @@ + char mysql_real_data_home[FN_REFLEN], + language[FN_REFLEN], reg_ext[FN_EXTLEN], mysql_charsets_dir[FN_REFLEN], + *opt_init_file, *opt_tc_log_file, ++ mysql_unpacked_real_data_home[FN_REFLEN], + def_ft_boolean_syntax[sizeof(ft_boolean_syntax)]; +- ++int mysql_unpacked_real_data_home_len; + const key_map key_map_empty(0); + key_map key_map_full(0); // Will be initialized later + +@@ -6526,6 +6527,7 @@ + /* Things reset to zero */ + opt_skip_slave_start= opt_reckless_slave = 0; + mysql_home[0]= pidfile_name[0]= log_error_file[0]= 0; ++ myisam_test_invalid_symlink= test_if_data_home_dir; + opt_log= opt_update_log= opt_slow_log= 0; + opt_bin_log= 0; + opt_disable_networking= opt_skip_show_db=0; +@@ -7567,7 +7569,11 @@ + convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); + convert_dirname(language,language,NullS); + (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir +- (void) my_load_path(mysql_real_data_home,mysql_real_data_home,mysql_home); ++ my_realpath(mysql_unpacked_real_data_home, mysql_real_data_home, MYF(0)); ++ mysql_unpacked_real_data_home_len= strlen(mysql_unpacked_real_data_home); ++ if (mysql_unpacked_real_data_home[mysql_unpacked_real_data_home_len-1] == FN_LIBCHAR) ++ --mysql_unpacked_real_data_home_len; ++ + (void) my_load_path(pidfile_name,pidfile_name,mysql_real_data_home); + + char *sharedir=get_relative_path(SHAREDIR); +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/sql_parse.cc mysql-dfsg-5.0-5.0.51a/sql/sql_parse.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/sql_parse.cc 2008-01-11 09:43:38.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/sql_parse.cc 2008-11-13 17:15:20.000000000 -0500 +@@ -3001,6 +3001,19 @@ + "INDEX DIRECTORY option ignored"); + create_info.data_file_name= create_info.index_file_name= NULL; + #else ++ if (test_if_data_home_dir(lex->create_info.data_file_name)) ++ { ++ my_error(ER_WRONG_ARGUMENTS,MYF(0),"DATA DIRECTORY"); ++ res= -1; ++ break; ++ } ++ if (test_if_data_home_dir(lex->create_info.index_file_name)) ++ { ++ my_error(ER_WRONG_ARGUMENTS,MYF(0),"INDEX DIRECTORY"); ++ res= -1; ++ break; ++ } ++ + /* Fix names if symlinked tables */ + if (append_file_to_dir(thd, &create_info.data_file_name, + create_table->table_name) || +@@ -7843,3 +7856,55 @@ + + return TRUE; + } ++ ++ ++/* ++ Check if path does not contain mysql data home directory ++ ++ SYNOPSIS ++ test_if_data_home_dir() ++ dir directory ++ conv_home_dir converted data home directory ++ home_dir_len converted data home directory length ++ ++ RETURN VALUES ++ 0 ok ++ 1 error ++*/ ++ ++C_MODE_START ++ ++int test_if_data_home_dir(const char *dir) ++{ ++ char path[FN_REFLEN]; ++ int dir_len; ++ DBUG_ENTER("test_if_data_home_dir"); ++ ++ if (!dir) ++ DBUG_RETURN(0); ++ ++ (void) fn_format(path, dir, "", "", ++ (MY_RETURN_REAL_PATH|MY_RESOLVE_SYMLINKS)); ++ dir_len= strlen(path); ++ if (mysql_unpacked_real_data_home_len<= dir_len) ++ { ++ if (dir_len > mysql_unpacked_real_data_home_len && ++ path[mysql_unpacked_real_data_home_len] != FN_LIBCHAR) ++ DBUG_RETURN(0); ++ ++ if (lower_case_file_system) ++ { ++ if (!my_strnncoll(default_charset_info, (const uchar*) path, ++ mysql_unpacked_real_data_home_len, ++ (const uchar*) mysql_unpacked_real_data_home, ++ mysql_unpacked_real_data_home_len)) ++ DBUG_RETURN(1); ++ } ++ else if (!memcmp(path, mysql_unpacked_real_data_home, ++ mysql_unpacked_real_data_home_len)) ++ DBUG_RETURN(1); ++ } ++ DBUG_RETURN(0); ++} ++ ++C_MODE_END --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/98_CVE-2010-3840.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/98_CVE-2010-3840.dpatch @@ -0,0 +1,60 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix denial of service via PolyFromWKB() function and improper data. +# Origin: upstream, http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/3452.1.42 +# Bug: http://bugs.mysql.com/bug.php?id=51875 + +@DPATCH@ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/r/gis.result mysql-dfsg-5.0-5.0.51a/mysql-test/r/gis.result +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/r/gis.result 2010-11-09 11:47:25.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/r/gis.result 2010-11-09 11:48:07.000000000 -0500 +@@ -901,3 +901,10 @@ + 1 + DROP TABLE t1; + End of 5.0 tests ++# ++# BUG#51875: crash when loading data into geometry function polyfromwkb ++# ++SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; ++SET @a=POLYFROMWKB(@a); ++SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; ++SET @a=POLYFROMWKB(@a); +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/mysql-test/t/gis.test mysql-dfsg-5.0-5.0.51a/mysql-test/t/gis.test +--- mysql-dfsg-5.0-5.0.51a~/mysql-test/t/gis.test 2010-11-09 11:47:25.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/mysql-test/t/gis.test 2010-11-09 11:48:36.000000000 -0500 +@@ -607,3 +607,13 @@ + + + --echo End of 5.0 tests ++ ++--echo # ++--echo # BUG#51875: crash when loading data into geometry function polyfromwkb ++--echo # ++SET @a=0x00000000030000000100000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; ++SET @a=POLYFROMWKB(@a); ++SET @a=0x00000000030000000000000000000000000000000000144000000000000014400000000000001840000000000000184000000000000014400000000000001440; ++SET @a=POLYFROMWKB(@a); ++ ++ +diff -urNad '--exclude=CVS' '--exclude=.svn' '--exclude=.git' '--exclude=.arch' '--exclude=.hg' '--exclude=_darcs' '--exclude=.bzr' mysql-dfsg-5.0-5.0.51a~/sql/spatial.cc mysql-dfsg-5.0-5.0.51a/sql/spatial.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/spatial.cc 2008-01-11 09:43:39.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/spatial.cc 2010-11-09 11:47:32.000000000 -0500 +@@ -519,7 +519,7 @@ + n_points= wkb_get_uint(wkb, bo); + proper_length= 4 + n_points * POINT_DATA_SIZE; + +- if (len < proper_length || res->reserve(proper_length)) ++ if (!n_points || len < proper_length || res->reserve(proper_length)) + return 0; + + res->q_append(n_points); +@@ -737,7 +737,9 @@ + if (len < 4) + return 0; + +- n_linear_rings= wkb_get_uint(wkb, bo); ++ if (!(n_linear_rings= wkb_get_uint(wkb, bo))) ++ return 0; ++ + if (res->reserve(4, 512)) + return 0; + wkb+= 4; --- mysql-dfsg-5.0-5.0.51a.orig/debian/patches/97_CVE-2009-2446.dpatch +++ mysql-dfsg-5.0-5.0.51a/debian/patches/97_CVE-2009-2446.dpatch @@ -0,0 +1,67 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +# Description: fix format string vulnerabilities in the dispatch_command function +# Origin: upstream, http://lists.mysql.com/commits/77649 +# Bug: http://bugs.mysql.com/bug.php?id=45790 +# Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=536726 + +@DPATCH@ +diff -urNad mysql-dfsg-5.0-5.0.51a~/sql/sql_parse.cc mysql-dfsg-5.0-5.0.51a/sql/sql_parse.cc +--- mysql-dfsg-5.0-5.0.51a~/sql/sql_parse.cc 2010-01-21 16:59:48.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/sql/sql_parse.cc 2010-01-21 16:59:54.000000000 -0500 +@@ -1935,7 +1935,7 @@ + } + if (check_access(thd,CREATE_ACL,db,0,1,0,is_schema_db(db))) + break; +- mysql_log.write(thd,command,packet); ++ mysql_log.write(thd, command, "%s", db); + bzero(&create_info, sizeof(create_info)); + mysql_create_db(thd, (lower_case_table_names == 2 ? alias : db), + &create_info, 0); +@@ -1960,7 +1960,7 @@ + ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); + break; + } +- mysql_log.write(thd,command,db); ++ mysql_log.write(thd, command, "%s", db); + mysql_rm_db(thd, db, 0, 0); + break; + } +diff -urNad mysql-dfsg-5.0-5.0.51a~/tests/mysql_client_test.c mysql-dfsg-5.0-5.0.51a/tests/mysql_client_test.c +--- mysql-dfsg-5.0-5.0.51a~/tests/mysql_client_test.c 2008-01-11 09:43:14.000000000 -0500 ++++ mysql-dfsg-5.0-5.0.51a/tests/mysql_client_test.c 2010-01-21 16:59:54.000000000 -0500 +@@ -12035,6 +12035,27 @@ + } + + ++/* ++ Verify that bogus database names are handled properly with ++ COM_CREATE_DB and COM_DROP_DB, i.e., cannot cause SIGSEGV through ++ the use of printf specifiers in the database name. ++*/ ++static void test_bug45790() ++{ ++ const char* bogus_db = "%s%s%s%s%s%s%s"; ++ int rc; ++ ++ myheader("test_bug45790"); ++ rc= simple_command(mysql, COM_CREATE_DB, bogus_db, ++ (ulong)strlen(bogus_db), 0); ++ myquery(rc); ++ ++ rc= simple_command(mysql, COM_DROP_DB, bogus_db, ++ (ulong)strlen(bogus_db), 0); ++ myquery(rc); ++} ++ ++ + static void test_bug6096() + { + MYSQL_STMT *stmt; +@@ -16068,6 +16089,7 @@ + { "test_bug6059", test_bug6059 }, + { "test_bug6046", test_bug6046 }, + { "test_bug6081", test_bug6081 }, ++ { "test_bug45790",test_bug45790 }, + { "test_bug6096", test_bug6096 }, + { "test_datetime_ranges", test_datetime_ranges }, + { "test_bug4172", test_bug4172 }, --- mysql-dfsg-5.0-5.0.51a.orig/debian/libmysqlclient15off.docs +++ mysql-dfsg-5.0-5.0.51a/debian/libmysqlclient15off.docs @@ -0,0 +1 @@ +EXCEPTIONS-CLIENT --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.postinst +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.postinst @@ -0,0 +1,281 @@ +#!/bin/bash -e + +. /usr/share/debconf/confmodule + +if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi +${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 } + +export PATH=$PATH:/sbin:/usr/sbin:/bin:/usr/bin + +# This command can be used as pipe to syslog. With "-s" it also logs to stderr. +ERR_LOGGER="logger -p daemon.err -t mysqld_safe -i" + +invoke() { + if [ -x /usr/sbin/invoke-rc.d ]; then + invoke-rc.d mysql $1 + else + /etc/init.d/mysql $1 + fi +} + +MYSQL_BOOTSTRAP="/usr/sbin/mysqld --bootstrap --user=mysql --skip-grant-tables --skip-bdb --skip-innodb " + +test_mysql_access() { + mysql --no-defaults -u root -h localhost /dev/null 2>&1 +} + +# call with $1 = "online" to connect to the server, otherwise it bootstraps +set_mysql_rootpw() { + # forget we ever saw the password. don't use reset to keep the seen status + db_set mysql-server/root_password "" + + tfile=`mktemp` + if [ ! -f "$tfile" ]; then + return 1 + fi + + # this avoids us having to call "test" or "[" on $rootpw + cat << EOF > $tfile +USE mysql; +UPDATE user SET password=PASSWORD("$rootpw") WHERE user='root'; +FLUSH PRIVILEGES; +EOF + if grep -q 'PASSWORD("")' $tfile; then + retval=0 + elif [ "$1" = "online" ]; then + mysql --no-defaults -u root -h localhost <$tfile >/dev/null + retval=$? + else + $MYSQL_BOOTSTRAP <$tfile + retval=$? + fi + rm -f $tfile + return $retval +} + +# This is necessary because mysql_install_db removes the pid file in /var/run +# and because changed configuration options should take effect immediately. +# In case the server wasn't running at all it should be ok if the stop +# script fails. I can't tell at this point because of the cleaned /var/run. +set +e; invoke stop; set -e + +case "$1" in + configure) + mysql_cnf=/etc/mysql/my.cnf + mysql_datadir=/usr/share/mysql + mysql_statedir=/var/lib/mysql + mysql_rundir=/var/run/mysqld + mysql_logdir=/var/log + mysql_cfgdir=/etc/mysql + mysql_newlogdir=/var/log/mysql + mysql_upgradedir=/var/lib/mysql-upgrade + + # first things first, if the following symlink exists, it is a preserved + # copy the old data dir from a mysql 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_statedir; else targetdir=$mysql_newlogdir; 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're 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 + + # Ensure the existence and right permissions for the database and + # log files. + if [ ! -d "$mysql_statedir" -a ! -L "$mysql_statedir" ]; then mkdir "$mysql_statedir"; fi + if [ ! -d "$mysql_statedir/mysql" -a ! -L "$mysql_statedir/mysql" ]; then mkdir "$mysql_statedir/mysql"; fi + if [ ! -d "$mysql_newlogdir" -a ! -L "$mysql_newlogdir" ]; then mkdir "$mysql_newlogdir"; fi + # When creating an ext3 jounal on an already mounted filesystem like e.g. + # /var/lib/mysql, you get a .journal file that is not modifyable by chown. + # The mysql_datadir must not be writable by the mysql user under any + # circumstances as it contains scripts that are executed by root. + set +e + chown -R 0.0 $mysql_datadir + chown -R mysql $mysql_statedir + chown -R mysql $mysql_rundir + chown -R mysql:adm $mysql_newlogdir; chmod 2750 $mysql_newlogdir; + for i in log err; do + touch $mysql_logdir/mysql.$i + chown mysql:adm $mysql_logdir/mysql.$i + chmod 0640 $mysql_logdir/mysql.$i + done + set -e + + # This is important to avoid dataloss when there is a removed + # mysql-server version from Woody lying around which used the same + # data directory and then somewhen gets purged by the admin. + db_set mysql-server/postrm_remove_database false || true + + # So that mysql-server (4.0) can check if it's safe to install. + touch $mysql_statedir/debian-5.0.flag + + # On dist-upgrades, we ensure that the old_password setting is updated + # before passwords are changed. Except for that my.cnf is taboo! + db_get mysql-server-5.0/need_sarge_compat_done || true + if [ "$RET" = "false" ]; then + db_get mysql-server-5.0/need_sarge_compat + echo -e "# created by debconf\n[mysqld]\nold_passwords = $RET" > /etc/mysql/conf.d/old_passwords.cnf + fi + db_set mysql-server-5.0/need_sarge_compat_done true + + # initiate databases. Output is not allowed by debconf :-( + # Debian: beware of the bashisms... + # Debian: can safely run on upgrades with existing databases + set +e + /bin/bash /usr/bin/mysql_install_db --rpm 2>&1 | $ERR_LOGGER + if [ "$?" != "0" ]; then + echo "ATTENTION: An error has occured. More info is in the syslog!" + fi + set -e + + ## On every reconfiguration the maintenance user is recreated. + # + # - It is easier to regenerate the password every time but as people + # use fancy rsync scripts and file alteration monitors, the existing + # password is used and existing files not touched. + # - The mysqld statement is like that in mysql_install_db because the + # server is not already running. This has some implications: + # - The amount of newlines and semicolons in the query is important! + # - GRANT is not possible with --skipt-grant-tables and "INSERT + # (user,host..) VALUES" is not --ansi compliant + # - The echo is just for readability. ash's buildin has no "-e" so use /bin/echo. + # - The Super_priv, Show_db_priv, Create_tmp_table_priv and Lock_tables_priv + # may not be present as old Woody 3.23 databases did not have it and the + # admin might not already have run mysql_upgrade which adds them. + # As the binlog cron scripts to need at least the Super_priv, I do first + # the old query which always succeeds and then the new which may or may not. + + # recreate the credentials file if not present or without mysql_upgrade stanza + dc=$mysql_cfgdir/debian.cnf; + if [ -e "$dc" -a -n "`fgrep mysql_upgrade $dc 2>/dev/null`" ]; then + pass="`sed -n 's/password *= *// p' $dc | head -n 1`" + else + pass=`perl -e 'print map{("a".."z","A".."Z",0..9)[int(rand(62))]}(1..16)'`; + if [ ! -d "$mysql_cfgdir" ]; then install -o 0 -g 0 -m 0755 -d $mysql_cfgdir; fi + cat /dev/null > $dc + echo "# Automatically generated for Debian scripts. DO NOT TOUCH!" >>$dc + echo "[client]" >>$dc + echo "host = localhost" >>$dc + echo "user = debian-sys-maint" >>$dc + echo "password = $pass" >>$dc + echo "socket = $mysql_rundir/mysqld.sock" >>$dc + echo "[mysql_upgrade]" >>$dc + echo "user = debian-sys-maint" >>$dc + echo "password = $pass" >>$dc + echo "socket = $mysql_rundir/mysqld.sock" >>$dc + echo "basedir = /usr" >>$dc + fi + # If this dir chmod go+w then the admin did it. But this file should not. + chown 0:0 $dc + chmod 0600 $dc + + # update privilege and timezone tables + password_column_fix_query=`/bin/echo -e \ + "USE mysql\n" \ + "ALTER TABLE user CHANGE password Password varchar(41) collate utf8_bin NOT NULL default ''"`; + replace_query=`/bin/echo -e \ + "USE mysql\n" \ + "REPLACE INTO user SET " \ + " host='localhost', user='debian-sys-maint', password=password('$pass'), " \ + " Select_priv='Y', Insert_priv='Y', Update_priv='Y', Delete_priv='Y', " \ + " Create_priv='Y', Drop_priv='Y', Reload_priv='Y', Shutdown_priv='Y', " \ + " Process_priv='Y', File_priv='Y', Grant_priv='Y', References_priv='Y', " \ + " Index_priv='Y', Alter_priv='Y' __EXTRA_PRIVS__"`; + extra_privs=`/bin/echo -e \ + ", Show_db_priv='Y' " \ + ", Super_priv='Y' " \ + ", Create_tmp_table_priv='Y' " \ + ", Lock_tables_priv='Y' " \ + ", Execute_priv='Y' " \ + ", Repl_slave_priv='Y' " \ + ", Repl_client_priv='Y' "`; + + # Upgrade password column format before the root password gets set. + echo "$password_column_fix_query" | $MYSQL_BOOTSTRAP 2>&1 | $ERR_LOGGER + + db_get mysql-server/root_password && rootpw="$RET" + if ! set_mysql_rootpw; then + password_error="yes" + fi + + echo "$replace_query" | sed "s/__EXTRA_PRIVS__//" | $MYSQL_BOOTSTRAP 2>&1 | $ERR_LOGGER + set +e + echo "$replace_query" | sed "s/__EXTRA_PRIVS__/$extra_privs/" | $MYSQL_BOOTSTRAP 2>&1 | $ERR_LOGGER + set -e + mysql_tzinfo_to_sql /usr/share/zoneinfo/ 2>&1 | egrep -v 'Skipping it.$' | $MYSQL_BOOTSTRAP 2>&1 | $ERR_LOGGER + + # The Sarge package "mysql-server" which used to include the mysqld daemon + # may still be in unselected-configured state (i.e. after a remove but not + # purge) in which case its now obsolete cronscript has to be moved away. + for i in /etc/cron.daily/mysql-server /etc/cron.daily/mysql-server-41 /etc/mysql/debian-log-rotate.conf; do + if [ -f $i ]; then mv $i $i.dpkg-old; fi + done + + # Reload AppArmor profile + if [ -x /etc/init.d/apparmor ]; then + invoke-rc.d apparmor force-reload || true + fi + ;; + + abort-upgrade|abort-remove|abort-configure) + ;; + + *) + echo "postinst called with unknown argument '$1'" 1>&2 + exit 1 + ;; +esac + +#DEBHELPER# + +# here we check to see if we can connect as root without a password +# this should catch upgrades from previous verisons where the root +# password wasn't set. if there is a password, or if the connection +# fails for any other reason, nothing happens. +if [ "$1" = "configure" ]; then + if test_mysql_access; then + db_input medium mysql-server/root_password || true + db_go + db_get mysql-server/root_password && rootpw="$RET" + + if ! set_mysql_rootpw "online"; then + password_error="yes" + fi + fi + + if [ "$password_error" = "yes" ]; then + db_input high mysql-server/error_setting_password || true + db_go + fi + +fi + +db_stop # in case invoke failes + +exit 0 --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-common.README.Debian +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-common.README.Debian @@ -0,0 +1,20 @@ +[passwords] +If you change the password of the root user (which is strongly recommended) +you have to create a personal mysql config file in order to let cron run +the /etc/cron.daily script without asking you for the password. +The /root/.my.cnf file should be chmod 0600 (-rw------- root root .my.cnf) +and have the following content: +[mysqladmin] +user = root +password = + +[more than one process] +Note that the shutdown script cannot use the pid number stored in +/var/run, since it is for the first mysqld thread, but we need to kill +the most recent thread to shutdown the server. The upstream developers +are aware of this bug. When maintaining your database, you should use +mysqladmin with your password to shutdown and reload the server rather +than /etc/init.d/mysql. + +Scott Hanson and Christian Hammers + --- mysql-dfsg-5.0-5.0.51a.orig/debian/libmysqlclient15-dev.lintian-overrides +++ mysql-dfsg-5.0-5.0.51a/debian/libmysqlclient15-dev.lintian-overrides @@ -0,0 +1,2 @@ +libmysqlclient15-dev: dev-pkg-without-shlib-symlink usr/lib/libndbclient.so.0.0.0 usr/lib/libndbclient.so +libmysqlclient15-dev: package-name-doesnt-match-sonames libndbclient0 --- mysql-dfsg-5.0-5.0.51a.orig/debian/rules +++ mysql-dfsg-5.0-5.0.51a/debian/rules @@ -0,0 +1,346 @@ +#!/usr/bin/make -f + +export DH_VERBOSE=1 + +PACKAGE=mysql-dfsg-5.0 + +include /usr/share/dpatch/dpatch.make + +TMP=$(CURDIR)/debian/tmp/ + +ARCH = $(shell dpkg-architecture -qDEB_BUILD_ARCH) +ARCH_OS = $(shell dpkg-architecture -qDEB_BUILD_ARCH_OS) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEBVERSION = $(shell dpkg-parsechangelog | awk '/^Version: / { print $$2 }' | sed 's/^.*-//' ) + +DEB_SOURCE_PACKAGE ?= $(strip $(shell egrep '^Source: ' debian/control | cut -f 2 -d ':')) +DEB_VERSION ?= $(shell dpkg-parsechangelog | egrep '^Version:' | cut -f 2 -d ' ') +DEB_NOEPOCH_VERSION ?= $(shell echo $(DEB_VERSION) | cut -d: -f2-) +DEB_UPSTREAM_VERSION ?= $(shell echo $(DEB_NOEPOCH_VERSION) | sed 's/-[^-]*$$//') +DEB_UPSTREAM_VERSION_MAJOR_MINOR := $(shell echo $(DEB_UPSTREAM_VERSION) | sed -r -n 's/^([0-9]+\.[0-9]+).*/\1/p') + +MAKE_J = -j$(shell grep -c processor.* /proc/cpuinfo) +ifeq (${MAKE_J}, -j0) + MAKE_J = -j1 +endif + +ifeq ($(findstring $(ARCH),i386 sparc lpia),$(ARCH)) + USE_ASSEMBLER=--enable-assembler +endif + +ifneq ($(findstring $(ARCH), alpha arm armel hppa mipsel powerpc sparc),) + TESTSUITE_FAIL_CMD=true +else + TESTSUITE_FAIL_CMD=exit 1 +endif + +# This causes seg11 crashes if LDAP is used for groups in /etc/nsswitch.conf +# so it is disabled by default although, according to MySQL, it brings >10% +# performance gain if enabled. See #299382. +ifeq ($(STATIC_MYSQLD), 1) + USE_STATIC_MYSQLD=--with-mysqld-ldflags=-all-static +endif + +configure: patch configure-stamp +configure-stamp: + @echo "RULES.configure-stamp" + dh_testdir + +ifneq ($(ARCH_OS),hurd) + if [ ! -d /proc/self ]; then echo "/proc IS NEEDED" 1>&2; exit 1; fi +endif + + sh -c 'PATH=$${MYSQL_BUILD_PATH:-"/bin:/usr/bin"} \ + CC=$${MYSQL_BUILD_CC:-gcc} \ + CFLAGS=$${MYSQL_BUILD_CFLAGS:-"-DBIG_JOINS=1 -O2 -fPIC"} \ + CXX=$${MYSQL_BUILD_CXX:-g++} \ + CXXFLAGS=$${MYSQL_BUILD_CXXFLAGS:-"-DBIG_JOINS=1 -felide-constructors -fno-rtti -O2"} \ + ./configure \ + --build=${DEB_BUILD_GNU_TYPE} \ + --host=${DEB_HOST_GNU_TYPE} \ + \ + --prefix=/usr \ + --exec-prefix=/usr \ + --libexecdir=/usr/sbin \ + --datadir=/usr/share \ + --localstatedir=/var/lib/mysql \ + --includedir=/usr/include \ + --infodir=/usr/share/info \ + --mandir=/usr/share/man \ + \ + --with-server-suffix="-$(DEBVERSION)" \ + --with-comment="(Ubuntu)" \ + --with-system-type="debian-linux-gnu" \ + \ + --enable-shared \ + --enable-static \ + --enable-thread-safe-client \ + $(USE_ASSEMBLER) \ + --enable-local-infile \ + \ + --with-big-tables \ + --with-raid \ + --with-unix-socket-path=/var/run/mysqld/mysqld.sock \ + --with-mysqld-user=mysql \ + --with-libwrap \ + $(USE_STATIC_MYSQLD) \ + --with-vio \ + --without-openssl \ + --with-yassl \ + --without-docs \ + --with-bench \ + --without-readline \ + --with-extra-charsets=all \ + --with-innodb \ + \ + --with-isam \ + --with-archive-storage-engine \ + --with-csv-storage-engine \ + --with-federated-storage-engine \ + --with-blackhole-storage-engine \ + --without-embedded-server \ + --with-ndbcluster \ + --with-ndb-ccflags="-fPIC" \ + --with-ndb-shm \ + --without-ndb-sci \ + --without-ndb-test \ + --with-embedded-server \ + --with-embedded-privilege-control \ + --with-ndb-docs' + + # --sysconfdir=/etc/mysql -- Appends /etc/mysql after ~/ in the my.cnf search patch! + # --with-embedded-server \ + # --with-embedded-privilege-control \ + # --with-debug \ + # --with-mysqlfs # does not build, no toplevel fs/ directory! Needs CORBA. + + touch configure-stamp + + +build: build-stamp +build-stamp: configure + dh_testdir + + $(MAKE) $(MAKE_J) + +ifeq ($(findstring $(DEB_BUILD_OPTIONS),nocheck),) + if [ ! -f testsuite-stamp ] ; then \ + cd mysql-test ; \ + /usr/bin/perl ./mysql-test-run.pl --mysqld=--user=root --force || $(TESTSUITE_FAIL_CMD) ; \ + /usr/bin/perl ./mysql-test-run.pl --mysqld=--user=root --force --ps-protocol || $(TESTSUITE_FAIL_CMD) ; \ + fi +endif + + touch testsuite-stamp + + touch build-stamp + + +clean: clean-patched unpatch + rm -rf debian/patched +clean-patched: + @echo "RULES.clean-patched" + dh_testdir + dh_testroot + rm -f configure-stamp + rm -f build-stamp + rm -f testsuite-stamp + + [ ! -f Makefile ] || $(MAKE) clean + + # We like to see how long this is neccessary + @echo "CRUFT BEGIN" + @find -type l -print0 | xargs --no-run-if-empty -0 rm -v + @find -name .deps -type d -print0 | xargs --no-run-if-empty -0 rm -rfv + @rm -vrf ndb/docs/.doxy* ndb/docs/*html ndb/docs/*pdf innobase/autom4te.cache + @for i in \ + readline/Makefile \ + sql-bench/Makefile \ + scripts/make_win_binary_distribution \ + scripts/mysql_explain_log \ + scripts/mysql_tableinfo \ + scripts/mysqlbug \ + sql/gen_lex_hash \ + sql/lex_hash.h \ + strings/ctype_autoconf.c \ + config.log \ + config.cache \ + ; \ + do \ + rm -vf $$i; \ + done + @echo "CRUFT END" + + #debconf-updatepo + dh_clean -v + + +install: +install: build + @echo "RULES.install" + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + # this is stupid, if mysql-server symlinks point to something in the + # mysql-client package they get not compressed and end up stale + mkdir -p $(TMP)/usr/share/man/man1/ + mkdir -p $(TMP)/usr/share/man/man8/ + cp debian/additions/manpages/*.1 $(TMP)/usr/share/man/man1/ + + # make install (trailing slash needed for innobase) + $(MAKE) install DESTDIR=$(TMP)/ + + # After installing, remove rpath to make lintian happy. + set +e; \ + find ./debian/tmp/ -type f -print0 \ + | xargs -0 --no-run-if-empty chrpath -k 2>/dev/null \ + | fgrep RPATH= \ + | cut -d: -f 1 \ + | xargs --no-run-if-empty chrpath -d; \ + set -e + + # libmysqlclient: move shared libraries (but not the rest like libheap.a & co) + mv $(TMP)/usr/lib/mysql/libmysqlclient* $(TMP)/usr/lib + perl -pi -e 's#/usr/lib/mysql#/usr/lib#' $(TMP)/usr/lib/libmysqlclient.la + perl -pi -e 's#/usr/lib/mysql#/usr/lib#' $(TMP)/usr/lib/libmysqlclient_r.la + # Check if our beloved versioned symbols are really there + if [ "`objdump -T $(TMP)/usr/lib/libmysqlclient.so.15.0.0 | grep -c libmysqlclient_15`" -lt 500 ]; then \ + echo "ERROR: versioned symbols are absent"; \ + exit 1; \ + fi + + # libmysqlclient-dev: forgotten header file since 3.23.25? + cp include/my_config.h $(TMP)/usr/include/mysql/ + cp include/my_dir.h $(TMP)/usr/include/mysql/ + + # mysql-common: We now provide our own config file. + install -d $(TMP)/etc/mysql + install -m 0644 debian/additions/my.cnf $(TMP)/etc/mysql/my.cnf + + # mysql-client + install -m 0755 debian/additions/mysqlreport/mysqlreport $(TMP)/usr/bin/ + install -m 0644 debian/additions/mysqlreport/mysqlreport.1 $(TMP)/usr/share/man/man1/ + install -m 0755 debian/additions/innotop/innotop $(TMP)/usr/bin/ + install -m 0644 debian/additions/innotop/innotop.1 $(TMP)/usr/share/man/man1/ + install -m 0644 -D debian/additions/innotop/InnoDBParser.pm $(TMP)/usr/share/perl5/InnoDBParser.pm + + # mysql-server + install -m 0755 scripts/mysqld_safe $(TMP)/usr/bin/mysqld_safe + mkdir -p $(TMP)/usr/share/doc/mysql-server-5.0/examples + mv $(TMP)/usr/share/mysql/*cnf $(TMP)/usr/share/doc/mysql-server-5.0/examples/ + rm -vf $(TMP)/usr/share/mysql/mi_test_all* \ + $(TMP)/usr/share/mysql/mysql-log-rotate \ + $(TMP)/usr/share/mysql/mysql.server \ + $(TMP)/usr/share/mysql/binary-configure + nm -n sql/mysqld |gzip -9 > $(TMP)/usr/share/doc/mysql-server-5.0/mysqld.sym.gz + install -m 0644 debian/additions/ndb_mgmd.cnf $(TMP)/usr/share/doc/mysql-server-5.0/examples/ + install -m 0755 debian/additions/echo_stderr $(TMP)/usr/share/mysql/ + install -m 0755 debian/additions/debian-start $(TMP)/etc/mysql/ + install -m 0755 debian/additions/debian-start.inc.sh $(TMP)/usr/share/mysql/ + sed "s#filename => 'ndb_size.tmpl#filename => '/usr/share/mysql/ndb_size.tmpl#" < $(TMP)/usr/bin/ndb_size.pl > $(TMP)/usr/bin/ndb_size + mv $(TMP)/usr/mysql-test $(TMP)/usr/share/mysql/ + mv $(TMP)/usr/sql-bench $(TMP)/usr/share/mysql/ + # lintian overrides + mkdir -p $(TMP)/usr/share/lintian/overrides/ + cp debian/mysql-server-5.0.lintian-overrides $(TMP)/usr/share/lintian/overrides/mysql-server-5.0 + cp debian/mysql-client-5.0.lintian-overrides $(TMP)/usr/share/lintian/overrides/mysql-client-5.0 + cp debian/libmysqlclient15-dev.lintian-overrides $(TMP)/usr/share/lintian/overrides/libmysqlclient15-dev + + # For 4.1 -> 5.0 transition + d=$(TMP)/usr/share/mysql-common/internal-use-only/; \ + mkdir -p $$d; \ + cp debian/mysql-server-5.0.mysql.init $$d/_etc_init.d_mysql; \ + cp debian/mysql-server-5.0.mysql-server.logrotate $$d/_etc_logrotate.d_mysql-server; \ + cp debian/additions/debian-start $$d/_etc_mysql_debian-start + + # install AppArmor profile + install -D -m 644 debian/apparmor-profile $(TMP)/etc/apparmor.d/usr.sbin.mysqld + + dh_movefiles + +# Build architecture-independent files here. +binary-indep: build install + @echo "RULES.binary-indep" + dh_testdir -i + dh_testroot -i + dh_installdebconf -i + dh_installdocs -i + dh_installexamples -i + dh_installmenu -i + dh_installlogrotate -i + dh_installinit -i + dh_installcron -i + dh_installman -i + dh_installinfo -i + dh_installlogcheck -i + dh_installchangelogs -i + dh_link -i + dh_compress -i + dh_fixperms -i + dh_installdeb -i + dh_perl -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i + +# Build architecture-dependent files here. +binary-arch: build install + @echo "RULES.binary-arch" + dh_testdir + dh_testroot + + dh_installdebconf -a + dh_installdocs -a + dh_installexamples -a + dh_installmenu -a + dh_installlogrotate -a --name mysql-server + # NDB needs to start before MySQL if they share a machine + # Neither should automatically restart on package install. There + # is a rolling order in which nodes in a cluster should be + # restarted that is not possible to manage here. + dh_installinit -a -r --no-start --name=mysql-ndb-mgm -- defaults 17 23 + dh_installinit -a -r --no-start --name=mysql-ndb -- defaults 18 22 + # Start mysql in runlevel 19 before 20 where apache, proftpd etc gets + # started which might depend on a running database server. + dh_installinit -a --name=mysql -- defaults 19 21 + dh_installcron -a --name mysql-server + dh_installman -a + dh_installinfo -a + dh_installlogcheck -a + dh_installchangelogs -a + dh_strip -a + dh_link -a # .so muss nach .so.1.2.3 installier werden! + dh_compress -a + dh_fixperms -a + dh_makeshlibs -a + dh_makeshlibs -plibmysqlclient15off -V'libmysqlclient15off (>= 5.0.27-1)' + dh_installdeb -a + dh_perl -a + dh_shlibdeps -a -l debian/libmysqlclient15off/usr/lib -L libmysqlclient15off + dh_gencontrol -a + dh_md5sums -a + dh_builddeb -a + +source diff: + @echo >&2 'source and diff are obsolete - use dpkg-source -b'; false + +binary: binary-indep binary-arch + +get-orig-source: + @wget -nv -T10 -t3 \ + -O /tmp/mysql-$(DEB_UPSTREAM_VERSION).tar.gz \ + http://ftp.gwdg.de/pub/misc/mysql/Downloads/MySQL-$(DEB_UPSTREAM_VERSION_MAJOR_MINOR)/mysql-$(DEB_UPSTREAM_VERSION).tar.gz + @tar xfz /tmp/mysql-$(DEB_UPSTREAM_VERSION).tar.gz -C /tmp + @rm -rf /tmp/mysql-$(DEB_UPSTREAM_VERSION)/Docs + @rm -rf /tmp/mysql-$(DEB_UPSTREAM_VERSION)/debian + @mv /tmp/mysql-$(DEB_UPSTREAM_VERSION) /tmp/$(DEB_SOURCE_PACKAGE)-$(DEB_UPSTREAM_VERSION).orig + @cd /tmp ; tar czf $(DEB_SOURCE_PACKAGE)_$(DEB_UPSTREAM_VERSION).orig.tar.gz $(DEB_SOURCE_PACKAGE)-$(DEB_UPSTREAM_VERSION).orig + @rm -f /tmp/mysql-$(DEB_UPSTREAM_VERSION).tar.gz + @rm -rf /tmp/$(DEB_SOURCE_PACKAGE)-$(DEB_UPSTREAM_VERSION).orig + +.PHONY: clean clean-patched configure build binary binary-indep binary-arch install patch unpatch + +# vim: ts=8 --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-common.preinst +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-common.preinst @@ -0,0 +1,215 @@ +#!/bin/bash -e +# +# summary of how this script can be called: +# * install +# * install +# * upgrade +# * abort-upgrade +# + +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 + +# Try to stop the server in a sane way. If it does not success let the admin +# do it himself. No database directories should be removed while the server +# is running! Another mysqld in e.g. a different chroot is fine for us. +stop_server() { + if [ ! -x /etc/init.d/mysql ]; then return; fi + + set +e + if [ -x /usr/sbin/invoke-rc.d ]; then + cmd="invoke-rc.d mysql stop" + else + cmd="/etc/init.d/mysql stop" + fi + $cmd + errno=$? + set -e + + # 0=ok, 100=no init script (fresh install) + if [ "$errno" != 0 -a "$errno" != 100 ]; then + echo "${cmd/ */} returned $errno" 1>&2 + echo "There is a MySQL server running, but we failed in our attempts to stop it." 1>&2 + echo "Stop it yourself and try again!" 1>&2 + exit 1 + fi +} + +start_server() { + if [ ! -x /etc/init.d/mysql ]; then return; fi + + set +e + if [ -x /usr/sbin/invoke-rc.d ]; then + cmd="invoke-rc.d mysql start" + else + cmd="/etc/init.d/mysql start" + fi + $cmd + set -e +} + +##### here's a bunch of helper functions for converting database formats ###### + +cvt_get_param(){ + /usr/sbin/mysqld --print-defaults \ + | tr " " "\n" \ + | grep -- "--$1" \ + | tail -n 1 \ + | cut -d= -f2 +} + +cvt_setup_stuff(){ + mytmp=`mktemp -d -t mysql-ISAM-convert.XXXXXX` + cvt_log="$mytmp/conversion.log" + if [ ! -d "$mytmp" ]; then + echo "can't create temporary directory, oh well." >&2 + exit 1 + fi + + chgrp mysql $mytmp + chmod g+rwx $mytmp + cvt_socket=${mytmp}/mysql.sock + + cvt_mysqld="mysqld --skip-grant-tables --skip-networking --socket $cvt_socket" + cvt_mysql="mysql --socket $cvt_socket" + cvt_mysqladmin="mysqladmin --socket $cvt_socket" +} + +cvt_get_databases(){ + echo fetching database list ... >&2 + $cvt_mysql -e 'show databases' | sed -n -e '2,$p' +} + +cvt_get_tables(){ + echo querying tables in $1 ... >&2 + $cvt_mysql $1 -e 'show table status' | sed -n -e '2,$p' | \ + cut -f 1,2 | grep -w 'ISAM$' | cut -f 1 +} + +cvt_convert_table(){ + echo converting $1.$2 ... >&2 + $cvt_mysql $1 -e "alter table $2 type=MyISAM" +} + +cvt_wait_for_server(){ + local count + echo -n waiting for server startup.. >&2 + while ! $cvt_mysql /dev/null 2>&1; do + echo -n . >&2 + sleep 1 + count=".$count" + if [ -f $mytmp/mysql.done ]; then + echo "sorry... looks like the server crashed :(" >&2 + return 1 + elif [ "$count" = "...................." ]; then + echo "sorry... looks like the server didn't start :(" >&2 + return 1 + fi + done + echo ok. >&2 +} + +cvt_wait_for_exit(){ + local count + echo -n waiting for server shutdown.. >&2 + while [ ! -f $mytmp/mysql.done ]; do + echo -n . >&2 + sleep 1 + count=".$count" + if [ "$count" = "...................." ]; then + echo "hrm... guess it never started?" >&2 + return 0 + fi + done + echo ok. >&2 +} + +cvt_cleanup(){ + local mysql_kids + rm -rf $mytmp + # kill any mysqld child processes left over. there *shouldn't* be any, + # but let's not take chances with that + mysql_kids=`ps o 'pid command' --ppid $$ | grep -E '^[[:digit:]]+ mysqld ' | cut -d' ' -f1` + if [ "$mysql_kids" ]; then + echo "strange, some mysql processes left around. killing them now." >&2 + kill $mysql_kids + sleep 10 + mysql_kids=`ps o 'pid command' --ppid $$ | grep -E '^[[:digit:]]+ mysqld ' | cut -d' ' -f1` + if [ "$mysql_kids" ]; then + echo "okay, they're really not getting the hint..." >&2 + kill -9 $mysql_kids + fi + fi +} + +################################ main() ########################## + +# test if upgrading from non conffile state +if [ "$1" = "upgrade" ] && [ -x /usr/sbin/mysqld ]; then + cvt_datadir=`cvt_get_param datadir` + # test for ISAM tables, which we must convert NOW + if [ -n "$cvt_datadir" ] && [ -d "$cvt_datadir" ] && [ -n "`find $cvt_datadir -name '*.ISM' 2>/dev/null`" ]; then + pidfile=`cvt_get_param pid-file` + if [ "$pidfile" ] && [ -f "$pidfile" ]; then + server_pid=`cat $pidfile` + if [ "$server_pid" ] && ps $server_pid >/dev/null 2>&1; then + server_running="yes" + fi + fi + # to be sure + stop_server + + set +e + cat << EOF >&2 +---------------------------------------- +WARNING WARNING WARNING +---------------------------------------- + +It has been detected that are are using ISAM format on some of your +mysql database tables. This format has been deprecated and no longer +supported. to prevent these databases from essentially disappearing, +an attempt at format conversion will now be made. please check after +your upgrade that all tables are present and accounted for. + +apologies for the noise, but we thought you'd appreciate it :) + +---------------------------------------- +WARNING WARNING WARNING +---------------------------------------- +EOF + cvt_setup_stuff + ($cvt_mysqld >$cvt_log 2>&1; touch $mytmp/mysql.done ) & + + if cvt_wait_for_server; then + dbs=`cvt_get_databases` + for db in $dbs; do + tables=`cvt_get_tables $db` + for tbl in $tables; do + cvt_convert_table $db $tbl + done + done + else + cvt_error="yes" + fi + + echo shutting down server... >&2 + $cvt_mysqladmin shutdown + cvt_wait_for_exit + echo "all done!" >&2 + if [ ! "$cvt_error" = "yes" ]; then + cvt_cleanup + else + echo "you might want to look in $mytmp..." >&2 + fi + + if [ "$server_running" ]; then + start_server + fi + + set -e + fi +fi + +exit 0 --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-client-5.0.dirs +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-client-5.0.dirs @@ -0,0 +1,3 @@ +usr/bin/ +usr/share/man/man1/ +usr/share/perl5/ --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.mysql-ndb-mgm.init +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.mysql-ndb-mgm.init @@ -0,0 +1,86 @@ +#!/bin/bash +# +### BEGIN INIT INFO +# Provides: mysql-ndb-mgm +# 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 mysql database cluster management daemon +# Description: Controls the MySQL NDB Management Node daemon "ndb_mgmd". +### END INIT INFO +# +set -e +set -u +${DEBIAN_SCRIPT_DEBUG:+ set -v -x} + +# Variables +SELF=$(cd $(dirname $0); pwd -P)/$(basename $0) +DAEMON=/usr/sbin/ndb_mgmd +CONF=/etc/mysql/ndb_mgmd.cnf +export HOME=/etc/mysql/ + +# Safeguard (relative paths, core dumps..) +cd / +umask 077 + +# Exit *silently* if we're not supposed to be started. +# +# The Debian scripts should execute these scripts to stop and start +# the daemon when upgrading if it is started. On the other hand it should +# remain silently if the server has not even been configured. +# See /usr/share/doc/mysql-server-*/README.Debian for more information. +test -x $DAEMON || exit 0 +test -r $CONF || exit 0 +. /lib/lsb/init-functions + +# +# main() +# +case "${1:-''}" in + 'start') + # Start daemon + log_daemon_msg "Starting MySQL NDB Management Node" "ndb_mgmd" + # --pid-file does not work as the daemon forks itself with $PID=$PID+1 + if start-stop-daemon \ + --start \ + --exec $DAEMON \ + --user mysql \ + -- \ + -f $CONF + then + log_end_msg 0 + else + log_end_msg 1 + log_warning_msg "Please take a look at the syslog." + exit 1 + fi + ;; + + 'stop') + log_daemon_msg "Stopping MySQL NDB Management Node" "ndb_mgmd" + if start-stop-daemon \ + --stop \ + --oknodo \ + --exec $DAEMON + then + log_end_msg 0 + else + log_end_msg 1 + exit 1 + fi + ;; + + 'restart'|'force-reload') + set +e; $SELF stop; set -e + $SELF start + ;; + + *) + echo "Usage: $SELF start|stop|restart|force-reload" + exit 1 + ;; +esac + --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-client-5.0.docs +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-client-5.0.docs @@ -0,0 +1,3 @@ +README +EXCEPTIONS-CLIENT +debian/additions/innotop/changelog.innotop --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-client-5.0.NEWS +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-client-5.0.NEWS @@ -0,0 +1,6 @@ +mysql-dfsg-5.0 (5.0.24a-2) unstable; urgency=low + + * This package now includes "mysqlreport" from hackmysql.com which generates + a friendly report on the performance relevant variables from SHOW STATUS. + + -- Christian Hammers Sun, 3 Sep 2006 16:26:41 +0200 --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.dirs +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.dirs @@ -0,0 +1,10 @@ +etc/apparmor.d/force-complain +etc/init.d +etc/logrotate.d +usr/bin +usr/sbin +usr/share/man/man8 +usr/share/mysql +var/run/mysqld +var/lib/mysql-upgrade +var/lib/mysql-cluster --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.files +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.files @@ -0,0 +1,90 @@ +etc/apparmor.d/usr.sbin.mysqld +etc/mysql/debian-start +usr/bin/comp_err +usr/bin/innochecksum +usr/bin/msql2mysql +usr/bin/myisamchk +usr/bin/myisamlog +usr/bin/myisampack +usr/bin/my_print_defaults +usr/bin/mysqlbinlog +usr/bin/mysql_convert_table_format +usr/bin/mysqld_multi +usr/bin/mysqld_safe +usr/bin/mysql_fix_privilege_tables +usr/bin/mysqlhotcopy +usr/bin/mysql_install_db +usr/bin/mysql_secure_installation +usr/bin/mysql_setpermission +usr/bin/mysqltest +usr/bin/mysql_tzinfo_to_sql +usr/bin/mysql_upgrade +usr/bin/mysql_upgrade_shell +usr/bin/mysql_zap +usr/bin/ndb_config +usr/bin/ndb_delete_all +usr/bin/ndb_desc +usr/bin/ndb_drop_index +usr/bin/ndb_drop_table +usr/bin/ndb_error_reporter +usr/bin/ndb_mgm +usr/bin/ndb_restore +usr/bin/ndb_select_all +usr/bin/ndb_select_count +usr/bin/ndb_show_tables +usr/bin/ndb_size +usr/bin/ndb_test_platform +usr/bin/ndb_waiter +usr/bin/perror +usr/bin/replace +usr/bin/resolveip +usr/bin/resolve_stack_dump +usr/sbin/mysqld +usr/sbin/ndb_cpcd +usr/sbin/ndbd +usr/sbin/ndb_mgmd +usr/share/doc/mysql-server-5.0/ +usr/share/lintian/overrides/mysql-server-5.0 +usr/share/man/man1/comp_err.1 +usr/share/man/man1/msql2mysql.1 +usr/share/man/man1/myisamchk.1 +usr/share/man/man1/myisamlog.1 +usr/share/man/man1/myisampack.1 +usr/share/man/man1/my_print_defaults.1 +usr/share/man/man1/mysqlbinlog.1 +usr/share/man/man1/mysql_convert_table_format.1 +usr/share/man/man1/mysqld_multi.1 +usr/share/man/man1/mysqld_safe.1 +usr/share/man/man1/mysql_fix_privilege_tables.1 +usr/share/man/man1/mysqlhotcopy.1 +usr/share/man/man1/mysql_install_db.1 +usr/share/man/man1/mysql_secure_installation.1 +usr/share/man/man1/mysql_setpermission.1 +usr/share/man/man1/mysqltest.1 +usr/share/man/man1/mysql_upgrade.1 +usr/share/man/man1/mysql_zap.1 +usr/share/man/man1/perror.1 +usr/share/man/man1/replace.1 +usr/share/man/man1/resolveip.1 +usr/share/man/man1/resolve_stack_dump.1 +usr/share/man/man1/innochecksum.1 +usr/share/man/man1/mysqltest_embedded.1 +usr/share/man/man1/mysql_tzinfo_to_sql.1 +usr/share/man/man1/ndb_config.1 +usr/share/man/man1/ndb_cpcd.1 +usr/share/man/man1/ndb_delete_all.1 +usr/share/man/man1/ndb_desc.1 +usr/share/man/man1/ndb_drop_index.1 +usr/share/man/man1/ndb_drop_table.1 +usr/share/man/man1/ndb_error_reporter.1 +usr/share/man/man1/ndb_mgm.1 +usr/share/man/man1/ndb_mgmd.1 +usr/share/man/man1/ndb_restore.1 +usr/share/man/man1/ndb_select_all.1 +usr/share/man/man1/ndb_select_count.1 +usr/share/man/man1/ndb_show_tables.1 +usr/share/man/man1/ndb_size.pl.1 +usr/share/man/man1/ndb_waiter.1 +usr/share/man/man1/ndbd.1 +usr/share/man/man8/mysqld.8 +usr/share/mysql/ --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.logcheck.ignore.server +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.logcheck.ignore.server @@ -0,0 +1,32 @@ +/etc/init.d/mysql\[[0-9]+\]: [0-9]+ processes alive and '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ +/etc/init.d/mysql\[[0-9]+\]: Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists\!$ +/etc/init.d/mysql\[[0-9]+\]: '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ +/etc/mysql/debian-start\[[0-9]+\]: Checking for crashed MySQL tables\.$ +mysqld\[[0-9]+\]: ?$ +mysqld\[[0-9]+\]: .*InnoDB: Shutdown completed +mysqld\[[0-9]+\]: .*InnoDB: Started; +mysqld\[[0-9]+\]: .*InnoDB: Starting shutdown\.\.\.$ +mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Normal shutdown$ +mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: ready for connections\.$ +mysqld\[[0-9]+\]: .*\[Note\] /usr/sbin/mysqld: Shutdown complete$ +mysqld\[[0-9]+\]: Support MySQL by buying support/licenses at http://shop.mysql.com$ +mysqld\[[0-9]+\]: /usr/sbin/mysqld: ready for connections\.$ +mysqld\[[0-9]+\]: .*/usr/sbin/mysqld: Shutdown Complete$ +mysqld\[[0-9]+\]: Version: .* socket +mysqld\[[0-9]+\]: Warning: Ignoring user change to 'mysql' because the user was set to 'mysql' earlier on the command line$ +mysqld_safe\[[0-9]+\]: ?$ +mysqld_safe\[[0-9]+\]: able to use the new GRANT command!$ +mysqld_safe\[[0-9]+\]: ended$ +mysqld_safe\[[0-9]+\]: http://www.mysql.com$ +mysqld_safe\[[0-9]+\]: NOTE: If you are upgrading from a MySQL <= 3.22.10 you should run$ +mysqld_safe\[[0-9]+\]: PLEASE REMEMBER TO SET A PASSWORD FOR THE MySQL root USER !$ +mysqld_safe\[[0-9]+\]: Please report any problems with the /usr/bin/mysqlbug script!$ +mysqld_safe\[[0-9]+\]: See the manual for more instructions.$ +mysqld_safe\[[0-9]+\]: started$ +mysqld_safe\[[0-9]+\]: Support MySQL by buying support/licenses at +mysqld_safe\[[0-9]+\]: The latest information about MySQL is available on the web at$ +mysqld_safe\[[0-9]+\]: the /usr/bin/mysql_fix_privilege_tables. Otherwise you will not be$ +mysqld_safe\[[0-9]+\]: To do so, start the server, then issue the following commands:$ +mysqld_safe\[[0-9]+\]: /usr/bin/mysqladmin -u root 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'$ --- mysql-dfsg-5.0-5.0.51a.orig/debian/libmysqlclient15-dev.links +++ mysql-dfsg-5.0-5.0.51a/debian/libmysqlclient15-dev.links @@ -0,0 +1,2 @@ +usr/lib/libmysqlclient.so.15 usr/lib/libmysqlclient.so +usr/lib/libmysqlclient_r.so.15 usr/lib/libmysqlclient_r.so --- mysql-dfsg-5.0-5.0.51a.orig/debian/libmysqlclient15-dev.files +++ mysql-dfsg-5.0-5.0.51a/debian/libmysqlclient15-dev.files @@ -0,0 +1,7 @@ +usr/bin/mysql_config +usr/include/* +usr/lib/*.a +usr/lib/*.la +usr/lib/mysql +usr/share/man/man1/mysql_config.1 +usr/share/lintian/overrides/libmysqlclient15-dev --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-common.files +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-common.files @@ -0,0 +1,2 @@ +etc/mysql/my.cnf +usr/share/mysql-common/internal-use-only --- mysql-dfsg-5.0-5.0.51a.orig/debian/libmysqlclient15off.files +++ mysql-dfsg-5.0-5.0.51a/debian/libmysqlclient15off.files @@ -0,0 +1 @@ +usr/lib/libmysqlclient*.so.* --- mysql-dfsg-5.0-5.0.51a.orig/debian/libmysqlclient15-dev.docs +++ mysql-dfsg-5.0-5.0.51a/debian/libmysqlclient15-dev.docs @@ -0,0 +1 @@ +EXCEPTIONS-CLIENT --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.logcheck.ignore.paranoid +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.logcheck.ignore.paranoid @@ -0,0 +1,11 @@ +/etc/init.d/mysql\[[0-9]+\]: Check that mysqld is running and that the socket: '/var/run/mysqld/mysqld.sock' exists\!$ +/etc/init.d/mysql\[[0-9]+\]: '/usr/bin/mysqladmin --defaults-(extra-)?file=/etc/mysql/debian.cnf ping' resulted in$ +/etc/mysql/debian-start\[[0-9]+\]: Checking for crashed MySQL tables\.$ +mysqld\[[0-9]+\]: $ +mysqld\[[0-9]+\]: Support MySQL by buying support/licenses at http://shop.mysql.com$ +mysqld\[[0-9]+\]: Version: .* socket: '/var/run/mysqld/mysqld.sock' port: 3306$ +mysqld\[[0-9]+\]: Warning: Ignoring user change to 'mysql' because the user was set to 'mysql' earlier on the command line$ +mysqld_safe\[[0-9]+\]: started$ +mysqld_safe\[[0-9]+\]: Support MySQL by buying support/licenses at http://shop.mysql.com *$ +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'$ --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.docs +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.docs @@ -0,0 +1,2 @@ +EXCEPTIONS-CLIENT +debian/copyright.more --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.links +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.links @@ -0,0 +1,2 @@ +usr/share/mysql/mysql-test/mysql-test-run.pl usr/share/mysql/mysql-test/mysql-test-run +usr/share/mysql/mysql-test/mysql-test-run.pl usr/share/mysql/mysql-test/mtr --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.postrm +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.postrm @@ -0,0 +1,100 @@ +#!/bin/bash -e + +# It is possible that Debconf has already been removed, too. +if [ -f /usr/share/debconf/confmodule ]; then + . /usr/share/debconf/confmodule +fi + +if [ -n "$DEBIAN_SCRIPT_DEBUG" ]; then set -v -x; DEBIAN_SCRIPT_TRACE=1; fi +${DEBIAN_SCRIPT_TRACE:+ echo "#42#DEBUG# RUNNING $0 $*" 1>&2 } + +MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf" + +# Try to stop the server in a sane way. If it does not success let the admin +# do it himself. No database directories should be removed while the server +# is running! +stop_server() { + set +e + if [ -x /usr/sbin/invoke-rc.d ]; then + invoke-rc.d mysql stop + else + /etc/init.d/mysql stop + fi + errno=$? + set -e + + if [ "$?" != 0 ]; then + echo "Trying to stop the MySQL server resulted in exitcode $?." 1>&2 + echo "Stop it yourself and try again!" 1>&2 + exit 1 + fi +} + +case "$1" in + purge|remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + if [ -n "`$MYADMIN ping 2>/dev/null`" ]; then + stop_server + sleep 2 + fi + ;; + *) + echo "postrm called with unknown argument '$1'" 1>&2 + exit 1 + ;; +esac + +# Remove Debconf generated config files to allow clean upgrades to 5.1. +rm -f /etc/mysql/conf.d/old_passwords.cnf + +# +# - Do NOT purge logs or data if another mysql-sever* package is installed (#307473) +# - Remove the mysql user only after all his owned files are purged. +# +if [ "$1" = "purge" -a ! \( -x /usr/sbin/mysqld -o -L /usr/sbin/mysqld \) ]; then + # we remove the mysql user only after all his owned files are purged + rm -f /var/log/mysql.{log,err}{,.0,.[1234567].gz} + rm -rf /var/log/mysql + + db_input high mysql-server-5.0/postrm_remove_databases || true + db_go || true + db_get mysql-server-5.0/postrm_remove_databases || true + if [ "$RET" = "true" ]; then + # never remove the debian.cnf when the databases are still existing + # else we ran into big trouble on the next install! + rm -f /etc/mysql/debian.cnf + rm -rf /var/lib/mysql + rm -rf /var/run/mysqld + userdel mysql || true + fi + + # (normally) Automatically added by dh_installinit + if [ "$1" = "purge" ] ; then + update-rc.d mysql remove >/dev/null || exit 0 + fi + # (normally) End automatically added section +fi + +# (normally) Automatically added by dh_installdebconf +if [ "$1" = purge ] && [ -e /usr/share/debconf/confmodule ]; then + . /usr/share/debconf/confmodule + db_purge +fi +# (normally) End automatically added section + +# (normally) Automatically added by dh_installinit +if [ "$1" = "purge" ] ; then + update-rc.d mysql-ndb-mgm remove >/dev/null || exit 0 +fi +# (normally) End automatically added section +# (normally) Automatically added by dh_installinit +if [ "$1" = "purge" ] ; then + update-rc.d mysql-ndb remove >/dev/null || exit 0 +fi +# (normally) End automatically added section + +if [ "$1" = "purge" ] ; then + rm -f /etc/apparmor.d/force-complain/usr.sbin.mysqld >/dev/null 2>&1 || true +fi +# no DEBHELPER here, "update-rc.d remove" fails if mysql-server-5.0 is installed + +exit 0 --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-common.postrm +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-common.postrm @@ -0,0 +1,7 @@ +#!/bin/bash + +if [ "$1" = "purge" ]; then + rmdir /etc/mysql 2>/dev/null || true +fi + +#DEBHELPER# --- mysql-dfsg-5.0-5.0.51a.orig/debian/mysql-server-5.0.NEWS +++ mysql-dfsg-5.0-5.0.51a/debian/mysql-server-5.0.NEWS @@ -0,0 +1,17 @@ +mysql-dfsg-5.0 (5.0.45-2) unstable; urgency=low + + * Binary logging is now disabled by default. If you really need it (e.g. on + a replication master), remove the comment from the log_bin line in my.cnf. + + -- Norbert Tretkowski Sat, 10 Nov 2007 16:26:35 +0100 + +mysql-dfsg-5.0 (5.0.18-9) unstable; urgency=low + + * Rotation of the binary logs is now configured in /etc/mysql/my.cnf with + "expire-logs-days" which defaults to 20 days. The old file + /etc/mysql/debian-log-rotate.conf should be removed together with + /etc/cron.daily/mysql-server after this value has been adjusted. Note that + the old variable defined the number of files whereas the new one defines + a time span in days. + + -- Christian Hammers Tue, 24 Jan 2006 22:18:21 +0100 --- mysql-dfsg-5.0-5.0.51a.orig/debian/changelog +++ mysql-dfsg-5.0-5.0.51a/debian/changelog @@ -0,0 +1,4025 @@ +mysql-dfsg-5.0 (5.0.51a-3ubuntu5.8) hardy-security; urgency=low + + * SECURITY UPDATE: denial of service via joins involving a table with a + unique SET column + - debian/patches/98_CVE-2010-3677.dpatch: improve logic in + sql/item_cmpfunc.cc. Add tests to mysql-test/*. + - CVE-2010-3677 + * SECURITY UPDATE: denial of service via TEMPORARY InnoDB tables with + nullable columns + - debian/patches/98_CVE-2010-3680.dpatch: check for null datatype in + sql/ha_innodb.cc. Add tests to mysql-test/*. + - CVE-2010-3680 + * SECURITY UPDATE: denial of service via alternate reads from two indexes + on a table using the HANDLER interface + - debian/patches/98_CVE-2010-3681.dpatch: check for the same index in + sql/sql_handler.cc. Add tests to mysql-test/*. + - CVE-2010-3681 + * SECURITY UPDATE: denial of service via use of EXPLAIN with certain + queries + - debian/patches/98_CVE-2010-3682.dpatch: improve conditional in + sql/sql_select.cc. Add tests to mysql-test/*. + - CVE-2010-3682 + * SECURITY UPDATE: denial of service via incorrect propagation of type + errors. + - debian/patches/98_CVE-2010-3833.dpatch: properly check for execution + errors in sql/item_func.cc. Add tests to mysql-test/*. + - CVE-2010-3833 + * SECURITY UPDATE: denial of service via derived table materializing. + - debian/patches/98_CVE-2010-3834.dpatch: handle temporary tables in + sql/field.cc, sql/sql_select.*. Add tests to mysql-test/*. + - CVE-2010-3834 + * SECURITY UPDATE: denial of service via user-variable assignment + expression. + - debian/patches/98_CVE-2010-3835.dpatch: fix logic in sql/item_func.*, + Add tests to mysql-test/*. + - CVE-2010-3835 + * SECURITY UPDATE: denial of service via pre-evaluation of LIKE + predicates during view preparation. + - debian/patches/98_CVE-2010-3836.dpatch: make sure we're not in view + preparation mode in sql/item_cmpfunc.cc. Add tests to mysql-test/*. + - CVE-2010-3836 + * SECURITY UPDATE: denial of service via use of GROUP_CONCAT() and + WITH ROLLUP together. + - debian/patches/98_CVE-2010-3837.dpatch: create a copy of the order + structures in sql/item_sum.cc, sql/table.h. Add tests to + mysql-test/*. + - CVE-2010-3837 + * SECURITY UPDATE: denial of service via longblob and union or update + with subquery. + - debian/patches/98_CVE-2010-3838.dpatch: handle REAL_RESULT in + sql/item_func.cc. Add tests to mysql-test/*. + - CVE-2010-3838 + * SECURITY UPDATE: denial of service via PolyFromWKB() function and + improper data. + - debian/patches/98_CVE-2010-3840.dpatch: improve data handling in + sql/spatial.cc. Add tests to mysql-test/*. + - CVE-2010-3840 + + -- Marc Deslauriers Tue, 09 Nov 2010 11:49:24 -0500 + +mysql-dfsg-5.0 (5.0.51a-3ubuntu5.7) hardy-security; urgency=low + + * SECURITY UPDATE: privilege check bypass via crafted table name argument + to COM_FIELD_LIST + - debian/patches/102_CVE-2010-1848.dpatch: check table name in + sql/sql_parse.cc, Add tests to tests/mysql_client_test.c. + - CVE-2010-1848 + * SECURITY UPDATE: denial of service via large packets + - debian/patches/101_CVE-2010-1849.dpatch: handle big packets in + sql/sql_parse.cc, include/mysql_com.h, sql/net_serv.cc. + - CVE-2010-1849 + * SECURITY UPDATE: arbitrary code execution via crafted table name + argument to COM_FIELD_LIST + - debian/patches/100_CVE-2010-1850.dpatch: check table name length in + sql/sql_parse.cc. + - CVE-2010-1850 + * SECURITY UPDATE: DROP TABLE privilege bypass via symlink attack + - debian/patches/103_CVE-2010-1626.dpatch: check for symlinks in + myisam/mi_delete_table.c. + - CVE-2010-1626 + + -- Marc Deslauriers Mon, 07 Jun 2010 09:01:22 -0400 + +mysql-dfsg-5.0 (5.0.51a-3ubuntu5.5) hardy-security; urgency=low + + * SECURITY UPDATE: Cross-site scripting in the command-line client + - debian/patches/97_CVE-2008-4456.dpatch: use xmlencode_print in + client/mysql.cc, add test to mysql-test/*. + - CVE-2008-4456 + * SECURITY UPDATE: format string vulnerabilities in the dispatch_command + function + - debian/patches/97_CVE-2009-2446.dpatch: use correct format string in + sql/sql_parse.cc, add test to tests/mysql_client_test.c. + - CVE-2009-2446 + * SECURITY UPDATE: denial of service via certain SELECT statements with + subqueries and statements that use the GeomFromWKB function + - debian/patches/97_CVE-2009-4019.dpatch: return proper errors in + sql/sql_class.cc, handle errors in sql/sql_select.cc, set correct + null_value in sql/item_geofunc.cc, add tests to mysql-test/*. + - CVE-2009-4019 + * SECURITY UPDATE: privilege restriction bypass via incorrect calculation + of the mysql_unpacked_real_data_home value + - debian/patches/97_CVE-2009-4030.dpatch: fix initialization order in + sql/mysqld.cc. + - CVE-2009-4030 + * SECURITY UPDATE: arbitrary code execution via yassl stack overflow + - debian/patches/98_CVE-2009-4484.dpatch: validate lengths in + extra/yassl/taocrypt/src/asn.*. + - CVE-2009-4484 + * debian/patches/99_ssl_test_certs.dpatch: update certificates in the + test suite as they are expired. The new certs expire 2015-01-28. + (LP: #323755) + + -- Marc Deslauriers Mon, 08 Feb 2010 09:01:56 -0500 + +mysql-dfsg-5.0 (5.0.51a-3ubuntu5.4) hardy-security; urgency=low + + * SECURITY UPDATE: denial of service via an empty bit-string literal (b'') + - debian/patches/95_SECURITY_CVE-2008-3963.dpatch: fix Item_bin_string:: + Item_bin_string() in sql/item.cc to parse an empty bit-string literal + as an empty string. + - CVE-2008-3963 + * SECURITY UPDATE: privilege circumvention via the creation of MyISAM + tables using the DATA DIRECTORY and INDEX DIRECTORY options to overwrite + existing table files in the data directory. This update is a complete + fix for the three CVE numbers listed below. This fix alters table creation + behaviour by disallowing the use of the MySQL data directory in DATA + DIRECTORY and INDEX DIRECTORY options. (LP: #254129) + - debian/patches/96_SECURITY_CVE-2008-4098.dpatch: Disallow use of MySQL + data directory in DATA DIRECTORY and INDEX DIRECTORY options. + - CVE-2008-2079 + - CVE-2008-4097 + - CVE-2008-4098 + * debian/rules: do not update po tree for security updates. + + -- Marc Deslauriers Thu, 13 Nov 2008 14:56:05 -0500 + +mysql-dfsg-5.0 (5.0.51a-3ubuntu5.3) hardy-proposed; urgency=low + + * debian/patches/94_fix_mysqldump_with_old_versions.dpatch: Fixes mysqldump + when dumping a database from mysql 4.1. (LP: #267696) + + -- Chuck Short Wed, 10 Sep 2008 12:34:24 +0000 + +mysql-dfsg-5.0 (5.0.51a-3ubuntu5.2) hardy-proposed; urgency=low + + * Add a Conflicts/Replaces on mysql-client-4.1 and mysql-server-4.1, + to ensure smooth upgrades for users of Ubuntu 6.06 that may still + have these universe packages installed. LP: #208695. + + -- Steve Langasek Wed, 09 Jul 2008 23:53:26 +0000 + +mysql-dfsg-5.0 (5.0.51a-3ubuntu5.1) hardy-proposed; urgency=low + + * debian/patches/93_fix_user_setup_on_localhost.dpatch + - Fix setup of user table, if hostname is "localhost". Thanks + to Daniel Hahler (LP: #223836) + * debian/patches/56-mysqlhotcopy-invalid-dbtable.dpatch + - Update patch to address mysqlhotcopy issues. (LP: #197606) + + -- Chuck Short Tue, 29 Apr 2008 15:09:33 -0400 + +mysql-dfsg-5.0 (5.0.51a-3ubuntu5) hardy; urgency=low + + * debian/patches/59-fix-mysql-replication-logs.dpatch: + Fix mysql replication: relay-logs were stored in /var/run. (LP: #119271). + Patch taken from 5.0.54. + * debian/patches/58-disable-ndb-backup-print.dpatch: + update description of ndb_backup_print patch. + + -- Mathias Gug Thu, 27 Mar 2008 19:02:38 -0400 + +mysql-dfsg-5.0 (5.0.51a-3ubuntu4) hardy; urgency=low + + * Disable ndb_backup_print tests as it fails sometimes (LP: #194542). + Patch taken from 5.0.54. + + -- Mathias Gug Wed, 26 Mar 2008 19:08:32 -0400 + +mysql-dfsg-5.0 (5.0.51a-3ubuntu3) hardy; urgency=low + + [ Nicolas Valcárcel ] + * Confirming password on install if given (LP: #162167) + + [ Jamie Strandboge ] + * follow ApparmorProfileMigration and force apparmor complain mode on some + upgrades (LP: #203531) + - debian/control: Recommends apparmor >= 2.1+1075-0ubuntu6 + - debian/mysql-server-5.0.dirs: add etc/apparmor.d/force-complain + - debian/mysql-server-5.0.preinst: create symlink for force-complain/ + on pre-feisty upgrades, upgrades where apparmor-profiles profile is + unchanged (ie non-enforcing) and upgrades where the profile doesn't + exist + - debian/mysql-server-5.0.postrm: remove symlink in force-complain/ on + purge + * debian/additions/my.cnf: add warning about apparmor (LP: #201799) + + -- Mathias Gug Tue, 25 Mar 2008 17:05:22 -0400 + +mysql-dfsg-5.0 (5.0.51a-3ubuntu2) hardy; urgency=low + + * debian/patches/92_fix_order_by32202.dpatch: fix for ORDER BY not working + with GROUP BY (LP: #202706) + * References: + http://bugs.mysql.com/bug.php?id=32202 + + -- Jamie Strandboge Mon, 17 Mar 2008 07:35:15 -0400 + +mysql-dfsg-5.0 (5.0.51a-3ubuntu1) hardy; urgency=low + + * Merge from debian unstable, remaining changes: + - debian/control: + - Set Maintainer to Ubuntu Core dev. Move Debian maintainer + to XSBC-Original-Maintainer. + - Add mysql-doc-5.0 as a Suggests to mysql-client-5.0, mysql-server-5.0 + and libmysqlclient15-dev. + - Preprend XS-Original- to Vcs-{Browser,Svn}. + - Fix man page conflicts with mysql-doc-5.0 when upgrading from gutsy + for mysql-server-5.0, mysql-client-5.0 and libmysqlclient15-dev + packages. + - Replaces and Conflicts apparmor-profiles << 2.1+1075-0ubuntu4 to allow + proper upgrade from gutsy. + - debian/rules: + - Apply same configuration options on lpia as for i386. + - Replace --with-comment="Debian" with --with-comment="Ubuntu". + - debian/additions/my.cnf: + Add note about the "/etc/mysql/conf.d" directory in my.cnf. + - debian/patches/56-mysqlhotcopy-invalid-dbtable.dpatch: + Fixed mysqlhotcopy failure. + - debian/patches/57-fix-mysqlslowdump-config.dpatch: + Fixed mysqlslowdump usage. + - debian/apparmor-profile, debian/mysql-server-5.0.files: add AppArmor + profile. + - debian/mysql-server-5.0.postinst: Reload AA profile on configuration. + - debian/mysql-server-5.0.README.Debian: add a note on AppArmor. + + -- Mathias Gug Mon, 03 Mar 2008 19:43:09 -0500 + +mysql-dfsg-5.0 (5.0.51a-3) unstable; urgency=low + + * Disable patch 60_raise-max-keylength.dpatch in default build, but still + ship it in the source package. + + -- Norbert Tretkowski Sun, 17 Feb 2008 18:54:42 +0100 + +mysql-dfsg-5.0 (5.0.51a-2) unstable; urgency=low + + * Replace 54_ssl-client-support.dpatch added in 5.0.51-2 with patch from + upstream. + * Ignore errors in testsuite on powerpc. + + -- Norbert Tretkowski Sun, 17 Feb 2008 12:42:58 +0100 + +mysql-dfsg-5.0 (5.0.51a-1ubuntu1) hardy; urgency=low + + [ Mathias Gug ] + * Merge from debian unstable, remaining changes: + - debian/control: + - Set Maintainer to Ubuntu Core dev. Move Debian maintainer + to XSBC-Original-Maintainer. + - Add mysql-doc-5.0 as a Suggests to mysql-client-5.0, mysql-server-5.0 + and libmysqlclient15-dev. + - Preprend XS-Original- to Vcs-{Browser,Svn}. + - Fix man page conflicts with mysql-doc-5.0 when upgrading from gutsy + for mysql-server-5.0, mysql-client-5.0 and libmysqlclient15-dev + packages. + - debian/rules: + - Apply same configuration options on lpia as for i386. + - Replace --with-comment="Debian" with --with-comment="Ubuntu". + - debian/additions/my.cnf: + Add note about the "/etc/mysql/conf.d" directory in my.cnf. + - debian/patches/56-mysqlhotcopy-invalid-dbtable.dpatch: + Fixed mysqlhotcopy failure. + - debian/patches/57-fix-mysqlslowdump-config.dpatch: + Fixed mysqlslowdump usage. + + * Dropped: + - debian/rules: + - Support DEB_BUILD_OPTIONS option 'nocheck' to skip tests. + + * debian/control: + - Add build dependency on texlive-extra-utils. + + [ Jamie Strandboge ] + * add AppArmor profile + + debian/apparmor-profile + + debian/mysql-server-5.0.postinst: Reload AA profile on configuration + * updated debian//mysql-server-5.0.README.Debian for note on AppArmor + * debian/control: Replaces apparmor-profiles << 2.1+1075-0ubuntu4 as we + should now take control + * debian/control: Conflicts with apparmor-profiles << 2.1+1075-0ubuntu4 + to make sure that if earlier version of apparmor-profiles gets installed + it won't overwrite our profile + + -- Mathias Gug Thu, 14 Feb 2008 13:47:59 -0500 + +mysql-dfsg-5.0 (5.0.51a-1) unstable; urgency=low + + [ Norbert Tretkowski ] + * New upstream security hotfix release. Low priority upload anyway because + 5.0.51-3 already contained all security fixes. + * Remove patches: + + debian/patches/51_mysqlcheck-result.dpatch + + debian/patches/92_SECURITY_CVE-2007-6303.dpatch + + debian/patches/93_SECURITY_CVE-2007-6304.dpatch + + debian/patches/94_SECURITY_CVE-2008-0226+0227.dpatch + * Add recommendation on libhtml-template-perl to -server package, used by + ndb_size. (closes: #462265) + * New patch 60_raise-max-keylength.dpatch to raise the maximum key length to + 4005 bytes or 1335 UTF-8 characters. (closes: #463137) + * New patch 51_sort-order.dpatch from 5.0.52 to fix incorrect order when + using range conditions on 2 tables or more. + * Support DEB_BUILD_OPTIONS option 'nocheck' to skip tests. + * Update mysqlreport to 3.4a release. + + [ Luk Claes ] + * Updated Japanese debconf translation. (closes: #462158) + + -- Norbert Tretkowski Wed, 06 Feb 2008 11:57:45 +0100 + +mysql-dfsg-5.0 (5.0.51-3ubuntu2) hardy; urgency=low + + * Fix man page conflicts. (LP: #189187) + + -- Chuck Short Tue, 05 Feb 2008 11:45:06 -0500 + +mysql-dfsg-5.0 (5.0.51-3ubuntu1) hardy; urgency=low + + [Mathias Gug] + * Merge from debian unstable, remaining changes: + - debian/control: + - Set Maintainer to Ubuntu Core dev. Move Debian maintainer + to XSBC-Original-Maintainer. + - Add mysql-doc-5.0 as a Suggests to mysql-client-5.0, mysql-server-5.0 + and libmysqlclient15-dev. + - debian/rules: Apply same configuration options on lpia as for i386. + * debian/control: + - Preprend XS-Original- to Vcs-{Browser,Svn}. + * debian/rules: + - Support DEB_BUILD_OPTIONS option 'nocheck' to skip tests. + * Dropped patches: + - debian/patches/91_bug29389.dpatch: + fix for mysql bug 27383 which causes mysql-test 'mysql_client_test' + to fail due to gcc 4.x optimizations. + - debian/libmysqlclient15-dev.files, debian/mysql-client-5.0.files, + debian/mysql-server-5.0.files: man pages are GPLed now. + * Improved error message when unable to connect using debian-sys-maint. (LP: + #153868) + + [Chuck Short] + * Replcaed --with-comment="Debian" with --with-comment="Ubuntu" in debian/rules (LP: #134384) + * Added note about the "/etc/mysql/conf.d" directory in my.cnf (LP: #136225) + * Fixed mysqlhotcopy failure. (LP: #162393) + * Fixed mysqlslowdump usage. Added patch from Arnold Daniels . (LP: #183762) + + -- Mathias Gug Fri, 25 Jan 2008 04:10:49 -0500 + +mysql-dfsg-5.0 (5.0.51-3) unstable; urgency=high + + * SECURITY: + Fix for CVE-2008-0226 and CVE-2008-0227: Three vulnerabilities in yaSSL + versions 1.7.5 and earlier were discovered that could lead to a server + crash or execution of unauthorized code. The exploit requires a server + with yaSSL enabled and TCP/IP connections enabled, but does not require + valid MySQL account credentials. The exploit does not apply to OpenSSL. + (closes: #460873) + * Fix LSB header in init scripts (patch from Petter Reinholdtsen). + (closes: #458798) + * Run testsuite on all archs, but ignore errors on alpha, arm, armel, hppa, + mipsel and sparc. (closes: #460402) + + -- Norbert Tretkowski Wed, 23 Jan 2008 11:37:11 +0100 + +mysql-dfsg-5.0 (5.0.51-2) unstable; urgency=low + + [ Monty Taylor ] + * Added --with-system-type to set the version_compile_os field. + * Cleaned up some lintian warnings. + * Removed 43_scripts__mysql_update__password.dpatch since we don't use + mysql_upgrade_shell anymore and use mysql_upgrade instead. + * Removed 88_mctype_attrib.dpatch, http://bugs.mysql.com/bug.php?id=25118 is + closed with http://lists.mysql.com/commits/24337 + * Added mysql-community/mysql-enterprise virtual packages in provides and + conflicts to ease transitions between versions. + + [ Norbert Tretkowski ] + * Add -fPIC to CFLAGS to allow other packages to be built against + libmysqld.a on amd64. (closes: #457915) + * New patch 55_testsuite-2008.dpatch to fix FTBFS in testsuite. + (closes: #458695) + * New patch 54_ssl-client-support.dpatch to fix SSL client support. + * Don't run testsuite on alpha, arm, hppa, mipsel and sparc. + + -- Norbert Tretkowski Wed, 02 Jan 2008 18:40:04 +0100 + +mysql-dfsg-5.0 (5.0.51-1) unstable; urgency=low + + * New upstream release. + + Fix a crash in mysql_client_test due to gcc 4.x optimizations. + (closes: #452558) + * Update patches: + + debian/patches/41_scripts__mysql_install_db.sh__no_test.dpatch + + debian/patches/89_ndb__staticlib.dpatch + * Run testsuite after build. + * Re-add manpages, they are licensed under GPL now and redistribution is + permitted. + * Drop linux-libc-dev build-dependency, it's now being pulled by libc-dev + which is build-essential. (closes: #431018) + * Remove old optimizations for MySQL 3.23.x, they are no longer required. + (closes: #436552) + * Don't fail when upgrading mysql-common if $datadir is empty or not defined + (patch from Edward Allcutt). (closes: #453127) + * New patch from 5.0.52 to fix mysqldump because 'null' is shown as type of + fields for view with bad definer. (closes: #454227) + * New patch from 5.0.52 to fix mysqlcheck test result. + * New patch from 5.0.52 to fix wrong optimization in ndb code when building + with gcc 4.2.x. + * New patch from 5.0.54 to fix wrong number output due to integer overflow + when building with gcc 4.2.x. + * New Finnish debconf translation from Esko Arajärvi. (closes: #448776) + * Update Basque debconf translation from Aitor Ibañez. (closes: #456193) + * Add Vcs-* and Homepage fields to source stanza in control file. + * Update mysqlreport to 3.2 release. + * Let mysql-server-5.0 pre-depend on debconf, because it's preinst is using + it. + * Drop menu item for innotop. + + -- Norbert Tretkowski Fri, 14 Dec 2007 09:59:36 +0100 + +mysql-dfsg-5.0 (5.0.45-5) unstable; urgency=high + + * SECURITY: + Fix for CVE-2007-6303: ALTER VIEW retained the original DEFINER value, + even when altered by another user, which could allow that user to gain the + access rights of the view. Now ALTER VIEW is allowed only to the original + definer or users with the SUPER privilege. (closes: #455737) + * SECURITY: + Fix for CVE-2007-6304: When using a FEDERATED table, the local server can + be forced to crash if the remote server returns a result with fewer columns + than expected. + + -- Norbert Tretkowski Wed, 12 Dec 2007 20:23:43 +0100 + +mysql-dfsg-5.0 (5.0.45-4) unstable; urgency=high + + * SECURITY: + Fix for CVE-2007-5969: Using RENAME TABLE against a table with explicit + DATA DIRECTORY and INDEX DIRECTORY options can be used to overwrite system + table information by replacing the file to which the symlink points. + (closes: #455010) + + -- Norbert Tretkowski Sun, 09 Dec 2007 12:29:54 +0100 + +mysql-dfsg-5.0 (5.0.45-3ubuntu1) hardy; urgency=low + + * Merge from Debian unstable. Remaining Ubuntu changes: + - debian/control: + - Set Maintainer to Ubuntu Core dev. Move Debian maintainer + to XSBC-Original-Maintainer. + - Add mysql-doc-5.0 as a Suggests to mysql-client-5.0, mysql-server-5.0 + and libmysqlclient15-dev. + - debian/rules: Apply same configuration options on lpia as for i386. + - debian/patches/91_bug29389.dpatch: + fix for mysql bug 27383 which causes mysql-test 'mysql_client_test' + to fail due to gcc 4.x optimizations. + - debian/libmysqlclient15-dev.files, debian/mysql-client-5.0.files, + debian/mysql-server-5.0.files: remove dummy man pages, as they are + shipped in mysql-doc-5.0 package in the restricted repository. + + -- Mathias Gug Wed, 21 Nov 2007 13:20:05 -0500 + +mysql-dfsg-5.0 (5.0.45-3) unstable; urgency=high + + * SECURITY: + Fix for CVE-2007-5925: The convert_search_mode_to_innobase function in + ha_innodb.cc in the InnoDB engine in MySQL 5.1.23-BK and earlier allows + remote authenticated users to cause a denial of service (database crash) + via a certain CONTAINS operation on an indexed column, which triggers an + assertion error. (closes: #451235) + + -- Norbert Tretkowski Thu, 15 Nov 2007 18:40:11 +0100 + +mysql-dfsg-5.0 (5.0.45-2) unstable; urgency=low + + * Package is now team-maintained. (closes: #421026) + + [ Sean Finney ] + * New/updated debconf translations: + - Spanish, from Javier Fernández-Sanguino Peña (closes: #426442). + - German, from Alwin Meschede (closes: #426545). + - Danish, from Claus Hindsgaul (closes: #426783). + - French, from Christian Perrier (closes: #430944). + * Add Recommends on libterm-readkey-perl for mysql-client-5.0 package, used + by mysqlreport add-on to mask password entry (closes: #438375). + + [ Norbert Tretkowski ] + * Add myself to uploaders. + * Suggest usage of an update statement on the user table to change the mysql + root user password instead using mysqladmin, to catch all root users from + all hosts. (closes: #435744) + * Remove informations about a crash in the server during flush-logs when + having expire_logs_days enabled but log-bin not, this bug was fixed in + 5.0.32 already. (closes: #368547) + * Disable log_bin option in default config file and add a note to the NEWS + file. (closes: #349661) + * Fix FTBFS if build twice in a row. (closes: #442684) + * Remove check for buggy options from init script. + * Update innotop to 1.6.0 release. + * Add mysqlreport and innotop to mysql-client description. + * Use shorter server version string. + + -- Norbert Tretkowski Wed, 14 Nov 2007 20:00:06 +0100 + +mysql-dfsg-5.0 (5.0.45-1ubuntu3) gutsy; urgency=low + + * fix for mysql bug 27383 which causes mysql-test 'mysql_client_test' + to fail due to gcc 4.x optimizations + + -- Jamie Strandboge Tue, 02 Oct 2007 19:28:58 +0000 + +mysql-dfsg-5.0 (5.0.45-1ubuntu2) gutsy; urgency=low + + * Apply same configuration options on lpia as for i386. + + -- Matthias Klose Wed, 08 Aug 2007 08:13:31 +0000 + +mysql-dfsg-5.0 (5.0.45-1ubuntu1) gutsy; urgency=low + + * debian/libmysqlclient15-dev.files, debian/mysql-client-5.0.files, + debian/mysql-server-5.0.files: remove dummy man pages, as they are + shipped in mysql-doc-5.0 package in the restricted repository. + * debian/control: + - Set Maintainer to Ubuntu Core dev. Move Debian maintainer + to XSBC-Original-Maintainer. + - Add mysql-doc-5.0 as a Suggests to mysql-client-5.0, mysql-server-5.0 + and libmysqlclient15-dev. + + -- Mathias Gug Mon, 30 Jul 2007 12:17:35 -0400 + +mysql-dfsg-5.0 (5.0.45-1) unstable; urgency=low + + * New upstream release. + + [sean finney] + * removed patches that are incorporated into the latest release: + - 70_cpuid_on_i486.dpatch + - 91_SECURITY_CVE-2007-2691_alter-drop + * new patch 90_upstreamdebiandir.dpatch to keep a few lingering references + to the upstream ./debian dir out of the build, at least until we find + a nice way to collaborate on sharing the directory. + * updated CRUFT list to fix double-build breakage (closes: #424590). + * add conditional build-deps for linux-libc-dev to fix FTBFS for + non-linux arch's (closes: #431018). + * added notes to my.cnf and README.Debian about setting tmpdir when + configuring a replication slave. thanks to Rudy Gevaert for pointing + this out (closes: #431825). + + -- sean finney Tue, 17 Jul 2007 23:50:33 +0200 + +mysql-dfsg-5.0 (5.0.41a-1) unstable; urgency=high + + [sean finney] + * SECURITY: + Fix for CVE-2007-2691: DROP/RENAME TABLE statements (closes: #424778). + [Christian Hammers] + * Removed all manpages from the source (therefore the "41a") as they + are not licensed under the GPL and redistribution is not permitted + (thanks to Mathias Gug). Closes: #430018 + * Added linux-libc-dev to the build-depends as else an illegal dependency to + asm/atomic.h is generated in /usr/include/mysql/my_global.h. Closes: 424276 + [Christian Perrier] + * Debconf templates and debian/control reviewed by the debian-l10n- + english team as part of the Smith review project. Closes: #419974 + * Debconf translation updates: + - French. Closes: #422187 + - Galician. Closes: #420118 + - Italian. Closes: #421349 + - Brazilian Portuguese. Closes: #421516 + - Arabic. Closes: #421751 + - Czech. Closes: #421766 + - Portuguese. Closes: #422428 + + -- Christian Hammers Sun, 24 Jun 2007 21:12:42 +0200 + +mysql-dfsg-5.0 (5.0.41-2) unstable; urgency=low + + * the previous "translation changes" inadvertently introduced unrelated + changes in the package control file. + + -- sean finney Sun, 13 May 2007 12:32:45 +0200 + +mysql-dfsg-5.0 (5.0.41-1) unstable; urgency=low + + * New upstream release + [sean finney] + * Bump the priority of the debconf prompt for the root password to high, to + ensure the question shows up in a default installation (closes: #418672). + * Debconf templates and debian/control reviewed by the debian-l10n- + english team as part of the Smith review project. Closes: #419974 + * Debconf translation updates: + - French. Closes: #422187 + - Galician. Closes: #420118 + - Italian. Closes: #421349 + - Brazilian Portuguese. Closes: #421516 + - Arabic. Closes: #421751 + - Czech. Closes: #421766 + - Portuguese. Closes: #422428 + * massaged the local PATH_MAX patch. + * removed temp sql parsing patch which has been incorporated upstream + * upstream no longer includes the mysql_create_system_tables command, + so removed our local patches for it. + * the following issues may have been fixed in a previous version of + mysql-server-5.0, but the exact version is not clear so they will be + marked as fixed in this version. + * lots of NDB-related fixes, including those related to problems with + AUTO_INCREMENT (closes: #310878). + * fix for "connections remaining in sleep state" (closes: #318011). + * fix for "denies queries randomly" (closes: #399602). + * problems indexing on char() binary fields were ISAM specific, which is + no longer supported (closes: #326698). + * fix for problems with "complicated joins" (closes: 348682). + * fix for problems with "flushing logs, server crash" (closes: #348682). + * fix for AUTO_INCREMENT and duplicate keys (closes: #416145). + * fix for "DROP FUNCTIONS doesn't work" (closes: #290670). + + -- sean finney Sat, 12 May 2007 12:10:20 +0200 + +mysql-dfsg-5.0 (5.0.38-3) unstable; urgency=low + + * Added innotop. + * Changed maintainer email address to + pkg-mysql-commits@lists.alioth.debian.org + + -- Christian Hammers Thu, 19 Apr 2007 19:21:15 +0200 + +mysql-dfsg-5.0 (5.0.38-2) unstable; urgency=high + + * SECURITY: + In some previous versions mysql_install_db was not idempotent and did + always create passwordless root accounts although it should only on + initial installs (thanks to Olaf van der Spek). Closes: #418672 + * Added check for passwordless root accounts to debian-start. + * As MySQL-5.0 is, at least currently, incompatible with Kernel 2.4 the + installation is aborted for such old kernels. Debian Etch does not support + them anyway according to the release notes but this might be unexpected + and many production servers still have self build ones installed (thanks + to Marc-Christian Petersen). See: #416841 + * Adjusted TeX build-deps to texlive. + + -- Christian Hammers Tue, 17 Apr 2007 01:00:41 +0200 + +mysql-dfsg-5.0 (5.0.38-1) unstable; urgency=low + + * New upstream release. + * Activated the blackhole engine as it's needed for replicating partition + designs (thanks to Cyril SCETBON). + * Fixed segfault on i486 systems without cpuid instruction (thanks to + Lennart Sorensen). Closes: #410474 + * Only use of the non-essential debconf package in postrm if it is still + installed (thanks to Michael Ablassmeier). Closes: #416838 + + -- Christian Hammers Thu, 5 Apr 2007 22:43:41 +0200 + +mysql-dfsg-5.0 (5.0.36-1) unstable; urgency=low + + * New upstream release. + Closes: #400460, #408159, #408533 + + -- Christian Hammers Thu, 22 Mar 2007 22:16:31 +0100 + +mysql-dfsg-5.0 (5.0.32-10) unstable; urgency=high + + * Really fixed FTBFS on Sparc introduced with the "make -j" trick in + 5.0.32-8 (thanks to Frank Lichtenheld). Closes: #415026 + + -- Christian Hammers Sun, 18 Mar 2007 20:52:33 +0100 + +mysql-dfsg-5.0 (5.0.32-9) unstable; urgency=high + + * Fixed FTBFS on Sparc introduced with the "make -j" trick in 5.0.32-8 + (thanks to Frank Lichtenheld). Closes: #415026 + + -- Christian Hammers Tue, 15 Mar 2007 18:55:42 +0100 + +mysql-dfsg-5.0 (5.0.32-8) unstable; urgency=high + + [Sean Finney] + * SECURITY: + - CVE-2007-1420: Single Row Subselect DoS. Specially crafted subselect + queries could crash the mysql server. Patch backported from upstream + changeset 19685 (46_CVE-2007-1420_subselect_dos.dpatch) + closes: #414790. + [Christian Hammers] + * Adapt MAKE_J to use the -j option with the number of available processors. + (thanks to Raphael Pinson). + * Updated mysqlreport to latest upstream (and patched --help usage message + and "return if qcache_size==0"). + + -- sean finney Wed, 14 Mar 2007 20:19:08 +0100 + +mysql-dfsg-5.0 (5.0.32-7) unstable; urgency=low + + * Updated French Debconf translation (thanks to Christian Perrier). + Closes: #411330 + * Updated Danish Debconf translation (thanks to Claus Hindsgaul). + Closes: #411328 + * Updated Portuguese Debconf translation (thanks to "Traduz"). + Closes: #411339 + * Updated Czech Debconf translation (thanks to Miroslav Kure). + Closes: #411341 + * Added Norwegian Debconf translation (thanks to Bjorn Steensrud). + Closes: #411345 + * Updated Spanish Debconf translation (thanks to Javier Fernandez-Sanguino + Pena). Closes: #411347 + * Updated Japanese Debconf translation (thanks to Hideki Yamane). + Closes: #411368 + * Updated Swedish Debconf translation (thanks to Andreas Henriksson). + Closes: #411370 + * Updated Italian Debconf translation (thanks to Luca Monducci). + Closes: #411377 + * Updated Galician Debconf translation (thanks to Jacobo Tarrio). + Closes: #411379 + * Updated Russian Debconf translation (thanks to Yuriy Talakan). + Closes: #411442 + * Updated Basque Debconf translation (thanks to Piarres Beobide). + Closes: #411457 + * Updated German Debconf translation (thanks to Alwin Meschede). + Closes: #411480 + * Updated Dutch Debconf translation (thanks to Thijs Kinkhorst). + * Updated Brazilian Portuguese translation (thanks to Andre Luis Lopes). + Closes: #411536 + * Updated Romanian Debconf translation (thanks to Stan Ioan-Eugen). + Closes: #411764 + + -- Christian Hammers Fri, 16 Feb 2007 23:20:42 +0100 + +mysql-dfsg-5.0 (5.0.32-6) unstable; urgency=low + + * Changed wording in Debconf templates to better fit to the graphical + interface (thanks to Frank Kuester). Closes: #411165 + * Lintian suggested style changes to some other Debconf questions. + * Removed accidently stdout output from init script. + + -- Christian Hammers Fri, 16 Feb 2007 20:29:18 +0100 + +mysql-dfsg-5.0 (5.0.32-5) unstable; urgency=medium + + * Backported upstream patch for a bug that crashed the server when using + certain join/group/limit combinations. + Users of the Joomla CMS seemed to be affected by this. Closes: #403721 + * The debian-start script that runs on every server start now first upgrades + the system tables (if neccessary) and then check them as it sometimes did + not work the other way around (e.g. for MediaWiki). The script now uses + mysql_update instead of mysql_update_script as recommended. Closes: 409780 + * Remove the Debconf generated config file in postrm. + + -- Christian Hammers Thu, 15 Feb 2007 04:47:04 +0100 + +mysql-dfsg-5.0 (5.0.32-4) unstable; urgency=high + + [Christian Hammers] + * Changed minimum required version in dh_makeshlibs to 5.0.27-1 as + 5.0.26 had an ABI breakage in it! + This is the cause for Perl programs crashing with the following error: + "Transactions not supported by database at /usr/lib/perl5/DBI.pm line 672" + * The old_passwords setting that is set according to a Debconf question is + now written to /etc/mysql/conf.d/old_passwords.cnf instead directly to the + conffile /etc/mysql/my.cnf which would be fobidden by policy (thanks to + Robert Bihlmeyer). Closes: #409750 + * Added some more comments to the default my.cnf. + [Monty Taylor] + * Added bison to build dependencies. + * Added a "start-initial" option to the Data Node init script to support + initial node starts. + * Changed NDB Data and Management node startup seqence. Prevented both from + restarting on upgrade to address rolling upgrade issues. + * Updated build-depends to depend on automake1.9 instead of automake1.8 + to match what upstream uses. + + -- Christian Hammers Wed, 31 Jan 2007 01:14:09 +0100 + +mysql-dfsg-5.0 (5.0.32-3) unstable; urgency=high + + * mysql-server-5.0 pre-depends on adduser now and has --disabled-login + explicitly added to be on the safe side (thanks to the puiparts team). + Closes: #408362 + * Corrections the terminology regarding NDB in the comments of all config + files and init scripts (thanks to Geert Vanderkelen of MySQL). + * Updated Swedish Debconf translation (thanks to Andreas Henriksson). + Closes: #407859 + * Updated Czech Debconf translation (thanks to Miroslav Kure). + Closes: #407809 + + -- Christian Hammers Thu, 11 Jan 2007 11:18:47 +0100 + +mysql-dfsg-5.0 (5.0.32-2) unstable; urgency=high + + * The last upload suffered from a regression that made NDB totally + unusable and caused a dependency to libmysqlclient15-dev in the + mysql-server-5.0 package. The relevant 85_* patch was re-added again. + Closes: #406435 + * Added lintian-overrides for an error that does not affect our packages. + There are now only warnings and not errors left. + + -- Christian Hammers Tue, 9 Jan 2007 23:55:10 +0100 + +mysql-dfsg-5.0 (5.0.32-1) unstable; urgency=high + + * New upstream version. + * SECURITY: mysql_fix_privilege_tables.sql altered the + table_privs.table_priv column to contain too few privileges, causing + loss of the CREATE VIEW and SHOW VIEW privileges. (MySQL Bug#20589) + * SECURITY (DoS): ALTER TABLE statements that performed both RENAME TO + and {ENABLE|DISABLE} KEYS operations caused a server crash. (MySQL + Bug#24089) + * SECURITY (DoS): LAST_DAY('0000-00-00') could cause a server crash. + (MySQL Bug#23653) + * SECURITY (DoS): Using EXPLAIN caused a server crash for queries that + selected from INFORMATION_SCHEMA in a subquery in the FROM clause. + (MySQL Bug#22413) + * SECURITY (DoS): Invalidating the query cache (e.g. when using stored procedures) + caused a server crash for INSERT INTO ... SELECT statements that + selected from a view. (MySQL Bug#20045) + * Using mysql_upgrade with a password crashed the server. Closes: #406229 + * yaSSL crashed on pre-Pentium Intel and Cyrix CPUs. (MySQL Bug#21765) + Closes: #383759 + * Lots of small fixes to the NDB cluster storage engine. + * Updated Japanese Debconf template (thanks to Hideki Yamane). + Closes: #405793 + * Fixed comment regarding "mycheck" in debian-start (thanks to + Enrico Zini). Closes: #405787 + + -- Christian Hammers Sat, 6 Jan 2007 14:26:20 +0100 + +mysql-dfsg-5.0 (5.0.30-3) unstable; urgency=low + + * Updated Brazilian Debconf translation (thanks to Andre Luis Lopes). + Closes: #403821 + * Added Romanian Debconf translation (thanks to Stan Ioan-Eugen). + Closes: #403943 + * Updated Spanish Debconf translation (thanks to Javier Fernandez-Sanguino + Pena). Closes: #404084 + * Updated Galician Debconf translation (thanks to Jacobo Tarrio). + Closes: #404318 + * Updated Dutch Debconf translation (thanks to Vincent Zweije). + Closes: #404566 + * Updated Danish Debconf translation (thanks to Claus Hindsgaul). + Closes: #405018 + + -- Christian Hammers Thu, 21 Dec 2006 21:35:09 +0100 + +mysql-dfsg-5.0 (5.0.30-2) unstable; urgency=high + + * Fixed upstream regression in header files that lead to FTBFS for + mysql-admin, mysql-query-browser and probably other pacakges. + (thanks to Andreas Henriksson). Closes: #403081, #403082 + * Fixed some upstream scripts by replacing /etc by /etc/mysql (thanks to + Julien Antony). Closes: #401083 + * Updated French Debconf translation (thanks to Christian Perrier). + Closes: #401434 + * Added Spanish Debconf translation (thanks to Javier Fernandez-Sanguino + Pena). Closes: #401953 + * Marked a Debconf question that is just a dummy and only internally + used as not-needing-translation. Closes: #403163 + * Fixed mysqlslowdump patch to not remove the usage() function (thanks + to Monty Tailor). + + -- Christian Hammers Sun, 3 Dec 2006 19:20:10 +0100 + +mysql-dfsg-5.0 (5.0.30-1) unstable; urgency=low + + * New upstream version (switch to the MySQL Enterprise branch). + * Upstream bugfix for the Innodb performance bug: + "Very poor performance with multiple queries running + concurrently (Bug#15815)". + * Upstream bugfix for a possible server crash: + "Selecting from a MERGE table could result in a server crash if the + underlying tables had fewer indexes than the MERGE table itself + (Bug#22937)" + * Upstream bugfies for *lot* of NDB problems. + * Upstream bugfix for Innodb optimizer bug. Closes: #397597 + * Updated Italian Debconf translation (thanks to Luca Monducci). + Closes: #401305 + * Updated debian/watch file to MySQL Enterprise branch. + + -- Christian Hammers Sat, 2 Dec 2006 16:36:38 +0100 + +mysql-dfsg-5.0 (5.0.27-2) unstable; urgency=medium + + * Disabled YaSSL x86 assembler as it was reported to crash applications + like pam-mysql or proftpd-mysql which are linked against libmysqlclient + on i486 and Cyrix (i586) CPUs. Closes: #385147 + * Adjusted mysql-server-4.1 priority to extra and section to oldlibs + according to the ftp masters overrides. + * Updated German Debconf translation (thanks to Alwin Meschede). + Closes: #400809 + + -- Christian Hammers Wed, 22 Nov 2006 13:36:31 +0100 + +mysql-dfsg-5.0 (5.0.27-1) unstable; urgency=medium + + * New upstream version (but no codechange, the only difference to 5.0.26 + was a patch to the ABI change which Debian already included. + * When dist-upgrading from mysql-server-4.1/sarge dpkg does not longer + ask unnecessary "config file has changed" questions regarding + /etc/init.d/mysql, /etc/logrotate.d/mysql-server and + /etc/mysql/debian-start just because these files previously belonged + to mysql-server-4.1 and not to mysql-server-5.0. + To archive this mysql-server-5.0 now pre-depends on mysql-common which + provides current versions of those files. + * The automatic run mysql_upgrade now works with non-standard datadir + settings, too (thanks to Benjami Villoslada). Closes: #394607 + * Debconf now asks if the old_passwords option is really needed. + * Improved explanations of the old_passwords variable in my.cnf. + * Removed possibly leftover cron script from MySQL-4.1 (thanks to + Mario Oyorzabal Salgado). Closes: #390889 + * Postrm ignores failed "userdel mysql". + * Updated Danish Debconf translation (thanks to Claus Hindsgaul). + Closes: #398784 + * Added Euskarian Debconf translation (thanks to Piarres Beobide). + Closes: #399045 + * Updated Japanese Debconf translation (thanks to Hideki Yamane). + Closes: #399074 + * Updated German Debconf translation (thanks to Alwin Meschede). + Closes: #399087 + * New Portuguese debconf translations from Miguel Figueiredo. + Closes: #398186 + + -- Christian Hammers Tue, 7 Nov 2006 21:26:25 +0100 + +mysql-dfsg-5.0 (5.0.26-3) unstable; urgency=high + + [sean finney] + * Fix for the deadly ISAM trap. Now during upgrades we will do our + very best to convert pre-existing ISAM format tables using the + binaries from the previous package. Success is not guaranteed, but + this is probably as good as it gets. Note that this also necessitates + re-introducing an (empty transitional) mysql-server-4.1 package. + Closes: #354544, #354850 + * Remove a couple spurious and wrongly placed WARNING statements from + 45_warn-CLI-passwords.dpatch. thanks to Dan Jacobsen for pointing these + out. Closes: #394262 + + -- sean finney Fri, 03 Nov 2006 18:34:46 +0100 + +mysql-dfsg-5.0 (5.0.26-2) unstable; urgency=high + + * Fixed FTBFS for Alpha by applying an upstream patch (thanks to Falk + Hueffner). Closes: #395921 + + -- Christian Hammers Sat, 28 Oct 2006 20:13:46 +0200 + +mysql-dfsg-5.0 (5.0.26-1) unstable; urgency=high + + * SECURITY: + This combined release of 5.0.25 and 5.0.26 fixes lot of possible server + crashs so it should get into Etch. Quoting the changelog (bug numbers are + bugs.mysql.com ones): + - character_set_results can be NULL to signify no conversion, but some + code did not check for NULL, resulting in a server crash. (Bug#21913) + - Using cursors with READ COMMITTED isolation level could cause InnoDB to + crash. (Bug#19834) + - Some prepared statements caused a server crash when executed a second + time. (Bug#21166) + - When DROP DATABASE or SHOW OPEN TABLES was issued while concurrently + issuing DROP TABLE (or RENAME TABLE, CREATE TABLE LIKE or any other + statement that required a name lock) in another connection, the server + crashed. (Bug#21216) + - Use of zero-length variable names caused a server crash. (Bug#20908) + - For InnoDB tables, the server could crash when executing NOT IN () + subqueries. (Bug#21077) + - Repeated DROP TABLE statements in a stored procedure could sometimes + cause the server to crash. (Bug#19399) + - Performing an INSERT on a view that was defined using a SELECT that + specified a collation and a column alias caused the server to crash + (Bug#21086). + - A query of the form shown here caused the server to crash. (Bug#21007) + - NDB Cluster: Some queries involving joins on very large NDB tables could + crash the MySQL server. (Bug#21059) + - The character set was not being properly initialized for CAST() with a + type like CHAR(2) BINARY, which resulted in incorrect results or even a + server crash. (Bug#17903) + - For certain queries, the server incorrectly resolved a reference to an + aggregate function and crashed. (Bug#20868) + - The server crashed when using the range access method to execut a + subquery with a ORDER BY DESC clause. (Bug#20869) + - Triggers on tables in the mysql database caused a server crash. Triggers + for tables in this database now are disallowed. (Bug#18361) + - Using SELECT on a corrupt MyISAM table using the dynamic record format + could cause a server crash. (Bug#19835) + - Use of MIN() or MAX() with GROUP BY on a ucs2 column could cause a + server crash. (Bug#20076) + - Selecting from a MERGE table could result in a server crash if the + underlying tables had fewer indexes than the MERGE table itself. + (Bug#21617, Bug#22937) + + * New upstream release. + - This bug would cause trouble for Sarge->Etch upgrades, it was supposed to + have been fixed in 5.0.16 but that apparently did not fix the whole + problem: + Using tables from MySQL 4.x in MySQL 5.x, in particular those with VARCHAR + fields and using INSERT DELAYED to update data in the table would result in + either data corruption or a server crash. (Bug#16611, Bug#16218, Bug#17294) + Closes: #386337 + - Fixes data corruption as an automatic client reconnect used to set + the wrong character set. Closes: #365050 + - Fixes an undefined ulong type in an include file. Closes: #389102 + - Fixes wrong output format when using Unicode characters. Closes: #355302 + - Fixes mysql_upgrade when using a password. Closes: #371841 + + [Christian Hammers] + * Removed --sysconfdir from debian/rules as it puts /etc/mysql/ at the + end of the my.cnf search patch thus overriding $HOME/my.cnf + (thanks to Christoph Biedl). Closes: #394992 + * The provided patch from bug #385947 was wrong, the variable is called + BLOCKSIZE not BLOCK_SIZE according to "strings `which df`" (thanks to + Bruno Muller). Closes: #385947 + + [sean finney] + * new dutch debconf translations from Vincent Zweije (closes: #392809). + * new japanese debconf translations from Hideki Yamane (closes: #391625). + * new italian debconf translations from Luca Monducci (closes: #391741). + * new french debconf translations from Christian Perrier (closes: #393334). + * ran debconf-updatepo to merge the fuzzies into svn. + * massage the following patches so they continue to apply cleanly: + - 44_scripts__mysql_config__libs.dpatch to cleanly apply. + - 45_warn-CLI-passwords.dpatch + - 96_TEMP__libmysqlclient_ssl_symbols.dpatch (note, this patch might + no longer be needed, but is retained "just in case" after massaging it) + * the following patches have been incorporated upstream: + - 70_kfreebsd.dpatch + - 80_hurd_mach.dpatch + - 87_ps_Hurd.dpatch + - 90_TEMP__client__mysql_upgrade__O_EXEC.dpatch + - 91_TEMP__client__mysql_upgrade__password.dpatch + - 92_TEMP__client__mysql_upgrade__defaultgroups.dpatch + - 94_TEMP__CVE-2006-4227.dpatch + - 95_TEMP__CVE-2006-4226.dpatch + * the udf_example.cc has disappeared from the source code, but there's + a udf_example.c which seems to be a good example to use instead :) + * update documentation in the configuration to no longer reference + using my.cnf in the DATADIR, as it's never been the recommended + method for debian systems and hasn't worked since 5.0 was released + anyway (closes: #393868). + + -- Christian Hammers Wed, 25 Oct 2006 19:54:04 +0200 + +mysql-dfsg-5.0 (5.0.24a-9) unstable; urgency=medium + + * Having expire_logs_days enabled but log-bin not crashes the server. Using + both or none of those options is safe. To prevent this happening during the + nightly log rotation via /etc/logrotate.d/mysql the initscript checks for + malicious combination of options. See: #368547 + * The Sarge package "mysql-server" which used to include the mysqld daemon + may still be in unselected-configured state (i.e. after a remove but not + purge) in which case its now obsolete cronscript has to be moved away + (thanks to Charles Lepple). Closes: #385669 + * Updated Danish Debconf translation (thanks to Claus Hindsgaul). + Closes: #390315 + * Updated Frensh Debconf translation (thanks to Christian Perrier). + Closes: #390980 + + -- Christian Hammers Tue, 3 Oct 2006 14:55:31 +0200 + +mysql-dfsg-5.0 (5.0.24a-8) unstable; urgency=low + + * (broken upload) + + -- Christian Hammers Tue, 3 Oct 2006 14:55:31 +0200 + +mysql-dfsg-5.0 (5.0.24a-7) unstable; urgency=low + + * Stopped mysql_config from announcing unnecessary library dependencies + which until now cause "NEEDED" dependencies in the "readelf -d" output + of libraries who only depend on libmysqlclient.so (thanks to Michal + Cihar). Closes: #390692 + + -- Christian Hammers Sun, 1 Oct 2006 23:59:43 +0200 + +mysql-dfsg-5.0 (5.0.24a-6) unstable; urgency=low + + [sean finney] + * finally add support for setting a root password at install. + while this is not a random password as requested in one bug + report, we believe it is the best solution and provides a + means to set a random password via preseeding if it's really + desired (Closes: #316127, #298295). + + -- sean finney Sun, 01 Oct 2006 23:34:30 +0200 + +mysql-dfsg-5.0 (5.0.24a-5) unstable; urgency=low + + * Added ${shlibs:Depends} to debian/control section libmysqlclient-dev as it + contains the experimental /usr/lib/mysql/libndbclient.so.0.0.0. + * Bumped standards version to 3.7.2. + * Added LSB info section to init scripts. + * Rephrased Debconf templates as suggested by lintian. + * Added benchmark suite in /usr/share/mysql/sql-bench/. + * The mysql.timezone* tables are now filled by the postinst script (thanks + to Mark Sheppard). Closes: #388491 + * Moved Debconf install notes to README.Debian. Displaying them with + medium priority was a bug anyway. Closes: #388941 + * Replaced /usr/bin/mysql_upgrade by /usr/bin/mysql_upgrade_shell in + /etc/mysql/debian-start.sh as it works without errors (thanks to Javier + Kohen). Closes: #389443 + + -- Christian Hammers Wed, 20 Sep 2006 15:01:42 +0200 + +mysql-dfsg-5.0 (5.0.24a-4) unstable; urgency=high + + * libmysqlclient.so.15 from 5.0.24 accidentaly exports some symbols that are + historically exported by OpenSSL's libcrypto.so. This bug was supposed to + be fixed in 5.0.24a bug according to the mysql bug tracking system will + only be fixed in 5.0.25 so I backported the patch. People already reported + crashing apps due to this (thanks to Duncan Simpson). See also: #385348 + Closes: #388262 + * Fixed BLOCKSIZE to BLOCK_SIZE in initscript (thanks to Bruno Muller). + Closes: #385947 + * Added hint to "--extended-insert=0" to mysqldump manpage (thanks to Martin + Schulze). + * Documented the meaning of "NDB" in README.Debian (thanks to Dan Jacobson). + Closes: #386274 + * Added patch to build on hurd-i386 (thanks to Cyril Brulebois). Closes: #387369 + * Fixed debian-start script to work together with the recend LSB modifications in + the initscript (thanks to wens). Closes: #387481 + * Reverted tmpdir change in my.cnf back to /tmp to comply with FHS (thanks + to Alessandro Valente). Closes: #382778 + * Added logcheck filter rule (thanks to Paul Wise). Closes: #381043 + * I will definetly not disable InnoDB but added a note to the default my.cnf + that disabling it saves about 100MB virtual memory (thanks to Olivier + Berger). Closes: #384399 + * Added thread_cache_size=8 to default my.cnf as this variable seems to have + a negligible memory footprint but can improve performance when lots of + threads connect simultaneously as often seen on web servers. + + -- Christian Hammers Mon, 4 Sep 2006 00:21:50 +0200 + +mysql-dfsg-5.0 (5.0.24a-3) unstable; urgency=low + + * Fixed potential tempfile problem in the newly added mysqlreport script. + + -- Christian Hammers Sun, 3 Sep 2006 23:17:24 +0200 + +mysql-dfsg-5.0 (5.0.24a-2) unstable; urgency=low + + * Added "mysqlreport" (GPL'ed) from hackmysql.com. + * Temporarily disabled expire_days option as it causes the server + to crash. See #368547 + * Made output of init scripts LSB compliant (thanks to David Haerdeman). + Closes: #385874 + + -- Christian Hammers Sun, 3 Sep 2006 19:06:53 +0200 + +mysql-dfsg-5.0 (5.0.24a-1) unstable; urgency=high + + * New upstream version. + * The shared library in the 5.0.24 upstream release accidently exported + some symbols that are also exported by the OpenSSL libraries (notably + BN_bin2bn) causing unexpected behaviour in applications using these + functions (thanks to Peter Cernak). Closes: #385348 + * Added note about possible crash on certain i486 clone CPUs. + * Made recipient address of startup mysqlcheck output configurable + (thanks to Mattias Guns). Closes: #385119 + + -- Christian Hammers Mon, 28 Aug 2006 01:22:12 +0200 + +mysql-dfsg-5.0 (5.0.24-3) unstable; urgency=high + + * SECURITY: + CVE-2006-4226: + When run on case-sensitive filesystems, MySQL allows remote + authenticated users to create or access a database when the database + name differs only in case from a database for which they have + permissions. + CVE-2006-4227: + MySQL evaluates arguments of suid routines in the security context of + the routine's definer instead of the routine's caller, which allows + remote authenticated users to gain privileges through a routine that + has been made available using GRANT EXECUTE. + Thanks to Stefan Fritsch for reporting. Closes: #384798 + + -- Christian Hammers Sat, 26 Aug 2006 04:55:17 +0200 + +mysql-dfsg-5.0 (5.0.24-2) unstable; urgency=high + + * 5.0.24-1 introduced an ABI incompatibility, which this patch reverts. + Programs compiled against 5.0.24-1 are not compatible with any other + version and needs a rebuild. + This bug already caused a lot of segfaults and crashes in various + programs. Thanks to Chad MILLER from MySQL for quickly providing a patch. + The shlibdeps version has been increased to 5.0.24-2. + Closes: #384047, #384221, #383700 + + -- Christian Hammers Fri, 25 Aug 2006 21:47:35 +0200 + +mysql-dfsg-5.0 (5.0.24-1) unstable; urgency=high + + * SECURITY: Upstream fixes a security bug which allows a user to continue + accessing a table using a MERGE TABLE after the right to direct access to + the database has been revoked (CVE-2006-4031, MySQL bug #15195). + (Well they did not exactly fixed it, they documented the behaviour and + allow the admin to disable merge table alltogether...). Closes: #380271 + * SECURITY: Applied patch that fixes a possibly insecure filehandling + in the recently added mysql_upgrade binary file (MySQL bug #10320). + * New upstream version. + - Fixes nasty MySQL bug #19618 that leads to crashes when using + "SELECT ... WHERE ... not in (1, -1)" (e.g. vbulletin was affected). + - Fixes upstream bug #16803 so that linking ~/.mysql_history to /dev/null + now has the desired effect of having no history. + * Really fixed the runlevels. Closes: #377651 + * Added patch for broken upstream handling of "host=" to mysql_upgrade.c. + * Adjusted /etc/mysql/debian-start to new mysql_upgrade.c + + -- Christian Hammers Tue, 8 Aug 2006 00:44:13 +0200 + +mysql-dfsg-5.0 (5.0.22-5) unstable; urgency=low + + * Added further line to the logcheck ignore files (thanks to Paul Wise). + Closes: #381038 + + -- Christian Hammers Wed, 2 Aug 2006 00:28:50 +0200 + +mysql-dfsg-5.0 (5.0.22-4) unstable; urgency=low + + * Upstream fixes a bug in the (never released) version 5.0.23 which could + maybe used to crash the server if the mysqlmanager daemon is in use + which is not yet the default in Debian. (CVE-2006-3486 *DISPUTED*) + * Changed runlevel priority of mysqld from 20 to 19 so that it gets started + before apache and proftpd etc. which might depend on an already running + database server (thanks to Martin Gruner). Closes: #377651 + * Added patch which sets PATH_MAX in ndb (thanks to Cyril Brulebois). + Closes: #378949 + * Activated YaSSL as licence issues are settled according to: + http://bugs.mysql.com/?id=16755. This also closes the FTBFS bug + regarding OpenSSL as it is discouraged to use now. Closes: #368639 + * Removed SSL-MINI-HOWTO as the official documentation is good enough now. + * mysql_upgrade no longer gives --password on the commandline which would + be insecure (thanks to Dean Gaudet). Closes: #379199 + * Adjusted debian/patches/45* to make consecutive builds in the same source + tree possible (thanks to Bob Tanner). Closes: #368661 + * mysql-server-5.0 is now suggesting tinyca as yaSSL is enabled and tinyca + was found to be really cool :) + * Moved tempdir from /tmp to /var/tmp as it will more likely have enough + free space as /tmp is often on the root partition and /var or at least + /var/tmp is on a bigger one. + + -- Christian Hammers Mon, 10 Jul 2006 23:30:26 +0200 + +mysql-dfsg-5.0 (5.0.22-3) unstable; urgency=low + + * Added patch for MySQL bug #19618: "select x from x + where x not in(1,-1)" may crash the server" (thanks to + Ruben Puettmann). + + -- Christian Hammers Fri, 9 Jun 2006 01:41:44 +0200 + +mysql-dfsg-5.0 (5.0.22-2) unstable; urgency=high + + * Fixed debian-sys-maint related bug in postinst (thanks to + Jean-Christophe Dubacq). Closes: #369970 + * The last upload was a security patch (which I did not know as I + uploaded before the announcement came). I now added the CVE id for + reference and set urgency to high as the last entry did not. + + -- Christian Hammers Wed, 31 May 2006 01:04:11 +0200 + +mysql-dfsg-5.0 (5.0.22-1) unstable; urgency=low + + * SECURITY: This upstream release fixes an SQL-injection with multibyte + encoding problem. (CVE-2006-2753) + * New upstream release. + * Upstream fixes REPAIR TABLE problem. Closes: #354300 + * Upstream fixes problem that empty strings in varchar and text columns + are displayed as NULL. Closes: #368663 + + -- Christian Hammers Tue, 30 May 2006 23:43:24 +0200 + +mysql-dfsg-5.0 (5.0.21-4) unstable; urgency=low + + * Added "BLOCKSIZE=" to the diskfree check (thanks to Farzad FARID). + Closes: #367027, #367083 + * Further fixed mysql_upgrade upstream script (thanks to Andreas Pakulat) + Closes: #366155 + * Adjusted the /proc test in debian/rules from /proc/1 to /proc/self + to make building on grsec systems possible (thanks to K. Rosenegger). + Closes: #366824 + * Updated Russion Debconf translation (thanks to Yuriy Talakan). + Closes: #367141 + * Updated Czech Debconf translation (thanks to Kiroslav Kure). + Closes: #367160 + * Updated Galician Debconf translation (thanks to Jacobo Tarrio). + Closes: #367384 + * Updated Swedish Debconf translation (thanks to Daniel Nylander). + Closes: #368186 + + -- Christian Hammers Wed, 10 May 2006 08:45:42 +0200 + +mysql-dfsg-5.0 (5.0.21-3) unstable; urgency=low + + * Fixed FTBFS problem which was caused by a patch that modifies Makefile.am + as well as Makefile.in and was not deteced because my desktop was fast + enough to patch both files within the same second and so fooled automake. + (thanks to Blars Blarson for notifying me). Closes: #366534 + + -- Christian Hammers Sat, 6 May 2006 19:03:58 +0200 + +mysql-dfsg-5.0 (5.0.21-2) unstable; urgency=low + + * Fixed bug in postinst that did not correctly rewrite + /etc/mysql/debian.cnf (thanks to Daniel Leidert). + Closes: #365433, #366155 + + -- Christian Hammers Thu, 4 May 2006 02:37:03 +0200 + +mysql-dfsg-5.0 (5.0.21-1) unstable; urgency=high + + * SECURITY: New upstream release with some security relevant bugfixes: + * "Buffer over-read in check_connection with usernames lacking a + trailing null byte" (CVE-2006-1516) + * "Anonymous Login Handshake - Information Leakage" (CVE-2006-1517) + * "COM_TABLE_DUMP Information Leakage and Arbitrary command execution" + (CVE-2006-1518) + Closes: #365938, #365939 + * Added diskfree check to the init script (thanks to Tim Baverstock). + Closes: #365460 + * First amd64 upload! + + -- Christian Hammers Sat, 29 Apr 2006 04:31:27 +0200 + +mysql-dfsg-5.0 (5.0.20a-2) unstable; urgency=low + + * The new mysql-upgrade which is started from /etc/mysql/debian-start + does now use the debian-sys-maint user for authentication (thanks to + Philipp). Closes: #364991 + * Wrote patch debian/patches/43* which adds a password option to + mysql_update. See MySQL bug #19400. + * Added "Provides: libmysqlclient-dev" to libmysqlclient15-dev as I saw no + obvious reasons against it (problems should be documented in + debian/README.Maintainer!) (thanks to Olaf van der Spek). Closes: #364899 + * Updated Netherlands debconf translation (thanks to Vincent Zweije) + Closes: #364464 + * Updated French debconf translation (thanks to Christian Perrier) + Closes: #364401 + * Updated Danish debconf translation (thanks to Claus Hindsgaul) + Closes: #365135 + + -- Christian Hammers Wed, 26 Apr 2006 01:14:53 +0200 + +mysql-dfsg-5.0 (5.0.20a-1) unstable; urgency=low + + * New upstream release. + * Added the new mysql_upgrade script and added it to + /etc/mysql/debian-start (thanks to Alessandro Polverini). + The script is currently very noise that is a known bug and will be + fixed in the next release! + Closes: #363458 + * No longer creates the "test" database. This actuallay had been tried + to archive before (at least patches) exists but apparently was not the + case in the last versions (thanks to Olaf van der Spek). Closes: #362126 + * Reformatted libmysqlclient15off.NEWS.Debian to changelog format + (thanks to Peter Palfrader). Closes: #363062 + + -- Christian Hammers Sat, 15 Apr 2006 13:05:22 +0200 + +mysql-dfsg-5.0 (5.0.20-1) unstable; urgency=high + + * Upstream contains a fix for a nasty bug (MySQL#18153) that users + already experienced and that caused corrupted triggers after + REPAIR/OPTIMIZE/ALTER TABLE statements. + (thanks to Jerome Despatis for pointing out) + * Added patch for the "updates on multiple tables is buggy after + upgrading from 4.1 to 5.0" problem which MySQL has been committed + for the upcoming 5.0.21 release. Closes #352704 + * Added Netherlands debconf translation (thanks to Vincent Zweije). + Closes: #360443 + * Added Galician debconf translation (thanks to Jacobo Tarrio). + Closes: #361257 + + -- Christian Hammers Fri, 7 Apr 2006 00:00:43 +0200 + +mysql-dfsg-5.0 (5.0.19-3) unstable; urgency=high + + [ Christian Hammers ] + * Fixed libmysqlclient15.README.Debian regarding package name changes + (thanks to Leppo). + * Moved libheap.a etc. back to /usr/lib/mysql/ as their names are just + too generic. Closes: #353924 + [ Sean Finney ] + * updated danish debconf translation, thanks to Claus Hindsgaul + (closes: #357424). + [ Adam Conrad ] + * Send stderr from 'find' in preinst to /dev/null to tidy up chatter. + * Backport patch for CVE-2006-0903 from the upcoming release to resolve + a log bypass vulnerability when using non-binary logs (closes: #359701) + + -- Adam Conrad Tue, 4 Apr 2006 15:23:18 +1000 + +mysql-dfsg-5.0 (5.0.19-2) unstable; urgency=medium + + * New upstream release. + * Renamed package libmysqlclient15 to libmysqlclient15off due to + binary incompatible changes. + See /usr/share/doc/libmysqlclient15off/README.Debian + * Updated Czech debconf translation (thanks to Miroslav Kure). + Closes: #356503 + * Updated French debconf translation (thanks to Christian Perrier). + Closes: #356332 + * Improved README.Debian (thanks to Olaf van der Spek). Closes: #355702 + * Fixed 5.0.18-8 changelog by saying in which package the NEWS.Debian + file is (thanks to Ross Boylan). Closes: #355978 + + -- Christian Hammers Fri, 17 Mar 2006 02:32:19 +0100 + +mysql-dfsg-5.0 (5.0.19-1) experimental; urgency=medium + + * New upstream release. + * SECURITY: CVE-2006-3081: A bug where str_to_date(1,NULL) lead to a + server crash has been fixed. + (this note has been added subsequently for reference) + * Renamed package libmysqlclient15 to libmysqlclient15off. + See /usr/share/doc/libmysqlclient15off/NEWS.Debian + * Updated Czech debconf translation (thanks to Miroslav Kure). + Closes: #356503 + * Updated French debconf translation (thanks to Christian Perrier). + Closes: #356332 + * Improved README.Debian (thanks to Olaf van der Spek). Closes: #355702 + * Fixed 5.0.18-8 changelog by saying in which package the NEWS.Debian + file is (thanks to Ross Boylan). Closes: #355978 + + -- Christian Hammers Tue, 14 Mar 2006 22:56:13 +0100 + +mysql-dfsg-5.0 (5.0.18-9) unstable; urgency=medium + + [ Christian Hammers ] + * When using apt-get the check for left-over ISAM tables can abort the + installation of mysql-server-5.0 but not prevent the mysql-server-4.1 + package from getting removed. The only thing I can do is reflect this + in the Debconf notice that is shown and suggest to reinstall + mysql-server-4.1 for converting. See: #354850 + * Suggests removing of /etc/cron.daily/mysql-server in last NEWS message + (thanks to Mourad De Clerck). Closes: #354111 + * Added versioned symbols for kfreebsd and Hurd, too (thanks to Aurelien + Jarno and Michael Bank). Closes: #353971 + * Added versioned symbols for kfreebsd, too (thanks to Aurelien Jarno). + Closes: #353971 + [ Adam Conrad ] + * Add 39_scripts__mysqld_safe.sh__port_dir.dpatch to ensure that the + permissions on /var/run/mysqld are always correct, even on a tmpfs. + + -- Christian Hammers Mon, 6 Mar 2006 21:42:13 +0100 + +mysql-dfsg-5.0 (5.0.18-8) unstable; urgency=low + + * The rotation of the binary logs is now configured via + expire-logs-days in /etc/mysql/my.cnf and handled completely + by the server and no longer in configured in debian-log-rotate.conf + and handled by a cron job. Thanks to David Johnson. + See /usr/share/doc/mysql-server-5.0/NEWS.Debian + * Ran aspell over some files in debian/ and learned a lot :) + * debian/rules: Added check if versioned symbols are really there. + * Updated SSL-MINI-HOWTO. + * Updated copyright (removed the parts regarding the now removed + BerkeleyDB table handler and mysql-doc package). + * Relocated a variable in preinst (thanks to Michael Heldebrant). + Closes: #349258, #352587, #351216 + * Updated Danish debconf translation (thanks to Claus Hindsgaul). + Closes: #349013 + * Updated Swedish debconf translation (thanks to Daniel Nylander). + Closes: #349522 + * Updated French debconf translation (thanks to Christian Perrier). + Closes: #349592 + * Fixed typo in README.Debian (thanks to Vincent Ricard). + * Prolonged waiting time for mysqld in the init script. Closes: #352070 + + -- Christian Hammers Mon, 23 Jan 2006 23:13:46 +0100 + +mysql-dfsg-5.0 (5.0.18-7) unstable; urgency=low + + * Made mailx in debian-start.inc.sh optional and changed the dependency on it + on it to a mere recommendation. Closes: #316297 + * the previous FTBFS patches for GNU/Hurd inadvertently led to configure + being regenerating, losing a couple trivial things like our versioned + symbols patch, causing many nasty problems (closes: #348854). + + -- sean finney Fri, 20 Jan 2006 20:59:27 +0100 + +mysql-dfsg-5.0 (5.0.18-6) unstable; urgency=low + + * Added version comment (thanks to Daniel van Eeden). + * Added two patches to build on GNU/Hurd (thanks to Michael Bank). + Closes: #348182 + * Abort upgrade if old and now unsupported ISAM tables are present + (thanks to David Coe). Closes: #345895 + + -- Christian Hammers Tue, 17 Jan 2006 19:25:59 +0100 + +mysql-dfsg-5.0 (5.0.18-5) unstable; urgency=low + + * Bump shlibdeps for libmysqlclient15 to (>= 5.0.15-1), which was + the first non-beta release from upstream, as well as being shortly + after we broke the ABI in Debian by introducing versioned symbols. + + -- Adam Conrad Fri, 13 Jan 2006 13:18:03 +1100 + +mysql-dfsg-5.0 (5.0.18-4) unstable; urgency=low + + * Munge our dependencies further to smooth upgrades even more, noting + that we really need 5.0 to conflict with 4.1, and stealing a page from + the book of mysql-common, it doesn't hurt to hint package managers in + the direction of "hey, this stuff is a complete replacement for 4.1" + * Change the description of mysql-server and mysql-client to remove the + references to it being "transition", and instead point out that it's + the way to get the "current best version" of each package installed. + + -- Adam Conrad Wed, 11 Jan 2006 11:39:45 +1100 + +mysql-dfsg-5.0 (5.0.18-3) unstable; urgency=low + + * Make the mysql-{client,server}-5.0 conflict against mysql-{client,server} + versioned, so they can be installed side-by-side and upgrade properly. + * Add myself to Uploaders; since I have access to the alioth repository. + + -- Adam Conrad Tue, 10 Jan 2006 19:15:48 +1100 + +mysql-dfsg-5.0 (5.0.18-2) unstable; urgency=low + + * Removed the transitional package that forced an upgrade from + mysql-server-4.1 to mysql-server-5.0 as I was convinced that + having a general "mysql-server" package with adjusted dependencies + is enough (thanks to Adam Conrad). + * Updated logcheck.ignore files (thanks to Jamie McCarthy). Closes: #340193 + + -- Christian Hammers Mon, 9 Jan 2006 21:54:53 +0100 + +mysql-dfsg-5.0 (5.0.18-1) unstable; urgency=low + + * New upstream version. + * Added empty transitional packages that force an upgrade from the + server and client packages that have been present in Sarge. + * Fixed SSL-MINI-HOWTO (thanks to Jonas Smedegaard). Closes: #340589 + + -- Christian Hammers Mon, 2 Jan 2006 21:17:51 +0100 + +mysql-dfsg-5.0 (5.0.17-1) unstable; urgency=low + + * Never released as Debian package. + + -- Christian Hammers Thu, 22 Dec 2005 07:49:52 +0100 + +mysql-dfsg-5.0 (5.0.16-1) unstable; urgency=low + + * New upstream version. + * Removed the error logs from the logrotate script as Debian does + not use them anymore. Closes: #339628 + + -- Christian Hammers Tue, 22 Nov 2005 01:19:11 +0100 + +mysql-dfsg-5.0 (5.0.15-2) unstable; urgency=medium + + * Added 14_configure__gcc-atomic.h.diff to fix FTBFS on m68k + (thanks to Stephen R Marenka). Closes: #337082 + * Removed dynamic linking against libstdc++ as it was not really + needed (thanks to Adam Conrad). Closes: #328613 + * Fixed the "/var/lib/mysql is a symlink" workaround that accidently + left a stalled symlink (thanks to Thomas Lamy). Closes: #336759 + * As the init script cannot distinguish between a broken startup and + one that just takes very long the "failed" message now says + "or took more than 6s" (thanks to Olaf van der Spek). Closes: #335547 + + -- Christian Hammers Thu, 3 Nov 2005 22:00:15 +0100 + +mysql-dfsg-5.0 (5.0.15-1) unstable; urgency=low + + * New upstream version. 5.0 has finally been declared STABLE! + * Added small patch to debian/rules that fixed sporadic build errors + where stdout and stderr were piped together, got mixed up and broke + * Added --with-big-tables to ./configure (thanks to tj.trevelyan). + Closes: #333090 + * Added capability to parse "-rc" to debian/watch. + * Fixed cronscript (thanks to Andrew Deason). Closes: #335244 + * Added Swedish debconf translation (thanks to Daniel Nylander). + Closes: #333670 + * Added comment to README.Debian regarding applications that manually + set new-style passwords... Closes: #334444 + * Sean Finney: + - Fix duplicate reference to [-e|--extended-insert]. Closes: #334957 + - Fix default behavior for mysqldumpslow. Closes: #334517 + - Reference documentation issue in mysql manpage. Closes: #335219 + + -- Christian Hammers Fri, 30 Sep 2005 00:10:39 +0200 + +mysql-dfsg-5.0 (5.0.13rc-1) unstable; urgency=low + + * New upstream release. Now "release-candidate"! + * Removed any dynamic link dependencies to libndbclient.so.0 which + is due to its version only distributed as a static library. + * Sean Finney: + - FTBFS fix related to stripping rpath in debian/rules + + -- Christian Hammers Mon, 26 Sep 2005 22:09:26 +0200 + +mysql-dfsg-5.0 (5.0.12beta-5) unstable; urgency=low + + * The recent FTBFS were probably result of a timing bug in the + debian/patches/75_*.dpatch file where Makefile.in got patched just + before the Makefile.shared which it depended on. For that reason + only some of the autobuilders failed. Closes: #330149 + * Fixed chrpath removal (option -k had to be added). + * Corrected debconf dependency as requested by Joey Hess. + + -- Christian Hammers Mon, 26 Sep 2005 18:37:07 +0200 + +mysql-dfsg-5.0 (5.0.12beta-4) unstable; urgency=low + + * Removed experimental shared library libndbclient.so.0.0.0 as it + is doomed to cause trouble as long as it is present in both MySQL 4.1 + and 5.0 without real soname and its own package. We still have + libndbclient.a for developers. (thanks to Adam Conrad and + mediaforest.net). Closes: #329772 + + -- Christian Hammers Fri, 23 Sep 2005 12:36:48 +0200 + +mysql-dfsg-5.0 (5.0.12beta-3) unstable; urgency=medium + + * Symbol versioning support! wooooohoooooo! + (thanks to Steve Langasek) Closes: #236288 + * Moved libndbcclient.so.0 to the -dev package as it is provided by + libmysqlclient14 and -15 which must be installable simultaneously. + * Removed mysql-*-doc suggestions. + + -- Christian Hammers Tue, 20 Sep 2005 00:07:03 +0200 + +mysql-dfsg-5.0 (5.0.12beta-2) unstable; urgency=low + + * Added patch to build on GNU/kFreeBSD (thanks to Aurelien Jarno). + Closes: #327702 + * Added patch that was already been present on the 4.1 branch which + makes the "status" command of the init script more sensible + (thanks to Stephen Gildea). Closes: #311836 + * Added Vietnamese Debconf translation (thanks to Clytie Siddal). + Closes: #313006 + * Updated German Debconf translation (thanks to Jens Seidel). + Closes: #313957 + * Corrected commends in example debian-log-rotate.conf. The default is + unlike the mysql-sever-4.1 package which needed to stay backwards + compatible now 2 to avoid filling up the disk endlessly. + * Fixed watch file to be "-beta" aware. + + -- Christian Hammers Thu, 15 Sep 2005 20:50:19 +0200 + +mysql-dfsg-5.0 (5.0.12beta-1) unstable; urgency=medium + + * Christian Hammers: + - New upstream release. + - Changed build-dep to libreadline5-dev as requested by Matthias Klose. + Closes: #326316 + - Applied fix for changed output format of SHOW MASTER LOGS for + binary log rotation (thanks to Martin Krueger). Closes: #326427, #326427 + - Removed explicit setting of $PATH as I saw no sense in it and + it introduced a bug (thanks to Quim Calpe). Closes: #326769 + - Removed PID file creation from /etc/init.d/mysql-ndb as it does + not work with this daemon (thanks to Quim Calpe). + - Updated French Debconf translation (thanks to Christian Perrier). + Closes: #324805 + - Moved conflicts line in debian/control from libmysqlclient15 to + libmysqlclient15-dev and removed some pre-sarge conflicts as + suggested by Adam Majer. Closes: #324623 + * Sean Finney: + - For posterity, CAN-2005-2558 has been fixed since 5.0.7beta. + + -- Christian Hammers Thu, 15 Sep 2005 19:58:22 +0200 + +mysql-dfsg-5.0 (5.0.11beta-3) unstable; urgency=low + + * Temporarily build only with -O2 to circumvent gcc internal errors + (thanks to Matthias Klose). Related to: #321165 + + -- Christian Hammers Thu, 18 Aug 2005 15:44:04 +0200 + +mysql-dfsg-5.0 (5.0.11beta-2) unstable; urgency=low + + * Fixed README.Debian regarding the status of mysql-doc. + * Added "set +e" around chgrp in mysql-server-5.0.preinst to + not fail on .journal files (thanks to Christophe Nowicki). + Closes: #318435 + + -- Christian Hammers Sun, 14 Aug 2005 18:02:08 +0200 + +mysql-dfsg-5.0 (5.0.11beta-1) unstable; urgency=low + + * New upstream version. + * Added Danish Debconf translations (thanks to Claus Hindsgaul). + Closes: #322384 + * Updated Czech Debconf translations (thanks to Miroslav Kure). + Closes: #321765 + + -- Christian Hammers Sat, 13 Aug 2005 11:56:15 +0000 + +mysql-dfsg-5.0 (5.0.10beta-1) unstable; urgency=low + + * New upstream release. + * Christian Hammers: + - Added check for mounted /proc to debian/rules. + * Sean Finney: + - fix for fix_mysql_privilege_tables/mysql_fix_privilege_tables typo + in mysql-server-5.0's README.Debian (see #319838). + + -- Christian Hammers Sun, 31 Jul 2005 00:30:45 +0200 + +mysql-dfsg-5.0 (5.0.7beta-1) unstable; urgency=low + + * Second try for new upstream release. + * Renamed mysql-common-5.0 to mysql-common as future libmysqlclient16 + from e.g. MySQL-5.1 would else introduce mysql-common-5.1 which makes + a simultanous installation of libmysqlclient14 impossible as that + depends on either mysql-common or mysql-common-5.0 but not on future + versions. Thus we decided to always let the newest MySQL version + provide mysql-common. + * Added ${misc:Depends} as suggested by debhelper manpage. + * Raised standard in control file to 3.6.2. + * Removed DH_COMPAT from rules in faviour of debian/compat. + * Checkes for presence of init script before executing it in preinst. + Referres: 315959 + * Added 60_includes_mysys.h__gcc40.dpatch for GCC-4.0 compatibility. + + -- Christian Hammers Wed, 29 Jun 2005 00:39:05 +0200 + +mysql-dfsg-5.0 (5.0.5beta-1) unstable; urgency=low + + * New major release! Still beta so be carefull... + * Added federated storage engine. + + -- Christian Hammers Wed, 8 Jun 2005 19:29:45 +0200 + +mysql-dfsg-4.1 (4.1.12-1) unstable; urgency=low + + * Christian Hammers: + - New upstream release. + - Disabled BerkeleyDB finally. It has been obsoleted by InnoDB. + * Sean Finney: + - Updated French translation from Christian Perrier (Closes: #310526). + - Updated Japanese translation from Hideki Yamane (Closes: #310263). + - Updated Russian translation from Yuriy Talakan (Closes: #310197). + + -- Christian Hammers Sat, 4 Jun 2005 05:49:11 +0200 + +mysql-dfsg-4.1 (4.1.11a-4) unstable; urgency=high + + * Fixed FTBFS problem which was caused due to the fact that last uploads + BerkeleyDB patch was tried to applied on all architectures and not only + on those where BerkeleyDB is actually beeing built. Closes: #310296 + + -- Christian Hammers Mon, 23 May 2005 00:54:51 +0200 + +mysql-dfsg-4.1 (4.1.11a-3) unstable; urgency=high + + * Added patch from Piotr Roszatycki to compile the bundled db3 library + that is needed for the BerkeleyDB support with versioned symbols so + that mysqld no longer crashes when it gets linked together with the + Debian db3 version which happens when e.g. using libnss-db. + Closes: #308966 + + -- Christian Hammers Thu, 19 May 2005 01:41:14 +0200 + +mysql-dfsg-4.1 (4.1.11a-2) unstable; urgency=high + + * Okay, the hackery with /var/lib/dpkg/info/mysql-server.list will not + stand and is removed from the preinst of mysql-server. + * New workaround for the symlink problem that does not involve mucking + with dpkg's file lists is storing the symlinks in a temporary location + across upgrades. + As this sometimes fails since apt-get does not always call new.preinst + before old.postrm, some remarks were added to README.Debian and the + Debconf installation notes to minimize the inconvinience this causes. + + -- sean finney Sun, 15 May 2005 10:25:31 -0400 + +mysql-dfsg-4.1 (4.1.11a-1) unstable; urgency=high + + * Added the "a" to the version number to be able to upload a new + .orig.tar.gz file which now has the non-free Docs/ directory removed + as this has been forgotten in the 4.1.11 release (thanks to Goeran + Weinholt). Closes: #308691 + * The Woody package listed /var/lib/mysql and /var/log/mysql in its + /var/lib/dpkg/info/mysql-server.list. These directories are often + replaced by symlinks to data partitions which triggers a dpkg bug + that causes these symlinks to be removed on upgrades. The new preinst + prevents this by removing the two lines from the .list file + (thanks to Andreas Barth and Jamin W. Collins). See dpkg bug #287978. + * Updated French Debconf translation (thanks to Christian Perrier). + Closes: #308353 + + -- Christian Hammers Thu, 12 May 2005 21:52:46 +0200 + +mysql-dfsg-4.1 (4.1.11-3) unstable; urgency=high + + * The "do you want to remove /var/lib/mysql when purging the package" flag + from old versions is removed once this package is beeing installed so + that purging an old Woody mysql-server package while having a + mysql-server-4.1 package installed can no longer lead to the removal of + all databases. Additionaly clarified the wording of this versions Debconf + template and added a check that skips this purge in the postrm script + if another mysql-server* package has /usr/sbin/mysqld installed. + (thanks to Adrian Bunk for spotting that problem) Closes: #307473 + * Cronfile was not beeing installed as the filename was not in the + correct format for "dh_installcron --name" (thanks to Tomislav + Gountchev). Closes: #302712 + + -- Christian Hammers Sat, 23 Apr 2005 22:55:15 +0200 + +mysql-dfsg-4.1 (4.1.11-2) unstable; urgency=low + + * Sean Finney: + - don't freak out if we can't remove /etc/mysql during purge. + - debian/rules clean works again. + * Christian Hammers: + - Fixed typo in README.Debian (thanks to Joerg Rieger). Closes: #304897 + - Completely removed the passwordless test user as it was not only + insecure but also lead to irritations as MySQL checks first the + permissions of this user and then those of a password having one. + See bug report from Hilko Bengen for details. Closes: #301741 + + -- Christian Hammers Sat, 16 Apr 2005 15:55:00 +0200 + +mysql-dfsg-4.1 (4.1.11-1) unstable; urgency=low + + * New upstream version. + * Upstream fix for charset/collation problem. Closes: #282256 + * Upstream fix for subselect crash. Closes: #297687 + * Corrected minor issue in Debconf template regarding skip-networking + (thanks to Isaac Clerencia). Closes: #303417 + * Made dependency to gawk unnecessary (thanks to Zoran Dzelajlija). + Closes: #302284 + * Removed obsolete 50_innodb_mixlen.dpatch. + * Removed obsolete 51_CAN-2004-0957_db_grant_underscore.dpatch. + + -- Christian Hammers Fri, 8 Apr 2005 00:23:53 +0200 + +mysql-dfsg-4.1 (4.1.10a-7) unstable; urgency=low + + * Sean Finney: + - fix for the mysteriously disappeared cronjob. thanks to + Peter Palfrader for pointing out this omission. + (closes: #302712). + + -- sean finney Sat, 02 Apr 2005 16:54:13 -0500 + +mysql-dfsg-4.1 (4.1.10a-6) unstable; urgency=high + + * Sean Finney: + - the previous upload did not completely address the issue. this one + should do so. d'oh. + + -- sean finney Thu, 31 Mar 2005 03:35:50 +0000 + +mysql-dfsg-4.1 (4.1.10a-5) unstable; urgency=high + + * Sean Finney: + - the following security issue is addressed in this upload: + CAN-2004-0957 (grant privilege escalation on tables with underscores) + thanks to sergei at mysql for all his help with this. + + -- sean finney Wed, 30 Mar 2005 21:19:26 -0500 + +mysql-dfsg-4.1 (4.1.10a-4) unstable; urgency=low + + * Sean Finney: + - FTBFS fix for amd64/gcc-4.0. Thanks to Andreas Jochens + for reporting this (closes: #301807). + - ANSI-compatible quoting fix in daily cron job. thanks to + Karl Hammar for pointing out the problem in + the 4.0 branch. + - Added myself as a co-maintainer in the control file (closes: #295312). + + -- sean finney Tue, 29 Mar 2005 18:54:42 -0500 + +mysql-dfsg-4.1 (4.1.10a-3) unstable; urgency=low + + * BerkeleyDB is now disabled by default as its use is discouraged by MySQL. + * Added embedded server libraries as they finally do compile. + They are currently in libmysqlclient-dev as they are still + experimental and only available as .a library (thanks to Keith Packard). + Closes: #297062 + * Fixed obsolete "tail" syntax (thanks to Sven Mueller). Closes: #301413 + * Added CAN numbers for the latest security bugfix upload. + * Updated manpage of mysqlmanager (thanks to Justin Pryzby). Closes: #299844 + * Added comments to default configuration. + + -- Christian Hammers Sun, 20 Mar 2005 17:40:18 +0100 + +mysql-dfsg-4.1 (4.1.10a-2) unstable; urgency=low + + * Disabled "--with-mysqld-ldflags=-all-static" as it causes sig11 crashes + if LDAP is used for groups in /etc/nsswitch.conf. Confirmed by Sean Finney + and Daniel Dehennin. Closes: #299382 + + -- Christian Hammers Mon, 14 Mar 2005 03:01:03 +0100 + +mysql-dfsg-4.1 (4.1.10a-1) unstable; urgency=high + + * SECURITY: + - The following security related updates are addressed: + CAN-2005-0711 (temporary file creation with "CREATE TEMPORARY TABLE") + CAN-2005-0709 (arbitrary library injection in udf_init()) + CAN-2005-0710 (arbitrary code execution via "CREATE FUNCTION") + Closes: #299029, #299031, #299065 + * New Upstream Release. + - Fixes some server crash conditions. + - Upstream includes fix for TMPDIR overriding my.cnf tmpdir setting + Closes: #294347 + - Fixes InnoDB error message. Closes: #298875 + - Fixes resouce limiting. Closes: #285044 + * Improved checking whether or not the server is alive in the init script + which should make it possible to run several mysqld instances in + different chroot environments. Closes: #297772 + * Fixed cron script name as dots are not allowed (thanks to Michel + v/d Ven). Closes: #298447 + * Added -O3 and --with-mysqld-ldflags=-all-static as MySQL recommends to + build the server binary statically in order to gain about 13% more + performance (thanks to Marcin Kowalski). + * Added patch to let mysqld_safe react to signals (thanks to Erich + Schubert). Closes: #208364 + * (Thanks to Sean Finney for doing a great share of work for this release!) + + -- Christian Hammers Thu, 3 Mar 2005 02:36:39 +0100 + +mysql-dfsg-4.1 (4.1.10-4) unstable; urgency=medium + + * Fixed bug that prevented MySQL from starting after upgrades. + Closes: #297198, #296403 + * Added comment about logging to syslog to the default my.cnf + and the logrotate script (thanks to Ryszard Lach). Closes: #295507 + + -- Christian Hammers Thu, 3 Mar 2005 00:28:02 +0100 + +mysql-dfsg-4.1 (4.1.10-3) unstable; urgency=low + + * Sean Finney: Cronjobs now exit silently when the server package + has been removed but not purged (thanks to Vineet Kumar). + Closes: #297404 + * Fixed comments of /etc/mysql/debian-log-rotate.conf (thanks to + Philip Ross). Closes: #297467 + * Made mysqld_safe reacting sane on signals (thanks to Erich Schubert). + Closes: #208364 + + -- Christian Hammers Tue, 1 Mar 2005 19:44:34 +0100 + +mysql-dfsg-4.1 (4.1.10-2) unstable; urgency=low + + * Converted to dpatch. + * debian/ is now maintained via Subversion on svn.debian.org. + + -- Christian Hammers Tue, 1 Mar 2005 02:16:36 +0100 + +mysql-dfsg-4.1 (4.1.10-1) unstable; urgency=low + + * New upstream version. + * Upstream fixed memleak bug. Closes: #205587 + * Added debian/copyright.more for personal reference. + * Lowered default query cache size as suggested by Arjen from MySQL. + * Switched from log to log-bin as suggested by Arjen from MySQL. + * Fixed typo in my.cnf (thanks to Sebastian Feltel). Closes: #295247 + * Replaced --defaults-extra-file by --defaults-file in Debian scripts + as former lets password/host etc be overwriteable by /root/.my.cnf. + Added socket to /etc/mysql/debian.cnf to let it work. (thanks to + SATOH Fumiyasu). Closes: #295170 + + -- Christian Hammers Tue, 15 Feb 2005 23:47:02 +0100 + +mysql-dfsg-4.1 (4.1.9-4) unstable; urgency=low + + * Improved the way mysqld is started and registered with update-rc.d + in cases where the admin modifies the runlevel configuration. + Most notably removed the debconf question whether or not mysql should + start on when booting. Closes: #274264 + * Renamed configuration option old-passwords to the more preferred + naming convention old_passwords. Same for some others (thanks to + Patrice Pawlak). Closes: #293983 + + -- Christian Hammers Tue, 8 Feb 2005 02:21:18 +0100 + +mysql-dfsg-4.1 (4.1.9-3) unstable; urgency=low + + * Renamed ca_ES.po to ca.po to reach a broader audience (thanks to + Christian Perrier). Closes: #293786 + * Expicitly disabled mysqlfs support as it has never been enabled by + configure during the autodetection but fails due to broken upstream + code when users try to build the package theirselves while having + liborbit-dev installed which triggers the mysqlfs autodetection + (thanks to Max Kellermann). Closes: #293431 + * Added dependencies to gawk as one script does not work with original-awk + (thanks to Petr Ferschmann). Closes: #291634 + + -- Christian Hammers Sun, 6 Feb 2005 23:33:11 +0100 + +mysql-dfsg-4.1 (4.1.9-2) unstable; urgency=high + + * SECURITY: + For historical reasons /usr/share/mysql/ was owned and writable by + the user "mysql". This is a security problem as some scripts that + are run by root are in this directory and could be modified and used + by a malicious user who already has mysql privileges to gain full root + rights (thanks to Matt Brubeck). Closes: #293345 + * Changed "skip-networking" to "bind-address 127.0.0.1" which is more + compatible and not less secure but maybe even more, as less people enable + networking for all interfaces (thanks to Arjen Lentz). + * Enabled InnoDB by default as recommended by Arjen Lentz from MySQL. + * Added remarks about hosts.allow to README.Debian (thanks to David + Chappell). Closes: #291300 + * mysql-server-4.1 now provides mysql-server (thanks to Paul van den Berg). + Closes: #287735 + + -- Christian Hammers Wed, 2 Feb 2005 23:31:55 +0100 + +mysql-dfsg-4.1 (4.1.9-1) unstable; urgency=low + + * New upstream version. + * mysql-client-4.1 now provides "mysql-client" so that packages depending + on mysql-client (ca. 40) can now be used with MySQL-4.1, too. + + -- Christian Hammers Sun, 23 Jan 2005 22:52:48 +0100 + +mysql-dfsg-4.1 (4.1.8a-6) unstable; urgency=high + + * SECURITY: + Javier Fernandez-Sanguino Pena from the Debian Security Audit Project + discovered a temporary file vulnerability in the mysqlaccess script of + MySQL that could allow an unprivileged user to let root overwrite + arbitrary files via a symlink attack and could also could unveil the + contents of a temporary file which might contain sensitive information. + (CAN-2005-0004, http://lists.mysql.com/internals/20600) Closes: #291122 + + -- Christian Hammers Tue, 18 Jan 2005 23:11:48 +0100 + +mysql-dfsg-4.1 (4.1.8a-5) unstable; urgency=medium + + * Fixed important upstream bug that causes from_unixtime(0) to return + NULL instead of "1970-01-01 00:00:00" which fails on NOT NULL columns. + Closes: #287792 + * Fixes upstream bug in mysql_list_fields() . Closes: #282486 + * Fixes bug that lead to double rotated logfiles when mysql-server 4.0 + was previously installed (thanks to Olaf van der Spek). Closes: #289851 + * Fixed typo in README.Debian (thanks to Mark Nipper). Closes: #289131 + * Changed max_allowed_packet in my.cnf to 16M as in 4.0.x (thanks to + Olaf van der Spek). Closes: #289840 + * Updated French debconf translation (thanks to Christian Perrier). + Closes: #287955 + + -- Christian Hammers Thu, 13 Jan 2005 01:29:05 +0100 + +mysql-dfsg-4.1 (4.1.8a-4) unstable; urgency=low + + * Broken patch again :-( + + -- Christian Hammers Sun, 9 Jan 2005 23:47:55 +0100 + +mysql-dfsg-4.1 (4.1.8a-3) unstable; urgency=low + + * The mutex patch was a bit too x86 centric. This broke the alpha build. + + -- Christian Hammers Sun, 9 Jan 2005 14:18:49 +0100 + +mysql-dfsg-4.1 (4.1.8a-2) unstable; urgency=medium + + * Some Makefiles that were patched by me got overwritten by the GNU + autotools, probably because I also patched ./configure. Fixed now, + the critical mutex patch is now back in again. Closes: #286961 + * Added patch to make MySQL compile on ARM (thanks to Adam Majer). + Closes: #285071 + + -- Christian Hammers Thu, 6 Jan 2005 09:30:13 +0100 + +mysql-dfsg-4.1 (4.1.8a-1) unstable; urgency=medium + + * Upstream 4.1.8 had some problems in their GNU Autotools files so they + released 4.1.8a. Debian's 4.1.8 was fixed by running autoreconf but this + again overwrote MySQL changes to ltmain.sh which are supposed to fix some + problems on uncommon architectures (maybe the FTBFS on alpha, arm, m68k + and sparc?). + * libmysqlclient_r.so.14 from 4.1.8-3 also missed a link dependency to + libz which lead to unresolved symbols visible with "ldd -r" (thanks + to Laurent Bonnaud). Closes: #287573 + + -- Christian Hammers Wed, 29 Dec 2004 14:26:33 +0100 + +mysql-dfsg-4.1 (4.1.8-3) unstable; urgency=low + + * Fixed checking for error messages by forcing english language + output by adding LC_ALL=C to debian-start (thanks to Rene + Konasz) Closes: #285709 + * Fixed bashisms in Debian scripts. Closes: #286863 + * Updated Japanese Debconf translation (thanks to Hideki Yamane). + Closes: #287003 + * Improved 4.0 to 4.1 upgrade if /var/lib/mysql is a symlink + (thanks to Thomas Lamy). Closes: #286560 + * Added patch for FTBFS problem where no LinuxThreads can be found. + I don't know if this still applies but it should not hurt. + The patch is debian/patches/configure__AMD64-LinuxThreads-vs-NPTL.diff + + -- Christian Hammers Sun, 26 Dec 2004 14:04:20 +0100 + +mysql-dfsg-4.1 (4.1.8-2) unstable; urgency=low + + * If /var/lib/mysql is a symlink then it is kept as such. + * Added the old-passwords option to the default my.cnf to stay + compatible to clients that are still compiled to libmysqlclient10 + and libmysqlclient12 for licence reasons. + * Adjusted tetex build-deps to ease backporting (thanks to Norbert + Tretkowski from backports.org). + + -- Christian Hammers Tue, 21 Dec 2004 01:00:27 +0100 + +mysql-dfsg-4.1 (4.1.8-1) unstable; urgency=medium + + * New upstream version. Closes: #286175 + * Added conflict to libmysqlclient-dev (thanks to Adam Majer). + Closes: #286538 + * Added debconf-updatepo to debian/rules:clean. + * Updated Japanese Debconf translation (thanks to Hideki Yamane). + Closes: #285107 + * Updated French Debconf translation (thanks to Christian Perrier). + Closes: #285977 + * Renamed cz.po to cs.po (thanks to Miroslav Kure). Closes: #285438 + * Aplied patch for changed server notice to debian-start (thanks to + Adam Majer). Closes: #286035 + * Changed nice value in default my.cnf as nohup changed its behaviour + (thanks to Dariush Pietrzak). Closes: #285446 + * Increased verbosity of preinst script in cases where it cannot stop + a running server (thanks to Jan Minar). Closes: #285982 + * Splitted the code parts of /etc/mysql/debian-start to + /usr/share/mysql/debian-start.inc.sh (thanks to Jan Minar). + Closes: #285988 + + -- Christian Hammers Mon, 20 Dec 2004 00:33:21 +0100 + +mysql-dfsg-4.1 (4.1.7-4) unstable; urgency=medium + + * Removed OpenSSL support. + After a short discussion with MySQL, I decided to drop OpenSSL support as + 1. MySQL started shipping their binaries without it, too and do not + seem to support it in favour of using a different library somewhen. + 2. MySQL did not adjust their licence to grant permission to link + against OpenSSL. + 3. Even if they did, third parties who use libmysqlclient.so often + do not realise licencing problems or even do not want OpenSSL. + (thanks to Jordi Mallach and the responders to MySQL bug #6924) + Closes: #283786 + * debian/control: Improved depends and conflicts to mysql-4.0. + + -- Christian Hammers Thu, 2 Dec 2004 22:02:28 +0100 + +mysql-dfsg-4.1 (4.1.7-3) unstable; urgency=low + + * Raised version to make it higher as the one in experimental. + + -- Christian Hammers Wed, 1 Dec 2004 21:09:20 +0100 + +mysql-dfsg-4.1 (4.1.7-2) unstable; urgency=low + + * Patched scripts/mysql_install_db so that it no longer creates a + passwordless test database during installation (thanks to Patrick + Schnorbus). Closes: #281158 + * Added Czech debconf translation (thanks to Miroslav Kure). + Closes: #283222 + + -- Christian Hammers Wed, 1 Dec 2004 01:29:31 +0100 + +mysql-dfsg-4.1 (4.1.7-1) unstable; urgency=low + + * New upstream branch! + * Adjusted debian/control to make this package suitable to get parallel + to version 4.0.x into unstable and sarge. The package names are + different so that "mysql-server" still defaults to the rock-stable + 4.0 instead to this announced-to-be-stable 4.1. + * Added --with-mutex=i86/gcc-assemler to the Berkeley-DB configure + to prevent the use of NPLT threads when compiling under kernel 2.6 + because the binaries are else not runable on kernel 2.4 hosts. + Closes: #278638, #274598 + + -- Christian Hammers Sun, 31 Oct 2004 20:15:03 +0100 + +mysql-dfsg (4.1.6-1) experimental; urgency=low + + * New upstream version. + * Fixed symlinks in libmysqlclient-dev package. Closes: #277028 + * This time I did not update the libtool files as they were pretty + up to date and I want to have a shorter diff file. + + -- Christian Hammers Wed, 20 Oct 2004 00:07:58 +0200 + +mysql-dfsg (4.1.5-3) experimental; urgency=low + + * debian/postinst: mysql_install_db changed parameter from --IN-RPM + to --rpm which caused problems during installs. Closes: #276320 + + -- Christian Hammers Sat, 16 Oct 2004 20:36:46 +0200 + +mysql-dfsg (4.1.5-2) experimental; urgency=low + + * Activated support for ndb clustering (thanks to Kevin M. Rosenberg). + Closes: #275109 + + -- Christian Hammers Wed, 6 Oct 2004 01:58:00 +0200 + +mysql-dfsg (4.1.5-1) experimental; urgency=low + + * WARNING: + The upstream branch 4.1 is still considered BETA. + The Debian packages for 4.1 were done without big testing. If you miss + a new functionality or binary, contact me and I check add the relevant + configure option or include the program. + * New MAJOR upstream version. + Thanks to the great demand here's now the first MySQL 4.1 experimental + release. FEEDBACK IS WELCOME. + * 4.0->4.1 notes: + - debian/patches/alpha.diff could not be applied, I fix that later + - debian/patches/scripts__mysql_install_db.sh.diff was obsolete + - debian/patches/scripts__Makefile.in was neccessary due to a dependency + to the removed non-free Docs/ directory. Upstream has been contacted. + - Build-Deps: += automake1.7 + - debian/rules: embedded servers examples did not compile, removed + + -- Christian Hammers Sun, 26 Sep 2004 19:46:47 +0200 + +mysql-dfsg (4.0.21-3) unstable; urgency=low + + * Upstream tried to fix a security bug in mysqlhotcopy and broke it :-) + Applied a patch (see debian/patches) from Martin Pitt. Closes: #271632 + * Between 4.0.20 and 4.0.21 the Debian specific changes in + /usr/bin/mysqld_safe that piped the error log to syslog got lost + and are now back again. + * Fixed capitalization in debconf headings. + * Changed wording of the initscript status message to make heartbeat + happier. Closes: #271591 + + -- Christian Hammers Fri, 17 Sep 2004 18:42:25 +0200 + +mysql-dfsg (4.0.21-2) unstable; urgency=medium + + * The dependencies between mysql-client and libmysqlclient12 were + too loose, when upgrading only the client this can lead to non working + binaries due to relocation errors (thanks to Dominic Cleal). + Closes: #271803 + * Fixed typo in mysqldump.1 manpage (thanks to Nicolas Francois). + Closes: #271334 + + -- Christian Hammers Wed, 15 Sep 2004 15:38:11 +0200 + +mysql-dfsg (4.0.21-1) unstable; urgency=high + + * SECURITY: + This upstream version fixes some security problems that might at least + allow a DoS attack on the server. + * Fixed an old bug in concurrent accesses to `MERGE' tables (even + one `MERGE' table and `MyISAM' tables), that could've resulted in + a crash or hang of the server. (Bug #2408) + * Fixed bug in privilege checking where, under some conditions, one + was able to grant privileges on the database, he has no privileges + on. (Bug #3933) + * Fixed crash in `MATCH ... AGAINST()' on a phrase search operator + with a missing closing double quote. (Bug #3870) + * Fixed potential memory overrun in `mysql_real_connect()' (which + required a compromised DNS server and certain operating systems). + (Bug #4017) + * New upstream version. + * Fixes bug that made x="foo" in WHERE sometimes the same as x="foo ". + Closes: #211618 + * Updated Japanese Debconf translation (thanks to Hideki Yamane). + Closes: #271097 + + -- Christian Hammers Sat, 11 Sep 2004 23:15:44 +0200 + +mysql-dfsg (4.0.20-14) unstable; urgency=low + + * Dave Rolsky spottet that -DBIG_JOINS was not properly enabled. + It allowes joining 64 instead of an 32 tables to join. + + -- Christian Hammers Thu, 9 Sep 2004 20:24:02 +0200 + +mysql-dfsg (4.0.20-13) unstable; urgency=medium + + * Fixed a bug in the initscript which caused the check for not properly + closed i.e. corrupt tables that is executed when the server starts + not to run in background as supposed. + Although the check does not repair anything on servers with several + thousand tables the script was reported to take some minutes which + is quite annoying. (Thanks to Jakob Goldbach). Closes: #270800 + + -- Christian Hammers Thu, 9 Sep 2004 17:11:05 +0200 + +mysql-dfsg (4.0.20-12) unstable; urgency=medium + + * Filter messages regarding table handles that do not support CHECK TABLE + in the script that checks for corrupted tables on every start which lead + to unnecessary mails (thanks to David Everly). Closes: #269811 + * Added a note to the corrupt-table-check mail which notes that a + false-positive is reported in the case that immediately after starting + the server a client starts using a table (thanks to Uwe Kappe). + Closes: #269985 + * Added "quote-names" as default to the [mysqldump] section in + /etc/mysql/my.cnf as too many users stumble over dump files that + could not be read in again due to the valid use of reserved words + as table names. This has also be done by upstream in 4.1.1 and has + no known drawbacks. Closes: #269865 + * Binary logs can now be rotated as well. Defaults to off, though, for + compatibilty reasons (thanks to Mark Ferlatte). Closes: #94230, #269110 + * The mysql user "debian-sys-maint" now gets all possible rights which + makes binary logging possible and helps other package maintainer who + wants to use it to create package specific databases and users. + * Added example how to change daemon nice level via /etc/mysql/my.cnf + * Updated French debconf translations (thanks to Christian Perrier). + Closes: #265811 + * Renamed options in the default config file that still had old names + (thanks to Yves Kreis). Closes: #266445 + * Fixed spelling in debconf note. + * Added -l and -L to dh_shlibdeps. + + -- Christian Hammers Fri, 3 Sep 2004 20:10:46 +0200 + +mysql-dfsg (4.0.20-11) unstable; urgency=high + + * SECURITY + This version fixes a security flaw in mysqlhotcopy which created + temporary files in /tmp which had predictable filenames and such + could be used for a tempfile run attack. + The issue has been recorded as CAN-2004-0457. + + -- Christian Hammers Sat, 14 Aug 2004 18:27:19 +0200 + +mysql-dfsg (4.0.20-10) unstable; urgency=low + + * MySQL finally updated their copyright page and installed v1.5 of + the "Free/Libre and Open Source Software License (FLOSS) - Exception" + which will hopefully end the license hell they created by putting the + client libraries under GPL instead of LGPL which conflicts with PHP and + other software that used to link against MySQL. + The license text is not yet in any release MySQL version but visible + on their web site and copied into the debian/copyright file. + Special thanks to Zak Greant and the debian-legal list + for helping to solve this release critical problem. + Closes: #242449 + * Updated Brazil debconf translation (thanks to Andre Luis Lopes). + Closes: #264233 + * Updated Japanese debconf translation (thanks to Hideki Yamane). + Closes: #264620 + * Fixed minor typo in debconf description (thanks to TROJETTE Mohammed + Adnene). Closes: #264840 + * Improved init and preinst script which now detects stalled servers which + do no longer communicate but are present in the process list (thanks to + Henrik Johansson). Closes: #263215 + + -- Christian Hammers Mon, 9 Aug 2004 19:44:28 +0200 + +mysql-dfsg (4.0.20-9) unstable; urgency=medium + + * Partly reverted the last patch which gave the mysql-user + "debian-sys-maint" more rights as there are old versions of MySQL which + have fewer privlige columns. Now only those are set (thanks to Alan Tam). + Closes: #263111 + + -- Christian Hammers Tue, 3 Aug 2004 13:03:02 +0200 + +mysql-dfsg (4.0.20-8) unstable; urgency=low + + * The mysqlcheck that is started from the initscript will now be + backgrounded because it might else prevent the boot process to continue. + It also now notifies root by mail and syslog if a table is corrupt. + * The "debian-sys-maint" MySQL user now has almost full rights so that other + packages might use this account to create databases and user (thanks to + Andreas Barth). Closes: #262541 + * Added paranoid rules for logcheck. + + -- Christian Hammers Sun, 1 Aug 2004 21:00:55 +0200 + +mysql-dfsg (4.0.20-8) unstable; urgency=low + + * Upload stalled. Not released. + + -- Christian Hammers Sun, 1 Aug 2004 20:27:55 +0200 + +mysql-dfsg (4.0.20-7) unstable; urgency=medium + + * Solved the upstream bug that error messages of the server are written + in a file that is then rotated away leaving mysqld logging effectively + to /dev/null. It now logs to a /usr/bin/logger process which puts the + messages into the syslog. + Modified files: /etc/init.d/mysql, /usr/bin/mysqld_safe and the + logchecker files. Closes: #254070 + * The initscript does no longer call mysqlcheck directly but via + /etc/mysql/debian-start which is a user customizable config script. + * Splitted the debconf "install and update notes" and only show them + when it is appropriate (thanks to Steve Langasek). Closes: #240515 + * Added NEWS.Debian. + * Added hint to -DBIG_ROWS, which is currently not used, to README.Debian. + * Corrected typo in myisampack manpage (thanks to Marc Lehmann). + Closes: #207090 + * Added Catalan debconf translation (thanks to Aleix Badia i Bosch). + Closes: #236651 + + -- Christian Hammers Wed, 28 Jul 2004 01:41:51 +0200 + +mysql-dfsg (4.0.20-6) unstable; urgency=low + + * The build arch detected by configure was "pc-linux-gnu (i686)" + instead of "pc-linux-gnu (i386)". Was no problem AFAIK but + Adam Majer asked me to explicitly change it to i386. Closes: #261382 + * Removed some unused shell scripts from /usr/share/mysql. + * Added lintian overrides. + * Removed rpath by using chrpath. + + -- Christian Hammers Mon, 26 Jul 2004 00:17:12 +0200 + +mysql-dfsg (4.0.20-5) unstable; urgency=medium + + * The mysqlcheck in the init script is only called when the server + is really alive. Also, the mysql-user 'debian-sys-maint' now has + global select rights (thanks to Nathan Poznick). Closes: #261130 + * Moved the debconf question whether to remove the databases or not + from mysql-server.config to mysql-server.postrm so that it shows + up on purge time and not months earlier (thanks to Wouter Verhelst). + Closes: #251838 + + -- Christian Hammers Fri, 23 Jul 2004 22:41:13 +0200 + +mysql-dfsg (4.0.20-4) unstable; urgency=low + + * Added a "mysqlcheck -A --fast" to the 'start' section of the + init script to help admins detect corrupt tables after a server crash. + Currently it exists with an error message but leaves the server + running. Feedback appreciated! + * Made postinst script more robust by calling db_stop earlier and + so prevent pipe-deadlocks. + * Fixed minor typos in initscript (thanks to "C.Y.M."). Closes: 259518 + * Added the undocumented "-DBIG_JOINS" that MySQL apparently uses in + their MAX binaries. It enables 62 instead of 30 tables in a "join". + (thanks to Dave Rolsky). Closes: #260843 + * Added a "df --portability /var/lib/mysql/." check to the preinst + script as users experienced hard to kill hanging mysqlds in such + a situation (thanks to Vaidas Pilkauskas). Closes: #260306 + + -- Christian Hammers Fri, 23 Jul 2004 00:51:32 +0200 + +mysql-dfsg (4.0.20-3) unstable; urgency=low + + * Improved tolerance if the init script has been deleted (thanks to + Leonid Shulov for spotting the problem). + * Minor wording changes to README.Debian generalizing /root/ by $HOME + (thanks to Santiago Vila). Closes: #257725 + * Added Japanese debconf translation (thanks to Hideki Yamane). + Closes: #256485 + * Fixed commend in my.cnf regarding logfile directory (thanks to Jayen + Ashar). Closes: #253434 + * Correted "ease to" by "ease of" in package description (thanks to + Johannes Berg). Closes: #253510 + + -- Christian Hammers Fri, 9 Jul 2004 00:57:42 +0200 + +mysql-dfsg (4.0.20-2) unstable; urgency=low + + * Removed RPM .spec file from the included documentation as it is pretty + useless (thanks to Loic Minier). + * Added turkish debconf translation (thanks to Recai Oktas). Closes: #252802 + + -- Christian Hammers Sun, 6 Jun 2004 14:48:26 +0200 + +mysql-dfsg (4.0.20-1) unstable; urgency=low + + * New upstream version. + + -- Christian Hammers Mon, 31 May 2004 23:36:39 +0200 + +mysql-dfsg (4.0.18-8) unstable; urgency=low + + * Updated french translation (thanks to Christian Perrier). Closes: #246789 + + -- Christian Hammers Tue, 4 May 2004 23:26:54 +0200 + +mysql-dfsg (4.0.18-7) unstable; urgency=low + + * Added CVE ids for the recent security fixes. + 4.0.18-4 is CAN-2004-0381 (mysqlbug) and + 4.0.18-6 is CAN-2004-0388 (mysql_multi) + + -- Christian Hammers Mon, 19 Apr 2004 18:32:03 +0200 + +mysql-dfsg (4.0.18-6) unstable; urgency=medium + + * SECURITY: + Fixed minor tempfile-run security problem in mysqld_multi. + Unprivileged users could create symlinks to files which were then + unknowingly overwritten by run when this script gets executed. + Upstream informed. Thanks to Martin Schulze for finding this. + + -- Christian Hammers Wed, 7 Apr 2004 01:28:22 +0200 + +mysql-dfsg (4.0.18-5) unstable; urgency=low + + * Little improvements in debian scripts for last upload. + * Added check to logrotate script for the case that a mysql + server is running but not be accessible with the username and + password from /etc/mysql/debian.conf (thanks to Jeffrey W. Baker). + Closes: 239421 + + -- Christian Hammers Sun, 4 Apr 2004 15:27:40 +0200 + +mysql-dfsg (4.0.18-4) unstable; urgency=medium + + * SECURITY: + Aplied fix for unprobable tempfile-symlink security problem in + mysqlbug reported by Shaun Colley on bugtraq on 2004-03-24. + * Updated french debconf translation (thanks to Christian Perrier). + Closes: #236878 + * Updated portugesian debconf translation (thanks to Nuno Senica). + Closes: #239168 + * Updated german debconf translation (thanks to Alwin Meschede). + Closes: #241749 + * Improved debconf template regarding fix_privileges_tables (thanks + to Matt Zimmermann for suggestions). Closes: #219400 + * Improved README.Debian regarding to password settings (thanks to + Yann Dirson). Closes: #241328 + + -- Christian Hammers Sat, 3 Apr 2004 19:52:15 +0200 + +mysql-dfsg (4.0.18-3) unstable; urgency=medium + + * Added Build-Depend to po-debconf to let it build everywhere. + + -- Christian Hammers Wed, 31 Mar 2004 23:43:33 +0200 + +mysql-dfsg (4.0.18-2) unstable; urgency=low + + * Added a "2>/dev/null" to a "which" command as there are two + "which" versions in Debian of which one needs it. Closes: #235363 + + -- Christian Hammers Tue, 2 Mar 2004 23:31:28 +0100 + +mysql-dfsg (4.0.18-1) unstable; urgency=low + + * New upstream version. + * Should now compile and run on ia64 (thanks to Thorsten Werner and + David Mosberger-Tang). Closes: #226863 #228834 + * Converted init scripts to invoce-rc.d (thanks to Erich Schubert). + Closes: 232118 + * Secondlast upload changed logfile location. Closes: #182655 + * Updated Brasilian translation (thanks to Andre Luis Lopes). Closes: + #219847 + + -- Christian Hammers Tue, 17 Feb 2004 23:44:58 +0100 + +mysql-dfsg (4.0.17-2) unstable; urgency=low + + * Improved manpage for mysqldumpslow.1 (thanks to Anthony DeRobertis). + Closes: #231039 + * Improved stopping of crashed daemons in init script (thanks to + Matthias Urlichs). Closes: #230327 + + -- Christian Hammers Mon, 9 Feb 2004 21:54:29 +0100 + +mysql-dfsg (4.0.17-1) unstable; urgency=low + + * Made logging into /var/log/mysql/ the default. Closes: #225206 + + * New upstream version. Closes: #225028 + * Turned on a 25MB query cache by default (thanks to Cyril Bouthors). + Closes: #226789 + * Updated russian translation (thanks to Ilgiz Kalmetev). Closes: #219263 + * Upstream fixes the problem that AND was not commutative (thanks for + Iain D Broadfoot for mentioning). Closes: #227927 + * Fixed minor typo in my.cnf comments (thanks to James Renken). + Closes: #221496 + * Better documents regex. Closes: #214952 + * Fixed minor germanism in debconf template (thanks to Marc Haber). + Closes: #224148 + * Added explaining comment to my.cnf regarding quoted passwords + (Thanks to Patrick von der Hagen). Closes: #224906 + * Changed "find -exec" to "find -print0 | xargs -0" in preinst to + speed it up. Thanks to Cyril Bouthors. Closes: #220229 + + -- Christian Hammers Sun, 18 Jan 2004 16:16:25 +0100 + +mysql-dfsg (4.0.16-2) unstable; urgency=low + + * Tried to repair undefined weak symbols by adding a little Makefile + patch. Closes: #215973 + + -- Christian Hammers Mon, 27 Oct 2003 22:52:10 +0100 + +mysql-dfsg (4.0.16-1) unstable; urgency=low + + * New upstream release. + (Mostly little memory problems and other bugfixes it seems) + * Replaced "." by ":" in chown calls to comply with the env setting + "_POSIX2_VERSION=2000112" (thanks to Robert Luberda). Closes: #217399 + * Adjusted syntax in my.cnf to 4.x standard (thanks to Guillaume Plessis). + Closes: #217273 + * Improved README.Debian password instructions (thanks to Levi Waldron). + Closes: #215046 + * Improved NIS warning debconf-template (thanks to Jeff Breidenbach). + Closes: #215791 + * Explicitly added libssl-dev to the libmysqlclient-dev package as it + is needed for mysql_config and the libmysqlclient package only depends + on libssl which has no unnumbered .so version (thanks to Simon Peter + and Davor Ocelic). Closes: #214436, #216162 + * Added "-lwrap" to "mysql_config --libmysqld-libs" and filed it as + upstream bug #1650 (thanks to Noah Levitt). Closes: #214636 + + -- Christian Hammers Sat, 25 Oct 2003 01:09:27 +0200 + +mysql-dfsg (4.0.15a-1) unstable; urgency=low + + * Same package as 4.0.15-2 but I could not convince the Debian + installer to move the packages out of incoming. + + -- Christian Hammers Tue, 7 Oct 2003 15:10:26 +0200 + +mysql-dfsg (4.0.15-2) unstable; urgency=low + + * Updated package description (thanks to Adrian Bunk). Closes: #210988 + * Fixed small typos in manpages (thanks to Nicolas Francois). + Closes: #211983 + * More updates to package description (thanks to Matthias Lutz/ddtp). + Closes: #213456 + * Updated standards to 3.6.1. + * Closes "new 4.0.15 available" bug. Closes: #213349 + * Updated README.Debian with notes regarding the MySQL manual section + "2.4 Post-installation Setup and Testing" (thanks to Daniel B.). + Closes: #210841 + + -- Christian Hammers Fri, 3 Oct 2003 15:59:39 +0200 + +mysql-dfsg (4.0.15-1) unstable; urgency=high + + * SECURITY: + Users who are able to use the "ALTER TABLE" command on the "mysql" + database may be able to exploit this vulnerability to gain a shell with + the privileges of the mysql server (usually running as the 'mysql' user). + Closes: #210403 + * Fixes small description typos (thanks to Oscar Jarkvik). + * Updated Brazilian Portuguese debconf translation. (thanks to Andre Luis + Lopes). Closes: 208030 + * Replaced depricated '.' by ':' in chown (thanks to Matt Zimmerman). + * Fixed manpage typo (thanks to Marc Lehmann). Closes: #207090 + + -- Christian Hammers Fri, 3 Oct 2003 15:59:35 +0200 + +mysql-dfsg (4.0.14-1) unstable; urgency=low + + * New upstream version. + + -- Christian Hammers Sun, 24 Aug 2003 16:40:36 +0200 + +mysql-dfsg (4.0.13-3) unstable; urgency=low + + * Now start mysqld as default unless you choose not when configurig + with debconf priority low. So packages depending on the server when + installing can access it. Thanks Matt Zimmermann (Closes: #200277) + * Made mysql-server de-installable if the config and database files were + removed by hand before. Thanks to Ard van Breemen (Closes: #200304) + + -- Christian Hammers Tue, 8 Jul 2003 22:30:40 +0200 + +mysql-dfsg (4.0.13-2) unstable; urgency=low + + * Added "nice" option for mysqld_safe to give mysqld a different priority. + Submitted to upstream as MySQL Bug #627. Closes: #192087 + * Fixed possible unbound variable in init script. Closes: #194621 + * Fixed french debconf translation (thx Christian Perrier) Closes: #194739 + * Get rid of automake1.5 (for Eric Dorland). + + -- Christian Hammers Wed, 11 Jun 2003 18:58:32 +0200 + +mysql-dfsg (4.0.13-1) unstable; urgency=medium + + * New upstream version. + !!! Fixes a very bad natural join bug which justifies the urgency=medium. + !!! http://bugs.mysql.com/bug.php?id=291 + * Fixed mysql_fix_privileges manpage (Frederic Briere) Closes: #191776 + * preinst: "which" is more chatty normal executable than as builtin. + (Thanks to David B Harris). Closes: #188659 + + -- Christian Hammers Tue, 6 May 2003 22:03:45 +0200 + +mysql-dfsg (4.0.12-3) unstable; urgency=medium + + * Reincluded new way of creating my debian-sys-maint user from + an old release from experimental. Now works again with old + and new privilege table format. (Thanks to Vincent Danjean + for spotting the problem) Closes: #188201 + * Reincluded hurd build dependency fix from 3.23 branch. + (Thanks to Robert Millan). Closes: #185929 + * Fixed soname in libmysqlclient-dev. Closes: #188160 + * Remove /var/log/mysql/ when purging the package. Closes: #188064 + * Removed /usr/share/doc/mysql/ from mysql-server. Closes: #188066 + * Let group "adm" be able to read logfiles. Closes: #188067 + * Do not call usermod on every upgrade. Closes: #188248 + (Thanks to Philippe Troin for the last three) + * Fixed mysql-server.preinst so that it works on shells where + which is a builtin, too. (Thanks to Erich Schubert) Closes: #181525 + + -- Christian Hammers Fri, 11 Apr 2003 11:32:45 +0200 + +mysql-dfsg (4.0.12-2) unstable; urgency=low + + * + * NEW MAJOR UPSTREAM RELEASE: + * + MySQL 4 has finally been declared as 'stable'. Hurray! Read changelogs. + Thanks to all testers, esp. Jose Luis Tallon, of the versions + that were in the "experimental" section before. + * Modified postinst script to run mysql_fix_privileges on every update. + IMPORTANT: Please report if this breaks anything, it is not supposed to. + * Wrote a SSL-MINI-HOWTO.txt! + * Added zlib1g-dev to libmysqlclient12-dev. Closes: 186656 + * Changed section of libmysqlclient12-dev to libdevel. + * Added even more selfwritten manpages. + * Fixed typos. + + -- Christian Hammers Sun, 6 Apr 2003 13:47:32 +0200 + +mysql-dfsg (4.0.10.gamma-1) experimental; urgency=low + + * New upstream version. + * They merged some of my patches from debian/patches. Whoa! + * This release should fix the error-logfile problem where mysqld + keeps the error.log open while logrotate removes it. + + -- Christian Hammers Wed, 12 Feb 2003 22:39:48 +0100 + +mysql-dfsg (4.0.9.gamma-1) experimental; urgency=low + + * New upstream version. + * Updated the GNU autoconf files to make building on MIPS work. + See bug #176829. + + -- Christian Hammers Wed, 29 Jan 2003 22:07:44 +0100 + +mysql-dfsg (4.0.8.gamma-1) experimental; urgency=low + + * New upstream release. + * Improved logging of init script. Closes: #174790 + * We have now libmysqlclient.so.12 instead of .11. + + -- Christian Hammers Thu, 9 Jan 2003 20:14:11 +0100 + +mysql-dfsg (4.0.7.gamma-1) experimental; urgency=high + + * SECURITY: This version fixes an upstream security release that is only + present in the 4.x branch which is currently only in the + experimental distribution and therefore will not get a DSA. + * New upstream release. + + -- Christian Hammers Sat, 28 Dec 2002 15:51:39 +0100 + +mysql-dfsg (4.0.6.gamma-2) experimental; urgency=low + + * Added --system to addgroup. Closes: #173866 + + -- Christian Hammers Sat, 21 Dec 2002 15:28:26 +0100 + +mysql-dfsg (4.0.6.gamma-1) experimental; urgency=low + + * New upstream version. Now Gamma! + * There are no longer changes to the .orig.tar.gz neccessary to make diff + happy. docs/ has still to be deleted, although, as it is non-free. + * Incorporated patches from unstable. + * Added mysqlmanager and a couple of other new scripts. + * Enabled libmysqld embedded server library. + * Enabled SSL and Virtual-IO support. + (CORBA based MySQL-FS seems to be not existing..) + + -- Christian Hammers Fri, 20 Dec 2002 22:30:51 +0100 + +mysql-dfsg (4.0.5a.beta-3) experimental; urgency=low + + * Modified postinst to work with old and new mysql.user table format + and fixed spelling typo in postinst. Thanks to Roger Aich. + * Updated config.{guess,sub} to make the mipsel porters happy. + Thanks to Ryan Murray. Closes: #173553 + + -- Christian Hammers Wed, 18 Dec 2002 15:56:34 +0100 + +mysql-dfsg (4.0.5a.beta-2) experimental; urgency=low + + * Upstream removed option "--skip-gemini". So did I. Closes: 173142 + + -- Christian Hammers Tue, 17 Dec 2002 10:35:49 +0100 + +mysql-dfsg (4.0.5a.beta-1) experimental; urgency=low + + * First 4.x experimental package due to continuous user requests :-) + Please test and report! + * upstream: safe_mysqld has been renamed to mysqld_safe + * upstream: new library soname version libmysqlclient.so.11 + * Renamed libmysqlclientXX-dev to libmysqlclient-dev as I don't plan to + support more than one development environment and this makes the + dependencies easier. + * FIXME: Skipped parts of the debian/patches/alpha patch as the global.h + is not existing. + * FIXME: How to get rid this? Old ltconfig patch already applied. + "lintian: binary-or-shlib-defines-rpath ./usr/bin/mysql /usr/lib/mysql" + + -- Christian Hammers Sun, 1 Dec 2002 18:32:32 +0100 + +mysql-dfsg (3.23.53-4) unstable; urgency=medium + + * Fixed errno.h problem. Closes: #168533, #168535 + + -- Christian Hammers Sun, 10 Nov 2002 18:32:08 +0100 + +mysql-dfsg (3.23.53-3) unstable; urgency=medium + + * Changed automake build-dep to unversioned automake1.4. Closes: #166391 + * Fixed description. Closes: #167270 + (Thanks to Soren Boll Overgaard) + + -- Christian Hammers Tue, 5 Nov 2002 01:25:01 +0100 + +mysql-dfsg (3.23.53-2) unstable; urgency=low + + * Reverted user creation in init scripts. Closes: #166432 + (Thanks to Birzan George Cristian) + + -- Christian Hammers Thu, 31 Oct 2002 15:36:25 +0100 + +mysql-dfsg (3.23.53-1) unstable; urgency=low + + * New upstream release. + + -- Christian Hammers Thu, 24 Oct 2002 23:04:16 +0200 + +mysql-dfsg (3.23.52-3) unstable; urgency=low + + * Substituted the first-install 'debian-sys-maint' user creation by + something ANSI SQL compliant. Closes: #163497 + (Thanks to Karl Hammar) + * Tightend dependency to debhelper (>= 4.0.12) to be sure that + debconf-utils gets installed, too, as I use dh_installdebconf. + * Fixed upstream manpage bug in mysqldump.1. Closes: #159779 + (Thanks to Colin Watson) + * Added comment about MIN_WORD_LEN to mysql-server.README.Debian + (Thanks to Philipp Dreimann) + * Added a dependency for zlib1g-dev to libmysqlclient10-dev. + (Thanks to Jordi Mallach) + + -- Christian Hammers Sun, 15 Sep 2002 17:14:44 +0200 + +mysql-dfsg (3.23.52-2) unstable; urgency=low + + * Fixed typo in preinst scripts. + * Removed bashism in init script. + * Fixed ambiguous debconf example. Closes: #158884 + + -- Christian Hammers Fri, 30 Aug 2002 00:51:29 +0200 + +mysql-dfsg (3.23.52-1) unstable; urgency=low + + * New upstream version. Closes: #157731 + * Clearified the meaning of the debian-sys-maint special user in the + README.Debian file. Closes: #153702 + * Wrote some words regarding the skip-networking in README.Debian. + Closes: #157038 + * Added dependency to passwd. + * Fixes typo and unnecessarily complication in is_mysql_alive(). + * Added check for /etc/mysql/my.cnf in init script. + + -- Christian Hammers Tue, 27 Aug 2002 01:53:32 +0200 + +mysql-dfsg (3.23.51-4) unstable; urgency=low + + * Added a compressed "nm mysqld" output to allow people to trace + core dumps with /usr/bin/resolve_stack_dump as suggested in the + INSTALL-SOURCE file. Thanks to atudor@labs.agilent.com for the hint. + + -- Christian Hammers Wed, 24 Jul 2002 20:44:55 +0200 + +mysql-dfsg (3.23.51-3) unstable; urgency=low + + * Corrected copyright file: the MySQL client library is licenced under + the LGPL-2 not the GPL. From version 4.x it actually will be GPL this + is why parts of http://www.mysql.com/ already say so. Closes: #153591 + * Corrected german translation. + Thanks to Roland Rosenfeld . Closes: #151903 + + -- Christian Hammers Thu, 11 Jul 2002 20:32:28 +0200 + +mysql-dfsg (3.23.51-2) unstable; urgency=low + + * Improved NIS tolerance in preinst script. + + -- Christian Hammers Sun, 7 Jul 2002 04:43:28 +0200 + +mysql-dfsg (3.23.51-1) unstable; urgency=medium + + * New upstream version. + * I applied a patch that fixes a binary imcompatibility in + the shared libary libmysqlclient.so.10 between 3.23.50 and + some versions earlier. Upstream has been contacted and asked + for clarification. Closes: #149952 + * Added support for NIS i.e. it shows a warning and fails if the + needed 'mysql' user does not exists but works if it does. + Closes: #143282, #147869 + * Substituted $0 in init scripts by something really weird so that + "./S20mysql restart" works now, too. (BTW: S20? install file-rc!!!) + Closes: #148658 + * Now postinst works even if /etc/init.d/mysql is removed. Closes: #151021 + * Decided to leave "set +x" in postinst but wrote comment. Closes: #151022 + + -- Christian Hammers Sun, 7 Jul 2002 04:43:25 +0200 + +mysql-dfsg (3.23.50-1) unstable; urgency=medium + + * New upstream version. + Fixes a very annoying and important bug that lets all mysql programs + including perl scripts etc. segfault when using the read_default_group() + function. 3.23.50 is currently a pre-release and expected to be released + next week. I plan to propose it for woody as soon as its stability has + been proven. The following bug reports are all regarding this issue. + Closes: #144960, #145322, #136798, #138143, + + -- Christian Hammers Sat, 18 May 2002 21:14:01 +0200 + +mysql-dfsg (3.23.49x-1) unstable; urgency=low + + * I had to split the package to seperate the manual as it is not GPL + like the rest of the software and docs but under a license that + e.g. forbids selling printed versions. + . + The upstream authors were contacted a while ago but did not like to + change the situation. + . + The names of the resulting packages have not changed as the manual + already was in a seperate mysql-doc package due to it's size. + The source packages are now splitted from one "mysql" to + "mysql-dfsg" in main and "mysql-nonfree" in non-free. + * No code change! + The "x" at the end of the version number ist just to be able to + upload a new source package. ("a" was already taken by upstream + for their binary upload correction) + + -- Christian Hammers Wed, 8 May 2002 02:01:41 +0200 + +mysql (3.23.49-8) unstable; urgency=low + + * Substituted $0 in init script to let e.g. "/etc# ./init.d/mysql restart" + works, too. Closes: #141555 + + -- Christian Hammers Sun, 7 Apr 2002 15:00:44 +0200 + +mysql (3.23.49-7) unstable; urgency=low + + * The Makefiles are totally broken for the --enable-local-infile + option. I now patched libmysql/libmysql.c#mysql_init() manually. + Closes: #138347 + + -- Christian Hammers Fri, 29 Mar 2002 23:55:15 +0100 + +mysql (3.23.49-6) unstable; urgency=low + + * Moved mysqlcheck from server to client package. Closes: #139799 + * Added manpage for mysqlhotcopy. Regarding: #87097 + * Added 'sharedscripts' directive to the logrotate script. + * Replaced grep by /usr/bin/getent to let the group/user checking work + on NIS/LDAP systems, too. Closes: #115677, #101529 + + -- Christian Hammers Fri, 22 Mar 2002 22:40:51 +0100 + +mysql (3.23.49-5) unstable; urgency=low + + * Added skip-innodb to default my.cnf. + * Enabled --enable-local-infile, it seems to be a new option that + defaults to disable a formerly enabled feaure. Closes: #137115 + + -- Christian Hammers Sat, 16 Mar 2002 00:29:10 +0100 + +mysql (3.23.49-4) unstable; urgency=medium + + * Recompiled against fixed libz. + + * Enabled --enable-local-infile, it seems to be a new option that + defaults to disable a formerly enabled feaure. Closes: #137115 + * Fixed README.compile_on_potato. Closes: #136529 + * Now a ext3 .jounal file in /var/lib/mysql does not prevent the + installation (happens when creating a jounal on an already mounted + partition). Closes: #137146 + + -- Christian Hammers Wed, 13 Mar 2002 13:34:24 +0100 + +mysql (3.23.49-3) unstable; urgency=low + + * Added Russian translation. Closes: #135846 + * Fixed installation of .info documents. Closes: #135030 + + -- Christian Hammers Wed, 27 Feb 2002 23:36:35 +0100 + +mysql (3.23.49-2) unstable; urgency=low + + * Updated french translation and split template files. Closes: #134754 + * Fixed a small debian.cnf related bug in mysql-server.postinst. + + -- Christian Hammers Tue, 19 Feb 2002 23:13:58 +0100 + +mysql (3.23.49-1) unstable; urgency=low + + * New upstream release. + (Mainly InnoDB related fixes) + * Exported a $HOME variable in the scripts so that /root/.my.cnf + is not read anymore. This will avoid problems when admins put + only passwords but no usernames in this file. Closes: #132048 + * New debian-sys-maint password algorithm (now ~96bit :-)) Closes: #133863 + * Recreating debian-sys-main pwd on every install to help people who + accidently delete user or password files... + * Added /var/log/mysql so that user can put the binary logs in there as + mysql cannot write the .001 etc files itself in /var/log which is + owned by root. + + -- Christian Hammers Thu, 14 Feb 2002 22:17:45 +0100 + +mysql (3.23.47-6) unstable; urgency=low + + * Dropped a sentence about the new debian-sys-maint user in the + debconf note and updated the README.Debian. Related: #132048 + * Added more french translation. Closes: #132390 + + -- Christian Hammers Wed, 6 Feb 2002 09:41:29 +0100 + +mysql (3.23.47-5) unstable; urgency=low + + * Fixed grammar error in template. Closes: #132238 + * Really fixed typo in logrotate script. Closes: #131711 + + -- Christian Hammers Tue, 5 Feb 2002 14:20:08 +0100 + +mysql (3.23.47-4) unstable; urgency=medium + + * Fixes typo in postinst that let init script fail. Closes: #131743 + * Fixed bashism bug that failed on ash. Closes: #131697 + * Fixed typo in logrotate script. Closes: #131711 + + -- Christian Hammers Thu, 31 Jan 2002 23:58:46 +0100 + +mysql (3.23.47-3) unstable; urgency=low + + * Added new Debian specific mysql user called 'debian-sys-maint' which + is used for pinging the server status, flushing the logs or shutting + down the server in maintenance scripts. The credentials of this user + are stored in the UID0-only readable file /etc/mysql/debian.cnf. + Closes: #129887, #130326, #99274 + * Fixed unintended server startup at boottime. Closes: #122676, #130105 + * New upstream fixes command line parsing bug: Closes: #128473 + * Fixed manpage headers to let apropos work: Closes: #119122 + * Added "status" options for /etc/init.d/mysql. Closes: #129020 + + -- Christian Hammers Sun, 27 Jan 2002 19:46:11 +0100 + +mysql (3.23.47-2) unstable; urgency=low + + * Enhanced init scripts by using mysqladmin instead of kill $pid. + Thanks to Aaron Brick. + + -- Christian Hammers Fri, 18 Jan 2002 01:42:23 +0100 + +mysql (3.23.47-1) unstable; urgency=low + + * New upstream release. + * Updated brazilian translation of debconf descriptions. Closes: #123332 + + -- Christian Hammers Sun, 6 Jan 2002 21:11:17 +0100 + +mysql (3.23.46-3) unstable; urgency=low + + * Fixed bug in postinst where a script was accidently called with + "bash -c