postgresql/contrib/reindexdb/reindexdb

253 lines
7.3 KiB
Bash

#!/bin/sh
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #
# Package : reindexdb Version : $Revision: 1.5 $
# Date : 05/08/2002 Author : Shaun Thomas
# Req : psql, sh, perl, sed Type : Utility
#
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #
# Function Definitions
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #
usage()
{
echo "$CMDNAME reindexes a PostgreSQL database."
echo
echo "Usage:"
echo " $CMDNAME [options] [dbname]"
echo
echo "Options:"
echo " -h, --host=HOSTNAME Database server host"
echo " -p, --port=PORT Database server port"
echo " -U, --username=USERNAME Username to connect as"
echo " -W, --password Prompt for password"
echo " -d, --dbname=DBNAME Database to reindex"
echo " -a, --all Reindex all databases"
echo " -t, --table=TABLE Reindex specific table only"
echo " -i, --index=INDEX Reindex specific index only"
echo " -e, --echo Show the command(s) sent to the backend"
echo " -q, --quiet Don't write any output"
echo
echo "Read the description of the SQL command REINDEX for details."
echo
exit 0
}
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #
# Program Body
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #
CMDNAME=`basename "$0"`
PATHNAME=`echo $0 | sed "s,$CMDNAME\$,,"`
# Try valiantly to get the location of psql, since you can't ever
# really know where it has been placed. We'll start by trying the
# path. If that fails, we'll try the directory where this script
# resides. Then on to whereis, and finally locate. Wish us luck.
if x=`psql -V 2>/dev/null | grep psql`; then
PSQL='psql'
elif [ -f ${PATHNAME}psql ]; then
PSQL=${PATHNAME}psql;
elif x=`whereis -b psql 2>/dev/null | sed 's/.* //'`; then
PSQL=$x
elif x=`locate -r bin/psql$ -n 1 2>/dev/null`; then
PSQL=$x
else
echo "$CMDNAME: Could not find psql to talk to postgres installation."
echo "Please make sure psql is in your path, or that this script is in"
echo "the same directory as psql was installed."
exit 1
fi
# Now, go through all of our command-line options and get each operation
# we said we'd accept in the usage listing.
while [ "$#" -gt 0 ]
do
# Show help.
case "$1" in
--help|-\?)
usage
exit 0
;;
# All of the following are postgres options. We can pass them on
# directly, without interpreting them in any way. We don't care.
# Anything that allows a space, we'll get the next *two* arguments
# and make sure to pass those along.
--host|-h|-p|--port|-U|--username)
PSQLOPT="$PSQLOPT $1 $2"
shift
;;
-h*|--host=*|-p*|--port=*|-U*|--username=*|-W|--password)
PSQLOPT="$PSQLOPT $1"
;;
# From this point on, we're setting options that are required for
# or only valid in This script. This includes which database(s) to
# reindex, which tables, or which indexes, and so on.
# Echoing. We'll *not* use this in queries we use to get lists.
--echo|-e)
ECHOOPT="-e"
;;
# Do not echo messages.
--quiet|-q)
ECHOOPT="-q"
quiet=1
;;
# Reindex all databases, all tables, all applicable indexes.
--all|-a)
alldb=1
;;
# Database to connect to, if not all of them.
--dbname|-d)
dbname="$2"
shift
;;
-d*)
dbname=`echo "$1" | sed 's/^-d/'`
;;
--dbname=*)
dbname=`echo "$1" | sed 's/^--dbname=//'`
;;
# Reindex specific Table. Disables index reindexing.
--table|-t)
table="$2"
shift
;;
-t*)
table=`echo "$1" | sed 's/^-t//'`
;;
--table=*)
table=`echo "$1" | sed 's/^--table=//'`
;;
# Reindex specific index. Disables table reindexing.
--index|-i)
index="$2"
shift
;;
-i*)
index=`echo "$1" | sed 's/^-i//'`
;;
--index=*)
index=`echo "$1" | sed 's/^--index=//'`
;;
# Yeah, no options? Whine, and show usage.
-*)
echo "$CMDNAME: invalid option: $1" 1>&2
usage;
exit 1
;;
# Finally, it's possible that the database name was just the last
# unlabeled option. So, let's get that.
*)
dbname="$1"
;;
esac
shift # Shift off each argument as we loop.
done
# Get a list of all databases we'll be using. This first case is if we
# were asked to do all databases.
if [ "$alldb" ]; then
if [ "$dbname" ] || [ "$index" ] || [ "$table" ]; then
echo "$CMDNAME: cannot reindex all databases and a specific database," 1>&2
echo " table, or index at the same time." 1>&2
exit 1
fi
# Execute a command to pull back all databases the user specified can
# connect to. That's the list we'll be using. It's also why it's
# a good idea for this to be run as a super-user.
sql='SELECT datname FROM pg_database WHERE datallowconn'
dbname=`$PSQL $PSQLOPT -q -t -A -d template1 -c "$sql"`
# Ok, if it's not all databases, make sure at least one database is
# specified before continuing.
elif [ -z "$dbname" ]; then
echo "$CMDNAME: missing required argument: database name" 1>&2
usage;
exit 1
fi
# No. We can't reindex a specific index and table at the same time.
# Complain about this, and move on.
if [ "$table" ] && [ "$index" ]; then
echo "$CMDNAME: cannot reindex a specific table and a specific index" 1>&2
echo "at the same time." 1>&2
exit 1
fi
# If index was selected, reindex that index.
if [ "$index" ]; then
$PSQL $PSQLOPT $ECHOOPT -c "REINDEX INDEX \"$index\"" -d "$dbname"
if [ "$?" -ne 0 ]; then
echo "$CMDNAME: reindex index \"$index\" failed" 1>&2
exit 1
fi
# Ok, no index. Is there a specific table to reindex?
elif [ "$table" ]; then
$PSQL $PSQLOPT $ECHOOPT -c "REINDEX TABLE \"$table\"" -d "$dbname"
if [ "$?" -ne 0 ]; then
echo "$CMDNAME: reindex table \"$table\" failed" 1>&2
exit 1
fi
# No specific table, no specific index, either we have a specific database,
# or were told to do all databases. Do it!
else
# We set IFS to newline only so that the for-loops won't misinterpret
# spaces in the lists we retrieved via psql. Note also the use of
# regclass to handle spaces, mixed-case names, and schema awareness.
sql="SELECT DISTINCT c.oid::pg_catalog.regclass FROM pg_catalog.pg_index x JOIN pg_catalog.pg_class c ON c.oid = x.indrelid JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid WHERE nspname NOT LIKE 'pg\\\\_%'"
IFS='
'
for db in $dbname; do
# Only print which database we're currently reindexing if not in
# quiet mode, and we're doing more than one database.
[ "$alldb" ] && [ -z "$quiet" ] && echo "Reindexing $db"
IFS='
'
# Get a list of non-system tables that have indexes.
tables=`$PSQL $PSQLOPT -q -t -A -d "$db" -c "$sql"`
# Ok, reindex every table in the database.
IFS='
'
for tab in $tables; do
IFS='
'
$PSQL $PSQLOPT $ECHOOPT -c "REINDEX TABLE $tab" -d "$db"
if [ "$?" -ne 0 ]; then
echo "$CMDNAME: reindex table $tab failed" 1>&2
exit 1
fi
IFS='
'
done
done
fi
exit 0