diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/commands/cluster.c | 32 | ||||
-rw-r--r-- | src/bin/scripts/Makefile | 5 | ||||
-rw-r--r-- | src/bin/scripts/clusterdb | 176 | ||||
-rw-r--r-- | src/test/regress/expected/cluster.out | 11 | ||||
-rw-r--r-- | src/test/regress/sql/cluster.sql | 7 |
5 files changed, 225 insertions, 6 deletions
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 7ca8e1dd329..e8d2aa7e7e3 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.86 2002/08/11 21:17:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.87 2002/08/27 03:38:27 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -45,11 +45,12 @@ typedef struct IndexInfo *indexInfo; Oid accessMethodOID; Oid *classOID; + bool isclustered; } IndexAttrs; static Oid make_new_heap(Oid OIDOldHeap, const char *NewName); static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex); -static List *get_indexattr_list(Relation OldHeap); +static List *get_indexattr_list(Relation OldHeap, Oid OldIndex); static void recreate_indexattr(Oid OIDOldHeap, List *indexes); static void swap_relfilenodes(Oid r1, Oid r2); @@ -121,7 +122,7 @@ cluster(RangeVar *oldrelation, char *oldindexname) RelationGetRelationName(OldHeap)); /* Save the information of all indexes on the relation. */ - indexes = get_indexattr_list(OldHeap); + indexes = get_indexattr_list(OldHeap, OIDOldIndex); /* Drop relcache refcnts, but do NOT give up the locks */ index_close(OldIndex); @@ -274,7 +275,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex) * return a list of IndexAttrs structures. */ static List * -get_indexattr_list(Relation OldHeap) +get_indexattr_list(Relation OldHeap, Oid OldIndex) { List *indexes = NIL; List *indlist; @@ -305,6 +306,12 @@ get_indexattr_list(Relation OldHeap) memcpy(attrs->classOID, indexForm->indclass, sizeof(Oid) * attrs->indexInfo->ii_NumIndexAttrs); + /* We'll set indisclustered at index creation time on the + * index we are currently clustering, and reset it on other + * indexes. + */ + attrs->isclustered = (OldIndex == indexOID ? true : false); + /* Name and access method of each index come from pg_class */ classTuple = SearchSysCache(RELOID, ObjectIdGetDatum(indexOID), @@ -343,6 +350,9 @@ recreate_indexattr(Oid OIDOldHeap, List *indexes) Oid newIndexOID; char newIndexName[NAMEDATALEN]; ObjectAddress object; + Form_pg_index index; + HeapTuple tuple; + Relation pg_index; /* Create the new index under a temporary name */ snprintf(newIndexName, NAMEDATALEN, "pg_temp_%u", attrs->indexOID); @@ -364,6 +374,20 @@ recreate_indexattr(Oid OIDOldHeap, List *indexes) CommandCounterIncrement(); + /* Set indisclustered to the correct value. Only one index is + * allowed to be clustered. + */ + pg_index = heap_openr(IndexRelationName, RowExclusiveLock); + tuple = SearchSysCacheCopy(INDEXRELID, + ObjectIdGetDatum(attrs->indexOID), + 0, 0, 0); + index = (Form_pg_index) GETSTRUCT(tuple); + index->indisclustered = attrs->isclustered; + simple_heap_update(pg_index, &tuple->t_self, tuple); + CatalogUpdateIndexes(pg_index, tuple); + heap_freetuple(tuple); + heap_close(pg_index, NoLock); + /* Destroy new index with old filenode */ object.classId = RelOid_pg_class; object.objectId = newIndexOID; diff --git a/src/bin/scripts/Makefile b/src/bin/scripts/Makefile index 4a574b464aa..db87a9efc01 100644 --- a/src/bin/scripts/Makefile +++ b/src/bin/scripts/Makefile @@ -5,7 +5,7 @@ # Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group # Portions Copyright (c) 1994, Regents of the University of California # -# $Header: /cvsroot/pgsql/src/bin/scripts/Makefile,v 1.15 2002/06/20 20:29:42 momjian Exp $ +# $Header: /cvsroot/pgsql/src/bin/scripts/Makefile,v 1.16 2002/08/27 03:38:27 momjian Exp $ # #------------------------------------------------------------------------- @@ -13,7 +13,8 @@ subdir = src/bin/scripts top_builddir = ../../.. include $(top_builddir)/src/Makefile.global -SCRIPTS := createdb dropdb createuser dropuser createlang droplang vacuumdb +SCRIPTS := createdb dropdb createuser dropuser createlang droplang vacuumdb \ + clusterdb all: $(SCRIPTS) diff --git a/src/bin/scripts/clusterdb b/src/bin/scripts/clusterdb new file mode 100644 index 00000000000..58430e2d6a9 --- /dev/null +++ b/src/bin/scripts/clusterdb @@ -0,0 +1,176 @@ +#!/bin/sh +#------------------------------------------------------------------------- +# +# clusterdb-- +# cluster a postgres database +# +# This script runs psql with the "-c" option to cluster +# the requested database. +# +# Copyright (c) 2002, PostgreSQL Global Development Group +# +# +# IDENTIFICATION +# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/clusterdb,v 1.1 2002/08/27 03:38:27 momjian Exp $ +# +#------------------------------------------------------------------------- + +CMDNAME=`basename "$0"` +PATHNAME=`echo "$0" | sed "s,$CMDNAME\$,,"` + +PSQLOPT= +table= +dbname= +alldb= +quiet=0 + +while [ "$#" -gt 0 ] +do + case "$1" in + --help|-\?) + usage=t + break + ;; +# options passed on to psql + --host|-h) + PSQLOPT="$PSQLOPT -h $2" + shift;; + -h*) + PSQLOPT="$PSQLOPT $1" + ;; + --host=*) + PSQLOPT="$PSQLOPT -h `echo \"$1\" | sed 's/^--host=//'`" + ;; + --port|-p) + PSQLOPT="$PSQLOPT -p $2" + shift;; + -p*) + PSQLOPT="$PSQLOPT $1" + ;; + --port=*) + PSQLOPT="$PSQLOPT -p `echo \"$1\" | sed 's/^--port=//'`" + ;; + --username|-U) + PSQLOPT="$PSQLOPT -U $2" + shift;; + -U*) + PSQLOPT="$PSQLOPT $1" + ;; + --username=*) + PSQLOPT="$PSQLOPT -U `echo \"$1\" | sed 's/^--username=//'`" + ;; + --password|-W) + PSQLOPT="$PSQLOPT -W" + ;; + --echo|-e) + ECHOOPT="-e" + ;; + --quiet|-q) + ECHOOPT="$ECHOOPT -o /dev/null" + quiet=1 + ;; + --dbname|-d) + dbname="$2" + shift;; + -d*) + dbname=`echo $1 | sed 's/^-d//'` + ;; + --dbname=*) + dbname=`echo $1 | sed 's/^--dbname=//'` + ;; + -a|--alldb) + alldb=1 + ;; +# options converted into SQL command + --table|-t) + table="$2" + shift;; + -t*) + table=`echo $1 | sed 's/^-t//'` + ;; + --table=*) + table=`echo $1 | sed 's/^--table=//'` + ;; + -*) + echo "$CMDNAME: invalid option: $1" 1>&2 + echo "Try '$CMDNAME --help' for more information." 1>&2 + exit 1 + ;; + *) + dbname="$1" + if [ "$#" -ne 1 ]; then + echo "$CMDNAME: invalid option: $2" 1>&2 + echo "Try '$CMDNAME --help' for more information." 1>&2 + exit 1 + fi + ;; + esac + shift +done + +if [ "$usage" ]; then + echo "$CMDNAME cluster all previously clustered tables in a 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 cluster" + echo " -a, --all Cluster all databases" + echo " -t, --table='TABLE[(columns)]' Cluster specific table only" + echo " -v, --verbose Write a lot of output" + echo " -e, --echo Show the command being sent to the backend" + echo " -q, --quiet Don't write any output" + echo + echo "Read the description of the SQL command VACUUM for details." + echo + echo "Report bugs to <pgsql-bugs@postgresql.org>." + exit 0 +fi + +if [ "$alldb" ]; then + if [ "$dbname" -o "$table" ]; then + echo "$CMDNAME: cannot cluster all databases and a specific one at the same time" 1>&2 + exit 1 + fi + dbname=`${PATHNAME}psql $PSQLOPT -q -t -A -d template1 -c 'SELECT datname FROM pg_database WHERE datallowconn'` + +elif [ -z "$dbname" ]; then + if [ "$PGDATABASE" ]; then + dbname="$PGDATABASE" + elif [ "$PGUSER" ]; then + dbname="$PGUSER" + else + dbname=`${PATHNAME}pg_id -u -n` + fi + [ "$?" -ne 0 ] && exit 1 +fi + +for db in $dbname +do + [ "$alldb" -a "$quiet" -ne 1 ] && echo "Clustering $db" + query="SELECT pg_class.relname, pg_class_2.relname FROM pg_class, \ + pg_class AS pg_class_2, pg_index WHERE pg_class.oid=pg_index.indrelid\ + AND pg_class_2.oid=pg_index.indexrelid AND pg_index.indisclustered" + if [ -z "$table" ]; then + tables=`${PATHNAME}psql $db $PSQLOPT -F: -P format=unaligned -t -c "$query"` + else + tables=`${PATHNAME}psql $db $PSQLOPT -F: -P format=unaligned -t -c \ + "$query AND pg_class.relname='$table'"` + fi + for tabs in $tables + do + tab=`echo $tabs | cut -d: -f1` + idx=`echo $tabs | cut -d: -f2` + ${PATHNAME}psql $PSQLOPT $ECHOOPT -c "CLUSTER $idx on $tab" -d $db + if [ "$?" -ne 0 ]; then + echo "$CMDNAME: cluster $table $db failed" 1>&2 + fi + done +done + +exit 0 diff --git a/src/test/regress/expected/cluster.out b/src/test/regress/expected/cluster.out index a76536ac8d4..6a2ba61e832 100644 --- a/src/test/regress/expected/cluster.out +++ b/src/test/regress/expected/cluster.out @@ -274,3 +274,14 @@ FROM pg_class c WHERE relname LIKE 'clstr_tst%' ORDER BY relname; clstr_tst_s_rf_a_seq | S | f (11 rows) +-- Verify that indisclustered is correctly set +SELECT pg_class.relname FROM pg_index, pg_class, pg_class AS pg_class_2 +WHERE pg_class.oid=indexrelid + AND indrelid=pg_class_2.oid + AND pg_class_2.relname = 'clstr_tst' + AND indisclustered; + relname +------------- + clstr_tst_c +(1 row) + diff --git a/src/test/regress/sql/cluster.sql b/src/test/regress/sql/cluster.sql index 599f6ebd82c..384a185d09e 100644 --- a/src/test/regress/sql/cluster.sql +++ b/src/test/regress/sql/cluster.sql @@ -79,3 +79,10 @@ SELECT conname FROM pg_constraint WHERE conrelid = 'clstr_tst'::regclass; SELECT relname, relkind, EXISTS(SELECT 1 FROM pg_class WHERE oid = c.reltoastrelid) AS hastoast FROM pg_class c WHERE relname LIKE 'clstr_tst%' ORDER BY relname; + +-- Verify that indisclustered is correctly set +SELECT pg_class.relname FROM pg_index, pg_class, pg_class AS pg_class_2 +WHERE pg_class.oid=indexrelid + AND indrelid=pg_class_2.oid + AND pg_class_2.relname = 'clstr_tst' + AND indisclustered; |