#!/bin/sh

 # Copyright (c) 2008 Pierre-Emmanuel Andre <pea@raveland.org>
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
 # are met:
 #
 # 1. Redistributions of source code must retain the above copyright
 #    notice, this list of conditions and the following disclaimer.
 # 2. The name of the author may not be used to endorse or promote products
 #    derived from this software without specific prior written permission.
 #
 # THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 # THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 # EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #

usage="usage: listlock [-H hostname] [-U username] [-d dbname] [-f]\
\n-H specifies the hostname of the machine on wich the server is running \
\n-U connect to the database as the user username \
\n-d specifies the database name name (default template1) \
\n-f Force version of PostgreSQL to X.Y (default is psql --version)\
\n\nTo see descriptions of the differents locks: \
http://www.postgresql.org/docs/8.3/interactive/explicit-locking.html"

HOST=""
DATABASE="template1"
USER=""
V=""

while getopts "H:U:f:d:h" options; do
  case $options in
    H ) HOST="-h $OPTARG";;
    U ) USER="-U $OPTARG";;
    f ) V=$OPTARG;;
    d ) DATABASE=$OPTARG;;
    h ) echo -e $usage
         exit 1;;
    \? ) echo -e $usage
         exit 1;;
    * ) echo -e $usage
          exit 1;;
  esac
done

#Get version
if [ -z $V ] ; then
    V=$(psql --version | grep PostgreSQL | awk '{print $3}')
else
    VAL=$(echo $V | sed 's/\.//' )
    if ! [[ ${#V} -eq 3 && $VAL -gt 74 && $VAL -le 85 ]] ; then
	echo "Wrong version number: $V"
	echo "Please enter something like this: $(basename $0) -f 7.4"
	exit 1
    fi
fi

#Something wrong
if [ -z $V ]; then
    echo "No version detected. Exit"
    exit 1
fi

MAJOR=$(echo $V | cut -d '.' -f 1)
MINOR=$(echo $V | cut -d '.' -f 2)

Q7="select pd.datname, relation::regclass, transaction, mode, granted, \
psa.procpid, psa.usename, psa.current_query \
from pg_locks pl \
join pg_class pc on ( (pc.relfilenode = pl.relation) and pc.relname not like 'pg_%') \
join pg_stat_activity psa on ( psa.procpid = pl.pid) \
join pg_database pd on ( pd.oid = pl.database and pd.datname = '$DATABASE') ;"

Q8="select pd.datname,pl.locktype, pl.relation::regclass,\
pl.page, pl.tuple, pl.transactionid,\
pl.classid, pl.objid, pl.objsubid,\
pl.virtualtransaction, pl.pid,\
pl.mode, pl.granted,\
psa.procpid, psa.usename, psa.current_query \
from pg_locks pl \
join pg_class pc on ( (pc.relfilenode = pl.relation) and pc.relname not like 'pg_%') \
join pg_stat_activity psa on ( psa.procpid = pl.pid) \
join pg_database pd on ( pd.oid = pl.database and pd.datname = '$DATABASE') ;"


if [[ $MAJOR -eq 7 || (  $MAJOR -eq 8 && $MINOR -eq 0  ) ]] ; then
    echo "Version < 8.1 detected"
    Q=$Q7;
elif [[ $MAJOR -eq 8 && $MINOR -ge 1 ]] ; then
    echo "Version > 8.1 detected"
    Q=$Q8
fi

psql $HOST -d $DATABASE --expanded -c "$Q"
RETURN=$?

if [ $RETURN -ne 0 ]
then
    echo "\nTry $(basename $0) -h to see help"
fi

exit $RETURN

=head1 NAME

listlock - List locks on database

=head1 SYNOPSIS

listlock [-H hostname] [-U username] [ -d name ] [-f version]

=head1 OPTIONS

=over

=item B<-H hostname>

connect to database server B<hostname>

=item B<-U username>

connect as user B<username>

=item B<-d name>

print locks of database B<name>

=item B<-f version>

force PostgreSQL version to B<version>

=back

=head1 ENVIRONMENT

B<PGDATABASE>, B<PGHOST>, B<PGPORT>, B<PGUSER> as described in psql(1).

=head1 AUTHOR

the "listlock" program: Pierre-Emmanuel Andre < pea at raveland.org>

=cut
