aboutsummaryrefslogtreecommitdiff
path: root/src/bin
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
committerMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
commitd31084e9d1118b25fd16580d9d8c2924b5740dff (patch)
tree3179e66307d54df9c7b966543550e601eb55e668 /src/bin
downloadpostgresql-d31084e9d1118b25fd16580d9d8c2924b5740dff.tar.gz
postgresql-d31084e9d1118b25fd16580d9d8c2924b5740dff.zip
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/bin')
-rw-r--r--src/bin/Makefile30
-rw-r--r--src/bin/Makefile.global33
-rw-r--r--src/bin/cleardbdir/Makefile21
-rw-r--r--src/bin/cleardbdir/cleardbdir.sh37
-rw-r--r--src/bin/createdb/Makefile21
-rw-r--r--src/bin/createdb/createdb.sh66
-rw-r--r--src/bin/createuser/Makefile21
-rw-r--r--src/bin/createuser/createuser.sh225
-rw-r--r--src/bin/destroydb/Makefile21
-rw-r--r--src/bin/destroydb/destroydb.sh69
-rw-r--r--src/bin/destroyuser/Makefile21
-rw-r--r--src/bin/destroyuser/destroyuser.sh192
-rw-r--r--src/bin/initdb/Makefile21
-rw-r--r--src/bin/initdb/initdb.sh222
-rw-r--r--src/bin/ipcclean/Makefile21
-rw-r--r--src/bin/ipcclean/ipcclean.sh8
-rw-r--r--src/bin/monitor/Makefile23
-rw-r--r--src/bin/monitor/monitor.c1058
-rw-r--r--src/bin/pg4_dump/Makefile13
-rw-r--r--src/bin/pg4_dump/README87
-rw-r--r--src/bin/pg4_dump/common.c417
-rw-r--r--src/bin/pg4_dump/pg4_dump.c1602
-rw-r--r--src/bin/pg4_dump/pg_dump.h195
-rw-r--r--src/bin/pg_dump/Makefile23
-rw-r--r--src/bin/pg_dump/README73
-rw-r--r--src/bin/pg_dump/common.c397
-rw-r--r--src/bin/pg_dump/pg_dump.c1443
-rw-r--r--src/bin/pg_dump/pg_dump.h195
-rw-r--r--src/bin/pg_id/Makefile23
-rw-r--r--src/bin/pg_id/pg_id.c52
-rw-r--r--src/bin/pg_version/Makefile26
-rw-r--r--src/bin/pg_version/pg_version.c35
-rw-r--r--src/bin/pgtclsh/Makefile46
-rw-r--r--src/bin/pgtclsh/README21
-rw-r--r--src/bin/pgtclsh/pgtclAppInit.c114
-rw-r--r--src/bin/pgtclsh/pgtclUtils.tcl16
-rw-r--r--src/bin/pgtclsh/pgtkAppInit.c117
-rw-r--r--src/bin/pgtclsh/updateStats.tcl71
-rw-r--r--src/bin/psql/Makefile65
-rw-r--r--src/bin/psql/psql.c1230
-rw-r--r--src/bin/psql/psqlHelp.h168
-rw-r--r--src/bin/psql/rlstubs.c41
-rw-r--r--src/bin/psql/stringutils.c104
-rw-r--r--src/bin/psql/stringutils.h51
44 files changed, 8735 insertions, 0 deletions
diff --git a/src/bin/Makefile b/src/bin/Makefile
new file mode 100644
index 00000000000..67ed0b86ad3
--- /dev/null
+++ b/src/bin/Makefile
@@ -0,0 +1,30 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for src/bin (utility programs)
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/Makefile,v 1.1.1.1 1996/07/09 06:22:11 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+#
+# C programs
+#
+SUBDIR= monitor pg_id pg_version psql pg_dump
+
+ifeq ($(USE_TCL), true)
+SUBDIR += pgtclsh
+endif
+
+#
+# Shell scripts
+#
+SUBDIR+= cleardbdir createdb createuser destroydb destroyuser initdb
+
+
+include ../mk/postgres.subdir.mk
+
diff --git a/src/bin/Makefile.global b/src/bin/Makefile.global
new file mode 100644
index 00000000000..dc6ed375b68
--- /dev/null
+++ b/src/bin/Makefile.global
@@ -0,0 +1,33 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# global configurations for Makefiles in src/bin
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/Attic/Makefile.global,v 1.1.1.1 1996/07/09 06:22:11 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+CFLAGS+= -I$(HEADERDIR) -I$(srcdir)/backend -I$(srcdir)/backend/include -I$(srcdir)/libpq
+
+#
+# try locating libpq.a in the following places
+# Almost all (all?) the C programs in this directory
+# link with libpq, so we put it here.
+#
+LIBPQ:= -L$(srcdir)/libpq/$(objdir) -L$(LIBDIR) -lpq
+
+LD_ADD+= $(LIBPQ)
+DPADD+= $(LIBPQ)
+
+
+#
+# And where libpq goes, so goes the authentication stuff...
+#
+ifdef KRBVERS
+LD_ADD+= $(KRBLIBS)
+CFLAGS+= $(KRBFLAGS)
+endif
diff --git a/src/bin/cleardbdir/Makefile b/src/bin/cleardbdir/Makefile
new file mode 100644
index 00000000000..43d78487c42
--- /dev/null
+++ b/src/bin/cleardbdir/Makefile
@@ -0,0 +1,21 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for bin/cleardbdir
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/cleardbdir/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:11 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+SHPROG= cleardbdir
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+include $(MKDIR)/postgres.shell.mk
+
diff --git a/src/bin/cleardbdir/cleardbdir.sh b/src/bin/cleardbdir/cleardbdir.sh
new file mode 100644
index 00000000000..d9c03ab75cb
--- /dev/null
+++ b/src/bin/cleardbdir/cleardbdir.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+#-------------------------------------------------------------------------
+#
+# cleardbdir.sh--
+# completely clear out the database directory
+#
+# this program clears out the database directory, but leaves the .bki
+# files so that initdb(1) can be run again.
+#
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/cleardbdir/Attic/cleardbdir.sh,v 1.1.1.1 1996/07/09 06:22:11 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+[ -z "$PGDATA" ] && PGDATA=_fUnKy_DATADIR_sTuFf_
+
+echo "This program completely destroys all the databases in the directory"
+echo "$PGDATA"
+echo _fUnKy_DASH_N_sTuFf_ "Are you sure you want to do this (y/n) [n]? "_fUnKy_BACKSLASH_C_sTuFf_
+read resp || exit
+case $resp in
+ y*) : ;;
+ *) exit ;;
+esac
+
+cd $PGDATA || exit
+for i in *
+do
+if [ $i != "files" -a $i != "pg_hba" ]
+then
+ /bin/rm -rf $i
+fi
+done
diff --git a/src/bin/createdb/Makefile b/src/bin/createdb/Makefile
new file mode 100644
index 00000000000..db5a63484ff
--- /dev/null
+++ b/src/bin/createdb/Makefile
@@ -0,0 +1,21 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for bin/createdb
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/createdb/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:12 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+SHPROG= createdb
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+include $(MKDIR)/postgres.shell.mk
+
diff --git a/src/bin/createdb/createdb.sh b/src/bin/createdb/createdb.sh
new file mode 100644
index 00000000000..2d2116d4699
--- /dev/null
+++ b/src/bin/createdb/createdb.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+#-------------------------------------------------------------------------
+#
+# createdb.sh--
+# create a postgres database
+#
+# this program runs the monitor with the "-c" option to create
+# the requested database.
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/createdb/Attic/createdb.sh,v 1.1.1.1 1996/07/09 06:22:12 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+# ----------------
+# Set paths from environment or default values.
+# The _fUnKy_..._sTuFf_ gets set when the script is installed
+# from the default value for this build.
+# Currently the only thing we look for from the environment is
+# PGDATA, PGHOST, and PGPORT
+#
+# ----------------
+[ -z "$PGPORT" ] && PGPORT=5432
+[ -z "$PGHOST" ] && PGHOST=localhost
+BINDIR=_fUnKy_BINDIR_sTuFf_
+PATH=$BINDIR:$PATH
+
+CMDNAME=`basename $0`
+
+if [ -z "$USER" ]; then
+ if [ -z "$LOGNAME" ]; then
+ if [ -z "`whoami`" ]; then
+ echo "$CMDNAME: cannot determine user name"
+ exit 1
+ fi
+ else
+ USER=$LOGNAME
+ export USER
+ fi
+fi
+
+dbname=$USER
+
+while test -n "$1"
+do
+ case $1 in
+ -a) AUTHSYS=$2; shift;;
+ -h) PGHOST=$2; shift;;
+ -p) PGPORT=$2; shift;;
+ *) dbname=$1;;
+ esac
+ shift;
+done
+
+AUTHOPT="-a $AUTHSYS"
+[ -z "$AUTHSYS" ] && AUTHOPT=""
+
+monitor -TN $AUTHOPT -h $PGHOST -p $PGPORT -c "create database $dbname" template1 || {
+ echo "$CMDNAME: database creation failed on $dbname."
+ exit 1
+}
+
+exit 0
diff --git a/src/bin/createuser/Makefile b/src/bin/createuser/Makefile
new file mode 100644
index 00000000000..7c0c3e13eef
--- /dev/null
+++ b/src/bin/createuser/Makefile
@@ -0,0 +1,21 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for bin/createuser
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/createuser/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:12 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+SHPROG= createuser
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+include $(MKDIR)/postgres.shell.mk
+
diff --git a/src/bin/createuser/createuser.sh b/src/bin/createuser/createuser.sh
new file mode 100644
index 00000000000..4178f945961
--- /dev/null
+++ b/src/bin/createuser/createuser.sh
@@ -0,0 +1,225 @@
+#!/bin/sh
+#-------------------------------------------------------------------------
+#
+# createuser.sh--
+# utility for creating a user in the POSTGRES database
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/createuser/Attic/createuser.sh,v 1.1.1.1 1996/07/09 06:22:12 scrappy Exp $
+#
+# Note - this should NOT be setuid.
+#
+#-------------------------------------------------------------------------
+
+# ----------------
+# Set paths from environment or default values.
+# The _fUnKy_..._sTuFf_ gets set when the script is installed
+# from the default value for this build.
+# Currently the only thing we look for from the environment is
+# PGDATA, PGHOST, and PGPORT
+#
+# ----------------
+[ -z "$PGPORT" ] && PGPORT=5432
+[ -z "$PGHOST" ] && PGHOST=localhost
+BINDIR=_fUnKy_BINDIR_sTuFf_
+PATH=$BINDIR:$PATH
+
+CMDNAME=`basename $0`
+
+if [ -z "$USER" ]; then
+ if [ -z "$LOGNAME" ]; then
+ if [ -z "`whoami`" ]; then
+ echo "$CMDNAME: cannot determine user name"
+ exit 1
+ fi
+ else
+ USER=$LOGNAME
+ export USER
+ fi
+fi
+
+while [ -n "$1" ]
+do
+ case $1 in
+ -a) AUTHSYS=$2; shift;;
+ -h) PGHOST=$2; shift;;
+ -p) PGPORT=$2; shift;;
+ *) NEWUSER=$1;;
+ esac
+ shift;
+done
+
+AUTHOPT="-a $AUTHSYS"
+[ -z "$AUTHSYS" ] && AUTHOPT=""
+
+MARGS="-TN $AUTHOPT -h $PGHOST -p $PGPORT"
+
+#
+# generate the first part of the actual monitor command
+#
+
+MONITOR="monitor $MARGS"
+
+#
+# see if user $USER is allowed to create new users
+#
+
+QUERY="select usesuper from pg_user where usename = '$USER'"
+#echo $QUERY
+
+ADDUSER=`$MONITOR -TN -c "$QUERY" template1`
+
+if [ $? -ne 0 ]
+then
+ echo "$CMDNAME: database access failed." 1>&2
+ exit 1
+fi
+
+if [ -n "$ADDUSER" ]
+then
+
+if [ $ADDUSER != "t" ]
+then
+ echo "$CMDNAME: $USER cannot create users." 1>&2
+ exit 1
+fi
+fi
+
+#
+# get the user name of the new user. Make sure it doesn't already exist.
+#
+
+if [ -z "$NEWUSER" ]
+then
+ echo _fUnKy_DASH_N_sTuFf_ "Enter name of user to add ---> "_fUnKy_BACKSLASH_C_sTuFf_
+ read NEWUSER
+fi
+
+QUERY="select usesysid from pg_user where usename = '$NEWUSER'"
+
+RES=`$MONITOR -TN -c "$QUERY" template1`
+
+if [ $? -ne 0 ]
+then
+ echo "$CMDNAME: database access failed." 1>&2
+ exit 1
+fi
+
+if [ -n "$RES" ]
+then
+ echo "$CMDNAME: user "\"$NEWUSER\"" already exists" 1>&2
+ exit 1
+fi
+
+done=0
+
+#
+# get the system id of the new user. Make sure it is unique.
+#
+
+while [ $done -ne 1 ]
+do
+ SYSID=
+ DEFSYSID=`pg_id $NEWUSER 2>/dev/null`
+ if [ $? -eq 0 ]; then
+ DEFMSG=" or RETURN to use unix user ID: $DEFSYSID"
+ else
+ DEFMSG=
+ DEFSYSID=
+ fi
+ while [ -z "$SYSID" ]
+ do
+ echo _fUnKy_DASH_N_sTuFf_ "Enter user's postgres ID$DEFMSG -> "_fUnKy_BACKSLASH_C_sTuFf_
+ read SYSID
+ [ -z "$SYSID" ] && SYSID=$DEFSYSID;
+ SYSIDISNUM=`echo $SYSID | egrep '^[0-9]+$'`
+ if [ -z "$SYSIDISNUM" ]
+ then
+ echo "$CMDNAME: the postgres ID must be a number"
+ exit 1
+ fi
+ QUERY="select usename from pg_user where usesysid = '$SYSID'::int4"
+ RES=`$MONITOR -TN -c "$QUERY" template1`
+ if [ $? -ne 0 ]
+ then
+ echo "$CMDNAME: database access failed."
+ exit 1
+ fi
+ if [ -n "$RES" ]
+ then
+ echo
+ echo "$CMDNAME: $SYSID already belongs to $RES, pick another"
+ DEFMSG= DEFSYSID= SYSID=
+ else
+ done=1
+ fi
+ done
+done
+
+#
+# get the rest of the user info...
+#
+
+#
+# can the user create databases?
+#
+
+yn=f
+
+while [ "$yn" != y -a "$yn" != n ]
+do
+ echo _fUnKy_DASH_N_sTuFf_ "Is user \"$NEWUSER\" allowed to create databases (y/n) "_fUnKy_BACKSLASH_C_sTuFf_
+ read yn
+done
+
+if [ "$yn" = y ]
+then
+ CANCREATE=t
+else
+ CANCREATE=f
+fi
+
+#
+# can the user add users?
+#
+
+yn=f
+
+while [ "$yn" != y -a "$yn" != n ]
+do
+ echo _fUnKy_DASH_N_sTuFf_ "Is user \"$NEWUSER\" allowed to add users? (y/n) "_fUnKy_BACKSLASH_C_sTuFf_
+ read yn
+done
+
+if (test "$yn" = y)
+then
+ CANADDUSER=t
+else
+ CANADDUSER=f
+fi
+
+QUERY="insert into pg_user \
+ (usename, usesysid, usecreatedb, usetrace, usesuper, usecatupd) \
+ values \
+ ('$NEWUSER', $SYSID, '$CANCREATE', 't', '$CANADDUSER','t')"
+
+RES=`$MONITOR -TN -c "$QUERY" template1`
+
+#
+# Wrap things up. If the user was created successfully, AND the user was
+# NOT allowed to create databases, remind the DBA to create one for the user.
+#
+
+if [ $? -ne 0 ]
+then
+ echo "$CMDNAME: $NEWUSER was NOT added successfully"
+else
+ echo "$CMDNAME: $NEWUSER was successfully added"
+ if [ "$CANCREATE" = f ]
+ then
+ echo "don't forget to create a database for $NEWUSER"
+ fi
+fi
diff --git a/src/bin/destroydb/Makefile b/src/bin/destroydb/Makefile
new file mode 100644
index 00000000000..4dadef6eb88
--- /dev/null
+++ b/src/bin/destroydb/Makefile
@@ -0,0 +1,21 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for bin/destroydb
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/destroydb/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:12 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+SHPROG= destroydb
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+include $(MKDIR)/postgres.shell.mk
+
diff --git a/src/bin/destroydb/destroydb.sh b/src/bin/destroydb/destroydb.sh
new file mode 100644
index 00000000000..564d503a1d3
--- /dev/null
+++ b/src/bin/destroydb/destroydb.sh
@@ -0,0 +1,69 @@
+#!/bin/sh
+#-------------------------------------------------------------------------
+#
+# destroydb.sh--
+# destroy a postgres database
+#
+# this program runs the monitor with the ? option to destroy
+# the requested database.
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/destroydb/Attic/destroydb.sh,v 1.1.1.1 1996/07/09 06:22:12 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+# ----------------
+# Set paths from environment or default values.
+# The _fUnKy_..._sTuFf_ gets set when the script is installed
+# from the default value for this build.
+# Currently the only thing we look for from the environment is
+# PGDATA, PGHOST, and PGPORT
+#
+# ----------------
+[ -z "$PGPORT" ] && PGPORT=5432
+[ -z "$PGHOST" ] && PGHOST=localhost
+BINDIR=_fUnKy_BINDIR_sTuFf_
+PATH=$BINDIR:$PATH
+
+CMDNAME=`basename $0`
+
+if [ -z "$USER" ]; then
+ if [ -z "$LOGNAME" ]; then
+ if [ -z "`whoami`" ]; then
+ echo "$CMDNAME: cannot determine user name"
+ exit 1
+ fi
+ else
+ USER=$LOGNAME
+ export USER
+ fi
+fi
+
+dbname=$USER
+
+while [ -n "$1" ]
+do
+ case $1 in
+ -a) AUTHSYS=$2; shift;;
+ -h) PGHOST=$2; shift;;
+ -p) PGPORT=$2; shift;;
+ *) dbname=$1;;
+ esac
+ shift;
+done
+
+AUTHOPT="-a $AUTHSYS"
+[ -z "$AUTHSYS" ] && AUTHOPT=""
+
+monitor -TN -h $PGHOST -p $PGPORT -c "drop database $dbname" template1
+
+if [ $? -ne 0 ]
+then
+ echo "$CMDNAME: database destroy failed on $dbname."
+ exit 1
+fi
+
+exit 0
diff --git a/src/bin/destroyuser/Makefile b/src/bin/destroyuser/Makefile
new file mode 100644
index 00000000000..7e5d5014f77
--- /dev/null
+++ b/src/bin/destroyuser/Makefile
@@ -0,0 +1,21 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for bin/destroyuser
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/destroyuser/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:12 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+SHPROG= destroyuser
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+include $(MKDIR)/postgres.shell.mk
+
diff --git a/src/bin/destroyuser/destroyuser.sh b/src/bin/destroyuser/destroyuser.sh
new file mode 100644
index 00000000000..e600748f14f
--- /dev/null
+++ b/src/bin/destroyuser/destroyuser.sh
@@ -0,0 +1,192 @@
+#!/bin/sh
+#-------------------------------------------------------------------------
+#
+# destroyuser.sh--
+# utility for destroying a user from the POSTGRES database.
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/destroyuser/Attic/destroyuser.sh,v 1.1.1.1 1996/07/09 06:22:12 scrappy Exp $
+#
+# Note - this should NOT be setuid.
+#
+#-------------------------------------------------------------------------
+
+# ----------------
+# Set paths from environment or default values.
+# The _fUnKy_..._sTuFf_ gets set when the script is installed
+# from the default value for this build.
+# Currently the only thing we look for from the environment is
+# PGDATA, PGHOST, and PGPORT
+#
+# ----------------
+[ -z "$PGPORT" ] && PGPORT=5432
+[ -z "$PGHOST" ] && PGHOST=localhost
+BINDIR=_fUnKy_BINDIR_sTuFf_
+PATH=$BINDIR:$PATH
+
+CMDNAME=`basename $0`
+
+if [ -z "$USER" ]; then
+ if [ -z "$LOGNAME" ]; then
+ if [ -z "`whoami`" ]; then
+ echo "$CMDNAME: cannot determine user name"
+ exit 1
+ fi
+ else
+ USER=$LOGNAME
+ export USER
+ fi
+fi
+
+while (test -n "$1")
+do
+ case $1 in
+ -a) AUTHSYS=$2; shift;;
+ -h) PGHOST=$2; shift;;
+ -p) PGPORT=$2; shift;;
+ *) DELUSER=$1;;
+ esac
+ shift;
+done
+
+AUTHOPT="-a $AUTHSYS"
+[ -z "$AUTHSYS" ] && AUTHOPT=""
+
+MARGS="-TN $AUTHOPT -p $PGPORT -h $PGHOST"
+
+#
+# generate the first part of the actual monitor command
+#
+MONITOR="monitor $MARGS"
+
+#
+# see if user $USER is allowed to create new users. Only a user who can
+# create users can delete them.
+#
+
+QUERY="select usesuper from pg_user where usename = '$USER'"
+ADDUSER=`$MONITOR -c "$QUERY" template1`
+
+if [ $? -ne 0 ]
+then
+ echo "$CMDNAME: database access failed."
+ exit 1
+fi
+
+if [ $ADDUSER != "t" ]
+then
+ echo "$CMDNAME: $USER cannot delete users."
+fi
+
+#
+# get the user name of the user to delete. Make sure it exists.
+#
+
+if [ -z "$DELUSER" ]
+then
+ echo _fUnKy_DASH_N_sTuFf_ "Enter name of user to delete ---> "_fUnKy_BACKSLASH_C_sTuFf_
+ read DELUSER
+fi
+
+QUERY="select usesysid from pg_user where usename = '$DELUSER'"
+
+RES=`$MONITOR -c "$QUERY" template1`
+
+if [ $? -ne 0 ]
+then
+ echo "$CMDNAME: database access failed."
+ exit 1
+fi
+
+if [ ! -n "$RES" ]
+then
+ echo "$CMDNAME: user "\"$DELUSER\"" does not exist."
+ exit 1
+fi
+
+SYSID=`echo $RES | sed 's/ //g'`
+
+#
+# destroy the databases owned by the deleted user. First, use this query
+# to find out what they are.
+#
+
+QUERY="select datname from pg_database where datdba = '$SYSID'::oid"
+
+
+ALLDBS=`$MONITOR -c "$QUERY" template1`
+
+if [ $? -ne 0 ]
+then
+ echo "$CMDNAME: database access failed - exiting..."
+ exit 1
+fi
+
+
+#
+# don't try to delete template1!
+#
+
+for i in $ALLDBS
+do
+ if [ $i != "template1" ]
+ then
+ DBLIST="$DBLIST $i"
+ fi
+done
+
+if [ -n "$DBLIST" ]
+then
+ echo "User $DELUSER owned the following databases:"
+ echo $DBLIST
+ echo
+
+#
+# Now we warn the DBA that deleting this user will destroy a bunch of databases
+#
+
+ yn=f
+ while [ $yn != y -a $yn != n ]
+ do
+ echo _fUnKy_DASH_N_sTuFf_ "Deleting user $DELUSER will destroy them. Continue (y/n)? "_fUnKy_BACKSLASH_C_sTuFf_
+ read yn
+ done
+
+ if [ $yn = n ]
+ then
+ echo "$CMDNAME: exiting"
+ exit 1
+ fi
+
+ #
+ # now actually destroy the databases
+ #
+
+ for i in $DBLIST
+ do
+ echo "destroying database $i"
+
+ QUERY="drop database $i"
+ $MONITOR -c "$QUERY" template1
+ if [ $? -ne 0 ]
+ then
+ echo "$CMDNAME: drop database on $i failed - exiting"
+ exit 1
+ fi
+ done
+fi
+
+QUERY="delete from pg_user where usename = '$DELUSER'"
+
+$MONITOR -c "$QUERY" template1
+if [ $? -ne 0 ]
+then
+ echo "$CMDNAME: delete of user $DELUSER was UNSUCCESSFUL"
+else
+ echo "$CMDNAME: delete of user $DELUSER was successful."
+fi
+
+exit 0
diff --git a/src/bin/initdb/Makefile b/src/bin/initdb/Makefile
new file mode 100644
index 00000000000..a63236aaff2
--- /dev/null
+++ b/src/bin/initdb/Makefile
@@ -0,0 +1,21 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for bin/initdb
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/initdb/Makefile,v 1.1.1.1 1996/07/09 06:22:13 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+SHPROG= initdb
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+include $(MKDIR)/postgres.shell.mk
+
diff --git a/src/bin/initdb/initdb.sh b/src/bin/initdb/initdb.sh
new file mode 100644
index 00000000000..8e9044981f3
--- /dev/null
+++ b/src/bin/initdb/initdb.sh
@@ -0,0 +1,222 @@
+#!/bin/sh
+#-------------------------------------------------------------------------
+#
+# initdb.sh--
+# create a postgres template database
+#
+# this program feeds the proper input to the ``postgres'' program
+# to create a postgres database and register it in the
+# shared ``pg_database'' database.
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.1.1.1 1996/07/09 06:22:13 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+# ----------------
+# Set paths from environment or default values.
+# The _fUnKy_..._sTuFf_ gets set when the script is installed
+# from the default value for this build.
+# Currently the only thing wee look for from the environment is
+# PGDATA, PGHOST, and PGPORT
+#
+# ----------------
+[ -z "$PGDATA" ] && { PGDATA=_fUnKy_DATADIR_sTuFf_; export PGDATA; }
+[ -z "$PGPORT" ] && { PGPORT=5432; export PGPORT; }
+[ -z "$PGHOST" ] && { PGHOST=localhost; export PGHOST; }
+POSTGRESDIR=_fUnKy_POSTGRESDIR_sTuFf_
+BINDIR=_fUnKy_BINDIR_sTuFf_
+FILESDIR=$PGDATA/files
+PATH=$BINDIR:$PATH
+export PATH
+
+CMDNAME=`basename $0`
+
+# ----------------
+# check arguments:
+# -d indicates debug mode.
+# -n means don't clean up on error (so your cores don't go away)
+# ----------------
+debug=0
+noclean=0
+verbose=0
+
+for ARG
+do
+ case "$ARG" in
+ -d) debug=1; echo "$CMDNAME: debug mode on";;
+ -n) noclean=1; echo "$CMDNAME: noclean mode on";;
+ -v) verbose=1; echo "$CMDNAME: verbose mode on";;
+ *) echo "initdb [-d][-n][-v]\n -d : debug mode\n -n : noclean mode, leaves temp files around \n -v : verbose mode"; exit 0;
+ esac
+done
+
+# ----------------
+# if the debug flag is set, then
+# ----------------
+if test "$debug" -eq 1
+then
+ BACKENDARGS="-boot -C -d"
+else
+ BACKENDARGS="-boot -C -Q"
+fi
+
+
+TEMPLATE=$FILESDIR/local1_template1.bki
+GLOBAL=$FILESDIR/global1.bki
+if [ ! -f $TEMPLATE -o ! -f $GLOBAL ]
+then
+ echo "$CMDNAME: error: database initialization files not found."
+ echo "$CMDNAME: either gmake install has not been run or you're trying to"
+ echo "$CMDNAME: run this program on a machine that does not store the"
+ echo "$CMDNAME: database (PGHOST doesn't work for this)."
+ exit 1
+fi
+
+if test "$verbose" -eq 1
+then
+ echo "$CMDNAME: using $TEMPLATE"
+ echo "$CMDNAME: using $GLOBAL"
+fi
+
+#
+# Figure out who I am...
+#
+
+PG_UID=`pg_id`
+
+if test $PG_UID -eq 0
+then
+ echo "$CMDNAME: do not install POSTGRES as root"
+ exit 1
+fi
+
+# ----------------
+# create the template database if necessary
+# the first we do is create data/base, so we'll check for that.
+# ----------------
+
+if test -d "$PGDATA/base"
+then
+ echo "$CMDNAME: error: it looks like initdb has already been run. You must"
+ echo "clean out the database directory first with the cleardbdir program"
+ exit 1
+fi
+
+# umask must disallow access to group, other for files and dirs
+umask 077
+
+mkdir $PGDATA/base $PGDATA/base/template1
+
+if test "$verbose" -eq 1
+then
+ echo "$CMDNAME: creating SHARED relations in $PGDATA"
+ echo "$CMDNAME: creating template database in $PGDATA/base/template1"
+ echo "postgres $BACKENDARGS template1 < $TEMPLATE "
+fi
+
+postgres $BACKENDARGS template1 < $TEMPLATE
+
+
+if test $? -ne 0
+then
+ echo "$CMDNAME: could not create template database"
+ if test $noclean -eq 0
+ then
+ echo "$CMDNAME: cleaning up."
+ cd $PGDATA
+ for i in *
+ do
+ if [ $i != "files" -a $i != "pg_hba" ]
+ then
+ /bin/rm -rf $i
+ fi
+ done
+ else
+ echo "$CMDNAME: cleanup not done (noclean mode set)."
+ fi
+ exit 1;
+fi
+
+pg_version $PGDATA/base/template1
+
+#
+# Add the template database to pg_database
+#
+
+echo "open pg_database" > /tmp/create.$$
+echo "insert (template1 $PG_UID template1)" >> /tmp/create.$$
+#echo "show" >> /tmp/create.$$
+echo "close pg_database" >> /tmp/create.$$
+
+if test "$verbose" -eq 1
+then
+ echo "postgres $BACKENDARGS template1 < $GLOBAL"
+fi
+
+postgres $BACKENDARGS template1 < $GLOBAL
+
+if (test $? -ne 0)
+then
+ echo "$CMDNAME: could create shared relations"
+ if (test $noclean -eq 0)
+ then
+ echo "$CMDNAME: cleaning up."
+ cd $PGDATA
+ for i in *
+ do
+ if [ $i != "files" ]
+ then
+ /bin/rm -rf $i
+ fi
+ done
+ else
+ echo "$CMDNAME: cleanup not done (noclean mode set)."
+ fi
+ exit 1;
+fi
+
+pg_version $PGDATA
+
+if test "$verbose" -eq 1
+then
+ echo "postgres $BACKENDARGS template1 < /tmp/create.$$"
+fi
+
+postgres $BACKENDARGS template1 < /tmp/create.$$
+
+if test $? -ne 0
+then
+ echo "$CMDNAME: could not log template database"
+ if (test $noclean -eq 0)
+ then
+ echo "$CMDNAME: cleaning up."
+ cd $PGDATA
+ for i in *
+ do
+ if [ $i != "files" ]
+ then
+ /bin/rm -rf $i
+ fi
+ done
+ else
+ echo "$CMDNAME: cleanup not done (noclean mode set)."
+ fi
+ exit 1;
+fi
+
+if test $debug -eq 0
+then
+
+if test "$verbose" -eq 1
+then
+ echo "vacuuming template1"
+fi
+
+ echo "vacuum" | postgres -Q template1 > /dev/null
+fi
+
+rm -f /tmp/create.$$
diff --git a/src/bin/ipcclean/Makefile b/src/bin/ipcclean/Makefile
new file mode 100644
index 00000000000..5f7993b9ba4
--- /dev/null
+++ b/src/bin/ipcclean/Makefile
@@ -0,0 +1,21 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for bin/initdb
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/ipcclean/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:13 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+SHPROG= ipcclean
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+include $(MKDIR)/postgres.shell.mk
+
diff --git a/src/bin/ipcclean/ipcclean.sh b/src/bin/ipcclean/ipcclean.sh
new file mode 100644
index 00000000000..d3ea2fc576c
--- /dev/null
+++ b/src/bin/ipcclean/ipcclean.sh
@@ -0,0 +1,8 @@
+#!/bin/sh
+#
+# $Header: /cvsroot/pgsql/src/bin/ipcclean/Attic/ipcclean.sh,v 1.1.1.1 1996/07/09 06:22:13 scrappy Exp $
+#
+PATH=_fUnKy_IPCCLEANPATH_sTuFf_:$PATH
+export PATH
+ipcs | egrep '^m .*|^s .*' | egrep "`whoami`|postgres" | \
+awk '{printf "ipcrm -%s %s\n", $1, $2}' '-' | sh
diff --git a/src/bin/monitor/Makefile b/src/bin/monitor/Makefile
new file mode 100644
index 00000000000..53e6f0d514d
--- /dev/null
+++ b/src/bin/monitor/Makefile
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for bin/monitor
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/monitor/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:13 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+PROG= monitor
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+SRCS= monitor.c
+
+include $(MKDIR)/postgres.prog.mk
+
diff --git a/src/bin/monitor/monitor.c b/src/bin/monitor/monitor.c
new file mode 100644
index 00000000000..f9bfa92237b
--- /dev/null
+++ b/src/bin/monitor/monitor.c
@@ -0,0 +1,1058 @@
+/*-------------------------------------------------------------------------
+ *
+ * monitor.c--
+ * POSTGRES Terminal Monitor
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/bin/monitor/Attic/monitor.c,v 1.1.1.1 1996/07/09 06:22:13 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <errno.h>
+#include "libpq/pqsignal.h" /* substitute for <signal.h> */
+#include <stdio.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#ifdef PORTNAME_sparc_solaris
+#include <netdb.h> /* for MAXHOSTNAMELEN on some */
+#endif
+#include <sys/types.h>
+/* #include <sys/uio.h> */
+#include <time.h>
+
+#include "libpq-fe.h"
+#include "libpq/libpq-fs.h"
+
+extern char *getenv();
+
+/*
+ * monitor.c -- function prototypes (all private)
+ */
+static void do_input(FILE *ifp);
+static void init_tmon();
+static void welcome();
+static void handle_editor();
+static void handle_shell();
+static void handle_send();
+static int handle_execution(char *query);
+static void handle_file_insert(FILE *ifp);
+static void handle_print();
+static void handle_exit(int exit_status);
+static void handle_clear();
+static void handle_print_time();
+static int handle_write_to_file();
+static void handle_help();
+static void stuff_buffer(char c);
+static void argsetup(int *argcP, char ***argvP);
+static void handle_copy_out(PGresult *res);
+static void handle_copy_in(PGresult *res);
+
+
+/*
+ * Functions which maintain the logical query buffer in
+ * /tmp/PQxxxxx. It in general just does a copy from input
+ * to query buffer, unless it gets a backslash escape character.
+ * It recognizes the following escapes:
+ *
+ * \e -- enter editor
+ * \g -- "GO": submit query to POSTGRES
+ * \i -- include (switch input to external file)
+ * \p -- print query buffer
+ * \q -- quit POSTGRES
+ * \r -- force reset (clear) of query buffer
+ * \s -- call shell
+ * \t -- print current time
+ * \w -- write query buffer to external file
+ * \h -- print the list of commands
+ * \? -- print the list of commands
+ * \\ -- produce a single backslash in query buffer
+ *
+ */
+
+/*
+ * Declaration of global variables (but only to the file monitor.c
+ */
+
+#define DEFAULT_EDITOR "/usr/ucb/vi"
+#define COPYBUFSIZ 8192
+static char *user_editor; /* user's desired editor */
+static int tmon_temp; /* file descriptor for temp. buffer file */
+static char *tmon_temp_filename;
+static char query_buffer[8192]; /* Max postgres buffer size */
+static char *RunOneFile = NULL;
+bool RunOneCommand = false;
+bool Debugging;
+bool Verbose;
+bool Silent;
+bool TerseOutput = false;
+bool PrintAttNames = true;
+bool SingleStepMode = false;
+bool SemicolonIsGo = true;
+
+#define COLWIDTH 12
+
+extern char *optarg;
+extern int optind,opterr;
+FILE *debug_port;
+
+/*
+ * As of release 4, we allow the user to specify options in the environment
+ * variable PGOPTION. These are treated as command-line options to the
+ * terminal monitor, and are parsed before the actual command-line args.
+ * The arge struct is used to construct an argv we can pass to getopt()
+ * containing the union of the environment and command line arguments.
+ */
+
+typedef struct arge {
+ char *a_arg;
+ struct arge *a_next;
+} arge;
+
+/* the connection to the backend */
+PGconn *conn;
+
+void
+main(int argc, char **argv)
+{
+ int c;
+ int errflag = 0;
+ char *progname;
+ char *debug_file;
+ char *dbname;
+ char *command;
+ int exit_status = 0;
+ char errbuf[ERROR_MSG_LENGTH];
+ char *username, usernamebuf[NAMEDATALEN + 1];
+
+ char *pghost = NULL;
+ char *pgtty = NULL;
+ char *pgoptions = NULL;
+ char *pgport = NULL;
+ int pgtracep = 0;
+
+ /*
+ * Processing command line arguments.
+ *
+ * h : sets the hostname.
+ * p : sets the coom. port
+ * t : sets the tty.
+ * o : sets the other options. (see doc/libpq)
+ * d : enable debugging mode.
+ * q : run in quiet mode
+ * Q : run in VERY quiet mode (no output except on errors)
+ * c : monitor will run one POSTQUEL command and exit
+ *
+ * s : step mode (pauses after each command)
+ * S : don't use semi colon as \g
+ *
+ * T : terse mode - no formatting
+ * N : no attribute names - only columns of data
+ * (these two options are useful in conjunction with the "-c" option
+ * in scripts.)
+ */
+
+ progname = *argv;
+ Debugging = false;
+ Verbose = true;
+ Silent = false;
+
+ /* prepend PGOPTION, if any */
+ argsetup(&argc, &argv);
+
+ while ((c = getopt(argc, argv, "a:h:f:p:t:d:qsSTNQc:")) != EOF) {
+ switch (c) {
+ case 'a':
+ fe_setauthsvc(optarg, errbuf);
+ break;
+ case 'h' :
+ pghost = optarg;
+ break;
+ case 'f' :
+ RunOneFile = optarg;
+ break;
+ case 'p' :
+ pgport = optarg;
+ break;
+ case 't' :
+ pgtty = optarg;
+ break;
+ case 'T' :
+ TerseOutput = true;
+ break;
+ case 'N' :
+ PrintAttNames = false;
+ break;
+ case 'd' :
+
+ /*
+ * When debugging is turned on, the debugging messages
+ * will be sent to the specified debug file, which
+ * can be a tty ..
+ */
+
+ Debugging = true;
+ debug_file = optarg;
+ debug_port = fopen(debug_file,"w+");
+ if (debug_port == NULL) {
+ fprintf(stderr,"Unable to open debug file %s \n", debug_file);
+ exit(1);
+ }
+ pgtracep = 1;
+ break;
+ case 'q' :
+ Verbose = false;
+ break;
+ case 's' :
+ SingleStepMode = true;
+ SemicolonIsGo = true;
+ break;
+ case 'S' :
+ SemicolonIsGo = false;
+ break;
+ case 'Q' :
+ Verbose = false;
+ Silent = true;
+ break;
+ case 'c' :
+ Verbose = false;
+ Silent = true;
+ RunOneCommand = true;
+ command = optarg;
+ break;
+ case '?' :
+ default :
+ errflag++;
+ break;
+ }
+ }
+
+ if (errflag ) {
+ fprintf(stderr, "usage: %s [options...] [dbname]\n", progname);
+ fprintf(stderr, "\t-a authsvc\tset authentication service\n");
+ fprintf(stderr, "\t-c command\t\texecute one command\n");
+ fprintf(stderr, "\t-d debugfile\t\tdebugging output file\n");
+ fprintf(stderr, "\t-h host\t\t\tserver host name\n");
+ fprintf(stderr, "\t-f file\t\t\trun query from file\n");
+ fprintf(stderr, "\t-p port\t\t\tserver port number\n");
+ fprintf(stderr, "\t-q\t\t\tquiet output\n");
+ fprintf(stderr, "\t-t logfile\t\terror-logging tty\n");
+ fprintf(stderr, "\t-N\t\t\toutput without attribute names\n");
+ fprintf(stderr, "\t-Q\t\t\tREALLY quiet output\n");
+ fprintf(stderr, "\t-T\t\t\tterse output\n");
+ exit(2);
+ }
+
+ /* Determine our username (according to the authentication system, if
+ * there is one).
+ */
+ if ((username = fe_getauthname(errbuf)) == (char *) NULL) {
+ fprintf(stderr, "%s: could not find a valid user name\n",
+ progname);
+ exit(2);
+ }
+ memset(usernamebuf, 0, sizeof(usernamebuf));
+ (void) strncpy(usernamebuf, username, NAMEDATALEN);
+ username = usernamebuf;
+
+ /* find database */
+ if (!(dbname = argv[optind]) &&
+ !(dbname = getenv("DATABASE")) &&
+ !(dbname = username)) {
+ fprintf(stderr, "%s: no database name specified\n", progname);
+ exit (2);
+ }
+
+ conn = PQsetdb(pghost, pgport, pgoptions, pgtty, dbname);
+ if (PQstatus(conn) == CONNECTION_BAD) {
+ fprintf(stderr,"Connection to database '%s' failed.\n", dbname);
+ fprintf(stderr,"%s",PQerrorMessage(conn));
+ exit(1);
+ }
+
+ if (pgtracep)
+ PQtrace(conn,debug_port);
+
+ /* print out welcome message and start up */
+ welcome();
+ init_tmon();
+
+ /* parse input */
+ if (RunOneCommand) {
+ exit_status = handle_execution(command);
+ } else if (RunOneFile) {
+ bool oldVerbose;
+ FILE *ifp;
+
+ if ((ifp = fopen(RunOneFile, "r")) == NULL) {
+ fprintf(stderr, "Cannot open %s\n", RunOneFile);
+ }
+
+ if (SingleStepMode) {
+ oldVerbose = Verbose;
+ Verbose = false;
+ }
+ do_input(ifp);
+ fclose(ifp);
+ if (SingleStepMode)
+ Verbose = oldVerbose;
+ } else {
+ do_input(stdin);
+ }
+
+ handle_exit(exit_status);
+}
+
+static void
+do_input(FILE *ifp)
+{
+ int c;
+ char escape;
+
+ /*
+ * Processing user input.
+ * Basically we stuff the user input to a temp. file until
+ * an escape char. is detected, after which we switch
+ * to the appropriate routine to handle the escape.
+ */
+
+ if (ifp == stdin) {
+ if (Verbose)
+ fprintf(stdout,"\nGo \n* ");
+ else {
+ if (!Silent)
+ fprintf(stdout, "* ");
+ }
+ }
+ while ((c = getc(ifp)) != EOF ) {
+ if ( c == '\\') {
+ /* handle escapes */
+ escape = getc(ifp);
+ switch( escape ) {
+ case 'e':
+ handle_editor();
+ break;
+ case 'g':
+ handle_send();
+ break;
+ case 'i':
+ {
+ bool oldVerbose;
+
+ if (SingleStepMode) {
+ oldVerbose = Verbose;
+ Verbose = false;
+ }
+ handle_file_insert(ifp);
+ if (SingleStepMode)
+ Verbose = oldVerbose;
+ }
+ break;
+ case 'p':
+ handle_print();
+ break;
+ case 'q':
+ handle_exit(0);
+ break;
+ case 'r':
+ handle_clear();
+ break;
+ case 's':
+ handle_shell();
+ break;
+ case 't':
+ handle_print_time();
+ break;
+ case 'w':
+ handle_write_to_file();
+ break;
+ case '?':
+ case 'h':
+ handle_help();
+ break;
+ case '\\':
+ c = escape;
+ stuff_buffer(c);
+ break;
+ case ';':
+ c = escape;
+ stuff_buffer(c);
+ break;
+ default:
+ fprintf(stderr, "unknown escape given\n");
+ break;
+ } /* end-of-switch */
+ if (ifp == stdin && escape != '\\') {
+ if (Verbose)
+ fprintf(stdout,"\nGo \n* ");
+ else {
+ if (!Silent)
+ fprintf(stdout, "* ");
+ }
+ }
+ } else {
+ stuff_buffer(c);
+ if (c == ';' && SemicolonIsGo) {
+ handle_send();
+ if (Verbose)
+ fprintf(stdout,"\nGo \n* ");
+ else {
+ if (!Silent)
+ fprintf(stdout, "* ");
+ }
+ }
+ }
+ }
+}
+
+/*
+ * init_tmon()
+ *
+ * set the following :
+ * user_editor, defaults to DEFAULT_EDITOR if env var is not set
+ */
+static void
+init_tmon()
+{
+ if (!RunOneCommand)
+ {
+ char *temp_editor = getenv("EDITOR");
+
+ if (temp_editor != NULL)
+ user_editor = temp_editor;
+ else
+ user_editor = DEFAULT_EDITOR;
+
+ tmon_temp_filename = malloc(20);
+ sprintf(tmon_temp_filename, "/tmp/PQ%d", getpid());
+ tmon_temp = open(tmon_temp_filename,O_CREAT | O_RDWR | O_APPEND,0666);
+ }
+
+ /*
+ * Catch signals so we can delete the scratch file GK
+ * but only if we aren't already ignoring them -mer
+ */
+
+#ifndef WIN32
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ signal(SIGHUP, handle_exit);
+ if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
+ signal(SIGQUIT, handle_exit);
+#endif /* WIN32 we'll have to figure out how to handle these */
+ if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+ signal(SIGTERM, handle_exit);
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ signal(SIGINT, handle_exit);
+}
+
+/*
+ * welcome simply prints the Postgres welcome mesg.
+ */
+static
+void welcome()
+{
+ if (Verbose) {
+ fprintf(stdout,"Welcome to the POSTGRES95 terminal monitor\n");
+ fprintf(stdout," Please read the file COPYRIGHT for copyright terms of POSTGRES95\n");
+ }
+}
+
+
+/*
+ * handle_editor()
+ *
+ * puts the user into edit mode using the editor specified
+ * by the variable "user_editor".
+ */
+static void
+handle_editor()
+{
+ char edit_line[100];
+
+ close(tmon_temp);
+ sprintf(edit_line,"%s %s",user_editor,tmon_temp_filename);
+ system(edit_line);
+ tmon_temp = open(tmon_temp_filename,O_CREAT | O_RDWR | O_APPEND,0666);
+}
+
+static void
+handle_shell()
+{
+ char *user_shell;
+
+ user_shell = getenv("SHELL");
+ if (user_shell != NULL) {
+ system(user_shell);
+ } else {
+ system("/bin/sh");
+ }
+}
+
+/*
+ * handle_send()
+ *
+ * This is the routine that initialises the comm. with the
+ * backend. After the tuples have been returned and
+ * displayed, the query_buffer is cleared for the
+ * next query.
+ *
+ */
+
+#include <ctype.h>
+
+static void
+handle_send()
+{
+ char c = (char)0;
+ off_t pos;
+ int cc = 0;
+ int i = 0;
+
+ pos = lseek(tmon_temp, (off_t) 0, SEEK_SET);
+
+ if (pos != 0)
+ fprintf(stderr, "Bogus file position\n");
+
+ if (Verbose)
+ printf("\n");
+
+ /* discard leading white space */
+ while ( ( cc = read(tmon_temp,&c,1) ) != 0 && isspace((int)c))
+ continue;
+
+ if ( cc != 0 ) {
+ pos = lseek(tmon_temp, (off_t) -1, SEEK_CUR);
+ }
+
+ if (SingleStepMode) {
+ char buf[1024];
+ fprintf(stdout, "\n*******************************************************************************\n");
+ while ((cc = read(tmon_temp,buf,1024))>0) {
+ buf[cc] = '\0';
+ fprintf(stdout, "%s", buf);
+ }
+ fprintf(stdout, "\n*******************************************************************************\n\n");
+ (void)lseek(tmon_temp, (off_t)pos, SEEK_SET);
+ }
+
+ query_buffer[0] = 0;
+
+ /*
+ * Stripping out comments (if any) from the query (should really be
+ * handled in the parser, of course).
+ */
+ while ( ( cc = read(tmon_temp,&c,1) ) != 0) {
+ switch(c) {
+ case '\n':
+ query_buffer[i++] = ' ';
+ break;
+ case '-': {
+ int temp;
+ char temp_c;
+ if ((temp = read(tmon_temp,&temp_c,1)) > 0) {
+ if (temp_c == '-' ) {
+ /* read till end of line */
+ while ((temp = read(tmon_temp,&temp_c,1)) != 0) {
+ if (temp_c=='\n')
+ break;
+ }
+ }else {
+ query_buffer[i++] = c;
+ query_buffer[i++] = temp_c;
+ }
+ } else {
+ query_buffer[i++] = c;
+ }
+ break;
+ }
+ case '$': {
+ int temp;
+ char temp_c[4];
+ /*
+ * monitor feature, not POSTGRES SQL. When monitor sees $PWD,
+ * it will substitute in the current directory.
+ */
+ if ((temp = read(tmon_temp,temp_c,3)) > 0) {
+ temp_c[temp] = '\0';
+ if (!strncmp(temp_c, "PWD", 3)) {
+ int len;
+ char cwdPath[MAXPATHLEN];
+ if (getcwd(cwdPath, MAXPATHLEN)==NULL) {
+ fprintf(stderr,
+ "cannot get current working directory\n");
+ break;
+ }
+ len = strlen(cwdPath);
+ query_buffer[i] = '\0';
+ strcat(query_buffer, cwdPath);
+ i += len;
+ } else {
+ int j;
+ query_buffer[i++] = c;
+ for(j = 0; j < temp; j++) {
+ query_buffer[i++] = temp_c[j];
+ }
+ }
+ } else {
+ query_buffer[i++] = c;
+ }
+ break;
+ }
+ default:
+ query_buffer[i++] = c;
+ break;
+ }
+ }
+
+ if (query_buffer[0] == 0) {
+ query_buffer[0] = ' ';
+ query_buffer[1] = 0;
+ }
+
+ if (Verbose && !SingleStepMode)
+ fprintf(stdout,"Query sent to backend is \"%s\"\n", query_buffer);
+
+ fflush(stderr);
+ fflush(stdout);
+
+ /*
+ * Repeat commands until done.
+ */
+
+ handle_execution(query_buffer);
+
+ /* clear the query buffer and temp file -- this is very expensive */
+ handle_clear();
+ memset(query_buffer,0,i);
+}
+
+/*
+ * Actually execute the query in *query.
+ *
+ * Returns 0 if the query finished successfully, 1 otherwise.
+ */
+static int
+handle_execution(char *query)
+{
+ PGresult *result;
+ int retval = 0;
+
+ result = PQexec(conn, query);
+
+ if (result == NULL) {
+ fprintf(stderr,"%s", PQerrorMessage(conn));
+ return 1;
+ }
+
+ switch (PQresultStatus(result)) {
+ case PGRES_EMPTY_QUERY:
+ break;
+ case PGRES_COMMAND_OK:
+ break;
+ case PGRES_TUPLES_OK:
+/* PQprintTuples(result,stdout,PrintAttNames,TerseOutput,COLWIDTH); */
+ if (TerseOutput)
+ PQdisplayTuples(result,stdout,1,"",PrintAttNames,TerseOutput);
+ else
+ PQdisplayTuples(result,stdout,1,"|",PrintAttNames,TerseOutput);
+ break;
+ case PGRES_COPY_OUT:
+ handle_copy_out(result);
+ break;
+ case PGRES_COPY_IN:
+ handle_copy_in(result);
+ break;
+ case PGRES_BAD_RESPONSE:
+ retval = 1;
+ break;
+ case PGRES_NONFATAL_ERROR:
+ retval = 1;
+ break;
+ case PGRES_FATAL_ERROR:
+ retval = 1;
+ break;
+ }
+
+ if (SingleStepMode) {
+ fflush(stdin);
+ printf("\npress return to continue ...\n");
+ getc(stdin); /* assume stdin is not a file! */
+ }
+ return(retval);
+}
+
+/*
+ * handle_file_insert()
+ *
+ * allows the user to insert a query file and execute it.
+ * NOTE: right now the full path name must be specified.
+ */
+static void
+handle_file_insert(FILE *ifp)
+{
+ char user_filename[50];
+ FILE *nifp;
+
+ fscanf(ifp, "%s",user_filename);
+ nifp = fopen(user_filename, "r");
+ if (nifp == (FILE *) NULL) {
+ fprintf(stderr, "Cannot open %s\n", user_filename);
+ } else {
+ do_input(nifp);
+ fclose (nifp);
+ }
+}
+
+/*
+ * handle_print()
+ *
+ * This routine prints out the contents (query) of the temp. file
+ * onto stdout.
+ */
+static void
+handle_print()
+{
+ char c;
+ off_t pos;
+ int cc;
+
+ pos = lseek(tmon_temp, (off_t) 0, SEEK_SET);
+
+ if (pos != 0 )
+ fprintf(stderr, "Bogus file position\n");
+
+ printf("\n");
+
+ while ( ( cc = read(tmon_temp,&c,1) ) != 0)
+ putchar(c);
+
+ printf("\n");
+}
+
+
+/*
+ * handle_exit()
+ *
+ * ends the comm. with the backend and exit the tm.
+ */
+static void
+handle_exit(int exit_status)
+{
+ if (!RunOneCommand) {
+ close(tmon_temp);
+ unlink(tmon_temp_filename);
+ }
+ PQfinish(conn);
+ exit(exit_status);
+}
+
+/*
+ * handle_clear()
+ *
+ * This routine clears the temp. file.
+ */
+static void
+handle_clear()
+{
+ /* high cost */
+ close(tmon_temp);
+ tmon_temp = open(tmon_temp_filename,O_TRUNC|O_RDWR|O_CREAT ,0666);
+}
+
+/*
+ * handle_print_time()
+ * prints out the date using the "date" command.
+ */
+static void
+handle_print_time()
+{
+ system("date");
+}
+
+/*
+ * handle_write_to_file()
+ *
+ * writes the contents of the temp. file to the
+ * specified file.
+ */
+static int
+handle_write_to_file()
+{
+ char filename[50];
+ static char command_line[512];
+ int status;
+
+ status = scanf("%s", filename);
+ if (status < 1 || !filename[0]) {
+ fprintf(stderr, "error: filename is empty\n");
+ return(-1);
+ }
+
+ /* XXX portable way to check return status? $%&! ultrix ... */
+ (void) sprintf(command_line, "rm -f %s", filename);
+ (void) system(command_line);
+ (void) sprintf(command_line, "cp %s %s", tmon_temp_filename, filename);
+ (void) system(command_line);
+
+ return(0);
+}
+
+/*
+ *
+ * Prints out a help message.
+ *
+ */
+static void
+handle_help()
+{
+ printf("Available commands include \n\n");
+ printf("\\e -- enter editor\n");
+ printf("\\g -- \"GO\": submit query to POSTGRES\n");
+ printf("\\i -- include (switch input to external file)\n");
+ printf("\\p -- print query buffer\n");
+ printf("\\q -- quit POSTGRES\n");
+ printf("\\r -- force reset (clear) of query buffer\n");
+ printf("\\s -- shell escape \n");
+ printf("\\t -- print current time\n");
+ printf("\\w -- write query buffer to external file\n");
+ printf("\\h -- print the list of commands\n");
+ printf("\\? -- print the list of commands\n");
+ printf("\\\\ -- produce a single backslash in query buffer\n");
+ fflush(stdin);
+}
+
+/*
+ * stuff_buffer()
+ *
+ * writes the user input into the temp. file.
+ */
+static void
+stuff_buffer(char c)
+{
+ int cc;
+
+ cc = write(tmon_temp,&c,1);
+
+ if(cc == -1)
+ fprintf(stderr, "error writing to temp file\n");
+}
+
+static void
+argsetup(int *argcP, char ***argvP)
+{
+ int argc;
+ char **argv, **curarg;
+ char *eopts;
+ char *envopts;
+ int neopts;
+ char *start, *end;
+ arge *head, *tail, *cur;
+
+ /* if no options specified in environment, we're done */
+ if ((envopts = getenv("PGOPTION")) == (char *) NULL)
+ return;
+
+ if ((eopts = (char *) malloc(strlen(envopts) + 1)) == (char *) NULL) {
+ fprintf(stderr, "cannot malloc copy space for PGOPTION\n");
+ fflush(stderr);
+ exit (2);
+ }
+
+ (void) strcpy(eopts, envopts);
+
+ /*
+ * okay, we have PGOPTION from the environment, and we want to treat
+ * them as user-specified options. to do this, we construct a new
+ * argv that has argv[0] followed by the arguments from the environment
+ * followed by the arguments on the command line.
+ */
+
+ head = cur = (arge *) NULL;
+ neopts = 0;
+
+ for (;;) {
+ while (isspace(*eopts) && *eopts)
+ eopts++;
+
+ if (*eopts == '\0')
+ break;
+
+ if ((cur = (arge *) malloc(sizeof(arge))) == (arge *) NULL) {
+ fprintf(stderr, "cannot malloc space for arge\n");
+ fflush(stderr);
+ exit (2);
+ }
+
+ end = start = eopts;
+
+ if (*start == '"') {
+ start++;
+ while (*++end != '\0' && *end != '"')
+ continue;
+ if (*end == '\0') {
+ fprintf(stderr, "unterminated string constant in env var PGOPTION\n");
+ fflush(stderr);
+ exit (2);
+ }
+ eopts = end + 1;
+ } else if (*start == '\'') {
+ start++;
+ while (*++end != '\0' && *end != '\'')
+ continue;
+ if (*end == '\0') {
+ fprintf(stderr, "unterminated string constant in env var PGOPTION\n");
+ fflush(stderr);
+ exit (2);
+ }
+ eopts = end + 1;
+ } else {
+ while (!isspace(*end) && *end)
+ end++;
+ if (isspace(*end))
+ eopts = end + 1;
+ else
+ eopts = end;
+ }
+
+ if (head == (arge *) NULL) {
+ head = tail = cur;
+ } else {
+ tail->a_next = cur;
+ tail = cur;
+ }
+
+ cur->a_arg = start;
+ cur->a_next = (arge *) NULL;
+
+ *end = '\0';
+ neopts++;
+ }
+
+ argc = *argcP + neopts;
+
+ if ((argv = (char **) malloc(argc * sizeof(char *))) == (char **) NULL) {
+ fprintf(stderr, "can't malloc space for modified argv\n");
+ fflush(stderr);
+ exit (2);
+ }
+
+ curarg = argv;
+ *curarg++ = *(*argvP)++;
+
+ /* copy env args */
+ while (head != (arge *) NULL) {
+ cur = head;
+ *curarg++ = head->a_arg;
+ head = head->a_next;
+ free(cur);
+ }
+
+ /* copy rest of args from command line */
+ while (--(*argcP))
+ *curarg++ = *(*argvP)++;
+
+ /* all done */
+ *argvP = argv;
+ *argcP = argc;
+}
+
+static void
+handle_copy_out(PGresult *res)
+{
+ bool copydone = false;
+ char copybuf[COPYBUFSIZ];
+ int ret;
+
+ if (!Silent)
+ fprintf(stdout, "Copy command returns...\n");
+
+ while (!copydone) {
+ ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
+
+ if (copybuf[0] == '.' && copybuf[1] =='\0') {
+ copydone = true; /* don't print this... */
+ } else {
+ fputs(copybuf, stdout);
+ switch (ret) {
+ case EOF:
+ copydone = true;
+ /*FALLTHROUGH*/
+ case 0:
+ fputc('\n', stdout);
+ break;
+ case 1:
+ break;
+ }
+ }
+ }
+ fflush(stdout);
+ PQendcopy(res->conn);
+}
+
+static void
+handle_copy_in(PGresult *res)
+{
+ bool copydone = false;
+ bool firstload;
+ bool linedone;
+ char copybuf[COPYBUFSIZ];
+ char *s;
+ int buflen;
+ int c;
+
+ if (!Silent) {
+ fputs("Enter info followed by a newline\n", stdout);
+ fputs("End with a dot on a line by itself.\n", stdout);
+ }
+
+ /*
+ * eat inevitable newline still in input buffer
+ *
+ * XXX the 'inevitable newline' is not always present
+ * for example `cat file | monitor -c "copy from stdin"'
+ */
+ fflush(stdin);
+ if ((c = getc(stdin)) != '\n' && c != EOF) {
+ (void) ungetc(c, stdin);
+ }
+
+ while (!copydone) { /* for each input line ... */
+ if (!Silent) {
+ fputs(">> ", stdout);
+ fflush(stdout);
+ }
+ firstload = true;
+ linedone = false;
+ while (!linedone) { /* for each buffer ... */
+ s = copybuf;
+ buflen = COPYBUFSIZ;
+ for (; buflen > 1 &&
+ !(linedone = (c = getc(stdin)) == '\n' || c == EOF);
+ --buflen) {
+ *s++ = c;
+ }
+ if (c == EOF) {
+ /* reading from stdin, but from a file */
+ PQputline(res->conn, ".");
+ copydone = true;
+ break;
+ }
+ *s = '\0';
+ PQputline(res->conn, copybuf);
+ if (firstload) {
+ if (!strcmp(copybuf, ".")) {
+ copydone = true;
+ }
+ firstload = false;
+ }
+ }
+ PQputline(res->conn, "\n");
+ }
+ PQendcopy(res->conn);
+}
diff --git a/src/bin/pg4_dump/Makefile b/src/bin/pg4_dump/Makefile
new file mode 100644
index 00000000000..286f96ea299
--- /dev/null
+++ b/src/bin/pg4_dump/Makefile
@@ -0,0 +1,13 @@
+#
+# /usr/local/devel/pglite/cvs/src/bin/pg_dump/Makefile.v4r2,v 1.1 1995/05/17 18:57:10 jolly Exp
+#
+
+.include <postgres.global.mk>
+
+CFLAGS+= -I${.CURDIR}/../../backend/tmp
+
+PROG= pg4_dump
+
+SRCS= pg4_dump.c common.c
+
+.include <postgres.prog.mk>
diff --git a/src/bin/pg4_dump/README b/src/bin/pg4_dump/README
new file mode 100644
index 00000000000..4ac54517096
--- /dev/null
+++ b/src/bin/pg4_dump/README
@@ -0,0 +1,87 @@
+pg4_dump is a utility for dumping out a postgres (version 4, release 2)
+database into a script file containing query commands. The script
+files are in a ASCII format and can be used to reconstruct the
+database, even on other machines and other architectures. pg_dump
+will produce the queries necessary to re-generate all user-defined
+types, functions, tables, indices, aggregates, and operators. In
+addition, all the data is copied out in ASCII format so that it can be
+readily copied in again.
+
+The sources in this directory can be used to build two different
+versions of the program. The two versions require different
+versions of libpq, and the same binary cannot serve both purposes.
+
+
+ To build:
+
+ % bmake clean install
+
+ This version of the program will read in your postgres v4r2
+database and output the schema and the data tuples in one of two
+formats: POSTQUEL or SQL. The POSTQUEL->POSTQUEL dumps are useful
+for moving from one v4r2 installation to another. The POSTQUEL->SQL
+dumps are useful for migrating from v4r2 to postgres95.
+
+Use the -o [SQL|POSTQUEL] option to specify output query language.
+
+
+How to use pg4_dump:
+-------------------
+
+The command line options are fairly self explanatory. Use -help to
+see the command line options. I recommend using -v to get more
+verbose descriptions of what pg_dump is doing.
+
+After running pg4_dump, one should examine the output script file for any
+warnings, especially in light of the limitations listed below.
+
+A typical use of pg4_dump:
+
+ % pg4_dump -v -f oldDB.dump oldDB
+ % createdb newDB
+ % monitor newDB < oldDB.dump
+
+
+Caveats and limitations:
+------------------------
+
+pg4_dump has a few limitations. The limitations mostly stem from
+difficulty in extracting certain meta-information from the system
+catalogs.
+
+ rules and views:
+ pg4_dump does not understand user-defined rules and views and
+ will fail to dump them properly. (This is due to the fact that
+ rules are stored as plans in the catalogs and not textually)
+
+ partial indices:
+ pg4_dump does not understand partial indices. (The reason is
+ the same as above. Partial index predicates are stored as plans)
+
+ source text of POSTQUEL functions:
+ pg4_dump does not convert the source text of a user-defined
+ POSTQUEL function into SQL. Manual intervention is required.
+
+ large objects:
+ pg4_dump does not handle large objects. Inversion large
+ objects are ignored and must be dealt with manually.
+
+ oid preservation:
+ pg4_dump does not preserve oid's while dumping. If you have
+ stored oid's explicitly in tables in user-defined attributes,
+ and are using them as keys, then the output scripts will not
+ regenerate your database correctly.
+
+pg4_dump has not been tested and will probably not work properly for
+versions of postgres prior to 4.2.
+
+Bug-reporting
+--------------
+
+If you should find a problem with pg4_dump, it is very important that
+you provide a (small) sample database which illustrates the problem.
+Please send bugs, questions, and feedback to the
+ postgres95@postgres.berkeley.edu
+
+
+
diff --git a/src/bin/pg4_dump/common.c b/src/bin/pg4_dump/common.c
new file mode 100644
index 00000000000..f485c152c67
--- /dev/null
+++ b/src/bin/pg4_dump/common.c
@@ -0,0 +1,417 @@
+/*-------------------------------------------------------------------------
+ *
+ * common.c--
+ * common routines between pg_dump and pg4_dump
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * /usr/local/devel/pglite/cvs/src/bin/pg_dump/common.c,v 1.5 1995/06/28 22:32:35 jolly Exp
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
+#ifdef PORTNAME_sparc_solaris
+#include <netdb.h> /* for MAXHOSTNAMELEN on some */
+#endif
+
+#include "postgres.h"
+#include "libpq-fe.h"
+#include "libpq/auth.h"
+
+#include "pg_dump.h"
+
+/*
+ * check_conn_and_db checks the connection and the database
+ */
+void
+check_conn_and_db()
+{
+ char *string= PQexec(" ");
+ switch(*string) {
+ case 'E':
+ case 'R':
+ PQfinish();
+ exit(2);
+ break;
+ }
+}
+
+
+/* dupstr : copies a string, while allocating space for it.
+ the CALLER is responsible for freeing the space
+ returns NULL if the argument is NULL*/
+char*
+dupstr(char *s)
+{
+ char* result;
+
+ if (s == NULL)
+ return NULL;
+
+ result = (char*)malloc(strlen(s)+1);
+ strcpy(result, s);
+ return result;
+}
+
+
+/*
+ * findTypeByOid
+ * given an oid of a type, return its typename
+ *
+ * if oid is "0", return "opaque" -- this is a special case
+ *
+ * NOTE: should hash this, but just do linear search for now
+ */
+
+char*
+findTypeByOid(TypeInfo* tinfo, int numTypes, char* oid)
+{
+ int i;
+
+ if (strcmp(oid, "0") == 0) return g_opaque_type;
+
+ for (i=0;i<numTypes;i++) {
+ if (strcmp(tinfo[i].oid, oid) == 0)
+ return tinfo[i].typname;
+ }
+
+ /* should never get here */
+ fprintf(stderr,"failed sanity check, type with oid %s was not found\n",
+ oid);
+ exit(2);
+}
+
+/*
+ * findOprByOid
+ * given the oid of an operator, return the name of the operator
+ *
+ *
+ * NOTE: should hash this, but just do linear search for now
+ *
+ */
+char*
+findOprByOid(OprInfo *oprinfo, int numOprs, char *oid)
+{
+ int i;
+ for (i=0;i<numOprs;i++) {
+ if (strcmp(oprinfo[i].oid, oid) == 0)
+ return oprinfo[i].oprname;
+ }
+
+ /* should never get here */
+ fprintf(stderr,"failed sanity check, opr with oid %s was not found\n",
+ oid);
+ exit(2);
+}
+
+
+/*
+ * findParentsByOid --
+ * given the oid of a class, return the names of its parent classes
+ * and assign the number of parents to the last argument.
+ *
+ *
+ * returns NULL if none
+ */
+
+char**
+findParentsByOid(TableInfo* tblinfo, int numTables,
+ InhInfo* inhinfo, int numInherits, char *oid,
+ int *numParentsPtr)
+{
+ int i,j;
+ int parentInd;
+ char** result;
+ int numParents;
+
+ numParents = 0;
+ for (i=0;i<numInherits;i++) {
+ if ( strcmp(inhinfo[i].inhrel, oid) == 0) {
+ numParents++;
+ }
+ }
+
+ *numParentsPtr = numParents;
+
+ if (numParents > 0) {
+ result = (char**)malloc(sizeof(char*) * numParents);
+ j = 0;
+ for (i=0;i<numInherits;i++) {
+ if ( strcmp(inhinfo[i].inhrel, oid) == 0) {
+ parentInd = findTableByOid(tblinfo, numTables,
+ inhinfo[i].inhparent);
+ result[j++] = tblinfo[parentInd].relname;
+ }
+ }
+ return result;
+ }
+ else
+ return NULL;
+}
+
+/*
+ * parseArgTypes
+ * parse a string of eight numbers delimited by spaces
+ * into a character array
+ */
+
+void
+parseArgTypes(char **argtypes, char* str)
+{
+ int i, j, argNum;
+ char temp[100];
+ char s;
+
+ argNum = 0;
+ j = 0;
+ while ( (s = *str) != '\0') {
+ if (s == ' ') {
+ temp[j] = '\0';
+ argtypes[argNum] = dupstr(temp);
+ argNum++;
+ j = 0;
+ } else {
+ temp[j] = s;
+ j++;
+ }
+ str++;
+ }
+ if (j != 0) {
+ temp[j] = '\0';
+ argtypes[argNum] = dupstr(temp);
+ }
+
+}
+
+
+/*
+ * strInArray:
+ * takes in a string and a string array and the number of elements in the
+ * string array.
+ * returns the index if the string is somewhere in the array, -1 otherwise
+ *
+ */
+
+int
+strInArray(char* pattern, char** arr, int arr_size)
+{
+ int i;
+ for (i=0;i<arr_size;i++) {
+ if (strcmp(pattern, arr[i]) == 0)
+ return i;
+ }
+ return -1;
+}
+
+/*
+ * dumpSchema:
+ * we have a valid connection, we are now going to dump the schema
+ * into the file
+ *
+ */
+
+TableInfo *
+dumpSchema(FILE* fout, int *numTablesPtr)
+{
+ int numTypes;
+ int numFuncs;
+ int numTables;
+ int numInherits;
+ int numIndices;
+ int numAggregates;
+ int numOperators;
+ TypeInfo *tinfo;
+ FuncInfo *finfo;
+ AggInfo *agginfo;
+ TableInfo *tblinfo;
+ InhInfo *inhinfo;
+ IndInfo *indinfo;
+ OprInfo *oprinfo;
+
+if (g_verbose) fprintf(stderr,"%s reading user-defined types %s\n",
+ g_comment_start, g_comment_end);
+ tinfo = getTypes(&numTypes);
+
+if (g_verbose) fprintf(stderr,"%s reading user-defined functions %s\n",
+ g_comment_start, g_comment_end);
+ finfo = getFuncs(&numFuncs);
+
+if (g_verbose) fprintf(stderr,"%s reading user-defined aggregates %s\n",
+ g_comment_start, g_comment_end);
+ agginfo = getAggregates(&numAggregates);
+
+if (g_verbose) fprintf(stderr,"%s reading user-defined operators %s\n",
+ g_comment_start, g_comment_end);
+ oprinfo = getOperators(&numOperators);
+
+if (g_verbose) fprintf(stderr,"%s reading user-defined tables %s\n",
+ g_comment_start, g_comment_end);
+ tblinfo = getTables(&numTables);
+
+if (g_verbose) fprintf(stderr,"%s reading table inheritance information %s\n",
+ g_comment_start, g_comment_end);
+ inhinfo = getInherits(&numInherits);
+
+if (g_verbose) fprintf(stderr, "%s finding the attribute names and types for each table %s\n",
+ g_comment_start, g_comment_end);
+ getTableAttrs(tblinfo, numTables);
+
+if (g_verbose) fprintf(stderr, "%s flagging inherited attributes in subtables %s\n",
+ g_comment_start, g_comment_end);
+ flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
+
+if (g_verbose) fprintf(stderr,"%s reading indices information %s\n",
+ g_comment_start, g_comment_end);
+ indinfo = getIndices(&numIndices);
+
+if (g_verbose) fprintf(stderr,"%s dumping out user-defined types %s\n",
+ g_comment_start, g_comment_end);
+ dumpTypes(fout, finfo, numFuncs, tinfo, numTypes);
+
+if (g_verbose) fprintf(stderr,"%s dumping out tables %s\n",
+ g_comment_start, g_comment_end);
+ dumpTables(fout, tblinfo, numTables, inhinfo, numInherits,
+ tinfo, numTypes);
+
+if (g_verbose) fprintf(stderr,"%s dumping out user-defined functions %s\n",
+ g_comment_start, g_comment_end);
+ dumpFuncs(fout, finfo, numFuncs, tinfo, numTypes);
+
+if (g_verbose) fprintf(stderr,"%s dumping out user-defined functions %s\n",
+ g_comment_start, g_comment_end);
+ dumpAggs(fout, agginfo, numAggregates, tinfo, numTypes);
+
+if (g_verbose) fprintf(stderr,"%s dumping out user-defined operators %s\n",
+ g_comment_start, g_comment_end);
+ dumpOprs(fout, oprinfo, numOperators, tinfo, numTypes);
+
+if (g_verbose) fprintf(stderr,"%s dumping out indices %s\n",
+ g_comment_start, g_comment_end);
+ dumpIndices(fout, indinfo, numIndices, tblinfo, numTables);
+
+ *numTablesPtr = numTables;
+ return tblinfo;
+}
+
+
+/* flagInhAttrs -
+ * for each table in tblinfo, flag its inherited attributes
+ * so when we dump the table out, we don't dump out the inherited attributes
+ *
+ * initializes the parentRels field of each table
+ *
+ * modifies tblinfo
+ *
+ */
+void
+flagInhAttrs(TableInfo* tblinfo, int numTables,
+ InhInfo* inhinfo, int numInherits)
+{
+ int i,j,k;
+ int parentInd;
+ char *parentRels;
+ int numParents;
+
+ /* we go backwards because the tables in tblinfo are in OID
+ order, meaning the subtables are after the parent tables
+ we flag inherited attributes from child tables first */
+ for (i = numTables-1; i >= 0; i--) {
+ tblinfo[i].parentRels = findParentsByOid(tblinfo, numTables,
+ inhinfo, numInherits,
+ tblinfo[i].oid,
+ &tblinfo[i].numParents);
+ for (k=0;k<tblinfo[i].numParents;k++) {
+ parentInd = findTableByName(tblinfo, numTables,
+ tblinfo[i].parentRels[k]);
+ for (j=0;j<tblinfo[i].numatts;j++) {
+ if (strInArray(tblinfo[i].attnames[j],
+ tblinfo[parentInd].attnames,
+ tblinfo[parentInd].numatts) != -1) {
+ tblinfo[i].inhAttrs[j] = 1;
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * findTableByName
+ * finds the index (in tblinfo) of the table with the given relname
+ * returns -1 if not found
+ *
+ * NOTE: should hash this, but just do linear search for now
+ */
+
+int
+findTableByName(TableInfo* tblinfo, int numTables, char* relname)
+{
+ int i;
+ for (i=0;i<numTables;i++) {
+ if (strcmp(tblinfo[i].relname, relname) == 0)
+ return i;
+ }
+ return -1;
+}
+
+/*
+ * findTableByOid
+ * finds the index (in tblinfo) of the table with the given oid
+ * returns -1 if not found
+ *
+ * NOTE: should hash this, but just do linear search for now
+ */
+
+int
+findTableByOid(TableInfo* tblinfo, int numTables, char* oid)
+{
+ int i;
+ for (i=0;i<numTables;i++) {
+ if (strcmp(tblinfo[i].oid, oid) == 0)
+ return i;
+ }
+ return -1;
+}
+
+
+/*
+ * findFuncByName
+ * finds the index (in finfo) of the function with the given name
+ * returns -1 if not found
+ *
+ * NOTE: should hash this, but just do linear search for now
+ */
+
+int
+findFuncByName(FuncInfo* finfo, int numFuncs, char* name)
+{
+ int i;
+ for (i=0;i<numFuncs;i++) {
+ if (strcmp(finfo[i].proname, name) == 0)
+ return i;
+ }
+ return -1;
+}
+
+/*
+ * isArchiveName
+ *
+ * returns true if the relation name is an archive name, false otherwise
+ */
+int
+isArchiveName(char* relname)
+{
+ return (strlen(relname) > 1 && relname[1] == ',');
+}
+
+
+
+
+
+
diff --git a/src/bin/pg4_dump/pg4_dump.c b/src/bin/pg4_dump/pg4_dump.c
new file mode 100644
index 00000000000..6e6ee6fa573
--- /dev/null
+++ b/src/bin/pg4_dump/pg4_dump.c
@@ -0,0 +1,1602 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg4_dump.c--
+ * pg4_dump is an utility for dumping out a postgres database
+ * into a script file.
+ *
+ * pg4_dump will read the system catalogs from a postgresV4r2 database and
+ * dump out a script that reproduces the schema of the database in terms of
+ * user-defined types
+ * user-defined functions
+ * tables
+ * indices
+ * aggregates
+ * operators
+ *
+ * the output script is either POSTQUEL or SQL
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * /usr/local/devel/pglite/cvs/src/bin/pg_dump/pg4_dump.c,v 1.1 1995/05/18 19:23:53 jolly Exp
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
+#ifdef PORTNAME_sparc_solaris
+#include <netdb.h> /* for MAXHOSTNAMELEN on some */
+#endif
+
+#include "tmp/postgres.h"
+#include "tmp/libpq-fe.h"
+#include "libpq/auth.h"
+
+#include "pg_dump.h"
+
+extern char *optarg;
+extern int optind, opterr;
+
+/* these are used in libpq */
+extern char *PQhost; /* machine on which the backend is running */
+extern char *PQport; /* comm. port with the postgres backend. */
+extern char *PQtty; /* the tty where postgres msgs are displayed */
+extern char *PQdatabase; /* the postgres db to access. */
+
+/* global decls */
+int g_verbose; /* verbose flag */
+int g_last_builtin_oid; /* value of the last builtin oid */
+FILE *g_fout; /* the script file */
+
+char g_opaque_type[10]; /* name for the opaque type */
+
+/* placeholders for the delimiters for comments */
+char g_comment_start[10];
+char g_comment_end[10];
+
+int g_outputSQL; /* if 1, output SQL, otherwise , output Postquel */
+
+static
+usage(char* progname)
+{
+ fprintf(stderr, "usage: %s [options] [dbname]\n",progname);
+ fprintf(stderr, "\t -f filename \t\t script output filename\n");
+ fprintf(stderr, "\t -H hostname \t\t server host name\n");
+ fprintf(stderr, "\t -o [SQL|POSTQUEL} \t\t output format\n");
+ fprintf(stderr, "\t -p port \t\t server port number\n");
+ fprintf(stderr, "\t -v \t\t verbose\n");
+ fprintf(stderr, "\t -S \t\t dump out only the schema, no data\n");
+ fprintf(stderr, "\n if dbname is not supplied, then the DATABASE environment name is used\n");
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "\tpg4_dump dumps out postgres databases and produces a script file\n");
+ fprintf(stderr, "\tof query commands to regenerate the schema\n");
+ fprintf(stderr, "\tThe output format is either POSTQUEL or SQL. The default is SQL\n");
+ exit(1);
+}
+
+void
+main(int argc, char** argv)
+{
+ int c;
+ char* progname;
+ char* filename;
+ char* dbname;
+ char *username, usernamebuf[NAMEDATALEN + 1];
+ char hostbuf[MAXHOSTNAMELEN];
+ int schemaOnly;
+
+ TableInfo *tblinfo;
+ int numTables;
+
+
+ dbname = NULL;
+ filename = NULL;
+ g_verbose = 0;
+ g_outputSQL = 1;
+ schemaOnly = 0;
+
+ progname = *argv;
+
+ while ((c = getopt(argc, argv,"f:H:o:p:vSD")) != EOF) {
+ switch(c) {
+ case 'f': /* output file name */
+ filename = optarg;
+ break;
+ case 'H' : /* server host */
+ PQhost = optarg;
+ break;
+ case 'o':
+ {
+ char *lang = optarg;
+ if (lang) {
+ if (strcmp(lang,"SQL") != 0)
+ g_outputSQL = 0;
+ }
+ }
+ break;
+ case 'p' : /* server port */
+ PQport = optarg;
+ break;
+ case 'v': /* verbose */
+ g_verbose = 1;
+ break;
+ case 'S': /* dump schema only */
+ schemaOnly = 1;
+ break;
+ default:
+ usage(progname);
+ break;
+ }
+ }
+
+ /* open the output file */
+ if (filename == NULL) {
+ g_fout = stdout;
+ } else {
+ g_fout = fopen(filename, "w");
+ if (g_fout == NULL) {
+ fprintf(stderr,"%s: could not open output file named %s for writing\n",
+ progname, filename);
+ exit(2);
+ }
+ }
+
+ /* Determine our username (according to the authentication system, if
+ * there is one).
+ */
+ if ((username = fe_getauthname()) == (char *) NULL) {
+ fprintf(stderr, "%s: could not find a valid user name\n",progname);
+ exit(2);
+ }
+ memset(usernamebuf, 0, sizeof(usernamebuf));
+ (void) strncpy(usernamebuf, username, NAMEDATALEN);
+ username = usernamebuf;
+
+ /*
+ * Determine the hostname of the database server. Try to avoid using
+ * "localhost" if at all possible.
+ */
+ if (!PQhost && !(PQhost = getenv("PGHOST")))
+ PQhost = "localhost";
+ if (!strcmp(PQhost, "localhost")) {
+ if (gethostname(hostbuf, MAXHOSTNAMELEN) != -1)
+ PQhost = hostbuf;
+ }
+
+
+ /* find database */
+ if (!(dbname = argv[optind]) &&
+ !(dbname = getenv("DATABASE")) &&
+ !(dbname = username)) {
+ fprintf(stderr, "%s: no database name specified\n",progname);
+ exit (2);
+ }
+
+ PQsetdb(dbname);
+
+ /* make sure things are ok before giving users a warm welcome! */
+ check_conn_and_db();
+
+ if (g_outputSQL) {
+ strcpy(g_comment_start,"-- ");
+ g_comment_end[0] = '\0';
+ strcpy(g_opaque_type, "opaque");
+ } else {
+ strcpy(g_comment_start,"/* ");
+ strcpy(g_comment_end,"*/ ");
+ strcpy(g_opaque_type, "any");
+ }
+
+ g_last_builtin_oid = findLastBuiltinOid();
+
+
+if (g_verbose)
+ fprintf(stderr, "%s last builtin oid is %d %s\n",
+ g_comment_start, g_last_builtin_oid, g_comment_end);
+
+ tblinfo = dumpSchema(g_fout, &numTables);
+
+ if (!schemaOnly) {
+
+if (g_verbose) {
+ fprintf(stderr, "%s dumping out the contents of each table %s\n",
+ g_comment_start, g_comment_end );
+ fprintf(stderr, "%s the output language is %s %s\n",
+ g_comment_start,
+ (g_outputSQL) ? "SQL" : "POSTQUEL",
+ g_comment_end);
+}
+
+ dumpClasses(tblinfo, numTables, g_fout);
+ }
+
+ fflush(g_fout);
+ fclose(g_fout);
+ exit(0);
+}
+
+/*
+ * getTypes:
+ * read all base types in the system catalogs and return them in the
+ * TypeInfo* structure
+ *
+ * numTypes is set to the number of types read in
+ *
+ */
+TypeInfo*
+getTypes(int *numTypes)
+{
+ char* res;
+ PortalBuffer* pbuf;
+ int ntups;
+ int i;
+ char query[MAXQUERYLEN];
+ TypeInfo *tinfo;
+
+ int i_oid;
+ int i_typowner;
+ int i_typname;
+ int i_typlen;
+ int i_typprtlen;
+ int i_typinput;
+ int i_typoutput;
+ int i_typreceive;
+ int i_typsend;
+ int i_typelem;
+ int i_typdelim;
+ int i_typdefault;
+ int i_typrelid;
+ int i_typbyval;
+
+ PQexec("begin");
+
+ /* find all base types */
+ /* we include even the built-in types
+ because those may be used as array elements by user-defined types */
+ /* we filter out the built-in types when
+ we dump out the types */
+
+/*
+ sprintf(query, "SELECT oid, typowner,typname, typlen, typprtlen, typinput, typoutput, typreceive, typsend, typelem, typdelim, typdefault, typrelid,typbyval from pg_type");
+*/
+ sprintf(query, "retrieve (t.oid, t.typowner, t.typname, t.typlen, t.typprtlen, t.typinput, t.typoutput, t.typreceive, t.typsend, t.typelem, t.typdelim, t.typdefault, t.typrelid, t.typbyval) from t in pg_type");
+
+
+ res = PQexec(query);
+ pbuf = PQparray(res+1);
+ ntups = PQntuplesGroup(pbuf,0);
+
+ tinfo = (TypeInfo*)malloc(ntups * sizeof(TypeInfo));
+
+ i_oid = PQfnumberGroup(pbuf,0,"oid");
+ i_typowner = PQfnumberGroup(pbuf,0,"typowner");
+ i_typname = PQfnumberGroup(pbuf,0,"typname");
+ i_typlen = PQfnumberGroup(pbuf,0,"typlen");
+ i_typprtlen = PQfnumberGroup(pbuf,0,"typprtlen");
+ i_typinput = PQfnumberGroup(pbuf,0,"typinput");
+ i_typoutput = PQfnumberGroup(pbuf,0,"typoutput");
+ i_typreceive = PQfnumberGroup(pbuf,0,"typreceive");
+ i_typsend = PQfnumberGroup(pbuf,0,"typsend");
+ i_typelem = PQfnumberGroup(pbuf,0,"typelem");
+ i_typdelim = PQfnumberGroup(pbuf,0,"typdelim");
+ i_typdefault = PQfnumberGroup(pbuf,0,"typdefault");
+ i_typrelid = PQfnumberGroup(pbuf,0,"typrelid");
+ i_typbyval = PQfnumberGroup(pbuf,0,"typbyval");
+
+ for (i=0;i<ntups;i++) {
+ tinfo[i].oid = dupstr(PQgetvalue(pbuf,i,i_oid));
+ tinfo[i].typowner = dupstr(PQgetvalue(pbuf,i,i_typowner));
+ tinfo[i].typname = dupstr(PQgetvalue(pbuf,i,i_typname));
+ tinfo[i].typlen = dupstr(PQgetvalue(pbuf,i,i_typlen));
+ tinfo[i].typprtlen = dupstr(PQgetvalue(pbuf,i,i_typprtlen));
+ tinfo[i].typinput = dupstr(PQgetvalue(pbuf,i,i_typinput));
+ tinfo[i].typoutput = dupstr(PQgetvalue(pbuf,i,i_typoutput));
+ tinfo[i].typreceive = dupstr(PQgetvalue(pbuf,i,i_typreceive));
+ tinfo[i].typsend = dupstr(PQgetvalue(pbuf,i,i_typsend));
+ tinfo[i].typelem = dupstr(PQgetvalue(pbuf,i,i_typelem));
+ tinfo[i].typdelim = dupstr(PQgetvalue(pbuf,i,i_typdelim));
+ tinfo[i].typdefault = dupstr(PQgetvalue(pbuf,i,i_typdefault));
+ tinfo[i].typrelid = dupstr(PQgetvalue(pbuf,i,i_typrelid));
+
+ if (strcmp(PQgetvalue(pbuf,i,i_typbyval), "f") == 0)
+ tinfo[i].passedbyvalue = 0;
+ else
+ tinfo[i].passedbyvalue = 1;
+
+ /* check for user-defined array types,
+ omit system generated ones */
+ if ( (strcmp(tinfo[i].typelem, "0") != 0) &&
+ tinfo[i].typname[0] != '_')
+ tinfo[i].isArray = 1;
+ else
+ tinfo[i].isArray = 0;
+ }
+
+ *numTypes = ntups;
+
+ PQexec("end");
+ PQclear(res+1);
+ return tinfo;
+}
+
+/*
+ * getOperators:
+ * read all operators in the system catalogs and return them in the
+ * OprInfo* structure
+ *
+ * numOprs is set to the number of operators read in
+ *
+ *
+ */
+
+OprInfo*
+getOperators(int *numOprs)
+{
+ char *res;
+ PortalBuffer *pbuf;
+ int ntups;
+ int i;
+ char query[MAXQUERYLEN];
+
+ OprInfo* oprinfo;
+
+ int i_oid;
+ int i_oprname;
+ int i_oprkind;
+ int i_oprcode;
+ int i_oprleft;
+ int i_oprright;
+ int i_oprcom;
+ int i_oprnegate;
+ int i_oprrest;
+ int i_oprjoin;
+ int i_oprcanhash;
+ int i_oprlsortop;
+ int i_oprrsortop;
+
+ /* find all operators, including builtin operators,
+ filter out system-defined operators at dump-out time */
+ PQexec("begin");
+/*
+ sprintf(query, "SELECT oid, oprname, oprkind, oprcode, oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, oprcanhash, oprlsortop, oprrsortop from pg_operator");
+*/
+ sprintf(query, "retrieve (o.oid, o.oprname, o.oprkind, o.oprcode, o.oprleft, o.oprright, o.oprcom, o.oprnegate, o.oprrest, o.oprjoin, o.oprcanhash, o.oprlsortop, o.oprrsortop) from o in pg_operator");
+
+
+ res = PQexec(query);
+ pbuf = PQparray(res+1);
+ ntups = PQntuplesGroup(pbuf,0);
+ *numOprs = ntups;
+
+ oprinfo = (OprInfo*)malloc(ntups * sizeof(OprInfo));
+
+ i_oid = PQfnumberGroup(pbuf,0,"oid");
+ i_oprname = PQfnumberGroup(pbuf,0,"oprname");
+ i_oprkind = PQfnumberGroup(pbuf,0,"oprkind");
+ i_oprcode = PQfnumberGroup(pbuf,0,"oprcode");
+ i_oprleft = PQfnumberGroup(pbuf,0,"oprleft");
+ i_oprright = PQfnumberGroup(pbuf,0,"oprright");
+ i_oprcom = PQfnumberGroup(pbuf,0,"oprcom");
+ i_oprnegate = PQfnumberGroup(pbuf,0,"oprnegate");
+ i_oprrest = PQfnumberGroup(pbuf,0,"oprrest");
+ i_oprjoin = PQfnumberGroup(pbuf,0,"oprjoin");
+ i_oprcanhash = PQfnumberGroup(pbuf,0,"oprcanhash");
+ i_oprlsortop = PQfnumberGroup(pbuf,0,"oprlsortop");
+ i_oprrsortop = PQfnumberGroup(pbuf,0,"oprrsortop");
+
+ for (i=0;i<ntups;i++) {
+ oprinfo[i].oid = dupstr(PQgetvalue(pbuf,i,i_oid));
+ oprinfo[i].oprname = dupstr(PQgetvalue(pbuf,i,i_oprname));
+ oprinfo[i].oprkind = dupstr(PQgetvalue(pbuf,i,i_oprkind));
+ oprinfo[i].oprcode = dupstr(PQgetvalue(pbuf,i,i_oprcode));
+ oprinfo[i].oprleft = dupstr(PQgetvalue(pbuf,i,i_oprleft));
+ oprinfo[i].oprright = dupstr(PQgetvalue(pbuf,i,i_oprright));
+ oprinfo[i].oprcom = dupstr(PQgetvalue(pbuf,i,i_oprcom));
+ oprinfo[i].oprnegate = dupstr(PQgetvalue(pbuf,i,i_oprnegate));
+ oprinfo[i].oprrest = dupstr(PQgetvalue(pbuf,i,i_oprrest));
+ oprinfo[i].oprjoin = dupstr(PQgetvalue(pbuf,i,i_oprjoin));
+ oprinfo[i].oprcanhash = dupstr(PQgetvalue(pbuf,i,i_oprcanhash));
+ oprinfo[i].oprlsortop = dupstr(PQgetvalue(pbuf,i,i_oprlsortop));
+ oprinfo[i].oprrsortop = dupstr(PQgetvalue(pbuf,i,i_oprrsortop));
+ }
+
+ PQclear(res+1);
+ PQexec("end");
+
+ return oprinfo;
+}
+
+
+/*
+ * getAggregates:
+ * read all the user-defined aggregates in the system catalogs and
+ * return them in the AggInfo* structure
+ *
+ * numAggs is set to the number of aggregates read in
+ *
+ *
+ */
+AggInfo*
+getAggregates(int *numAggs)
+{
+ char* res;
+ PortalBuffer *pbuf;
+ int ntups;
+ int i;
+ char query[MAXQUERYLEN];
+ AggInfo *agginfo;
+
+ int i_oid;
+ int i_aggname;
+ int i_aggtransfn1;
+ int i_aggtransfn2;
+ int i_aggfinalfn;
+ int i_aggtranstype1;
+ int i_aggbasetype;
+ int i_aggtranstype2;
+ int i_agginitval1;
+ int i_agginitval2;
+
+ /* find all user-defined aggregates */
+
+ PQexec("begin");
+/*
+ sprintf(query,
+ "SELECT oid, aggname, aggtransfn1, aggtransfn2, aggfinalfn, aggtranstype1, aggbasetype, aggtranstype2, agginitval1, agginitval2 from pg_aggregate;");
+*/
+ sprintf(query,
+ "retrieve (a.oid, a.aggname, a.aggtransfn1, a.aggtransfn2, a.aggfinalfn, a.aggtranstype1, a.aggbasetype, a.aggtranstype2, a.agginitval1, a.agginitval2) from a in pg_aggregate");
+
+ res = PQexec(query);
+ pbuf = PQparray(res+1);
+ ntups = PQntuplesGroup(pbuf,0);
+ *numAggs = ntups;
+
+ agginfo = (AggInfo*)malloc(ntups * sizeof(AggInfo));
+
+ i_oid = PQfnumberGroup(pbuf,0,"oid");
+ i_aggname = PQfnumberGroup(pbuf,0,"aggname");
+ i_aggtransfn1 = PQfnumberGroup(pbuf,0,"aggtransfn1");
+ i_aggtransfn2 = PQfnumberGroup(pbuf,0,"aggtransfn2");
+ i_aggfinalfn = PQfnumberGroup(pbuf,0,"aggfinalfn");
+ i_aggtranstype1 = PQfnumberGroup(pbuf,0,"aggtranstype1");
+ i_aggbasetype = PQfnumberGroup(pbuf,0,"aggbasetype");
+ i_aggtranstype2 = PQfnumberGroup(pbuf,0,"aggtranstype2");
+ i_agginitval1 = PQfnumberGroup(pbuf,0,"agginitval1");
+ i_agginitval2 = PQfnumberGroup(pbuf,0,"agginitval2");
+
+ for (i=0;i<ntups;i++) {
+ agginfo[i].oid = dupstr(PQgetvalue(pbuf,i,i_oid));
+ agginfo[i].aggname = dupstr(PQgetvalue(pbuf,i,i_aggname));
+ agginfo[i].aggtransfn1 = dupstr(PQgetvalue(pbuf,i,i_aggtransfn1));
+ agginfo[i].aggtransfn2 = dupstr(PQgetvalue(pbuf,i,i_aggtransfn2));
+ agginfo[i].aggfinalfn = dupstr(PQgetvalue(pbuf,i,i_aggfinalfn));
+ agginfo[i].aggtranstype1 = dupstr(PQgetvalue(pbuf,i,i_aggtranstype1));
+ agginfo[i].aggbasetype = dupstr(PQgetvalue(pbuf,i,i_aggbasetype));
+ agginfo[i].aggtranstype2 = dupstr(PQgetvalue(pbuf,i,i_aggtranstype2));
+ agginfo[i].agginitval1 = dupstr(PQgetvalue(pbuf,i,i_agginitval1));
+ agginfo[i].agginitval2 = dupstr(PQgetvalue(pbuf,i,i_agginitval2));
+ }
+
+ PQclear(res+1);
+ PQexec("end");
+
+ return agginfo;
+}
+
+/*
+ * getFuncs:
+ * read all the user-defined functions in the system catalogs and
+ * return them in the FuncInfo* structure
+ *
+ * numFuncs is set to the number of functions read in
+ *
+ *
+ */
+FuncInfo*
+getFuncs(int *numFuncs)
+{
+ char* res;
+ PortalBuffer *pbuf;
+ int ntups;
+ int i, j;
+ char query[MAXQUERYLEN];
+ FuncInfo *finfo;
+ char *proargtypes;
+
+ int i_oid;
+ int i_proname;
+ int i_proowner;
+ int i_prolang;
+ int i_pronargs;
+ int i_proargtypes;
+ int i_prorettype;
+ int i_proretset;
+ int i_prosrc;
+ int i_probin;
+
+ /* find all user-defined funcs */
+
+ PQexec("begin");
+
+/*
+ sprintf(query,
+ "SELECT oid, proname, proowner, prolang, pronargs, prorettype, proretset, proargtypes, prosrc, probin from pg_proc where oid > '%d'::oid",
+ g_last_builtin_oid);
+*/
+ sprintf(query,
+ "retrieve (f.oid, f.proname, f.proowner, f.prolang, f.pronargs, f.prorettype, f.proretset, f.proargtypes, f.prosrc, f.probin) from f in pg_proc where f.oid > \"%d\"::oid",
+ g_last_builtin_oid);
+
+ res = PQexec(query);
+ pbuf = PQparray(res+1);
+ ntups = PQntuplesGroup(pbuf,0);
+
+ *numFuncs = ntups;
+
+ finfo = (FuncInfo*)malloc(ntups * sizeof(FuncInfo));
+
+ i_oid = PQfnumberGroup(pbuf,0,"oid");
+ i_proname = PQfnumberGroup(pbuf,0,"proname");
+ i_proowner = PQfnumberGroup(pbuf,0,"proowner");
+ i_prolang = PQfnumberGroup(pbuf,0,"prolang");
+ i_pronargs = PQfnumberGroup(pbuf,0,"pronargs");
+ i_proargtypes = PQfnumberGroup(pbuf,0,"proargtypes");
+ i_prorettype = PQfnumberGroup(pbuf,0,"prorettype");
+ i_proretset = PQfnumberGroup(pbuf,0,"proretset");
+ i_prosrc = PQfnumberGroup(pbuf,0,"prosrc");
+ i_probin = PQfnumberGroup(pbuf,0,"probin");
+
+ for (i=0;i<ntups;i++) {
+ finfo[i].oid = dupstr(PQgetvalue(pbuf,i,i_oid));
+ finfo[i].proname = dupstr(PQgetvalue(pbuf,i,i_proname));
+ finfo[i].proowner = dupstr(PQgetvalue(pbuf,i,i_proowner));
+
+ finfo[i].prosrc = checkForQuote(PQgetvalue(pbuf,i,i_prosrc));
+ finfo[i].probin = dupstr(PQgetvalue(pbuf,i,i_probin));
+
+ finfo[i].prorettype = dupstr(PQgetvalue(pbuf,i,i_prorettype));
+ finfo[i].retset = (strcmp(PQgetvalue(pbuf,i,i_proretset),"t") == 0);
+ finfo[i].nargs = atoi(PQgetvalue(pbuf,i,i_pronargs));
+ finfo[i].lang = (atoi(PQgetvalue(pbuf,i,i_prolang)) == C_PROLANG_OID);
+
+ parseArgTypes(finfo[i].argtypes, PQgetvalue(pbuf,i,i_proargtypes));
+
+ finfo[i].dumped = 0;
+ }
+
+ PQclear(res+1);
+ PQexec("end");
+
+ return finfo;
+
+}
+
+/*
+ * getTables
+ * read all the user-defined tables (no indices, no catalogs)
+ * in the system catalogs return them in the TableInfo* structure
+ *
+ * numTables is set to the number of tables read in
+ *
+ *
+ */
+TableInfo*
+getTables(int *numTables)
+{
+ char* res;
+ PortalBuffer* pbuf;
+ int ntups;
+ int i, j;
+ char query[MAXQUERYLEN];
+ TableInfo *tblinfo;
+
+ int i_oid;
+ int i_relname;
+ int i_relarch;
+
+ /* find all the user-defined tables (no indices and no catalogs),
+ ordering by oid is important so that we always process the parent
+ tables before the child tables when traversing the tblinfo* */
+ PQexec("begin");
+/*
+ sprintf(query,
+ "SELECT oid, relname, relarch from pg_class where relkind = 'r' and relname !~ '^pg_' order by oid;");
+*/
+ sprintf(query,
+ "retrieve (r.oid, r.relname, r.relarch) from r in pg_class where r.relkind = \"r\" and r.relname !~ \"^pg_\" and r.relname !~ \"^Xinv\" sort by oid");
+
+ res = PQexec(query);
+ pbuf = PQparray(res+1);
+ ntups = PQntuplesGroup(pbuf,0);
+
+ *numTables = ntups;
+
+ tblinfo = (TableInfo*)malloc(ntups * sizeof(TableInfo));
+
+ i_oid = PQfnumberGroup(pbuf,0,"oid");
+ i_relname = PQfnumberGroup(pbuf,0,"relname");
+ i_relarch = PQfnumberGroup(pbuf,0,"relarch");
+
+ for (i=0;i<ntups;i++) {
+ tblinfo[i].oid = dupstr(PQgetvalue(pbuf,i,i_oid));
+ tblinfo[i].relname = dupstr(PQgetvalue(pbuf,i,i_relname));
+ tblinfo[i].relarch = dupstr(PQgetvalue(pbuf,i,i_relarch));
+ }
+
+ PQclear(res+1);
+ PQexec("end");
+
+ return tblinfo;
+
+}
+
+/*
+ * getInherits
+ * read all the inheritance information
+ * from the system catalogs return them in the InhInfo* structure
+ *
+ * numInherits is set to the number of tables read in
+ *
+ *
+ */
+InhInfo*
+getInherits(int *numInherits)
+{
+ char* res;
+ PortalBuffer* pbuf;
+ int ntups;
+ int i;
+ char query[MAXQUERYLEN];
+ InhInfo *inhinfo;
+
+ int i_inhrel;
+ int i_inhparent;
+
+ /* find all the inheritance information */
+ PQexec("begin");
+/*
+ sprintf(query, "SELECT inhrel, inhparent from pg_inherits");
+*/
+ sprintf(query, "retrieve (i.inhrel, i.inhparent) from i in pg_inherits");
+
+ res = PQexec(query);
+ pbuf = PQparray(res+1);
+ ntups = PQntuplesGroup(pbuf,0);
+
+ *numInherits = ntups;
+
+ inhinfo = (InhInfo*)malloc(ntups * sizeof(InhInfo));
+
+ i_inhrel = PQfnumberGroup(pbuf,0,"inhrel");
+ i_inhparent = PQfnumberGroup(pbuf,0,"inhparent");
+
+ for (i=0;i<ntups;i++) {
+ inhinfo[i].inhrel = dupstr(PQgetvalue(pbuf,i,i_inhrel));
+ inhinfo[i].inhparent = dupstr(PQgetvalue(pbuf,i,i_inhparent));
+ }
+
+ PQclear(res+1);
+ PQexec("end");
+ return inhinfo;
+}
+
+/*
+ * getTableAttrs -
+ * for each table in tblinfo, read its attributes types and names
+ *
+ * this is implemented in a very inefficient way right now, looping
+ * through the tblinfo and doing a join per table to find the attrs and their
+ * types
+ *
+ * modifies tblinfo
+ */
+void
+getTableAttrs(TableInfo* tblinfo, int numTables)
+{
+ int i,j;
+ char q[MAXQUERYLEN];
+ int i_attname;
+ int i_typname;
+ char *res;
+ PortalBuffer *pbuf;
+ int ntups;
+
+ for (i=0;i<numTables;i++) {
+
+ /* find all the user attributes and their types*/
+ /* we must read the attribute names in attribute number order! */
+ /* because we will use the attnum to index into the attnames array
+ later */
+/*
+ sprintf(q,"SELECT a.attnum, a.attname, t.typname from pg_attribute a, pg_type t where a.attrelid = '%s' and a.atttypid = t.oid and a.attnum > 0 order by attnum",tblinfo[i].oid);
+*/
+if (g_verbose)
+ fprintf(stderr,"%s finding the attrs and types for table: %s %s\n",
+ g_comment_start,
+ tblinfo[i].relname,
+ g_comment_end);
+
+
+ sprintf(q,"retrieve (a.attnum, a.attname, t.typname) from a in pg_attribute, t in pg_type where a.attrelid = \"%s\" and a.atttypid = t.oid and a.attnum > 0 sort by attnum",tblinfo[i].oid);
+
+ res = PQexec(q);
+ pbuf = PQparray(res+1);
+ ntups = PQntuplesGroup(pbuf,0);
+
+ i_attname = PQfnumberGroup(pbuf,0,"attname");
+ i_typname = PQfnumberGroup(pbuf,0,"typname");
+
+ tblinfo[i].numatts = ntups;
+ tblinfo[i].attnames = (char**) malloc( ntups * sizeof(char*));
+ tblinfo[i].out_attnames = (char**) malloc( ntups * sizeof(char*));
+ tblinfo[i].typnames = (char**) malloc( ntups * sizeof(char*));
+ tblinfo[i].inhAttrs = (int*) malloc (ntups * sizeof(int));
+ tblinfo[i].parentRels = NULL;
+ tblinfo[i].numParents = 0;
+ for (j=0;j<ntups;j++) {
+ tblinfo[i].attnames[j] = dupstr(PQgetvalue(pbuf,j,i_attname));
+ tblinfo[i].typnames[j] = dupstr(PQgetvalue(pbuf,j,i_typname));
+ tblinfo[i].inhAttrs[j] = 0; /* this flag is set in flagInhAttrs()*/
+ }
+ PQclear(res+1);
+ }
+}
+
+
+/*
+ * getIndices
+ * read all the user-defined indices information
+ * from the system catalogs return them in the InhInfo* structure
+ *
+ * numIndices is set to the number of indices read in
+ *
+ *
+ */
+IndInfo*
+getIndices(int *numIndices)
+{
+ int i;
+ char query[MAXQUERYLEN];
+ char *res;
+ PortalBuffer *pbuf;
+ int ntups;
+ IndInfo *indinfo;
+
+ int i_indexrelname;
+ int i_indrelname;
+ int i_indamname;
+ int i_indproc;
+ int i_indkey;
+ int i_indclassname;
+
+ /* find all the user-define indices.
+ We do not handle partial indices.
+ We also assume that only single key indices
+
+ this is a 5-way join !!
+ */
+
+ PQexec("begin");
+/*
+ sprintf(query,
+ "SELECT t1.relname as indexrelname, t2.relname as indrelname, i.indproc, i.indkey[0], o.opcname as indclassname, a.amname as indamname from pg_index i, pg_class t1, pg_class t2, pg_opclass o, pg_am a where t1.oid = i.indexrelid and t2.oid = i.indrelid and o.oid = i.indclass[0] and t1.relam = a.oid and i.indexrelid > '%d'::oid and t2.relname !~ '^pg_';",
+ g_last_builtin_oid);
+*/
+
+ sprintf(query,
+ "retrieve (indexrelname = t1.relname, indrelname = t2.relname, i.indproc, i.indkey[0], indclassname = o.opcname, indamname = a.amname) from i in pg_index, t1 in pg_class, t2 in pg_class, o in pg_opclass, a in pg_am where t1.oid = i.indexrelid and t2.oid = i.indrelid and o.oid = i.indclass[0] and t1.relam = a.oid and i.indexrelid > \"%d\"::oid and t2.relname !~ \"^pg_\" and t1.relname !~ \"^Xinx\"",
+ g_last_builtin_oid);
+
+ res = PQexec(query);
+ pbuf = PQparray(res+1);
+ ntups = PQntuplesGroup(pbuf,0);
+
+ *numIndices = ntups;
+
+ indinfo = (IndInfo*)malloc(ntups * sizeof (IndInfo));
+
+ i_indexrelname = PQfnumberGroup(pbuf,0,"indexrelname");
+ i_indrelname = PQfnumberGroup(pbuf,0,"indrelname");
+ i_indamname = PQfnumberGroup(pbuf,0,"indamname");
+ i_indproc = PQfnumberGroup(pbuf,0,"indproc");
+ i_indkey = PQfnumberGroup(pbuf,0,"indkey");
+ i_indclassname = PQfnumberGroup(pbuf,0,"indclassname");
+
+ for (i=0;i<ntups;i++) {
+ indinfo[i].indexrelname = dupstr(PQgetvalue(pbuf,i,i_indexrelname));
+ indinfo[i].indrelname = dupstr(PQgetvalue(pbuf,i,i_indrelname));
+ indinfo[i].indamname = dupstr(PQgetvalue(pbuf,i,i_indamname));
+ indinfo[i].indproc = dupstr(PQgetvalue(pbuf,i,i_indproc));
+ indinfo[i].indkey = dupstr(PQgetvalue(pbuf,i,i_indkey));
+ indinfo[i].indclassname = dupstr(PQgetvalue(pbuf,i,i_indclassname));
+ }
+ PQclear(res+1);
+ PQexec("end");
+
+ return indinfo;
+}
+
+/*
+ * dumpTypes
+ * writes out to fout queries to recreate all the user-defined types
+ *
+ */
+
+void
+dumpTypes(FILE* fout, FuncInfo* finfo, int numFuncs,
+ TypeInfo* tinfo, int numTypes)
+{
+ int i;
+ char q[MAXQUERYLEN];
+ int funcInd;
+
+ for (i=0;i<numTypes;i++) {
+
+ /* skip all the builtin types */
+ if (atoi(tinfo[i].oid) < g_last_builtin_oid)
+ continue;
+
+ /* skip relation types */
+ if (atoi(tinfo[i].typrelid) != 0)
+ continue;
+
+ /* skip all array types that start w/ underscore */
+ if ( (tinfo[i].typname[0] == '_') &&
+ (strcmp(tinfo[i].typinput, "array_in") == 0))
+ continue;
+
+ /* before we create a type, we need to create the input and
+ output functions for it, if they haven't been created already */
+ funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typinput);
+ if (funcInd != -1)
+ dumpOneFunc(fout,finfo,funcInd,tinfo,numTypes);
+
+ funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typoutput);
+ if (funcInd != -1)
+ dumpOneFunc(fout,finfo,funcInd,tinfo,numTypes);
+
+ if (g_outputSQL) {
+ sprintf(q,
+ "CREATE TYPE %s ( internallength = %s, externallength = %s, input = %s, output = %s, send = %s, receive = %s, default = '%s'",
+ tinfo[i].typname,
+ tinfo[i].typlen,
+ tinfo[i].typprtlen,
+ tinfo[i].typinput,
+ tinfo[i].typoutput,
+ tinfo[i].typsend,
+ tinfo[i].typreceive,
+ tinfo[i].typdefault);
+ } else {
+ sprintf(q,
+ "define type %s ( internallength = %s, externallength = %s, input = %s, output = %s, send = %s, receive = %s, default = \"%s\"",
+ tinfo[i].typname,
+ (strcmp(tinfo[i].typlen, "-1") == 0) ? "variable" : tinfo[i].typlen,
+ (strcmp(tinfo[i].typprtlen, "-1") == 0) ? "variable " :tinfo[i].typprtlen,
+ tinfo[i].typinput,
+ tinfo[i].typoutput,
+ tinfo[i].typsend,
+ tinfo[i].typreceive,
+ tinfo[i].typdefault);
+ }
+
+ if (tinfo[i].isArray) {
+ char* elemType;
+
+ elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem);
+
+ if (g_outputSQL)
+ sprintf(q,"%s, element = %s, delimiter = '%s'",
+ q, elemType,tinfo[i].typdelim);
+ else
+ sprintf(q,"%s, element = %s, delimiter = \"%s\"",
+ q, elemType,tinfo[i].typdelim);
+ }
+ if (tinfo[i].passedbyvalue)
+ strcat(q,",passedbyvalue");
+ else
+ strcat(q,")");
+
+ if (g_outputSQL)
+ strcat(q,";\n");
+ else
+ strcat(q,"\\g\n");
+
+ fputs(q,fout);
+ }
+ fflush(fout);
+}
+
+/*
+ * dumpFuncs
+ * writes out to fout the queries to recreate all the user-defined functions
+ *
+ */
+void
+dumpFuncs(FILE* fout, FuncInfo* finfo, int numFuncs,
+ TypeInfo *tinfo, int numTypes)
+{
+ int i;
+ char q[MAXQUERYLEN];
+ for (i=0;i<numFuncs;i++) {
+ dumpOneFunc(fout,finfo,i,tinfo,numTypes);
+ }
+}
+
+/*
+ * dumpOneFunc:
+ * dump out only one function, the index of which is given in the third
+ * argument
+ *
+ */
+
+void
+dumpOneFunc(FILE* fout, FuncInfo* finfo, int i,
+ TypeInfo *tinfo, int numTypes)
+{
+ char q[MAXQUERYLEN];
+ int j;
+
+ if (finfo[i].dumped)
+ return;
+ else
+ finfo[i].dumped = 1;
+
+ if (g_outputSQL) {
+ sprintf(q,"CREATE FUNCTION %s (",finfo[i].proname);
+
+ for (j=0;j<finfo[i].nargs;j++) {
+ char* typname;
+ typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j]);
+ sprintf(q, "%s%s%s",
+ q,
+ (j > 0) ? "," : "",
+ typname);
+ }
+ sprintf(q,"%s ) RETURNS %s%s AS '%s' LANGUAGE '%s';\n",
+ q,
+ finfo[i].retset ? " SETOF " : "",
+ findTypeByOid(tinfo, numTypes, finfo[i].prorettype),
+ (finfo[i].lang) ? finfo[i].probin : finfo[i].prosrc,
+ (finfo[i].lang) ? "C" : "SQL");
+if (finfo[i].lang != 1) {
+ fprintf(stderr,
+ "%s WARNING: text of function named %s is in POSTQUEL %s\n",
+ g_comment_start,
+ finfo[i].proname,
+ g_comment_end);
+}
+
+ } else {
+ sprintf(q,"define function %s ( language = \"%s\", returntype = %s%s) arg is (",
+ finfo[i].proname,
+ (finfo[i].lang) ? "c" : "postquel",
+ finfo[i].retset ? " setof " : "",
+ findTypeByOid(tinfo, numTypes, finfo[i].prorettype)
+ );
+
+ for (j=0;j<finfo[i].nargs;j++) {
+ char* typname;
+ typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j]);
+ sprintf(q, "%s%s%s",
+ q,
+ (j > 0) ? "," : "",
+ typname);
+ }
+ sprintf(q,"%s ) as \"%s\"\\g\n",
+ q,
+ (finfo[i].lang) ? finfo[i].probin : finfo[i].prosrc);
+ }
+
+ fputs(q,fout);
+ fflush(fout);
+
+}
+
+/*
+ * dumpOprs
+ * writes out to fout the queries to recreate all the user-defined operators
+ *
+ */
+void
+dumpOprs(FILE* fout, OprInfo* oprinfo, int numOperators,
+ TypeInfo *tinfo, int numTypes)
+{
+ int i;
+ char q[MAXQUERYLEN];
+ char leftarg[MAXQUERYLEN];
+ char rightarg[MAXQUERYLEN];
+ char commutator[MAXQUERYLEN];
+ char negator[MAXQUERYLEN];
+ char restrict[MAXQUERYLEN];
+ char join[MAXQUERYLEN];
+ char sortop[MAXQUERYLEN];
+ char comma[2];
+
+ for (i=0;i<numOperators;i++) {
+
+ /* skip all the builtin oids */
+ if (atoi(oprinfo[i].oid) < g_last_builtin_oid)
+ continue;
+
+ /* some operator are invalid because they were the result
+ of user defining operators before commutators exist */
+ if (strcmp(oprinfo[i].oprcode, "-") == 0)
+ continue;
+
+ leftarg[0] = '\0';
+ rightarg[0] = '\0';
+ /* right unary means there's a left arg
+ and left unary means there's a right arg */
+ if (strcmp(oprinfo[i].oprkind, "r") == 0 ||
+ strcmp(oprinfo[i].oprkind, "b") == 0 ) {
+ sprintf(leftarg, ", %s = %s ",
+ (g_outputSQL) ? "LEFTARG" : "arg1",
+ findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft));
+ }
+ if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
+ strcmp(oprinfo[i].oprkind, "b") == 0 ) {
+ sprintf(rightarg, ", %s = %s ",
+ (g_outputSQL) ? "RIGHTARG" : "arg2",
+ findTypeByOid(tinfo, numTypes, oprinfo[i].oprright));
+ }
+ if (strcmp(oprinfo[i].oprcom, "0") == 0)
+ commutator[0] = '\0';
+ else
+ sprintf(commutator,", commutator = %s ",
+ findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom));
+
+ if (strcmp(oprinfo[i].oprnegate, "0") == 0)
+ negator[0] = '\0';
+ else
+ sprintf(negator,", negator = %s ",
+ findOprByOid(oprinfo, numOperators, oprinfo[i].oprnegate));
+
+ if (strcmp(oprinfo[i].oprrest, "-") == 0)
+ restrict[0] = '\0';
+ else
+ sprintf(restrict,", restrict = %s ", oprinfo[i].oprrest);
+
+ if (strcmp(oprinfo[i].oprjoin,"-") == 0)
+ join[0] = '\0';
+ else
+ sprintf(join,", join = %s ", oprinfo[i].oprjoin);
+
+ if (strcmp(oprinfo[i].oprlsortop, "0") == 0)
+ sortop[0] = '\0';
+ else
+ {
+ sprintf(sortop,", SORT = %s ",
+ findOprByOid(oprinfo, numOperators,
+ oprinfo[i].oprlsortop));
+ if (strcmp(oprinfo[i].oprrsortop, "0") != 0)
+ sprintf(sortop, "%s , %s", sortop,
+ findOprByOid(oprinfo, numOperators,
+ oprinfo[i].oprlsortop));
+ }
+
+ if (g_outputSQL) {
+ sprintf(q,
+ "CREATE OPERATOR %s (PROCEDURE = %s %s %s %s %s %s %s %s %s);\n ",
+ oprinfo[i].oprname,
+ oprinfo[i].oprcode,
+ leftarg,
+ rightarg,
+ commutator,
+ negator,
+ restrict,
+ (strcmp(oprinfo[i].oprcanhash, "t")) ? ", HASHES" : "",
+ join,
+ sortop);
+ } else
+ sprintf(q,
+ "define operator %s (procedure = %s %s %s %s %s %s %s %s %s)\\g\n ",
+ oprinfo[i].oprname,
+ oprinfo[i].oprcode,
+ leftarg,
+ rightarg,
+ commutator,
+ negator,
+ restrict,
+ (strcmp(oprinfo[i].oprcanhash, "t")) ? ", hashes" : "",
+ join,
+ sortop);
+
+ fputs(q,fout);
+ }
+ fflush(fout);
+
+}
+
+/*
+ * dumpAggs
+ * writes out to fout the queries to create all the user-defined aggregates
+ *
+ */
+void
+dumpAggs(FILE* fout, AggInfo* agginfo, int numAggs,
+ TypeInfo *tinfo, int numTypes)
+{
+ int i;
+ char q[MAXQUERYLEN];
+ char sfunc1[MAXQUERYLEN];
+ char sfunc2[MAXQUERYLEN];
+ char finalfunc[MAXQUERYLEN];
+ char *basetype;
+ char *stype1;
+ char *stype2;
+ char comma1[2], comma2[2];
+
+ for (i=0;i<numAggs;i++) {
+ /* skip all the builtin oids */
+ if (atoi(agginfo[i].oid) < g_last_builtin_oid)
+ continue;
+
+ if ( strcmp(agginfo[i].aggtransfn1, "-") == 0)
+ sfunc1[0] = '\0';
+ else {
+ sprintf(sfunc1,
+ "sfunc1 = %s, basetype = %s, stype1 = %s",
+ agginfo[i].aggtransfn1,
+ findTypeByOid(tinfo,numTypes,agginfo[i].aggbasetype),
+ findTypeByOid(tinfo,numTypes,agginfo[i].aggtranstype1));
+ if (agginfo[i].agginitval1) {
+ if (g_outputSQL)
+ sprintf(sfunc1, "%s ,INITCOND1 = '%s'",
+ sfunc1, agginfo[i].agginitval1);
+ else
+ sprintf(sfunc1, "%s ,initcond1 = \"%s\"",
+ sfunc1, agginfo[i].agginitval1);
+
+ }
+
+ }
+
+ if ( strcmp(agginfo[i].aggtransfn2, "-") == 0)
+ sfunc2[0] = '\0';
+ else {
+ sprintf(sfunc2,
+ "sfunc2 = %s, stype2 = %s",
+ agginfo[i].aggtransfn2,
+ findTypeByOid(tinfo,numTypes,agginfo[i].aggtranstype2));
+ if (agginfo[i].agginitval2) {
+ if (g_outputSQL)
+ sprintf(sfunc2,"%s ,initcond2 = '%s'",
+ sfunc2, agginfo[i].agginitval2);
+ else
+ sprintf(sfunc2,"%s ,initcond2 = \"%s\"",
+ sfunc2, agginfo[i].agginitval2);
+
+ }
+ }
+
+ if ( strcmp(agginfo[i].aggfinalfn, "-") == 0)
+ finalfunc[0] = '\0';
+ else {
+ sprintf(finalfunc, "finalfunc = %s", agginfo[i].aggfinalfn);
+ }
+ if (sfunc1[0] != '\0' && sfunc2[0] != '\0') {
+ comma1[0] = ','; comma1[1] = '\0';
+ } else
+ comma1[0] = '\0';
+
+ if (finalfunc[0] != '\0' && (sfunc1[0] != '\0' || sfunc2[0] != '\0')) {
+ comma2[0] = ',';comma2[1] = '\0';
+ } else
+ comma2[0] = '\0';
+
+ if (g_outputSQL) {
+ sprintf(q,"CREATE AGGREGATE %s ( %s %s %s %s %s );\n",
+ agginfo[i].aggname,
+ sfunc1,
+ comma1,
+ sfunc2,
+ comma2,
+ finalfunc);
+ } else {
+ sprintf(q,"define aggregate %s ( %s %s %s %s %s )\\g\n",
+ agginfo[i].aggname,
+ sfunc1,
+ comma1,
+ sfunc2,
+ comma2,
+ finalfunc);
+ }
+
+ fputs(q,fout);
+ }
+ fflush(fout);
+}
+
+/*
+ * dumpTables:
+ * write out to fout all the user-define tables
+ */
+
+void
+dumpTables(FILE* fout, TableInfo *tblinfo, int numTables,
+ InhInfo *inhinfo, int numInherits,
+ TypeInfo *tinfo, int numTypes)
+{
+ int i,j,k;
+ char q[MAXQUERYLEN];
+ char **parentRels; /* list of names of parent relations */
+ int numParents;
+ char *res;
+ PortalBuffer *pbuf;
+ int ntups;
+ int actual_atts; /* number of attrs in this CREATE statment */
+ char *archiveMode;
+
+ for (i=0;i<numTables;i++) {
+ parentRels = tblinfo[i].parentRels;
+ numParents = tblinfo[i].numParents;
+
+ if (g_outputSQL) {
+ sprintf(q, "CREATE TABLE %s (", tblinfo[i].relname);
+ } else {
+ sprintf(q, "create %s (", tblinfo[i].relname);
+ }
+
+ actual_atts = 0;
+ for (j=0;j<tblinfo[i].numatts;j++) {
+ if (tblinfo[i].inhAttrs[j] == 0) {
+ if (g_outputSQL) {
+ sprintf(q, "%s%s%s %s",
+ q,
+ (actual_atts > 0) ? ", " : "",
+ tblinfo[i].attnames[j],
+ tblinfo[i].typnames[j]);
+ }
+ else {
+ sprintf(q, "%s%s %s = %s",
+ q,
+ (actual_atts > 0) ? ", " : "",
+ tblinfo[i].attnames[j],
+ tblinfo[i].typnames[j]);
+
+ }
+ actual_atts++;
+ }
+ }
+
+ strcat(q,")");
+
+ if (numParents > 0) {
+ int oa = 0; /* index for the out_attnames array */
+ int l;
+ int parentInd;
+
+ sprintf(q, "%s inherits ( ",q);
+ for (k=0;k<numParents;k++){
+ sprintf(q, "%s%s%s",
+ q,
+ (k>0) ? ", " : "",
+ parentRels[k]);
+ parentInd = findTableByName(tblinfo,numTables,parentRels[k]);
+
+ /* the out_attnames are in order of the out_attnames
+ of the parent tables */
+ for (l=0; l<tblinfo[parentInd].numatts;l++)
+ tblinfo[i].out_attnames[oa++] =
+ tblinfo[parentInd].out_attnames[l];
+ }
+
+ /* include non-inherited attrs in out_attnames also,
+ oa should never exceed numatts */
+ for (l=0; l < tblinfo[i].numatts && oa < tblinfo[i].numatts ; l++)
+ if (tblinfo[i].inhAttrs[l] == 0) {
+ tblinfo[i].out_attnames[oa++] =
+ tblinfo[i].attnames[l];
+ }
+
+ strcat(q,")");
+ } else { /* for non-inherited tables, out_attnames
+ and attnames are the same */
+ tblinfo[i].out_attnames = tblinfo[i].attnames;
+ }
+
+ switch(tblinfo[i].relarch[0]) {
+ case 'n':
+ archiveMode = "none";
+ break;
+ case 'h':
+ archiveMode = "heavy";
+ break;
+ case 'l':
+ archiveMode = "light";
+ break;
+ default:
+ fprintf(stderr, "unknown archive mode\n");
+ archiveMode = "none";
+ break;
+ }
+
+ if (g_outputSQL) {
+ sprintf(q, "%s archive = %s;\n",
+ q,
+ archiveMode);
+ } else {
+ sprintf(q, "%s archive = %s\\g\n",
+ q,
+ archiveMode);
+ }
+
+ fputs(q,fout);
+ }
+ fflush(fout);
+}
+
+/*
+ * dumpIndices:
+ * write out to fout all the user-define indices
+ */
+void
+dumpIndices(FILE* fout, IndInfo* indinfo, int numIndices,
+ TableInfo* tblinfo, int numTables)
+{
+ int i,j;
+ int tableInd;
+ char *attname; /* the name of the indexed attribute */
+ char *funcname; /* the name of the function to compute the index key from*/
+ int indkey;
+
+ char q[MAXQUERYLEN];
+ char *res;
+ PortalBuffer *pbuf;
+
+ for (i=0;i<numIndices;i++) {
+ tableInd = findTableByName(tblinfo, numTables,
+ indinfo[i].indrelname);
+ indkey = atoi(indinfo[i].indkey) - 1;
+ attname = tblinfo[tableInd].attnames[indkey];
+ if (strcmp(indinfo[i].indproc,"0") == 0) {
+ funcname = NULL;
+ } else {
+ /* the funcname is an oid which we use to
+ find the name of the pg_proc. We need to do this
+ because getFuncs() only reads in the user-defined funcs
+ not all the funcs. We might not find what we want
+ by looking in FuncInfo**/
+ sprintf(q,
+ "retrieve(p.proname) from p in pg_proc where p.oid = \"%s\"::oid",
+ indinfo[i].indproc);
+ res = PQexec(q);
+ pbuf = PQparray(res+1);
+ funcname = dupstr(PQgetvalue(pbuf,0,
+ PQfnumberGroup(pbuf,0,"proname")));
+ PQclear(res+1);
+ }
+ if (g_outputSQL) {
+ sprintf(q,"CREATE INDEX %s on %s using %s (",
+ indinfo[i].indexrelname,
+ indinfo[i].indrelname,
+ indinfo[i].indamname);
+ } else {
+ sprintf(q,"define index %s on %s using %s (",
+ indinfo[i].indexrelname,
+ indinfo[i].indrelname,
+ indinfo[i].indamname);
+
+ }
+ if (funcname) {
+ sprintf(q, "%s %s(%s) %s",
+ q,funcname, attname, indinfo[i].indclassname);
+ free(funcname);
+ } else
+ sprintf(q, "%s %s %s",
+ q,attname,indinfo[i].indclassname);
+
+ if (g_outputSQL) {
+ strcat(q,");\n");
+ } else
+ strcat(q,")\\g\n");
+
+ fputs(q,fout);
+ }
+ fflush(fout);
+}
+
+
+/*
+ * dumpClasses -
+ * dump the contents of all the classes.
+ */
+void
+dumpClasses(TableInfo *tblinfo, int numTables, FILE *fout)
+{
+ char query[255];
+ char *res;
+ int i,j;
+
+ int *attrmap; /* this is an vector map of how the actual attributes
+ map to the corresponding output attributes.
+ This is necessary because of a difference between
+ SQL and POSTQUEL in the order of inherited attributes */
+
+ for(i = 0; i < numTables; i++) {
+ char *classname = tblinfo[i].relname;
+
+ if (g_outputSQL)
+ fprintf(fout, "copy %s from stdin;\n", classname);
+ else
+ fprintf(fout, "copy %s from stdin\\g\n", classname);
+
+ sprintf(query, "retrieve (p.all) from p in %s", classname);
+ res = PQexec(query);
+
+ attrmap = (int*)malloc(tblinfo[i].numatts * sizeof(int));
+ if (tblinfo[i].numParents == 0) {
+ /* table with no inheritance use an identity mapping */
+ for (j=0;j<tblinfo[i].numatts;j++)
+ attrmap[j] = j;
+ } else {
+ int n = tblinfo[i].numatts;
+ for (j=0;j < n;j++) {
+ attrmap[j] = strInArray(tblinfo[i].attnames[j],
+ tblinfo[i].out_attnames,
+ n);
+ }
+ }
+
+/*
+ {
+ int j;
+ for (j=0;j<tblinfo[i].numatts;j++) {
+ fprintf(stderr,":%s\t",tblinfo[i].out_attnames[j]);
+ }
+ fprintf(stderr,"\n");
+ }
+*/
+
+ fflush(stdout);
+ fflush(stderr);
+ switch (*res) {
+ case 'P':
+ dumpTuples(&(res[1]), fout, attrmap);
+ PQclear(&(res[1]));
+ break;
+ case 'E':
+ case 'R':
+ fprintf(stderr, "Error while dumping %s\n", classname);
+ exit(1);
+ break;
+ }
+
+ fprintf(fout, ".\n");
+ free(attrmap);
+ }
+}
+
+/*
+ * dumpTuples --
+ * prints out the tuples in ASCII representaiton. The output is a valid
+ * input to COPY FROM stdin.
+ *
+ * We only need to do this for POSTGRES 4.2 databases since the
+ * COPY TO statement doesn't escape newlines properly. It's been fixed
+ * in Postgres95.
+ *
+ * the attrmap passed in tells how to map the attributes copied in to the
+ * attributes copied out
+ */
+void
+dumpTuples(char *portalname, FILE *fout, int* attrmap)
+{
+ PortalBuffer *pbuf;
+ int i, j, k;
+ int m, n, t;
+ char **outVals = NULL; /* values to copy out */
+
+ /* Now to examine all tuples fetched. */
+ pbuf = PQparray(portalname);
+
+ n = PQntuplesGroup(pbuf,0); /* always assume only one group */
+ m = PQnfieldsGroup(pbuf,0);
+
+ if ( m > 0 ) {
+ /*
+ * Print out the tuples but only print tuples with at least
+ * 1 field.
+ */
+ outVals = (char**)malloc(m * sizeof(char*));
+
+ for (j = 0; j < n; j++) {
+ for (k = 0; k < m; k++) {
+ outVals[attrmap[k]] = PQgetvalue(pbuf, j, k);
+ }
+ for (k = 0; k < m; k++) {
+ char *pval = outVals[k];
+
+ if (k!=0)
+ fputc('\t', fout); /* delimiter for attribute */
+
+ if (pval) {
+ while (*pval != '\0') {
+ /* escape tabs, newlines and backslashes */
+ if (*pval=='\t' || *pval=='\n' || *pval=='\\')
+ fputc('\\', fout);
+ fputc(*pval, fout);
+ pval++;
+ }
+ }
+ }
+ fputc('\n', fout); /* delimiter for a tuple */
+ }
+ free (outVals);
+ }
+
+}
+
+
+
+/*
+ * findLastBuiltInOid -
+ * find the last built in oid
+ * we do this by looking up the oid of 'template1' in pg_database,
+ * this is probably not foolproof but comes close
+*/
+
+int
+findLastBuiltinOid()
+{
+ char *res;
+ PortalBuffer* pbuf;
+ int ntups;
+ int last_oid;
+
+ res = PQexec("retrieve (d.oid) from d in pg_database where d.datname = \"template1\"");
+ pbuf = PQparray(res+1);
+ ntups = PQntuplesGroup(pbuf,0);
+ if (ntups != 1) {
+ fprintf(stderr,"pg_dump: couldn't find the template1 database. You are really hosed\nGiving up\n");
+ exit(2);
+ }
+ return (atoi(PQgetvalue(pbuf,0, PQfnumberGroup(pbuf,0,"oid"))));
+
+}
+
+
+/*
+ * checkForQuote:
+ * checks a string for quote characters and backslashes them
+ */
+char*
+checkForQuote(char* s)
+{
+ char *r;
+ char c;
+ char *result;
+
+ int j = 0;
+
+ r = malloc(strlen(s)*3 + 1); /* definitely long enough */
+
+ while ( (c = *s) != '\0') {
+
+ if (c == '\"') {
+ /* backslash the double quotes */
+ if (g_outputSQL) {
+ r[j++] = '\\';
+ c = '\'';
+ } else {
+ r[j++] = '\\';
+ r[j++] = '\\';
+ }
+ }
+ r[j++] = c;
+ s++;
+ }
+ r[j] = '\0';
+
+ result = dupstr(r);
+ free(r);
+
+ return result;
+
+}
diff --git a/src/bin/pg4_dump/pg_dump.h b/src/bin/pg4_dump/pg_dump.h
new file mode 100644
index 00000000000..0708f671be9
--- /dev/null
+++ b/src/bin/pg4_dump/pg_dump.h
@@ -0,0 +1,195 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_dump.h
+ * header file for the pg_dump utility
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * pg_dump.h,v 1.5 1995/06/28 22:32:36 jolly Exp
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+/* The *Info data structures run-time C structures used to store
+ system catalog information */
+
+typedef struct _typeInfo {
+ char* oid;
+ char* typowner;
+ char* typname;
+ char* typlen;
+ char* typprtlen;
+ char* typinput;
+ char* typoutput;
+ char* typreceive;
+ char* typsend;
+ char* typelem;
+ char* typdelim;
+ char* typdefault;
+ char* typrelid;
+ int passedbyvalue;
+ int isArray;
+} TypeInfo;
+
+typedef struct _funcInfo {
+ char* oid;
+ char* proname;
+ char* proowner;
+ int lang; /* 1 if C, else SQL */
+ int nargs;
+ char* argtypes[8]; /* should be derived from obj/fmgr.h instead of hardwired*/
+ char* prorettype;
+ int retset; /* 1 if the function returns a set, 0 otherwise */
+ char* prosrc;
+ char* probin;
+ int dumped; /* 1 if already dumped */
+} FuncInfo;
+
+typedef struct _tableInfo {
+ char *oid;
+ char *relname;
+ char *relarch;
+ int numatts; /* number of attributes */
+ int *inhAttrs; /* an array of flags, one for each attribute
+ if the value is 1, then this attribute is
+ an inherited attribute */
+ char **attnames; /* the attribute names */
+ char **typnames; /* fill out attributes */
+ int numParents; /* number of (immediate) parent supertables */
+ char **parentRels; /* names of parent relations, NULL
+ if numParents == 0 */
+ char **out_attnames; /* the attribute names, in the order they would
+ be in, when the table is created in the
+ target query language.
+ this is needed because the SQL tables will
+ not have the same order of attributes as
+ the POSTQUEL tables */
+
+} TableInfo;
+
+typedef struct _inhInfo {
+ char *oid;
+ char *inhrel;
+ char *inhparent;
+} InhInfo;
+
+typedef struct _indInfo {
+ char *indexrelname; /* name of the secondary index class */
+ char *indrelname; /* name of the indexed heap class */
+ char *indamname; /* name of the access method (e.g. btree, rtree, etc.) */
+ char *indproc; /* oid of the function to compute the index, 0 if none*/
+ char *indkey; /* attribute number of the key attribute */
+ char *indclassname; /* name of the opclass of the key */
+} IndInfo;
+
+typedef struct _aggInfo {
+ char *oid;
+ char *aggname;
+ char *aggtransfn1;
+ char *aggtransfn2;
+ char *aggfinalfn;
+ char *aggtranstype1;
+ char *aggbasetype;
+ char *aggtranstype2;
+ char *agginitval1;
+ char *agginitval2;
+} AggInfo;
+
+typedef struct _oprInfo {
+ char *oid;
+ char *oprname;
+ char *oprkind; /* "b" = binary, "l" = left unary, "r" = right unary */
+ char *oprcode; /* operator function name */
+ char *oprleft; /* left operand type */
+ char *oprright; /* right operand type */
+ char *oprcom; /* oid of the commutator operator */
+ char *oprnegate; /* oid of the negator operator */
+ char *oprrest; /* name of the function to calculate operator restriction
+ selectivity */
+ char *oprjoin; /* name of the function to calculate operator join
+ selectivity */
+ char *oprcanhash; /* can we use hash join strategy ? */
+ char *oprlsortop; /* oid's of the left and right sort operators */
+ char *oprrsortop;
+} OprInfo;
+
+
+/* global decls */
+extern int g_verbose; /* verbose flag */
+extern int g_last_builtin_oid; /* value of the last builtin oid */
+extern FILE *g_fout; /* the script file */
+
+/* placeholders for comment starting and ending delimiters */
+extern char g_comment_start[10];
+extern char g_comment_end[10];
+
+extern char g_opaque_type[10]; /* name for the opaque type */
+
+/* pg_dump is really two programs in one
+ one version works with postgres v4r2
+ and the other works with postgres95
+ the common routines are declared here
+
+/*
+ * common utility functions
+*/
+
+extern TableInfo* dumpSchema(FILE* fout, int *numTablesPtr);
+
+extern char* findTypeByOid(TypeInfo* tinfo, int numTypes, char* oid);
+extern char* findOprByOid(OprInfo *oprinfo, int numOprs, char *oid);
+extern int findFuncByName(FuncInfo* finfo, int numFuncs, char* name);
+extern char** findParentsByOid(TableInfo* tbinfo, int numTables,
+ InhInfo* inhinfo, int numInherits,
+ char *oid,
+ int *numParents);
+extern int findTableByName(TableInfo *tbinfo, int numTables, char *relname);
+extern int findTableByOid(TableInfo *tbinfo, int numTables, char *oid);
+extern void flagInhAttrs(TableInfo* tbinfo, int numTables,
+ InhInfo* inhinfo, int numInherits);
+
+extern void check_conn_and_db();
+extern char* dupstr(char *s);
+extern int strInArray(char* pattern, char** arr, int arr_size);
+extern void parseArgTypes(char **argtypes, char* str);
+extern int isArchiveName(char*);
+
+/*
+ * version specific routines
+ */
+extern TypeInfo* getTypes(int *numTypes);
+extern FuncInfo* getFuncs(int *numFuncs);
+extern AggInfo* getAggregates(int *numAggregates);
+extern OprInfo* getOperators(int *numOperators);
+extern TableInfo* getTables(int *numTables);
+extern InhInfo* getInherits(int *numInherits);
+extern void getTableAttrs(TableInfo* tbinfo, int numTables);
+extern IndInfo* getIndices(int *numIndices);
+extern void dumpTypes(FILE* fout, FuncInfo* finfo, int numFuncs,
+ TypeInfo* tinfo, int numTypes);
+extern void dumpFuncs(FILE* fout, FuncInfo* finfo, int numFuncs,
+ TypeInfo *tinfo, int numTypes);
+extern void dumpAggs(FILE* fout, AggInfo* agginfo, int numAggregates,
+ TypeInfo *tinfo, int numTypes);
+extern void dumpOprs(FILE* fout, OprInfo* agginfo, int numOperators,
+ TypeInfo *tinfo, int numTypes);
+extern void dumpOneFunc(FILE* fout, FuncInfo* finfo, int i,
+ TypeInfo *tinfo, int numTypes);
+extern void dumpTables(FILE* fout, TableInfo* tbinfo, int numTables,
+ InhInfo *inhinfo, int numInherits,
+ TypeInfo *tinfo, int numTypes);
+extern void dumpIndices(FILE* fout, IndInfo* indinfo, int numIndices,
+ TableInfo* tbinfo, int numTables);
+
+extern void dumpClasses(TableInfo *tbinfo, int numTables, FILE *fout);
+extern void dumpTuples(char *portalname, FILE *fout, int *attrmap);
+extern char* checkForQuote(char* s);
+extern int findLastBuiltinOid();
+
+
+/* largest query string size */
+#define MAXQUERYLEN 5000
+
+/* these voodoo constants are from the backend */
+#define C_PROLANG_OID 13
diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile
new file mode 100644
index 00000000000..5512f249fa4
--- /dev/null
+++ b/src/bin/pg_dump/Makefile
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for bin/pg_dump
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/pg_dump/Makefile,v 1.1.1.1 1996/07/09 06:22:14 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+PROG= pg_dump
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+SRCS= pg_dump.c common.c
+
+include $(MKDIR)/postgres.prog.mk
+
diff --git a/src/bin/pg_dump/README b/src/bin/pg_dump/README
new file mode 100644
index 00000000000..17c433c8981
--- /dev/null
+++ b/src/bin/pg_dump/README
@@ -0,0 +1,73 @@
+pg_dump is a utility for dumping out a postgres database into a script
+file containing query commands. The script files are in a ASCII
+format and can be used to reconstruct the database, even on other
+machines and other architectures. pg_dump will produce the queries
+necessary to re-generate all user-defined types, functions, tables,
+indices, aggregates, and operators. In addition, all the data is
+copied out in ASCII format so that it can be readily copied in again.
+
+
+To build:
+
+ % gmake clean install
+
+This version of the program will read in your postgres95 database and
+output the schema and the data tuples in SQL. The dumps are useful
+for moving from one postgres95 installation to another.
+
+
+How to use pg_dump:
+-------------------
+
+The command line options are fairly self explanatory. Use -help to
+see the command line options. recommend using -v to get
+more verbose descriptions of what pg_dump is doing.
+
+After running pg_dump, one should examine the output script file for any
+warnings, especially in light of the limitations listed below.
+
+A typical use of pg_dump:
+
+ % pg_dump -v -f oldDB.dump oldDB
+ % createdb newDB
+ % psql newDB < oldDB.dump
+
+
+Caveats and limitations:
+------------------------
+
+pg_dump has a few limitations. The limitations mostly stem from
+difficulty in extracting certain meta-information from the system
+catalogs.
+
+ rules and views:
+ pg_dump does not understand user-defined rules and views and
+ will fail to dump them properly. (This is due to the fact that
+ rules are stored as plans in the catalogs and not textually)
+
+ partial indices:
+ pg_dump does not understand partial indices. (The reason is
+ the same as above. Partial index predicates are stored as plans)
+
+ large objects:
+ pg_dump does not handle large objects. Large
+ objects are ignored and must be dealt with manually.
+
+ oid preservation:
+ pg_dump does not preserve oid's while dumping. If you have
+ stored oid's explicitly in tables in user-defined attributes,
+ and are using them as keys, then the output scripts will not
+ regenerate your database correctly.
+
+pg_dump requires postgres95 beta0.03 or later.
+
+Bug-reporting
+--------------
+
+If you should find a problem with pg_dump, it is very important that
+you provide a (small) sample database which illustrates the problem.
+Please send bugs, questions, and feedback to the
+ postgres95@postgres95.vnet.net
+
+
+
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
new file mode 100644
index 00000000000..96ea7f72951
--- /dev/null
+++ b/src/bin/pg_dump/common.c
@@ -0,0 +1,397 @@
+/*-------------------------------------------------------------------------
+ *
+ * common.c--
+ * common routines between pg_dump and pg4_dump
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.1.1.1 1996/07/09 06:22:14 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
+#ifdef PORTNAME_sparc_solaris
+#include <netdb.h> /* for MAXHOSTNAMELEN on some */
+#endif
+
+#include "postgres.h"
+#include "libpq-fe.h"
+
+#include "pg_dump.h"
+
+/* dupstr : copies a string, while allocating space for it.
+ the CALLER is responsible for freeing the space
+ returns NULL if the argument is NULL*/
+char*
+dupstr(char *s)
+{
+ char* result;
+
+ if (s == NULL)
+ return NULL;
+
+ result = (char*)malloc(strlen(s)+1);
+ strcpy(result, s);
+ return result;
+}
+
+
+/*
+ * findTypeByOid
+ * given an oid of a type, return its typename
+ *
+ * if oid is "0", return "opaque" -- this is a special case
+ *
+ * NOTE: should hash this, but just do linear search for now
+ */
+
+char*
+findTypeByOid(TypeInfo* tinfo, int numTypes, char* oid)
+{
+ int i;
+
+ if (strcmp(oid, "0") == 0) return g_opaque_type;
+
+ for (i=0;i<numTypes;i++) {
+ if (strcmp(tinfo[i].oid, oid) == 0)
+ return tinfo[i].typname;
+ }
+
+ /* should never get here */
+ fprintf(stderr,"failed sanity check, type with oid %s was not found\n",
+ oid);
+ exit(2);
+}
+
+/*
+ * findOprByOid
+ * given the oid of an operator, return the name of the operator
+ *
+ *
+ * NOTE: should hash this, but just do linear search for now
+ *
+ */
+char*
+findOprByOid(OprInfo *oprinfo, int numOprs, char *oid)
+{
+ int i;
+ for (i=0;i<numOprs;i++) {
+ if (strcmp(oprinfo[i].oid, oid) == 0)
+ return oprinfo[i].oprname;
+ }
+
+ /* should never get here */
+ fprintf(stderr,"failed sanity check, opr with oid %s was not found\n",
+ oid);
+ exit(2);
+}
+
+
+/*
+ * findParentsByOid --
+ * given the oid of a class, return the names of its parent classes
+ * and assign the number of parents to the last argument.
+ *
+ *
+ * returns NULL if none
+ */
+
+char**
+findParentsByOid(TableInfo* tblinfo, int numTables,
+ InhInfo* inhinfo, int numInherits, char *oid,
+ int *numParentsPtr)
+{
+ int i,j;
+ int parentInd;
+ char** result;
+ int numParents;
+
+ numParents = 0;
+ for (i=0;i<numInherits;i++) {
+ if ( strcmp(inhinfo[i].inhrel, oid) == 0) {
+ numParents++;
+ }
+ }
+
+ *numParentsPtr = numParents;
+
+ if (numParents > 0) {
+ result = (char**)malloc(sizeof(char*) * numParents);
+ j = 0;
+ for (i=0;i<numInherits;i++) {
+ if ( strcmp(inhinfo[i].inhrel, oid) == 0) {
+ parentInd = findTableByOid(tblinfo, numTables,
+ inhinfo[i].inhparent);
+ result[j++] = tblinfo[parentInd].relname;
+ }
+ }
+ return result;
+ }
+ else
+ return NULL;
+}
+
+/*
+ * parseArgTypes
+ * parse a string of eight numbers delimited by spaces
+ * into a character array
+ */
+
+void
+parseArgTypes(char **argtypes, char* str)
+{
+ int j, argNum;
+ char temp[100];
+ char s;
+
+ argNum = 0;
+ j = 0;
+ while ( (s = *str) != '\0') {
+ if (s == ' ') {
+ temp[j] = '\0';
+ argtypes[argNum] = dupstr(temp);
+ argNum++;
+ j = 0;
+ } else {
+ temp[j] = s;
+ j++;
+ }
+ str++;
+ }
+ if (j != 0) {
+ temp[j] = '\0';
+ argtypes[argNum] = dupstr(temp);
+ }
+
+}
+
+
+/*
+ * strInArray:
+ * takes in a string and a string array and the number of elements in the
+ * string array.
+ * returns the index if the string is somewhere in the array, -1 otherwise
+ *
+ */
+
+int
+strInArray(char* pattern, char** arr, int arr_size)
+{
+ int i;
+ for (i=0;i<arr_size;i++) {
+ if (strcmp(pattern, arr[i]) == 0)
+ return i;
+ }
+ return -1;
+}
+
+/*
+ * dumpSchema:
+ * we have a valid connection, we are now going to dump the schema
+ * into the file
+ *
+ */
+
+TableInfo *
+dumpSchema(FILE *fout, int *numTablesPtr)
+{
+ int numTypes;
+ int numFuncs;
+ int numTables;
+ int numInherits;
+ int numIndices;
+ int numAggregates;
+ int numOperators;
+ TypeInfo *tinfo;
+ FuncInfo *finfo;
+ AggInfo *agginfo;
+ TableInfo *tblinfo;
+ InhInfo *inhinfo;
+ IndInfo *indinfo;
+ OprInfo *oprinfo;
+
+if (g_verbose) fprintf(stderr,"%s reading user-defined types %s\n",
+ g_comment_start, g_comment_end);
+ tinfo = getTypes(&numTypes);
+
+if (g_verbose) fprintf(stderr,"%s reading user-defined functions %s\n",
+ g_comment_start, g_comment_end);
+ finfo = getFuncs(&numFuncs);
+
+if (g_verbose) fprintf(stderr,"%s reading user-defined aggregates %s\n",
+ g_comment_start, g_comment_end);
+ agginfo = getAggregates(&numAggregates);
+
+if (g_verbose) fprintf(stderr,"%s reading user-defined operators %s\n",
+ g_comment_start, g_comment_end);
+ oprinfo = getOperators(&numOperators);
+
+if (g_verbose) fprintf(stderr,"%s reading user-defined tables %s\n",
+ g_comment_start, g_comment_end);
+ tblinfo = getTables(&numTables);
+
+if (g_verbose) fprintf(stderr,"%s reading table inheritance information %s\n",
+ g_comment_start, g_comment_end);
+ inhinfo = getInherits(&numInherits);
+
+if (g_verbose) fprintf(stderr, "%s finding the attribute names and types for each table %s\n",
+ g_comment_start, g_comment_end);
+ getTableAttrs(tblinfo, numTables);
+
+if (g_verbose) fprintf(stderr, "%s flagging inherited attributes in subtables %s\n",
+ g_comment_start, g_comment_end);
+ flagInhAttrs(tblinfo, numTables, inhinfo, numInherits);
+
+if (g_verbose) fprintf(stderr,"%s reading indices information %s\n",
+ g_comment_start, g_comment_end);
+ indinfo = getIndices(&numIndices);
+
+if (g_verbose) fprintf(stderr,"%s dumping out user-defined types %s\n",
+ g_comment_start, g_comment_end);
+ dumpTypes(fout, finfo, numFuncs, tinfo, numTypes);
+
+if (g_verbose) fprintf(stderr,"%s dumping out tables %s\n",
+ g_comment_start, g_comment_end);
+ dumpTables(fout, tblinfo, numTables, inhinfo, numInherits,
+ tinfo, numTypes);
+
+if (g_verbose) fprintf(stderr,"%s dumping out user-defined functions %s\n",
+ g_comment_start, g_comment_end);
+ dumpFuncs(fout, finfo, numFuncs, tinfo, numTypes);
+
+if (g_verbose) fprintf(stderr,"%s dumping out user-defined functions %s\n",
+ g_comment_start, g_comment_end);
+ dumpAggs(fout, agginfo, numAggregates, tinfo, numTypes);
+
+if (g_verbose) fprintf(stderr,"%s dumping out user-defined operators %s\n",
+ g_comment_start, g_comment_end);
+ dumpOprs(fout, oprinfo, numOperators, tinfo, numTypes);
+
+if (g_verbose) fprintf(stderr,"%s dumping out indices %s\n",
+ g_comment_start, g_comment_end);
+ dumpIndices(fout, indinfo, numIndices, tblinfo, numTables);
+
+ *numTablesPtr = numTables;
+ return tblinfo;
+}
+
+
+/* flagInhAttrs -
+ * for each table in tblinfo, flag its inherited attributes
+ * so when we dump the table out, we don't dump out the inherited attributes
+ *
+ * initializes the parentRels field of each table
+ *
+ * modifies tblinfo
+ *
+ */
+void
+flagInhAttrs(TableInfo* tblinfo, int numTables,
+ InhInfo* inhinfo, int numInherits)
+{
+ int i,j,k;
+ int parentInd;
+
+ /* we go backwards because the tables in tblinfo are in OID
+ order, meaning the subtables are after the parent tables
+ we flag inherited attributes from child tables first */
+ for (i = numTables-1; i >= 0; i--) {
+ tblinfo[i].parentRels = findParentsByOid(tblinfo, numTables,
+ inhinfo, numInherits,
+ tblinfo[i].oid,
+ &tblinfo[i].numParents);
+ for (k=0;k<tblinfo[i].numParents;k++) {
+ parentInd = findTableByName(tblinfo, numTables,
+ tblinfo[i].parentRels[k]);
+ for (j=0;j<tblinfo[i].numatts;j++) {
+ if (strInArray(tblinfo[i].attnames[j],
+ tblinfo[parentInd].attnames,
+ tblinfo[parentInd].numatts) != -1) {
+ tblinfo[i].inhAttrs[j] = 1;
+ }
+ }
+ }
+ }
+}
+
+
+/*
+ * findTableByName
+ * finds the index (in tblinfo) of the table with the given relname
+ * returns -1 if not found
+ *
+ * NOTE: should hash this, but just do linear search for now
+ */
+
+int
+findTableByName(TableInfo* tblinfo, int numTables, char* relname)
+{
+ int i;
+ for (i=0;i<numTables;i++) {
+ if (strcmp(tblinfo[i].relname, relname) == 0)
+ return i;
+ }
+ return -1;
+}
+
+/*
+ * findTableByOid
+ * finds the index (in tblinfo) of the table with the given oid
+ * returns -1 if not found
+ *
+ * NOTE: should hash this, but just do linear search for now
+ */
+
+int
+findTableByOid(TableInfo* tblinfo, int numTables, char* oid)
+{
+ int i;
+ for (i=0;i<numTables;i++) {
+ if (strcmp(tblinfo[i].oid, oid) == 0)
+ return i;
+ }
+ return -1;
+}
+
+
+/*
+ * findFuncByName
+ * finds the index (in finfo) of the function with the given name
+ * returns -1 if not found
+ *
+ * NOTE: should hash this, but just do linear search for now
+ */
+
+int
+findFuncByName(FuncInfo* finfo, int numFuncs, char* name)
+{
+ int i;
+ for (i=0;i<numFuncs;i++) {
+ if (strcmp(finfo[i].proname, name) == 0)
+ return i;
+ }
+ return -1;
+}
+
+/*
+ * isArchiveName
+ *
+ * returns true if the relation name is an archive name, false otherwise
+ */
+int
+isArchiveName(char* relname)
+{
+ return (strlen(relname) > 1 && relname[1] == ',');
+}
+
+
+
+
+
+
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
new file mode 100644
index 00000000000..9ef8f8f35e8
--- /dev/null
+++ b/src/bin/pg_dump/pg_dump.c
@@ -0,0 +1,1443 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_dump.c--
+ * pg_dump is an utility for dumping out a postgres database
+ * into a script file.
+ *
+ * pg_dump will read the system catalogs in a database and
+ * dump out a script that reproduces
+ * the schema of the database in terms of
+ * user-defined types
+ * user-defined functions
+ * tables
+ * indices
+ * aggregates
+ * operators
+ *
+ * the output script is SQL that is understood by Postgres95
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.1.1.1 1996/07/09 06:22:14 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
+#ifdef PORTNAME_sparc_solaris
+#include <netdb.h> /* for MAXHOSTNAMELEN on some */
+#endif
+
+#include "postgres.h"
+#include "libpq-fe.h"
+
+#include "pg_dump.h"
+
+extern char *optarg;
+extern int optind, opterr;
+
+/* global decls */
+int g_verbose; /* verbose flag */
+int g_last_builtin_oid; /* value of the last builtin oid */
+FILE *g_fout; /* the script file */
+PGconn *g_conn; /* the database connection */
+
+char g_opaque_type[10]; /* name for the opaque type */
+
+/* placeholders for the delimiters for comments */
+char g_comment_start[10];
+char g_comment_end[10];
+
+
+static void
+usage(char* progname)
+{
+ fprintf(stderr, "usage: %s [options] [dbname]\n",progname);
+ fprintf(stderr, "\t -f filename \t\t script output filename\n");
+ fprintf(stderr, "\t -H hostname \t\t server host name\n");
+ fprintf(stderr, "\t -p port \t\t server port number\n");
+ fprintf(stderr, "\t -v \t\t verbose\n");
+ fprintf(stderr, "\t -S \t\t dump out only the schema, no data\n");
+ fprintf(stderr, "\n if dbname is not supplied, then the DATABASE environment name is used\n");
+ fprintf(stderr, "\n");
+
+ fprintf(stderr, "\tpg_dump dumps out postgres databases and produces a script file\n");
+ fprintf(stderr, "\tof SQL commands to regenerate the schema\n");
+ fprintf(stderr, "\tThe SQL output is designed for import into Postgres95\n");
+ exit(1);
+}
+
+void
+exit_nicely(PGconn* conn)
+{
+ PQfinish(conn);
+ exit(1);
+}
+
+
+void
+main(int argc, char** argv)
+{
+ int c;
+ char* progname;
+ char* filename;
+ char* dbname;
+ int schemaOnly;
+ char *pghost = NULL;
+ char *pgport = NULL;
+
+ TableInfo *tblinfo;
+ int numTables;
+
+ dbname = NULL;
+ filename = NULL;
+ g_verbose = 0;
+
+ strcpy(g_comment_start,"-- ");
+ g_comment_end[0] = '\0';
+ strcpy(g_opaque_type, "opaque");
+
+ schemaOnly = 0;
+
+ progname = *argv;
+
+ while ((c = getopt(argc, argv,"f:H:p:vSD")) != EOF) {
+ switch(c) {
+ case 'f': /* output file name */
+ filename = optarg;
+ break;
+ case 'H' : /* server host */
+ pghost = optarg;
+ break;
+ case 'p' : /* server port */
+ pgport = optarg;
+ break;
+ case 'v': /* verbose */
+ g_verbose = 1;
+ break;
+ case 'S': /* dump schema only */
+ schemaOnly = 1;
+ break;
+ default:
+ usage(progname);
+ break;
+ }
+ }
+
+ /* open the output file */
+ if (filename == NULL) {
+ g_fout = stdout;
+ } else {
+ g_fout = fopen(filename, "w");
+ if (g_fout == NULL) {
+ fprintf(stderr,"%s: could not open output file named %s for writing\n",
+ progname, filename);
+ exit(2);
+ }
+ }
+
+ /* find database */
+ if (!(dbname = argv[optind]) &&
+ !(dbname = getenv("DATABASE")) ) {
+ fprintf(stderr, "%s: no database name specified\n",progname);
+ exit (2);
+ }
+
+ g_conn = PQsetdb(pghost, pgport, NULL, NULL, dbname);
+ /* check to see that the backend connection was successfully made */
+ if (PQstatus(g_conn) == CONNECTION_BAD) {
+ fprintf(stderr,"Connection to database '%s' failed.\n", dbname);
+ fprintf(stderr,"%s",PQerrorMessage(g_conn));
+ exit_nicely(g_conn);
+ }
+
+ g_last_builtin_oid = findLastBuiltinOid();
+
+if (g_verbose)
+ fprintf(stderr, "%s last builtin oid is %d %s\n",
+ g_comment_start, g_last_builtin_oid, g_comment_end);
+
+ tblinfo = dumpSchema(g_fout, &numTables);
+
+ if (!schemaOnly) {
+
+if (g_verbose) fprintf(stderr,"%s dumping out the contents of each table %s\n",
+ g_comment_start, g_comment_end);
+
+ dumpClasses(tblinfo, numTables, g_fout);
+ }
+
+ fflush(g_fout);
+ fclose(g_fout);
+
+ PQfinish(g_conn);
+ exit(0);
+}
+
+
+/*
+ * getTypes:
+ * read all base types in the system catalogs and return them in the
+ * TypeInfo* structure
+ *
+ * numTypes is set to the number of types read in
+ *
+ */
+TypeInfo*
+getTypes(int *numTypes)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ char query[MAXQUERYLEN];
+ TypeInfo *tinfo;
+
+ int i_oid;
+ int i_typowner;
+ int i_typname;
+ int i_typlen;
+ int i_typprtlen;
+ int i_typinput;
+ int i_typoutput;
+ int i_typreceive;
+ int i_typsend;
+ int i_typelem;
+ int i_typdelim;
+ int i_typdefault;
+ int i_typrelid;
+ int i_typbyval;
+
+ res = PQexec(g_conn, "begin");
+ if (!res ||
+ PQresultStatus(res) != PGRES_COMMAND_OK) {
+ fprintf(stderr,"BEGIN command failed\n");
+ exit_nicely(g_conn);
+ }
+ PQclear(res);
+
+ /* find all base types */
+ /* we include even the built-in types
+ because those may be used as array elements by user-defined types */
+ /* we filter out the built-in types when
+ we dump out the types */
+
+ sprintf(query, "SELECT oid, typowner,typname, typlen, typprtlen, typinput, typoutput, typreceive, typsend, typelem, typdelim, typdefault, typrelid,typbyval from pg_type");
+
+ res = PQexec(g_conn,query);
+ if (!res ||
+ PQresultStatus(res) != PGRES_TUPLES_OK) {
+ fprintf(stderr,"getTypes(): SELECT failed");
+ exit_nicely(g_conn);
+ }
+
+ ntups = PQntuples(res);
+
+ tinfo = (TypeInfo*)malloc(ntups * sizeof(TypeInfo));
+
+ i_oid = PQfnumber(res,"oid");
+ i_typowner = PQfnumber(res,"typowner");
+ i_typname = PQfnumber(res,"typname");
+ i_typlen = PQfnumber(res,"typlen");
+ i_typprtlen = PQfnumber(res,"typprtlen");
+ i_typinput = PQfnumber(res,"typinput");
+ i_typoutput = PQfnumber(res,"typoutput");
+ i_typreceive = PQfnumber(res,"typreceive");
+ i_typsend = PQfnumber(res,"typsend");
+ i_typelem = PQfnumber(res,"typelem");
+ i_typdelim = PQfnumber(res,"typdelim");
+ i_typdefault = PQfnumber(res,"typdefault");
+ i_typrelid = PQfnumber(res,"typrelid");
+ i_typbyval = PQfnumber(res,"typbyval");
+
+ for (i=0;i<ntups;i++) {
+ tinfo[i].oid = dupstr(PQgetvalue(res,i,i_oid));
+ tinfo[i].typowner = dupstr(PQgetvalue(res,i,i_typowner));
+ tinfo[i].typname = dupstr(PQgetvalue(res,i,i_typname));
+ tinfo[i].typlen = dupstr(PQgetvalue(res,i,i_typlen));
+ tinfo[i].typprtlen = dupstr(PQgetvalue(res,i,i_typprtlen));
+ tinfo[i].typinput = dupstr(PQgetvalue(res,i,i_typinput));
+ tinfo[i].typoutput = dupstr(PQgetvalue(res,i,i_typoutput));
+ tinfo[i].typreceive = dupstr(PQgetvalue(res,i,i_typreceive));
+ tinfo[i].typsend = dupstr(PQgetvalue(res,i,i_typsend));
+ tinfo[i].typelem = dupstr(PQgetvalue(res,i,i_typelem));
+ tinfo[i].typdelim = dupstr(PQgetvalue(res,i,i_typdelim));
+ tinfo[i].typdefault = dupstr(PQgetvalue(res,i,i_typdefault));
+ tinfo[i].typrelid = dupstr(PQgetvalue(res,i,i_typrelid));
+
+ if (strcmp(PQgetvalue(res,i,i_typbyval), "f") == 0)
+ tinfo[i].passedbyvalue = 0;
+ else
+ tinfo[i].passedbyvalue = 1;
+
+ /* check for user-defined array types,
+ omit system generated ones */
+ if ( (strcmp(tinfo[i].typelem, "0") != 0) &&
+ tinfo[i].typname[0] != '_')
+ tinfo[i].isArray = 1;
+ else
+ tinfo[i].isArray = 0;
+ }
+
+ *numTypes = ntups;
+
+ PQclear(res);
+
+ res = PQexec(g_conn,"end");
+ PQclear(res);
+
+ return tinfo;
+}
+
+/*
+ * getOperators:
+ * read all operators in the system catalogs and return them in the
+ * OprInfo* structure
+ *
+ * numOprs is set to the number of operators read in
+ *
+ *
+ */
+OprInfo*
+getOperators(int *numOprs)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ char query[MAXQUERYLEN];
+
+ OprInfo* oprinfo;
+
+ int i_oid;
+ int i_oprname;
+ int i_oprkind;
+ int i_oprcode;
+ int i_oprleft;
+ int i_oprright;
+ int i_oprcom;
+ int i_oprnegate;
+ int i_oprrest;
+ int i_oprjoin;
+ int i_oprcanhash;
+ int i_oprlsortop;
+ int i_oprrsortop;
+
+ /* find all operators, including builtin operators,
+ filter out system-defined operators at dump-out time */
+ res = PQexec(g_conn, "begin");
+ if (!res ||
+ PQresultStatus(res) != PGRES_COMMAND_OK) {
+ fprintf(stderr,"BEGIN command failed\n");
+ exit_nicely(g_conn);
+ }
+ PQclear(res);
+
+ sprintf(query, "SELECT oid, oprname, oprkind, oprcode, oprleft, oprright, oprcom, oprnegate, oprrest, oprjoin, oprcanhash, oprlsortop, oprrsortop from pg_operator");
+
+ res = PQexec(g_conn, query);
+ if (!res ||
+ PQresultStatus(res) != PGRES_TUPLES_OK) {
+ fprintf(stderr,"getOperators(): SELECT failed");
+ exit_nicely(g_conn);
+ }
+
+ ntups = PQntuples(res);
+ *numOprs = ntups;
+
+ oprinfo = (OprInfo*)malloc(ntups * sizeof(OprInfo));
+
+ i_oid = PQfnumber(res,"oid");
+ i_oprname = PQfnumber(res,"oprname");
+ i_oprkind = PQfnumber(res,"oprkind");
+ i_oprcode = PQfnumber(res,"oprcode");
+ i_oprleft = PQfnumber(res,"oprleft");
+ i_oprright = PQfnumber(res,"oprright");
+ i_oprcom = PQfnumber(res,"oprcom");
+ i_oprnegate = PQfnumber(res,"oprnegate");
+ i_oprrest = PQfnumber(res,"oprrest");
+ i_oprjoin = PQfnumber(res,"oprjoin");
+ i_oprcanhash = PQfnumber(res,"oprcanhash");
+ i_oprlsortop = PQfnumber(res,"oprlsortop");
+ i_oprrsortop = PQfnumber(res,"oprrsortop");
+
+ for (i=0;i<ntups;i++) {
+ oprinfo[i].oid = dupstr(PQgetvalue(res,i,i_oid));
+ oprinfo[i].oprname = dupstr(PQgetvalue(res,i,i_oprname));
+ oprinfo[i].oprkind = dupstr(PQgetvalue(res,i,i_oprkind));
+ oprinfo[i].oprcode = dupstr(PQgetvalue(res,i,i_oprcode));
+ oprinfo[i].oprleft = dupstr(PQgetvalue(res,i,i_oprleft));
+ oprinfo[i].oprright = dupstr(PQgetvalue(res,i,i_oprright));
+ oprinfo[i].oprcom = dupstr(PQgetvalue(res,i,i_oprcom));
+ oprinfo[i].oprnegate = dupstr(PQgetvalue(res,i,i_oprnegate));
+ oprinfo[i].oprrest = dupstr(PQgetvalue(res,i,i_oprrest));
+ oprinfo[i].oprjoin = dupstr(PQgetvalue(res,i,i_oprjoin));
+ oprinfo[i].oprcanhash = dupstr(PQgetvalue(res,i,i_oprcanhash));
+ oprinfo[i].oprlsortop = dupstr(PQgetvalue(res,i,i_oprlsortop));
+ oprinfo[i].oprrsortop = dupstr(PQgetvalue(res,i,i_oprrsortop));
+ }
+
+ PQclear(res);
+ res = PQexec(g_conn, "end");
+ PQclear(res);
+
+ return oprinfo;
+}
+
+
+/*
+ * getAggregates:
+ * read all the user-defined aggregates in the system catalogs and
+ * return them in the AggInfo* structure
+ *
+ * numAggs is set to the number of aggregates read in
+ *
+ *
+ */
+AggInfo*
+getAggregates(int *numAggs)
+{
+ PGresult* res;
+ int ntups;
+ int i;
+ char query[MAXQUERYLEN];
+ AggInfo *agginfo;
+
+ int i_oid;
+ int i_aggname;
+ int i_aggtransfn1;
+ int i_aggtransfn2;
+ int i_aggfinalfn;
+ int i_aggtranstype1;
+ int i_aggbasetype;
+ int i_aggtranstype2;
+ int i_agginitval1;
+ int i_agginitval2;
+
+ /* find all user-defined aggregates */
+
+ res = PQexec(g_conn, "begin");
+ if (!res ||
+ PQresultStatus(res) != PGRES_COMMAND_OK) {
+ fprintf(stderr,"BEGIN command failed\n");
+ exit_nicely(g_conn);
+ }
+ PQclear(res);
+
+ sprintf(query,
+ "SELECT oid, aggname, aggtransfn1, aggtransfn2, aggfinalfn, aggtranstype1, aggbasetype, aggtranstype2, agginitval1, agginitval2 from pg_aggregate;");
+
+ res = PQexec(g_conn, query);
+ if (!res ||
+ PQresultStatus(res) != PGRES_TUPLES_OK) {
+ fprintf(stderr,"getAggregates(): SELECT failed");
+ exit_nicely(g_conn);
+ }
+
+ ntups = PQntuples(res);
+ *numAggs = ntups;
+
+ agginfo = (AggInfo*)malloc(ntups * sizeof(AggInfo));
+
+ i_oid = PQfnumber(res,"oid");
+ i_aggname = PQfnumber(res,"aggname");
+ i_aggtransfn1 = PQfnumber(res,"aggtransfn1");
+ i_aggtransfn2 = PQfnumber(res,"aggtransfn2");
+ i_aggfinalfn = PQfnumber(res,"aggfinalfn");
+ i_aggtranstype1 = PQfnumber(res,"aggtranstype1");
+ i_aggbasetype = PQfnumber(res,"aggbasetype");
+ i_aggtranstype2 = PQfnumber(res,"aggtranstype2");
+ i_agginitval1 = PQfnumber(res,"agginitval1");
+ i_agginitval2 = PQfnumber(res,"agginitval2");
+
+ for (i=0;i<ntups;i++) {
+ agginfo[i].oid = dupstr(PQgetvalue(res,i,i_oid));
+ agginfo[i].aggname = dupstr(PQgetvalue(res,i,i_aggname));
+ agginfo[i].aggtransfn1 = dupstr(PQgetvalue(res,i,i_aggtransfn1));
+ agginfo[i].aggtransfn2 = dupstr(PQgetvalue(res,i,i_aggtransfn2));
+ agginfo[i].aggfinalfn = dupstr(PQgetvalue(res,i,i_aggfinalfn));
+ agginfo[i].aggtranstype1 = dupstr(PQgetvalue(res,i,i_aggtranstype1));
+ agginfo[i].aggbasetype = dupstr(PQgetvalue(res,i,i_aggbasetype));
+ agginfo[i].aggtranstype2 = dupstr(PQgetvalue(res,i,i_aggtranstype2));
+ agginfo[i].agginitval1 = dupstr(PQgetvalue(res,i,i_agginitval1));
+ agginfo[i].agginitval2 = dupstr(PQgetvalue(res,i,i_agginitval2));
+ }
+
+ PQclear(res);
+
+ res = PQexec(g_conn, "end");
+ PQclear(res);
+ return agginfo;
+}
+
+/*
+ * getFuncs:
+ * read all the user-defined functions in the system catalogs and
+ * return them in the FuncInfo* structure
+ *
+ * numFuncs is set to the number of functions read in
+ *
+ *
+ */
+FuncInfo*
+getFuncs(int *numFuncs)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ char query[MAXQUERYLEN];
+ FuncInfo *finfo;
+
+ int i_oid;
+ int i_proname;
+ int i_proowner;
+ int i_prolang;
+ int i_pronargs;
+ int i_proargtypes;
+ int i_prorettype;
+ int i_proretset;
+ int i_prosrc;
+ int i_probin;
+
+ /* find all user-defined funcs */
+
+ res = PQexec(g_conn, "begin");
+ if (!res ||
+ PQresultStatus(res) != PGRES_COMMAND_OK) {
+ fprintf(stderr,"BEGIN command failed\n");
+ exit_nicely(g_conn);
+ }
+ PQclear(res);
+
+ sprintf(query,
+ "SELECT oid, proname, proowner, prolang, pronargs, prorettype, proretset, proargtypes, prosrc, probin from pg_proc where oid > '%d'::oid",
+ g_last_builtin_oid);
+
+ res = PQexec(g_conn, query);
+ if (!res ||
+ PQresultStatus(res) != PGRES_TUPLES_OK) {
+ fprintf(stderr,"getFuncs(): SELECT failed");
+ exit_nicely(g_conn);
+ }
+
+ ntups = PQntuples(res);
+
+ *numFuncs = ntups;
+
+ finfo = (FuncInfo*)malloc(ntups * sizeof(FuncInfo));
+
+ i_oid = PQfnumber(res,"oid");
+ i_proname = PQfnumber(res,"proname");
+ i_proowner = PQfnumber(res,"proowner");
+ i_prolang = PQfnumber(res,"prolang");
+ i_pronargs = PQfnumber(res,"pronargs");
+ i_proargtypes = PQfnumber(res,"proargtypes");
+ i_prorettype = PQfnumber(res,"prorettype");
+ i_proretset = PQfnumber(res,"proretset");
+ i_prosrc = PQfnumber(res,"prosrc");
+ i_probin = PQfnumber(res,"probin");
+
+ for (i=0;i<ntups;i++) {
+ finfo[i].oid = dupstr(PQgetvalue(res,i,i_oid));
+ finfo[i].proname = dupstr(PQgetvalue(res,i,i_proname));
+ finfo[i].proowner = dupstr(PQgetvalue(res,i,i_proowner));
+
+ finfo[i].prosrc = checkForQuote(PQgetvalue(res,i,i_prosrc));
+ finfo[i].probin = dupstr(PQgetvalue(res,i,i_probin));
+
+ finfo[i].prorettype = dupstr(PQgetvalue(res,i,i_prorettype));
+ finfo[i].retset = (strcmp(PQgetvalue(res,i,i_proretset),"t") == 0);
+ finfo[i].nargs = atoi(PQgetvalue(res,i,i_pronargs));
+ finfo[i].lang = (atoi(PQgetvalue(res,i,i_prolang)) == C_PROLANG_OID);
+
+ parseArgTypes(finfo[i].argtypes, PQgetvalue(res,i,i_proargtypes));
+
+ finfo[i].dumped = 0;
+ }
+
+ PQclear(res);
+ res = PQexec(g_conn, "end");
+ PQclear(res);
+
+ return finfo;
+
+}
+
+/*
+ * getTables
+ * read all the user-defined tables (no indices, no catalogs)
+ * in the system catalogs return them in the TableInfo* structure
+ *
+ * numTables is set to the number of tables read in
+ *
+ *
+ */
+TableInfo*
+getTables(int *numTables)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ char query[MAXQUERYLEN];
+ TableInfo *tblinfo;
+
+ int i_oid;
+ int i_relname;
+ int i_relarch;
+
+ /* find all the user-defined tables (no indices and no catalogs),
+ ordering by oid is important so that we always process the parent
+ tables before the child tables when traversing the tblinfo*
+
+ we ignore tables that start with Xinv */
+
+ res = PQexec(g_conn, "begin");
+ if (!res ||
+ PQresultStatus(res) != PGRES_COMMAND_OK) {
+ fprintf(stderr,"BEGIN command failed\n");
+ exit_nicely(g_conn);
+ }
+ PQclear(res);
+
+ sprintf(query,
+ "SELECT oid, relname, relarch from pg_class where relkind = 'r' and relname !~ '^pg_' and relname !~ '^Xinv' order by oid;");
+
+ res = PQexec(g_conn, query);
+ if (!res ||
+ PQresultStatus(res) != PGRES_TUPLES_OK) {
+ fprintf(stderr,"getTables(): SELECT failed");
+ exit_nicely(g_conn);
+ }
+
+ ntups = PQntuples(res);
+
+ *numTables = ntups;
+
+ tblinfo = (TableInfo*)malloc(ntups * sizeof(TableInfo));
+
+ i_oid = PQfnumber(res,"oid");
+ i_relname = PQfnumber(res,"relname");
+ i_relarch = PQfnumber(res,"relarch");
+
+ for (i=0;i<ntups;i++) {
+ tblinfo[i].oid = dupstr(PQgetvalue(res,i,i_oid));
+ tblinfo[i].relname = dupstr(PQgetvalue(res,i,i_relname));
+ tblinfo[i].relarch = dupstr(PQgetvalue(res,i,i_relarch));
+ }
+
+ PQclear(res);
+ res = PQexec(g_conn, "end");
+ PQclear(res);
+
+ return tblinfo;
+
+}
+
+/*
+ * getInherits
+ * read all the inheritance information
+ * from the system catalogs return them in the InhInfo* structure
+ *
+ * numInherits is set to the number of tables read in
+ *
+ *
+ */
+InhInfo*
+getInherits(int *numInherits)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ char query[MAXQUERYLEN];
+ InhInfo *inhinfo;
+
+ int i_inhrel;
+ int i_inhparent;
+
+ /* find all the inheritance information */
+ res = PQexec(g_conn, "begin");
+ if (!res ||
+ PQresultStatus(res) != PGRES_COMMAND_OK) {
+ fprintf(stderr,"BEGIN command failed\n");
+ exit_nicely(g_conn);
+ }
+ PQclear(res);
+
+ sprintf(query, "SELECT inhrel, inhparent from pg_inherits");
+
+ res = PQexec(g_conn, query);
+ if (!res ||
+ PQresultStatus(res) != PGRES_TUPLES_OK) {
+ fprintf(stderr,"getInherits(): SELECT failed");
+ exit_nicely(g_conn);
+ }
+
+ ntups = PQntuples(res);
+
+ *numInherits = ntups;
+
+ inhinfo = (InhInfo*)malloc(ntups * sizeof(InhInfo));
+
+ i_inhrel = PQfnumber(res,"inhrel");
+ i_inhparent = PQfnumber(res,"inhparent");
+
+ for (i=0;i<ntups;i++) {
+ inhinfo[i].inhrel = dupstr(PQgetvalue(res,i,i_inhrel));
+ inhinfo[i].inhparent = dupstr(PQgetvalue(res,i,i_inhparent));
+ }
+
+ PQclear(res);
+ res = PQexec(g_conn, "end");
+ PQclear(res);
+ return inhinfo;
+}
+
+/*
+ * getTableAttrs -
+ * for each table in tblinfo, read its attributes types and names
+ *
+ * this is implemented in a very inefficient way right now, looping
+ * through the tblinfo and doing a join per table to find the attrs and their
+ * types
+ *
+ * modifies tblinfo
+ */
+void
+getTableAttrs(TableInfo* tblinfo, int numTables)
+{
+ int i,j;
+ char q[MAXQUERYLEN];
+ int i_attname;
+ int i_typname;
+ PGresult *res;
+ int ntups;
+
+ for (i=0;i<numTables;i++) {
+
+ /* skip archive tables */
+ if (isArchiveName(tblinfo[i].relname))
+ continue;
+
+ /* find all the user attributes and their types*/
+ /* we must read the attribute names in attribute number order! */
+ /* because we will use the attnum to index into the attnames array
+ later */
+if (g_verbose)
+ fprintf(stderr,"%s finding the attrs and types for table: %s %s\n",
+ g_comment_start,
+ tblinfo[i].relname,
+ g_comment_end);
+
+ sprintf(q,"SELECT a.attnum, a.attname, t.typname from pg_attribute a, pg_type t where a.attrelid = '%s'::oid and a.atttypid = t.oid and a.attnum > 0 order by attnum",tblinfo[i].oid);
+ res = PQexec(g_conn, q);
+ if (!res ||
+ PQresultStatus(res) != PGRES_TUPLES_OK) {
+ fprintf(stderr,"getTableAttrs(): SELECT failed");
+ exit_nicely(g_conn);
+ }
+
+ ntups = PQntuples(res);
+
+ i_attname = PQfnumber(res,"attname");
+ i_typname = PQfnumber(res,"typname");
+
+ tblinfo[i].numatts = ntups;
+ tblinfo[i].attnames = (char**) malloc( ntups * sizeof(char*));
+ tblinfo[i].typnames = (char**) malloc( ntups * sizeof(char*));
+ tblinfo[i].inhAttrs = (int*) malloc (ntups * sizeof(int));
+ tblinfo[i].parentRels = NULL;
+ tblinfo[i].numParents = 0;
+ for (j=0;j<ntups;j++) {
+ tblinfo[i].attnames[j] = dupstr(PQgetvalue(res,j,i_attname));
+ tblinfo[i].typnames[j] = dupstr(PQgetvalue(res,j,i_typname));
+ tblinfo[i].inhAttrs[j] = 0; /* this flag is set in flagInhAttrs()*/
+ }
+ PQclear(res);
+ }
+}
+
+
+/*
+ * getIndices
+ * read all the user-defined indices information
+ * from the system catalogs return them in the InhInfo* structure
+ *
+ * numIndices is set to the number of indices read in
+ *
+ *
+ */
+IndInfo*
+getIndices(int *numIndices)
+{
+ int i;
+ char query[MAXQUERYLEN];
+ PGresult *res;
+ int ntups;
+ IndInfo *indinfo;
+
+ int i_indexrelname;
+ int i_indrelname;
+ int i_indamname;
+ int i_indproc;
+ int i_indkey;
+ int i_indclassname;
+
+ /* find all the user-defined indices.
+ We do not handle partial indices.
+ We also assume that only single key indices
+
+ skip 'Xinx*' - indices on inversion objects
+
+ this is a 5-way join !!
+ */
+
+ res = PQexec(g_conn, "begin");
+ if (!res ||
+ PQresultStatus(res) != PGRES_COMMAND_OK) {
+ fprintf(stderr,"BEGIN command failed\n");
+ exit_nicely(g_conn);
+ }
+ PQclear(res);
+
+ sprintf(query,
+ "SELECT t1.relname as indexrelname, t2.relname as indrelname, i.indproc, i.indkey[0], o.opcname as indclassname, a.amname as indamname from pg_index i, pg_class t1, pg_class t2, pg_opclass o, pg_am a where t1.oid = i.indexrelid and t2.oid = i.indrelid and o.oid = i.indclass[0] and t1.relam = a.oid and i.indexrelid > '%d'::oid and t2.relname !~ '^pg_' and t1.relname !~ '^Xinx' ;",
+ g_last_builtin_oid);
+
+ res = PQexec(g_conn, query);
+ if (!res ||
+ PQresultStatus(res) != PGRES_TUPLES_OK) {
+ fprintf(stderr,"getIndices(): SELECT failed");
+ exit_nicely(g_conn);
+ }
+
+ ntups = PQntuples(res);
+
+ *numIndices = ntups;
+
+ indinfo = (IndInfo*)malloc(ntups * sizeof (IndInfo));
+
+ i_indexrelname = PQfnumber(res,"indexrelname");
+ i_indrelname = PQfnumber(res,"indrelname");
+ i_indamname = PQfnumber(res,"indamname");
+ i_indproc = PQfnumber(res,"indproc");
+ i_indkey = PQfnumber(res,"indkey");
+ i_indclassname = PQfnumber(res,"indclassname");
+
+ for (i=0;i<ntups;i++) {
+ indinfo[i].indexrelname = dupstr(PQgetvalue(res,i,i_indexrelname));
+ indinfo[i].indrelname = dupstr(PQgetvalue(res,i,i_indrelname));
+ indinfo[i].indamname = dupstr(PQgetvalue(res,i,i_indamname));
+ indinfo[i].indproc = dupstr(PQgetvalue(res,i,i_indproc));
+ indinfo[i].indkey = dupstr(PQgetvalue(res,i,i_indkey));
+ indinfo[i].indclassname = dupstr(PQgetvalue(res,i,i_indclassname));
+ }
+ PQclear(res);
+ res = PQexec(g_conn,"end");
+
+ return indinfo;
+}
+
+/*
+ * dumpTypes
+ * writes out to fout the queries to recreate all the user-defined types
+ *
+ */
+void
+dumpTypes(FILE* fout, FuncInfo* finfo, int numFuncs,
+ TypeInfo* tinfo, int numTypes)
+{
+ int i;
+ char q[MAXQUERYLEN];
+ int funcInd;
+
+ for (i=0;i<numTypes;i++) {
+
+ /* skip all the builtin types */
+ if (atoi(tinfo[i].oid) < g_last_builtin_oid)
+ continue;
+
+ /* skip relation types */
+ if (atoi(tinfo[i].typrelid) != 0)
+ continue;
+
+ /* skip all array types that start w/ underscore */
+ if ( (tinfo[i].typname[0] == '_') &&
+ (strcmp(tinfo[i].typinput, "array_in") == 0))
+ continue;
+
+ /* before we create a type, we need to create the input and
+ output functions for it, if they haven't been created already */
+ funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typinput);
+ if (funcInd != -1)
+ dumpOneFunc(fout,finfo,funcInd,tinfo,numTypes);
+
+ funcInd = findFuncByName(finfo, numFuncs, tinfo[i].typoutput);
+ if (funcInd != -1)
+ dumpOneFunc(fout,finfo,funcInd,tinfo,numTypes);
+
+ sprintf(q,
+ "CREATE TYPE %s ( internallength = %s, externallength = %s, input = %s, output = %s, send = %s, receive = %s, default = '%s'",
+ tinfo[i].typname,
+ tinfo[i].typlen,
+ tinfo[i].typprtlen,
+ tinfo[i].typinput,
+ tinfo[i].typoutput,
+ tinfo[i].typsend,
+ tinfo[i].typreceive,
+ tinfo[i].typdefault);
+
+ if (tinfo[i].isArray) {
+ char* elemType;
+
+ elemType = findTypeByOid(tinfo, numTypes, tinfo[i].typelem);
+
+ sprintf(q,"%s, element = %s, delimiter = '%s'",
+ q, elemType,tinfo[i].typdelim);
+ }
+ if (tinfo[i].passedbyvalue)
+ strcat(q,",passedbyvalue);\n");
+ else
+ strcat(q,");\n");
+
+ fputs(q,fout);
+ }
+}
+
+/*
+ * dumpFuncs
+ * writes out to fout the queries to recreate all the user-defined functions
+ *
+ */
+void
+dumpFuncs(FILE* fout, FuncInfo* finfo, int numFuncs,
+ TypeInfo *tinfo, int numTypes)
+{
+ int i;
+ for (i=0;i<numFuncs;i++) {
+ dumpOneFunc(fout,finfo,i,tinfo,numTypes);
+ }
+}
+
+/*
+ * dumpOneFunc:
+ * dump out only one function, the index of which is given in the third
+ * argument
+ *
+ */
+
+void
+dumpOneFunc(FILE* fout, FuncInfo* finfo, int i,
+ TypeInfo *tinfo, int numTypes)
+{
+ char q[MAXQUERYLEN];
+ int j;
+
+ if (finfo[i].dumped)
+ return;
+ else
+ finfo[i].dumped = 1;
+
+ sprintf(q,"CREATE FUNCTION %s (",finfo[i].proname);
+ for (j=0;j<finfo[i].nargs;j++) {
+ char* typname;
+ typname = findTypeByOid(tinfo, numTypes, finfo[i].argtypes[j]);
+ sprintf(q, "%s%s%s",
+ q,
+ (j > 0) ? "," : "",
+ typname);
+ }
+ sprintf(q,"%s ) RETURNS %s%s AS '%s' LANGUAGE '%s';\n",
+ q,
+ finfo[i].retset ? " SETOF " : "",
+ findTypeByOid(tinfo, numTypes, finfo[i].prorettype),
+ (finfo[i].lang) ? finfo[i].probin : finfo[i].prosrc,
+ (finfo[i].lang) ? "C" : "SQL");
+
+ fputs(q,fout);
+
+}
+
+/*
+ * dumpOprs
+ * writes out to fout the queries to recreate all the user-defined operators
+ *
+ */
+void
+dumpOprs(FILE* fout, OprInfo* oprinfo, int numOperators,
+ TypeInfo *tinfo, int numTypes)
+{
+ int i;
+ char q[MAXQUERYLEN];
+ char leftarg[MAXQUERYLEN];
+ char rightarg[MAXQUERYLEN];
+ char commutator[MAXQUERYLEN];
+ char negator[MAXQUERYLEN];
+ char restrict[MAXQUERYLEN];
+ char join[MAXQUERYLEN];
+ char sortop[MAXQUERYLEN];
+
+ for (i=0;i<numOperators;i++) {
+
+ /* skip all the builtin oids */
+ if (atoi(oprinfo[i].oid) < g_last_builtin_oid)
+ continue;
+
+ /* some operator are invalid because they were the result
+ of user defining operators before commutators exist */
+ if (strcmp(oprinfo[i].oprcode, "-") == 0)
+ continue;
+
+ leftarg[0] = '\0';
+ rightarg[0] = '\0';
+ /* right unary means there's a left arg
+ and left unary means there's a right arg */
+ if (strcmp(oprinfo[i].oprkind, "r") == 0 ||
+ strcmp(oprinfo[i].oprkind, "b") == 0 ) {
+ sprintf(leftarg, ", LEFTARG = %s ",
+ findTypeByOid(tinfo, numTypes, oprinfo[i].oprleft));
+ }
+ if (strcmp(oprinfo[i].oprkind, "l") == 0 ||
+ strcmp(oprinfo[i].oprkind, "b") == 0 ) {
+ sprintf(rightarg, ", RIGHTARG = %s ",
+ findTypeByOid(tinfo, numTypes, oprinfo[i].oprright));
+ }
+ if (strcmp(oprinfo[i].oprcom, "0") == 0)
+ commutator[0] = '\0';
+ else
+ sprintf(commutator,", COMMUTATOR = %s ",
+ findOprByOid(oprinfo, numOperators, oprinfo[i].oprcom));
+
+ if (strcmp(oprinfo[i].oprnegate, "0") == 0)
+ negator[0] = '\0';
+ else
+ sprintf(negator,", NEGATOR = %s ",
+ findOprByOid(oprinfo, numOperators, oprinfo[i].oprnegate));
+
+ if (strcmp(oprinfo[i].oprrest, "-") == 0)
+ restrict[0] = '\0';
+ else
+ sprintf(restrict,", RESTRICT = %s ", oprinfo[i].oprrest);
+
+ if (strcmp(oprinfo[i].oprjoin,"-") == 0)
+ join[0] = '\0';
+ else
+ sprintf(join,", JOIN = %s ", oprinfo[i].oprjoin);
+
+ if (strcmp(oprinfo[i].oprlsortop, "0") == 0)
+ sortop[0] = '\0';
+ else
+ {
+ sprintf(sortop,", SORT = %s ",
+ findOprByOid(oprinfo, numOperators,
+ oprinfo[i].oprlsortop));
+ if (strcmp(oprinfo[i].oprrsortop, "0") != 0)
+ sprintf(sortop, "%s , %s", sortop,
+ findOprByOid(oprinfo, numOperators,
+ oprinfo[i].oprlsortop));
+ }
+
+ sprintf(q,
+ "CREATE OPERATOR %s (PROCEDURE = %s %s %s %s %s %s %s %s %s);\n ",
+ oprinfo[i].oprname,
+ oprinfo[i].oprcode,
+ leftarg,
+ rightarg,
+ commutator,
+ negator,
+ restrict,
+ (strcmp(oprinfo[i].oprcanhash, "t")) ? ", HASHES" : "",
+ join,
+ sortop);
+
+ fputs(q,fout);
+ }
+}
+
+/*
+ * dumpAggs
+ * writes out to fout the queries to create all the user-defined aggregates
+ *
+ */
+void
+dumpAggs(FILE* fout, AggInfo* agginfo, int numAggs,
+ TypeInfo *tinfo, int numTypes)
+{
+ int i;
+ char q[MAXQUERYLEN];
+ char sfunc1[MAXQUERYLEN];
+ char sfunc2[MAXQUERYLEN];
+ char finalfunc[MAXQUERYLEN];
+ char comma1[2], comma2[2];
+
+ for (i=0;i<numAggs;i++) {
+ /* skip all the builtin oids */
+ if (atoi(agginfo[i].oid) < g_last_builtin_oid)
+ continue;
+
+ if ( strcmp(agginfo[i].aggtransfn1, "-") == 0)
+ sfunc1[0] = '\0';
+ else {
+ sprintf(sfunc1,
+ "SFUNC1 = %s, BASETYPE = %s, STYPE1 = %s",
+ agginfo[i].aggtransfn1,
+ findTypeByOid(tinfo,numTypes,agginfo[i].aggbasetype),
+ findTypeByOid(tinfo,numTypes,agginfo[i].aggtranstype1));
+ if (agginfo[i].agginitval1)
+ sprintf(sfunc1, "%s ,INITCOND1 = '%s'",
+ sfunc1, agginfo[i].agginitval1);
+
+ }
+
+ if ( strcmp(agginfo[i].aggtransfn2, "-") == 0)
+ sfunc2[0] = '\0';
+ else {
+ sprintf(sfunc2,
+ "SFUNC2 = %s, STYPE2 = %s",
+ agginfo[i].aggtransfn2,
+ findTypeByOid(tinfo,numTypes,agginfo[i].aggtranstype2));
+ if (agginfo[i].agginitval2)
+ sprintf(sfunc2,"%s ,INITCOND2 = '%s'",
+ sfunc2, agginfo[i].agginitval2);
+ }
+
+ if ( strcmp(agginfo[i].aggfinalfn, "-") == 0)
+ finalfunc[0] = '\0';
+ else {
+ sprintf(finalfunc, "FINALFUNC = %s", agginfo[i].aggfinalfn);
+ }
+ if (sfunc1[0] != '\0' && sfunc2[0] != '\0') {
+ comma1[0] = ','; comma1[1] = '\0';
+ } else
+ comma1[0] = '\0';
+
+ if (finalfunc[0] != '\0' && (sfunc1[0] != '\0' || sfunc2[0] != '\0')) {
+ comma2[0] = ',';comma2[1] = '\0';
+ } else
+ comma2[0] = '\0';
+
+ sprintf(q,"CREATE AGGREGATE %s ( %s %s %s %s %s );\n",
+ agginfo[i].aggname,
+ sfunc1,
+ comma1,
+ sfunc2,
+ comma2,
+ finalfunc);
+
+ fputs(q,fout);
+ }
+}
+
+/*
+ * dumpTables:
+ * write out to fout all the user-define tables
+ */
+void
+dumpTables(FILE* fout, TableInfo *tblinfo, int numTables,
+ InhInfo *inhinfo, int numInherits,
+ TypeInfo *tinfo, int numTypes)
+{
+ int i,j,k;
+ char q[MAXQUERYLEN];
+ char **parentRels; /* list of names of parent relations */
+ int numParents;
+ int actual_atts; /* number of attrs in this CREATE statment */
+ char *archiveMode;
+
+ for (i=0;i<numTables;i++) {
+
+ /* skip archive names*/
+ if (isArchiveName(tblinfo[i].relname))
+ continue;
+
+ parentRels = tblinfo[i].parentRels;
+ numParents = tblinfo[i].numParents;
+
+ sprintf(q, "CREATE TABLE %s (", tblinfo[i].relname);
+ actual_atts = 0;
+ for (j=0;j<tblinfo[i].numatts;j++) {
+ if (tblinfo[i].inhAttrs[j] == 0) {
+ sprintf(q, "%s%s%s %s",
+ q,
+ (actual_atts > 0) ? ", " : "",
+ tblinfo[i].attnames[j],
+ tblinfo[i].typnames[j]);
+ actual_atts++;
+ }
+ }
+
+ strcat(q,")");
+
+ if (numParents > 0) {
+ sprintf(q, "%s inherits ( ",q);
+ for (k=0;k<numParents;k++){
+ sprintf(q, "%s%s%s",
+ q,
+ (k>0) ? ", " : "",
+ parentRels[k]);
+ }
+ strcat(q,")");
+ }
+
+ switch(tblinfo[i].relarch[0]) {
+ case 'n':
+ archiveMode = "none";
+ break;
+ case 'h':
+ archiveMode = "heavy";
+ break;
+ case 'l':
+ archiveMode = "light";
+ break;
+ default:
+ fprintf(stderr, "unknown archive mode\n");
+ archiveMode = "none";
+ break;
+ }
+
+ sprintf(q, "%s archive = %s;\n",
+ q,
+ archiveMode);
+ fputs(q,fout);
+ }
+}
+
+/*
+ * dumpIndices:
+ * write out to fout all the user-define indices
+ */
+void
+dumpIndices(FILE* fout, IndInfo* indinfo, int numIndices,
+ TableInfo* tblinfo, int numTables)
+{
+ int i;
+ int tableInd;
+ char *attname; /* the name of the indexed attribute */
+ char *funcname; /* the name of the function to comput the index key from*/
+ int indkey;
+
+ char q[MAXQUERYLEN];
+ PGresult *res;
+
+ for (i=0;i<numIndices;i++) {
+ tableInd = findTableByName(tblinfo, numTables,
+ indinfo[i].indrelname);
+ indkey = atoi(indinfo[i].indkey) - 1;
+ attname = tblinfo[tableInd].attnames[indkey];
+ if (strcmp(indinfo[i].indproc,"0") == 0) {
+ funcname = NULL;
+ } else {
+ /* the funcname is an oid which we use to
+ find the name of the pg_proc. We need to do this
+ because getFuncs() only reads in the user-defined funcs
+ not all the funcs. We might not find what we want
+ by looking in FuncInfo**/
+ sprintf(q,
+ "SELECT proname from pg_proc where pg_proc.oid = '%s'::oid",
+ indinfo[i].indproc);
+ res = PQexec(g_conn, q);
+ funcname = dupstr(PQgetvalue(res, 0,
+ PQfnumber(res,"proname")));
+ PQclear(res);
+ }
+ sprintf(q,"CREATE INDEX %s on %s using %s (",
+ indinfo[i].indexrelname,
+ indinfo[i].indrelname,
+ indinfo[i].indamname);
+ if (funcname) {
+ sprintf(q, "%s %s(%s) %s);\n",
+ q,funcname, attname, indinfo[i].indclassname);
+ free(funcname);
+ } else
+ sprintf(q, "%s %s %s);\n",
+ q,attname,indinfo[i].indclassname);
+
+ fputs(q,fout);
+ }
+
+}
+
+
+
+
+
+/*
+ * DumpClasses -
+ * dump the contents of all the classes.
+ */
+void
+dumpClasses(TableInfo *tblinfo, int numTables, FILE *fout)
+{
+ char query[255];
+#define COPYBUFSIZ 8192
+ char copybuf[COPYBUFSIZ];
+ PGresult *res;
+ int i;
+ int ret;
+ int copydone;
+
+ for(i = 0; i < numTables; i++) {
+ char *classname = tblinfo[i].relname;
+
+ /* skip archive names*/
+ if (isArchiveName(classname))
+ continue;
+
+ fprintf(fout, "COPY %s from stdin;\n", classname);
+ sprintf(query, "COPY %s to stdout;\n", classname);
+ res = PQexec(g_conn, query);
+ if (!res ||
+ PQresultStatus(res) != PGRES_COPY_OUT) {
+ fprintf(stderr,"dumpClasses(): COPY to stdout failed");
+ exit_nicely(g_conn);
+ }
+ copydone = 0;
+ while (!copydone) {
+ ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
+
+ if (copybuf[0] == '.' && copybuf[1] =='\0') {
+ copydone = true; /* don't print this... */
+ } else {
+ fputs(copybuf, stdout);
+ switch (ret) {
+ case EOF:
+ copydone = true;
+ /*FALLTHROUGH*/
+ case 0:
+ fputc('\n', stdout);
+ break;
+ case 1:
+ break;
+ }
+ }
+ }
+ fprintf(fout, ".\n");
+ PQclear(res);
+ PQendcopy(res->conn);
+ }
+
+}
+
+/*
+ * dumpTuples --
+ * prints out the tuples in ASCII representation. The output is a valid
+ * input to COPY FROM stdin.
+ *
+ * We only need to do this for POSTGRES 4.2 databases since the
+ * COPY TO statment doesn't escape newlines properly. It's been fixed
+ * in Postgres95.
+ *
+ * the attrmap passed in tells how to map the attributes copied in to the
+ * attributes copied out
+ */
+void
+dumpTuples(PGresult *res, FILE *fout, int* attrmap)
+{
+ int j, k;
+ int m, n;
+ char **outVals = NULL; /* values to copy out */
+
+ n = PQntuples(res);
+ m = PQnfields(res);
+
+ if ( m > 0 ) {
+ /*
+ * Print out the tuples but only print tuples with at least
+ * 1 field.
+ */
+ outVals = (char**)malloc(m * sizeof(char*));
+
+ for (j = 0; j < n; j++) {
+ for (k = 0; k < m; k++) {
+ outVals[attrmap[k]] = PQgetvalue(res, j, k);
+ }
+ for (k = 0; k < m; k++) {
+ char *pval = outVals[k];
+
+ if (k!=0)
+ fputc('\t', fout); /* delimiter for attribute */
+
+ if (pval) {
+ while (*pval != '\0') {
+ /* escape tabs, newlines and backslashes */
+ if (*pval=='\t' || *pval=='\n' || *pval=='\\')
+ fputc('\\', fout);
+ fputc(*pval, fout);
+ pval++;
+ }
+ }
+ }
+ fputc('\n', fout); /* delimiter for a tuple */
+ }
+ free (outVals);
+ }
+}
+
+
+
+/*
+ * findLastBuiltInOid -
+ * find the last built in oid
+ * we do this by looking up the oid of 'template1' in pg_database,
+ * this is probably not foolproof but comes close
+*/
+
+int
+findLastBuiltinOid()
+{
+ PGresult* res;
+ int ntups;
+ int last_oid;
+
+ res = PQexec(g_conn,
+ "SELECT oid from pg_database where datname = 'template1';");
+ if (res == NULL ||
+ PQresultStatus(res) != PGRES_TUPLES_OK) {
+ fprintf(stderr,"pg_dump error in finding the template1 database");
+ exit_nicely(g_conn);
+ }
+ ntups = PQntuples(res);
+ if (ntups != 1) {
+ fprintf(stderr,"pg_dump: couldn't find the template1 database. You are really hosed\nGiving up\n");
+ exit_nicely(g_conn);
+ }
+ last_oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "oid")));
+ PQclear(res);
+ return last_oid;
+}
+
+
+/*
+ * checkForQuote:
+ * checks a string for quote characters and quotes them
+ */
+char*
+checkForQuote(char* s)
+{
+ char *r;
+ char c;
+ char *result;
+
+ int j = 0;
+
+ r = malloc(strlen(s)*3 + 1); /* definitely long enough */
+
+ while ( (c = *s) != '\0') {
+
+ if (c == '\'') {
+ r[j++] = '\''; /* quote the single quotes */
+ }
+ r[j++] = c;
+ s++;
+ }
+ r[j] = '\0';
+
+ result = dupstr(r);
+ free(r);
+
+ return result;
+
+}
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
new file mode 100644
index 00000000000..e77960afe4b
--- /dev/null
+++ b/src/bin/pg_dump/pg_dump.h
@@ -0,0 +1,195 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_dump.h
+ * header file for the pg_dump utility
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: pg_dump.h,v 1.1.1.1 1996/07/09 06:22:14 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+
+/* The *Info data structures run-time C structures used to store
+ system catalog information */
+
+typedef struct _typeInfo {
+ char* oid;
+ char* typowner;
+ char* typname;
+ char* typlen;
+ char* typprtlen;
+ char* typinput;
+ char* typoutput;
+ char* typreceive;
+ char* typsend;
+ char* typelem;
+ char* typdelim;
+ char* typdefault;
+ char* typrelid;
+ int passedbyvalue;
+ int isArray;
+} TypeInfo;
+
+typedef struct _funcInfo {
+ char* oid;
+ char* proname;
+ char* proowner;
+ int lang; /* 1 if C, else SQL */
+ int nargs;
+ char* argtypes[8]; /* should be derived from obj/fmgr.h instead of hardwired*/
+ char* prorettype;
+ int retset; /* 1 if the function returns a set, 0 otherwise */
+ char* prosrc;
+ char* probin;
+ int dumped; /* 1 if already dumped */
+} FuncInfo;
+
+typedef struct _tableInfo {
+ char *oid;
+ char *relname;
+ char *relarch;
+ int numatts; /* number of attributes */
+ int *inhAttrs; /* an array of flags, one for each attribute
+ if the value is 1, then this attribute is
+ an inherited attribute */
+ char **attnames; /* the attribute names */
+ char **typnames; /* fill out attributes */
+ int numParents; /* number of (immediate) parent supertables */
+ char **parentRels; /* names of parent relations, NULL
+ if numParents == 0 */
+ char **out_attnames; /* the attribute names, in the order they would
+ be in, when the table is created in the
+ target query language.
+ this is needed because the SQL tables will
+ not have the same order of attributes as
+ the POSTQUEL tables */
+
+} TableInfo;
+
+typedef struct _inhInfo {
+ char *oid;
+ char *inhrel;
+ char *inhparent;
+} InhInfo;
+
+typedef struct _indInfo {
+ char *indexrelname; /* name of the secondary index class */
+ char *indrelname; /* name of the indexed heap class */
+ char *indamname; /* name of the access method (e.g. btree, rtree, etc.) */
+ char *indproc; /* oid of the function to compute the index, 0 if none*/
+ char *indkey; /* attribute number of the key attribute */
+ char *indclassname; /* name of the opclass of the key */
+} IndInfo;
+
+typedef struct _aggInfo {
+ char *oid;
+ char *aggname;
+ char *aggtransfn1;
+ char *aggtransfn2;
+ char *aggfinalfn;
+ char *aggtranstype1;
+ char *aggbasetype;
+ char *aggtranstype2;
+ char *agginitval1;
+ char *agginitval2;
+} AggInfo;
+
+typedef struct _oprInfo {
+ char *oid;
+ char *oprname;
+ char *oprkind; /* "b" = binary, "l" = left unary, "r" = right unary */
+ char *oprcode; /* operator function name */
+ char *oprleft; /* left operand type */
+ char *oprright; /* right operand type */
+ char *oprcom; /* oid of the commutator operator */
+ char *oprnegate; /* oid of the negator operator */
+ char *oprrest; /* name of the function to calculate operator restriction
+ selectivity */
+ char *oprjoin; /* name of the function to calculate operator join
+ selectivity */
+ char *oprcanhash; /* can we use hash join strategy ? */
+ char *oprlsortop; /* oid's of the left and right sort operators */
+ char *oprrsortop;
+} OprInfo;
+
+
+/* global decls */
+extern int g_verbose; /* verbose flag */
+extern int g_last_builtin_oid; /* value of the last builtin oid */
+extern FILE *g_fout; /* the script file */
+
+/* placeholders for comment starting and ending delimiters */
+extern char g_comment_start[10];
+extern char g_comment_end[10];
+
+extern char g_opaque_type[10]; /* name for the opaque type */
+
+/* pg_dump is really two programs in one
+ one version works with postgres v4r2
+ and the other works with postgres95
+ the common routines are declared here
+*/
+/*
+ * common utility functions
+*/
+
+extern TableInfo* dumpSchema(FILE* fout, int *numTablesPtr);
+
+extern char* findTypeByOid(TypeInfo* tinfo, int numTypes, char* oid);
+extern char* findOprByOid(OprInfo *oprinfo, int numOprs, char *oid);
+extern int findFuncByName(FuncInfo* finfo, int numFuncs, char* name);
+extern char** findParentsByOid(TableInfo* tbinfo, int numTables,
+ InhInfo* inhinfo, int numInherits,
+ char *oid,
+ int *numParents);
+extern int findTableByName(TableInfo *tbinfo, int numTables, char *relname);
+extern int findTableByOid(TableInfo *tbinfo, int numTables, char *oid);
+extern void flagInhAttrs(TableInfo* tbinfo, int numTables,
+ InhInfo* inhinfo, int numInherits);
+
+extern void check_conn_and_db();
+extern char* dupstr(char *s);
+extern int strInArray(char* pattern, char** arr, int arr_size);
+extern void parseArgTypes(char **argtypes, char* str);
+extern int isArchiveName(char*);
+
+/*
+ * version specific routines
+ */
+extern TypeInfo* getTypes(int *numTypes);
+extern FuncInfo* getFuncs(int *numFuncs);
+extern AggInfo* getAggregates(int *numAggregates);
+extern OprInfo* getOperators(int *numOperators);
+extern TableInfo* getTables(int *numTables);
+extern InhInfo* getInherits(int *numInherits);
+extern void getTableAttrs(TableInfo* tbinfo, int numTables);
+extern IndInfo* getIndices(int *numIndices);
+extern void dumpTypes(FILE* fout, FuncInfo* finfo, int numFuncs,
+ TypeInfo* tinfo, int numTypes);
+extern void dumpFuncs(FILE* fout, FuncInfo* finfo, int numFuncs,
+ TypeInfo *tinfo, int numTypes);
+extern void dumpAggs(FILE* fout, AggInfo* agginfo, int numAggregates,
+ TypeInfo *tinfo, int numTypes);
+extern void dumpOprs(FILE* fout, OprInfo* agginfo, int numOperators,
+ TypeInfo *tinfo, int numTypes);
+extern void dumpOneFunc(FILE* fout, FuncInfo* finfo, int i,
+ TypeInfo *tinfo, int numTypes);
+extern void dumpTables(FILE* fout, TableInfo* tbinfo, int numTables,
+ InhInfo *inhinfo, int numInherits,
+ TypeInfo *tinfo, int numTypes);
+extern void dumpIndices(FILE* fout, IndInfo* indinfo, int numIndices,
+ TableInfo* tbinfo, int numTables);
+
+extern void dumpClasses(TableInfo *tbinfo, int numTables, FILE *fout);
+extern void dumpTuples(PGresult *res, FILE *fout, int *attrmap);
+extern char* checkForQuote(char* s);
+extern int findLastBuiltinOid();
+
+
+/* largest query string size */
+#define MAXQUERYLEN 5000
+
+/* these voodoo constants are from the backend */
+#define C_PROLANG_OID 13
diff --git a/src/bin/pg_id/Makefile b/src/bin/pg_id/Makefile
new file mode 100644
index 00000000000..db056f89f2c
--- /dev/null
+++ b/src/bin/pg_id/Makefile
@@ -0,0 +1,23 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for bin/pg_id
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/pg_id/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:14 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+PROG= pg_id
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+SRCS= pg_id.c
+
+include $(MKDIR)/postgres.prog.mk
+
diff --git a/src/bin/pg_id/pg_id.c b/src/bin/pg_id/pg_id.c
new file mode 100644
index 00000000000..675326acbca
--- /dev/null
+++ b/src/bin/pg_id/pg_id.c
@@ -0,0 +1,52 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_id.c--
+ * Print the user ID for the login name passed as argument,
+ * or the real user ID of the caller if no argument. If the
+ * login name doesn't exist, print "NOUSER" and exit 1.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/bin/pg_id/Attic/pg_id.c,v 1.1.1.1 1996/07/09 06:22:14 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <sys/types.h>
+#include <pwd.h>
+#include <stdio.h>
+
+int
+main(int argc, char **argv)
+{
+ struct passwd *pw;
+ int ch;
+ extern int optind;
+
+ while ((ch = getopt(argc, argv, "")) != EOF)
+ switch (ch) {
+ case '?':
+ default:
+ fprintf(stderr, "usage: pg_id [login]\n");
+ exit(1);
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc > 0) {
+ if (argc > 1) {
+ fprintf(stderr, "usage: pg_id [login]\n");
+ exit(1);
+ }
+ if ((pw = getpwnam(argv[0])) == NULL) {
+ printf("NOUSER\n");
+ exit(1);
+ }
+ printf("%d\n", pw->pw_uid);
+ } else {
+ printf("%d\n", getuid());
+ }
+
+ exit(0);
+}
diff --git a/src/bin/pg_version/Makefile b/src/bin/pg_version/Makefile
new file mode 100644
index 00000000000..9e46bd27b08
--- /dev/null
+++ b/src/bin/pg_version/Makefile
@@ -0,0 +1,26 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for bin/pg_version
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/pg_version/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:14 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+PROG= pg_version
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+VPATH:=$(VPATH):$(srcdir)/backend/utils/init
+SRCS= pg_version.c magic.c
+
+CFLAGS+= -I$(srcdir)/backend/port/$(PORTNAME)
+
+include $(MKDIR)/postgres.prog.mk
+
diff --git a/src/bin/pg_version/pg_version.c b/src/bin/pg_version/pg_version.c
new file mode 100644
index 00000000000..6844692be7e
--- /dev/null
+++ b/src/bin/pg_version/pg_version.c
@@ -0,0 +1,35 @@
+/*-------------------------------------------------------------------------
+ *
+ * pg_version.c--
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/bin/pg_version/Attic/pg_version.c,v 1.1.1.1 1996/07/09 06:22:14 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdio.h>
+
+int Noversion = 0;
+char *DataDir = (char *) NULL;
+
+int
+main(int argc, char **argv)
+{
+ if (argc < 2) {
+ fprintf(stderr, "pg_version: missing argument\n");
+ exit(1);
+ }
+ SetPgVersion(argv[1]);
+ exit(0);
+}
+
+elog() {}
+
+GetDataHome()
+{
+ return(NULL);
+}
diff --git a/src/bin/pgtclsh/Makefile b/src/bin/pgtclsh/Makefile
new file mode 100644
index 00000000000..a99ab39f082
--- /dev/null
+++ b/src/bin/pgtclsh/Makefile
@@ -0,0 +1,46 @@
+#-------------------------------------------------------------------------
+#
+# Makefile
+# Makefile for a tclsh workalike with pgtcl commands installed
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/pgtclsh/Attic/Makefile,v 1.1.1.1 1996/07/09 06:22:15 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+CFLAGS+= -I$(TCL_INCDIR) -I$(TK_INCDIR)
+
+# try to find libpgtcl.a in either directory
+LIBPGTCL= -L$(srcdir)/libpgtcl/$(objdir) -L$(LIBDIR) -lpgtcl
+
+pgtclsh: $(objdir)/pgtclAppInit.o
+ $(CC) $(CDEBUG) -o $(objdir)/$(@F) $(objdir)/pgtclAppInit.o\
+ $(LIBPGTCL) $(LIBPQ) -L$(TCL_LIBDIR) $(TCL_LIB) -lm $(LD_ADD)
+
+pgtksh: $(objdir)/pgtkAppInit.o
+ $(CC) $(CDEBUG) -o $(objdir)/$(@F) $(objdir)/pgtkAppInit.o \
+ $(LIBPGTCL) $(LIBPQ) -L$(TCL_LIBDIR) -L$(TK_LIBDIR) \
+ $(TK_LIB) $(TCL_LIB) -lX11 -lm $(LD_ADD)
+
+install:: localobj pgtclsh pgtksh
+ $(INSTALL) $(INSTL_EXE_OPTS) $(objdir)/pgtclsh $(DESTDIR)$(BINDIR)/pgtclsh
+ $(INSTALL) $(INSTL_EXE_OPTS) $(objdir)/pgtksh $(DESTDIR)$(BINDIR)/pgtksh
+
+CLEANFILES = pgtclAppInit.o pgtkAppInit.o pgtclsh pgtksh
+
+PROG=pgtclsh
+
+all:: pgtclsh pgtksh
+
+# don't use the default template for generating executables since we have
+# two executable targets
+# include $(MKDIR)/postgres.prog.mk
+
+
diff --git a/src/bin/pgtclsh/README b/src/bin/pgtclsh/README
new file mode 100644
index 00000000000..bbd89e012f9
--- /dev/null
+++ b/src/bin/pgtclsh/README
@@ -0,0 +1,21 @@
+pgtclsh is an example of a tclsh extended with the new Tcl
+commands provided by the libpgtcl library. By using pgtclsh, one can
+write front-end applications to Postgres95 in Tcl without having to
+deal with any libpq programming at all.
+
+The pgtclsh is an enhanced version of tclsh. Similarly, pgtksh is a
+wish replacement with postgres95 bindings. The Makefile is also set up
+so that you can choose "pgtksh" as a target.
+
+pgtclsh has been tested with the official releases of
+ Tcl version 7.4
+and Tk version 4.0
+
+and will probably not work with versions older than those (including
+earlier beta releases).
+
+For details of the libpgtcl interface, please see the file
+src/doc/libpgtcl.doc.
+
+If you have any questions or bug reports, please send them to
+Jolly Chen at jolly@cs.berkeley.edu.
diff --git a/src/bin/pgtclsh/pgtclAppInit.c b/src/bin/pgtclsh/pgtclAppInit.c
new file mode 100644
index 00000000000..cc38ca34a70
--- /dev/null
+++ b/src/bin/pgtclsh/pgtclAppInit.c
@@ -0,0 +1,114 @@
+/*
+ * pgtclAppInit.c --
+ *
+ * a skeletal Tcl_AppInit that provides pgtcl initialization
+ * to create a tclsh that can talk to pglite backends
+ *
+ * Copyright (c) 1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#) tclAppInit.c 1.11 94/12/17 16:14:03";
+#endif /* not lint */
+
+#include "tcl.h"
+
+#include "libpgtcl.h"
+
+/*
+ * The following variable is a special hack that is needed in order for
+ * Sun shared libraries to be used for Tcl.
+ */
+
+#ifdef NEED_MATHERR
+extern int matherr();
+int *tclDummyMathPtr = (int *) matherr;
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * main --
+ *
+ * This is the main program for the application.
+ *
+ * Results:
+ * None: Tcl_Main never returns here, so this procedure never
+ * returns either.
+ *
+ * Side effects:
+ * Whatever the application does.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+main(argc, argv)
+ int argc; /* Number of command-line arguments. */
+ char **argv; /* Values of command-line arguments. */
+{
+ Tcl_Main(argc, argv, Tcl_AppInit);
+ return 0; /* Needed only to prevent compiler warning. */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AppInit --
+ *
+ * This procedure performs application-specific initialization.
+ * Most applications, especially those that incorporate additional
+ * packages, will have their own version of this procedure.
+ *
+ * Results:
+ * Returns a standard Tcl completion code, and leaves an error
+ * message in interp->result if an error occurs.
+ *
+ * Side effects:
+ * Depends on the startup script.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_AppInit(interp)
+ Tcl_Interp *interp; /* Interpreter for application. */
+{
+ if (Tcl_Init(interp) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Call the init procedures for included packages. Each call should
+ * look like this:
+ *
+ * if (Mod_Init(interp) == TCL_ERROR) {
+ * return TCL_ERROR;
+ * }
+ *
+ * where "Mod" is the name of the module.
+ */
+
+ if (Pg_Init(interp) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Call Tcl_CreateCommand for application-specific commands, if
+ * they weren't already created by the init procedures called above.
+ */
+
+ /*
+ * Specify a user-specific startup file to invoke if the application
+ * is run interactively. Typically the startup file is "~/.apprc"
+ * where "app" is the name of the application. If this line is deleted
+ * then no user-specific startup file will be run under any conditions.
+ */
+
+ tcl_RcFileName = "~/.tclshrc";
+ return TCL_OK;
+}
diff --git a/src/bin/pgtclsh/pgtclUtils.tcl b/src/bin/pgtclsh/pgtclUtils.tcl
new file mode 100644
index 00000000000..dff87a484f4
--- /dev/null
+++ b/src/bin/pgtclsh/pgtclUtils.tcl
@@ -0,0 +1,16 @@
+# getDBs :
+# get the names of all the databases at a given host and port number
+# with the defaults being the localhost and port 5432
+# return them in alphabetical order
+proc getDBs { {host "localhost"} {port "5432"} } {
+ # datnames is the list to be result
+ set conn [pg_connect template1 -host $host -port $port]
+ set res [pg_exec $conn "SELECT datname FROM pg_database ORDER BY datname"]
+ set ntups [pg_result $res -numTuples]
+ for {set i 0} {$i < $ntups} {incr i} {
+ lappend datnames [pg_result $res -getTuple $i]
+ }
+ pg_disconnect $conn
+ return $datnames
+}
+
diff --git a/src/bin/pgtclsh/pgtkAppInit.c b/src/bin/pgtclsh/pgtkAppInit.c
new file mode 100644
index 00000000000..33763458b51
--- /dev/null
+++ b/src/bin/pgtclsh/pgtkAppInit.c
@@ -0,0 +1,117 @@
+/*
+ * pgtkAppInit.c --
+ *
+ * a skeletal Tcl_AppInit that provides pgtcl initialization
+ * to create a tclsh that can talk to pglite backends
+ *
+ * Copyright (c) 1993 The Regents of the University of California.
+ * Copyright (c) 1994 Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#) tkAppInit.c 1.12 94/12/17 16:30:56";
+#endif /* not lint */
+
+#include "tk.h"
+#include "libpgtcl.h"
+
+/*
+ * The following variable is a special hack that is needed in order for
+ * Sun shared libraries to be used for Tcl.
+ */
+
+#ifdef NEED_MATHERR
+extern int matherr();
+int *tclDummyMathPtr = (int *) matherr;
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * main --
+ *
+ * This is the main program for the application.
+ *
+ * Results:
+ * None: Tk_Main never returns here, so this procedure never
+ * returns either.
+ *
+ * Side effects:
+ * Whatever the application does.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+main(argc, argv)
+ int argc; /* Number of command-line arguments. */
+ char **argv; /* Values of command-line arguments. */
+{
+ Tk_Main(argc, argv, Tcl_AppInit);
+ return 0; /* Needed only to prevent compiler warning. */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tcl_AppInit --
+ *
+ * This procedure performs application-specific initialization.
+ * Most applications, especially those that incorporate additional
+ * packages, will have their own version of this procedure.
+ *
+ * Results:
+ * Returns a standard Tcl completion code, and leaves an error
+ * message in interp->result if an error occurs.
+ *
+ * Side effects:
+ * Depends on the startup script.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+Tcl_AppInit(interp)
+ Tcl_Interp *interp; /* Interpreter for application. */
+{
+ Tk_Window main;
+
+ if (Tcl_Init(interp) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ if (Tk_Init(interp) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+
+ /*
+ * Call the init procedures for included packages. Each call should
+ * look like this:
+ *
+ * if (Mod_Init(interp) == TCL_ERROR) {
+ * return TCL_ERROR;
+ * }
+ *
+ * where "Mod" is the name of the module.
+ */
+
+ if (Pg_Init(interp) == TCL_ERROR) {
+ return TCL_ERROR;
+ }
+ /*
+ * Call Tcl_CreateCommand for application-specific commands, if
+ * they weren't already created by the init procedures called above.
+ */
+
+ /*
+ * Specify a user-specific startup file to invoke if the application
+ * is run interactively. Typically the startup file is "~/.apprc"
+ * where "app" is the name of the application. If this line is deleted
+ * then no user-specific startup file will be run under any conditions.
+ */
+
+ tcl_RcFileName = "~/.wishrc";
+ return TCL_OK;
+}
diff --git a/src/bin/pgtclsh/updateStats.tcl b/src/bin/pgtclsh/updateStats.tcl
new file mode 100644
index 00000000000..62c9564fea1
--- /dev/null
+++ b/src/bin/pgtclsh/updateStats.tcl
@@ -0,0 +1,71 @@
+#
+# updateStats
+# updates the statistic of number of distinct attribute values
+# (this should really be done by the vacuum command)
+# this is kind of brute force and slow, but it works
+# since we use SELECT DISTINCT to calculate the number of distinct values
+# and that does a sort, you need to have plenty of disk space for the
+# intermediate sort files.
+#
+# - jolly 6/8/95
+
+#
+# update_attnvals
+# takes in a table and updates the attnvals columns for the attributes
+# of that table
+#
+# conn is the database connection
+# rel is the table name
+proc update_attnvals {conn rel} {
+
+ # first, get the oid of the rel
+ set res [pg_exec $conn "SELECT oid FROM pg_class where relname = '$rel'"]
+ if { [pg_result $res -numTuples] == "0"} {
+ puts stderr "update_attnvals: Relation named $rel was not found"
+ return
+ }
+ set oid [pg_result $res -getTuple 0]
+ pg_result $res -clear
+
+ # use this query to find the names of the attributes
+ set res [pg_exec $conn "SELECT * FROM $rel WHERE 'f'::bool"]
+ set attrNames [pg_result $res -attributes]
+
+ puts "attrNames = $attrNames"
+ foreach att $attrNames {
+ # find how many distinct values there are for this attribute
+ # this may fail if the user-defined type doesn't have
+ # comparison operators defined
+ set res2 [pg_exec $conn "SELECT DISTINCT $att FROM $rel"]
+ set NVALS($att) [pg_result $res2 -numTuples]
+ puts "NVALS($att) is $NVALS($att)"
+ pg_result $res2 -clear
+ }
+ pg_result $res -clear
+
+ # now, update the pg_attribute table
+ foreach att $attrNames {
+ # first find the oid of the row to change
+ set res [pg_exec $conn "SELECT oid FROM pg_attribute a WHERE a.attname = '$att' and a.attrelid = '$oid'"]
+ set attoid [pg_result $res -getTuple 0]
+ set res2 [pg_exec $conn "UPDATE pg_attribute SET attnvals = $NVALS($att) where pg_attribute.oid = '$attoid'::oid"]
+ }
+}
+
+# updateStats
+# takes in a database name
+# and updates the attnval stat for all the user-defined tables
+# in the database
+proc updateStats { dbName } {
+ # datnames is the list to be result
+ set conn [pg_connect $dbName]
+ set res [pg_exec $conn "SELECT relname FROM pg_class WHERE relkind = 'r' and relname !~ '^pg_' and relname !~ '^Xinv'"]
+ set ntups [pg_result $res -numTuples]
+ for {set i 0} {$i < $ntups} {incr i} {
+ set rel [pg_result $res -getTuple $i]
+ puts "updating attnvals stats on table $rel"
+ update_attnvals $conn $rel
+ }
+ pg_disconnect $conn
+}
+
diff --git a/src/bin/psql/Makefile b/src/bin/psql/Makefile
new file mode 100644
index 00000000000..8e6ab5bb4f1
--- /dev/null
+++ b/src/bin/psql/Makefile
@@ -0,0 +1,65 @@
+#-------------------------------------------------------------------------
+#
+# Makefile.inc--
+# Makefile for bin/psql
+#
+# Copyright (c) 1994, Regents of the University of California
+#
+#
+# IDENTIFICATION
+# $Header: /cvsroot/pgsql/src/bin/psql/Makefile,v 1.1.1.1 1996/07/09 06:22:15 scrappy Exp $
+#
+#-------------------------------------------------------------------------
+
+PROG= psql
+
+MKDIR= ../../mk
+include $(MKDIR)/postgres.mk
+include ../Makefile.global
+
+#
+#USE_READLINE is set in Makefile.global
+#
+
+ifeq ($(USE_READLINE), true)
+ CFLAGS += -I$(READLINE_INCDIR) -I$(HISTORY_INCDIR)
+
+# if you are using an older readline that uses #include "readline.h" instead
+# of #include <readline/readline.h>,
+# uncomment this
+# CFLAGS += -DOLD_READLINE
+
+ LIBCURSES= -lcurses
+ LD_ADD += -L$(READLINE_LIBDIR) -L$(HISTORY_LIBDIR) -lreadline -lhistory $(LIBCURSES)
+# use the following if your readline has no separate history lib
+# LD_ADD += -L$(READLINE_LIBDIR) -lreadline $(LIBCURSES)
+
+ ifeq ($(PORTNAME), ultrix4)
+ LD_ADD += -ltermcap
+ else
+ ifeq ($(PORTNAME), sparc)
+ LD_ADD += -ltermcap
+ else
+ ifeq ($(PORTNAME), linux)
+ LD_ADD += -ltermcap
+ endif
+ ifeq ($(PORTNAME), next)
+ LD_ADD += -ltermcap
+ endif
+ endif
+ endif
+else
+ CFLAGS += -DNOREADLINE
+endif
+
+SRCS= psql.c stringutils.c
+
+ifneq ($(USE_READLINE), true)
+SRCS+= rlstubs.c
+endif
+
+include $(MKDIR)/postgres.prog.mk
+
+
+
+
diff --git a/src/bin/psql/psql.c b/src/bin/psql/psql.c
new file mode 100644
index 00000000000..d5dbfcea6fd
--- /dev/null
+++ b/src/bin/psql/psql.c
@@ -0,0 +1,1230 @@
+/*-------------------------------------------------------------------------
+ *
+ * psql.c--
+ * an interactive front-end to postgres95
+ *
+ * Copyright (c) 1996, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.1.1.1 1996/07/09 06:22:15 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "libpq-fe.h"
+#include "stringutils.h"
+
+#include "psqlHelp.h"
+
+#ifdef NOREADLINE
+extern char *readline(char *); /* in rlstubs.c */
+#else
+/* from the GNU readline library */
+#ifdef OLD_READLINE
+#include "readline.h"
+#include "history.h"
+#else
+#include <readline/readline.h>
+#include <history.h>
+#endif
+#endif
+
+#define MAX_QUERY_BUFFER 20000
+#define MAX_FIELD_SEP_LENGTH 40
+
+#define COPYBUFSIZ 8192
+
+#define DEFAULT_FIELD_SEP " "
+#define DEFAULT_EDITOR "vi"
+#define DEFAULT_SHELL "/bin/sh"
+
+typedef struct _psqlSettings {
+ int echoQuery; /* if 1, echo the query before sending it */
+ int quiet; /* run quietly, no messages, no promt */
+ int singleStep; /* if 1, prompt for each query */
+ int singleLineMode; /* if 1, query terminated by newline */
+ int useReadline; /* use the readline routines or not */
+ int printHeader; /* print output field headers or not */
+ int fillAlign; /* fill align the fields */
+ FILE *queryFout; /* where to send the query results */
+ char fieldSep[MAX_FIELD_SEP_LENGTH]; /* field separator */
+} PsqlSettings;
+
+/* declarations for functions in this file */
+static void usage(char* progname);
+static void slashUsage();
+static void handleCopyOut(PGresult *res, int quiet);
+static void handleCopyIn(PGresult *res, int quiet);
+static int tableList(PGconn* conn, int deep_tablelist);
+static int tableDesc(PGconn* conn, char* table);
+
+char* gets_noreadline(char* prompt, FILE* source);
+char* gets_readline(char* prompt, FILE* source);
+char* gets_fromFile(char* prompt, FILE* source);
+int listAllDbs(PGconn *db, PsqlSettings *settings);
+int SendQuery(PGconn* db, char* query, PsqlSettings *settings);
+int HandleSlashCmds(PGconn** db_ptr,
+ char *line,
+ char** prompt_ptr,
+ char *query,
+ PsqlSettings *settings);
+int MainLoop(PGconn** db_ptr, FILE *source, PsqlSettings *settings);
+FILE* setFout(char *fname);
+
+
+/*
+ * usage
+ * print out usage for command line arguments
+ */
+
+static void
+usage(char* progname)
+{
+ fprintf(stderr,"Usage: %s [options] [dbname]\n",progname);
+ fprintf(stderr,"\t -a authsvc set authentication service\n");
+ fprintf(stderr,"\t -A turn off fill-justification when printing out attributes\n");
+ fprintf(stderr,"\t -c query run single query (slash commands too)\n");
+ fprintf(stderr,"\t -d dbName specify database name\n");
+ fprintf(stderr,"\t -e echo the query sent to the backend\n");
+ fprintf(stderr,"\t -f filename use file as a source of queries\n");
+ fprintf(stderr,"\t -F sep set the field separator (default is " ")\n");
+ fprintf(stderr,"\t -h help information\n");
+ fprintf(stderr,"\t -H host set database server host\n");
+ fprintf(stderr,"\t -l list available databases\n");
+ fprintf(stderr,"\t -n don't use readline library\n");
+ fprintf(stderr,"\t -o filename send output to filename\n");
+ fprintf(stderr,"\t -p port set port number\n");
+ fprintf(stderr,"\t -q run quietly (no messages, no prompts)\n");
+ fprintf(stderr,"\t -s single step mode (prompts for each query)\n");
+ fprintf(stderr,"\t -S single line mode (i.e. query terminated by newline)\n");
+ fprintf(stderr,"\t -T turn off printing of attribute names\n");
+ exit(1);
+}
+
+/*
+ * slashUsage
+ * print out usage for the backslash commands
+ */
+
+static void
+slashUsage()
+{
+ fprintf(stderr,"\t \\a -- toggle fill-justification of display of attributes\n");
+ fprintf(stderr,"\t \\d [<table>] -- list tables in database or columns in <table>\n");
+ fprintf(stderr,"\t \\d * -- list tables in database and columns in all tables\n");
+ fprintf(stderr,"\t \\e [<fname>] -- edit the current query buffer or <fname>\n");
+ fprintf(stderr,"\t \\f <sep> -- change field separator\n");
+ fprintf(stderr,"\t \\g -- query to backend\n");
+ fprintf(stderr,"\t \\h <command> -- help on syntax of sql commands\n");
+ fprintf(stderr,"\t \\h * -- complete description of all sql commands\n");
+ fprintf(stderr,"\t \\g -- send query to backend\n");
+ fprintf(stderr,"\t \\i <fname> -- read queries from filename\n");
+ fprintf(stderr,"\t \\l -- list all databases\n");
+ fprintf(stderr,"\t \\o [<fname>] -- send query results file named <fname> or stdout\n");
+ fprintf(stderr,"\t \\p -- print the current query buffer\n");
+ fprintf(stderr,"\t \\q -- quit\n");
+ fprintf(stderr,"\t \\s [<fname>] -- save or print history\n");
+ fprintf(stderr,"\t \\t -- toggle output field headers (defaults to on)\n");
+ fprintf(stderr,"\t \\! [<cmd>] -- shell escape\n");
+ fprintf(stderr,"\t \\? -- help\n");
+}
+
+/*
+ * listAllDbs
+ *
+ * list all the databases in the system
+ * returns 0 if all went well
+ *
+ *
+ */
+int
+listAllDbs(PGconn *db, PsqlSettings *settings)
+{
+ PGresult *results;
+ char* query = "select * from pg_database;";
+
+ results = PQexec(db, query);
+ if (results == NULL) {
+ fprintf(stderr,"%s", PQerrorMessage(db));
+ return 1;
+ }
+
+ if (PQresultStatus(results) != PGRES_TUPLES_OK)
+ {
+ fprintf(stderr,"Unexpected error from executing: %s\n", query);
+ return 2;
+ }
+ else
+ {
+ PQdisplayTuples(results,
+ settings->queryFout,
+ settings->fillAlign,
+ settings->fieldSep,
+ settings->printHeader,
+ settings->quiet);
+ PQclear(results);
+ return 0;
+ }
+}
+
+/*
+ * tableList (PGconn* conn)
+ *
+ * List The Database Tables
+ * returns 0 if all went well
+ *
+ */
+int
+tableList (PGconn* conn, int deep_tablelist)
+{
+ char listbuf[256];
+ int nColumns;
+ int i;
+ char* ru;
+ char* rk;
+ char* rr;
+
+ PGresult* res;
+
+ listbuf[0] = '\0';
+ strcat(listbuf,"SELECT usename, relname, relkind, relhasrules");
+ strcat(listbuf," FROM pg_class, pg_user ");
+ strcat(listbuf,"WHERE ( relkind = 'r' OR relkind = 'i') ");
+ strcat(listbuf," and relname !~ '^pg_'");
+ strcat(listbuf," and relname !~ '^Inv'");
+/* the usesysid = relowner won't work on stock 1.0 dbs, need to
+ add in the int4oideq function */
+ strcat(listbuf," and usesysid = relowner");
+ strcat(listbuf," ORDER BY relname ");
+ res = PQexec(conn,listbuf);
+ if (res == NULL) {
+ fprintf(stderr,"%s", PQerrorMessage(conn));
+ return (-1);
+ }
+
+ if ((PQresultStatus(res) != PGRES_TUPLES_OK) || (PQntuples(res) <= 0)) {
+ fprintf(stderr,"No tables found in database %s.\n", PQdb(conn));
+ PQclear(res);
+ return (-1);
+ }
+
+ /* first, print out the attribute names */
+ nColumns = PQntuples(res);
+ if (nColumns > 0)
+ {
+ if ( deep_tablelist ) {
+ /* describe everything here */
+ char **table;
+ table = (char**)malloc(nColumns * sizeof(char*));
+ if ( table == NULL )
+ perror("malloc");
+
+ /* load table table*/
+ for (i=0; i < nColumns; i++) {
+ table[i] = (char *) malloc(PQgetlength(res,i,1) * sizeof(char) + 1);
+ if ( table[i] == NULL )
+ perror("malloc");
+ strcpy(table[i],PQgetvalue(res,i,1));
+ }
+
+ PQclear(res);
+ for (i=0; i < nColumns; i++) {
+ tableDesc(conn,table[i]);
+ }
+ free(table);
+ }
+ else {
+ /* Display the information */
+
+ printf ("\nDatabase = %s\n", PQdb(conn));
+ printf (" +------------------+----------------------------------+----------+\n");
+ printf (" | Owner | Relation | Type |\n");
+ printf (" +------------------+----------------------------------+----------+\n");
+
+ /* next, print out the instances */
+ for (i=0; i < PQntuples(res); i++) {
+ printf (" | %-16.16s", PQgetvalue(res,i,0));
+ printf (" | %-32.32s | ", PQgetvalue(res,i,1));
+ rk = PQgetvalue(res,i,2);
+ rr = PQgetvalue(res,i,3);
+ if (strcmp(rk, "r") == 0)
+ printf ("%-8.8s |", (rr[0] == 't') ? "view?" : "table" );
+ else
+ printf ("%-8.8s |", "index");
+ printf("\n");
+ }
+ printf (" +------------------+----------------------------------+----------+\n");
+ PQclear(res);
+ }
+ return (0);
+
+ } else {
+ fprintf (stderr, "Couldn't find any tables!\n");
+ return (-1);
+ }
+}
+
+/*
+ * Describe a table (PGconn* conn, char* table)
+ *
+ * Describe the columns in a database table.
+ * returns 0 if all went well
+ *
+ *
+ */
+int
+tableDesc (PGconn* conn, char* table)
+{
+ char descbuf[256];
+ int nColumns;
+ char *rtype;
+ int i;
+ int rsize;
+
+ PGresult* res;
+
+ /* Build the query */
+
+ descbuf[0] = '\0';
+ strcat(descbuf,"SELECT a.attnum, a.attname, t.typname, a.attlen");
+ strcat(descbuf," FROM pg_class c, pg_attribute a, pg_type t ");
+ strcat(descbuf," WHERE c.relname = '");
+ strcat(descbuf,table);
+ strcat(descbuf,"'");
+ strcat(descbuf," and a.attnum > 0 ");
+ strcat(descbuf," and a.attrelid = c.oid ");
+ strcat(descbuf," and a.atttypid = t.oid ");
+ strcat(descbuf," ORDER BY attnum ");
+ res = PQexec(conn,descbuf);
+ if (res == NULL) {
+ fprintf(stderr,"%s", PQerrorMessage(conn));
+ return (-1);
+ }
+ if ((PQresultStatus(res) != PGRES_TUPLES_OK) || (PQntuples(res) <= 0)) {
+ fprintf(stderr,"Couldn't find table %s!\n", table);
+ PQclear(res);
+ return (-1);
+ }
+ /* first, print out the attribute names */
+ nColumns = PQntuples(res);
+ if (nColumns > 0)
+ {
+ /*
+ ** Display the information
+ */
+
+ printf ("\nTable = %s\n", table);
+ printf ("+----------------------------------+----------------------------------+-------+\n");
+ printf ("| Field | Type | Length|\n");
+ printf ("+----------------------------------+----------------------------------+-------+\n");
+
+ /* next, print out the instances */
+ for (i=0; i < PQntuples(res); i++) {
+ printf ("| %-32.32s | ", PQgetvalue(res,i,1));
+ rtype = PQgetvalue(res,i,2);
+ rsize = atoi(PQgetvalue(res,i,3));
+ if (strcmp(rtype, "text") == 0) {
+ printf ("%-32.32s |", rtype);
+ printf (" %-6s |", "var" );
+ }
+ else if (strcmp(rtype, "bpchar") == 0) {
+ printf ("%-32.32s |", "char");
+ printf (" %-6i |", rsize > 0 ? rsize - 4 : 0 );
+ }
+ else if (strcmp(rtype, "varchar") == 0) {
+ printf ("%-32.32s |", rtype);
+ printf (" %-6i |", rsize > 0 ? rsize - 4 : 0 );
+ }
+ else {
+ /* array types start with an underscore */
+ if (rtype[0] != '_')
+ printf ("%-32.32s |", rtype);
+ else {
+ char *newname;
+ newname = malloc(strlen(rtype) + 2);
+ strcpy(newname, rtype+1);
+ strcat(newname, "[]");
+ printf ("%-32.32s |", newname);
+ free(newname);
+ }
+ if (rsize > 0)
+ printf ("%-6i |", rsize);
+ else
+ printf ("%-6s |", "var");
+ }
+ printf("\n");
+ }
+ printf ("+----------------------------------+----------------------------------+-------+\n");
+
+ PQclear(res);
+ return (0);
+
+ } else {
+ fprintf (stderr, "Couldn't find table %s!\n", table);
+ return (-1);
+ }
+}
+
+typedef char* (*READ_ROUTINE)(char* prompt, FILE* source);
+
+/* gets_noreadline prompt source
+ gets a line of input without calling readline, the source is ignored
+*/
+char*
+gets_noreadline(char* prompt, FILE* source)
+{
+ fputs(prompt, stdout);
+ fflush(stdout);
+ return(gets_fromFile(prompt,stdin));
+}
+
+/*
+ * gets_readline prompt source
+ * the routine to get input from GNU readline(), the source is ignored
+ * the prompt argument is used as the prompting string
+ */
+char*
+gets_readline(char* prompt, FILE* source)
+{
+ return (readline(prompt));
+}
+
+
+/*
+ * gets_fromFile prompt source
+ *
+ * the routine to read from a file, the prompt argument is ignored
+ * the source argument is a FILE*
+ */
+char*
+gets_fromFile(char* prompt, FILE* source)
+{
+ char* line;
+ int len;
+
+ line = malloc(MAX_QUERY_BUFFER+1);
+
+ /* read up to MAX_QUERY_BUFFER characters */
+ if (fgets(line, MAX_QUERY_BUFFER, source) == NULL)
+ return NULL;
+
+ line[MAX_QUERY_BUFFER-1] = '\0';
+ len = strlen(line);
+ if (len == MAX_QUERY_BUFFER)
+ {
+ fprintf(stderr, "line read exceeds maximum length. Truncating at %d\n", MAX_QUERY_BUFFER);
+ }
+
+ return line;
+}
+
+/*
+ * SendQuery:
+ SendQuery: send the query string to the backend
+ *
+ * return 0 if the query executed successfully
+ * returns 1 otherwise
+ */
+int
+SendQuery(PGconn* db, char* query, PsqlSettings *settings)
+{
+ PGresult* results;
+ PGnotify* notify;
+ int status = 0;
+
+ if (settings->singleStep)
+ fprintf(stdout, "\n*******************************************************************************\n");
+
+ if (settings->echoQuery || settings->singleStep) {
+ fprintf(stderr,"QUERY: %s\n",query);
+ fflush(stderr);
+ }
+
+ if (settings->singleStep) {
+ fprintf(stdout, "\n*******************************************************************************\n");
+ fflush(stdout);
+ printf("\npress return to continue ..\n");
+ gets_fromFile("",stdin);
+ }
+
+ results = PQexec(db, query);
+ if (results == NULL) {
+ fprintf(stderr,"%s",PQerrorMessage(db));
+ return 1;
+ }
+
+ switch (PQresultStatus(results)) {
+ case PGRES_TUPLES_OK:
+ PQdisplayTuples(results,
+ settings->queryFout,
+ settings->fillAlign,
+ settings->fieldSep,
+ settings->printHeader,
+ settings->quiet);
+ PQclear(results);
+ break;
+ case PGRES_EMPTY_QUERY:
+ /* do nothing */
+ break;
+ case PGRES_COMMAND_OK:
+ if (!settings->quiet)
+ fprintf(stdout,"%s\n",PQcmdStatus(results));
+ break;
+ case PGRES_COPY_OUT:
+ handleCopyOut(results, settings->quiet);
+ break;
+ case PGRES_COPY_IN:
+ handleCopyIn(results, settings->quiet);
+ break;
+ case PGRES_NONFATAL_ERROR:
+ case PGRES_FATAL_ERROR:
+ case PGRES_BAD_RESPONSE:
+ status = 1;
+ fprintf(stderr,"%s",PQerrorMessage(db));
+ break;
+
+ }
+
+ /* check for asynchronous returns */
+ notify = PQnotifies(db);
+ if (notify) {
+ fprintf(stderr,"ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
+ notify->relname, notify->be_pid);
+ free(notify);
+ }
+
+ return status;
+
+}
+
+/*
+ HandleSlashCmds:
+
+ Handles all the different commands that start with \
+ db_ptr is a pointer to the TgDb* structure
+ line is the current input line
+ prompt_ptr is a pointer to the prompt string,
+ a pointer is used because the prompt can be used with
+ a connection to a new database
+ returns a status:
+ 0 - send currently constructed query to backend (i.e. we got a \g)
+ 1 - skip processing of this line, continue building up query
+ 2 - terminate processing of this query entirely
+*/
+int
+HandleSlashCmds(PGconn** db_ptr,
+ char* line,
+ char** prompt_ptr,
+ char *query,
+ PsqlSettings *settings)
+{
+ int status = 0;
+ PGconn* db = *db_ptr;
+ char* dbname = PQdb(db);
+ char *optarg = NULL;
+ int len;
+
+ len = strlen(line);
+ if (len > 2)
+ optarg = leftTrim(line+2);
+ switch (line[1])
+ {
+ case 'a': /* toggles to fill fields on output */
+ if (settings->fillAlign)
+ settings->fillAlign = 0;
+ else
+ settings->fillAlign = 1;
+ if (!settings->quiet)
+ fprintf(stderr,"turning %s fill-justification\n",
+ (settings->fillAlign) ? "on" : "off" );
+ break;
+ case 'c': /* \c means connect to new database */
+ {
+ if (!optarg) {
+ fprintf(stderr,"\\c must be followed by a database name\n");
+ status = 1;
+ break;
+ }
+ if (strcmp(optarg, dbname) == 0) {
+ fprintf(stderr,"already connected to %s\n", dbname);
+ status = 1;
+ break;
+ }
+ else {
+ PGconn *olddb;
+
+ printf("closing connection to database:%s\n", dbname);
+ olddb = db;
+ db = PQsetdb(PQhost(olddb), PQport(olddb), NULL, NULL, optarg);
+ *db_ptr = db;
+ printf("connecting to new database: %s\n", optarg);
+ if (PQstatus(db) == CONNECTION_BAD) {
+ fprintf(stderr,"%s\n", PQerrorMessage(db));
+ printf("reconnecting to %s\n", dbname);
+ db = PQsetdb(PQhost(olddb), PQport(olddb),
+ NULL, NULL, dbname);
+ *db_ptr = db;
+ if (PQstatus(db) == CONNECTION_BAD) {
+ fprintf(stderr,
+ "could not reconnect to %s. exiting\n", dbname);
+ exit(2);
+ }
+ status = 1;
+ break;
+ }
+ PQfinish(olddb);
+ free(*prompt_ptr);
+ *prompt_ptr = malloc(strlen(optarg) + 10);
+ sprintf(*prompt_ptr,"%s=> ", optarg);
+ status = 1;
+ break;
+ }
+ }
+ break;
+ case 'd': /* \d describe tables or columns in a table */
+ {
+ if (!optarg) {
+ tableList(db,0);
+ status = 1;
+ break;
+ }
+ if ( strcmp(optarg,"*") == 0 ) {
+ tableList(db, 0);
+ tableList(db, 1);
+ }
+ else {
+ tableDesc(db,optarg);
+ }
+ status = 1;
+ break;
+ }
+ case 'e':
+ {
+ char s[256];
+ int fd;
+ int ql = strlen(query);
+ int f_arg = 0;
+ int cc;
+ if (optarg)
+ {
+ f_arg = 1;
+ strcpy(s, optarg);
+ }
+ else
+ {
+ sprintf(s, "/tmp/psql.%d.%d", getuid(), getpid());
+ unlink(s);
+ if (ql)
+ {
+ if ((fd=open(s, O_EXCL|O_CREAT|O_WRONLY, 0600))==-1)
+ {
+ perror(s);
+ break;
+ }
+ if (query[ql-1]!='\n')
+ strcat(query, "\n");
+ if (write(fd, query, ql)!=ql)
+ {
+ perror(s);
+ close(fd);
+ unlink(s);
+ break;
+ }
+ close(fd);
+ }
+ }
+ {
+ char sys[256];
+ char *editorName;
+ editorName = getenv("EDITOR");
+ if (editorName == NULL)
+ editorName = DEFAULT_EDITOR;
+ sprintf(sys, "exec %s %s", editorName, s);
+ system(sys);
+ }
+ if ((fd=open(s, O_RDONLY))==-1)
+ {
+ if (!f_arg)
+ unlink(s);
+ break;
+ }
+ if ((cc=read(fd, query, MAX_QUERY_BUFFER))==-1)
+ {
+ perror(s);
+ close(fd);
+ if (!f_arg)
+ unlink(s);
+ break;
+ }
+ query[cc]='\0';
+ close(fd);
+ if (!f_arg)
+ unlink(s);
+ rightTrim(query);
+ if (query[strlen(query)-1]==';')
+ return 0;
+ break;
+ }
+ case 'f':
+ if (optarg)
+ strcpy(settings->fieldSep,optarg);
+ else
+ strcpy(settings->fieldSep,DEFAULT_FIELD_SEP);
+ break;
+ case 'g': /* \g means send query */
+ status = 0;
+ break;
+ case 'i': /* \i is include file */
+ {
+ FILE* fd;
+
+ if (!optarg) {
+ fprintf(stderr,"\\i must be followed by a file name\n");
+ status = 1;
+ break;
+ }
+
+ if ( (fd = fopen(optarg, "r")) == NULL)
+ {
+ fprintf(stderr,"file named %s could not be opened\n",optarg);
+ status = 1;
+ break;
+ }
+ MainLoop(&db, fd, settings);
+ fclose(fd);
+ status = 1;
+ break;
+ }
+ case 'h':
+ {
+ char* cmd;
+ int i, numCmds;
+ int all_help = 0;
+
+ if (!optarg) {
+ printf("type \\h <cmd> where <cmd> is one of the following:\n");
+ i = 0;
+ while (QL_HELP[i].cmd != NULL)
+ {
+ printf("\t%s\n", QL_HELP[i].cmd);
+ i++;
+ }
+ printf("type \\h * for a complete description of all commands\n");
+ }
+ else
+ {
+ cmd = optarg;
+
+ numCmds = 0;
+ while (QL_HELP[numCmds++].cmd != NULL);
+
+ numCmds = numCmds - 1;
+
+ if ( strcmp(cmd,"*") == 0 ) {
+ all_help=1;
+ }
+
+ for (i=0; i<numCmds;i++) {
+ if (strcmp(QL_HELP[i].cmd, cmd) == 0 || all_help) {
+ printf("Command: %s\n",QL_HELP[i].cmd);
+ printf("Description: %s\n", QL_HELP[i].help);
+ printf("Syntax:\n");
+ printf("%s\n", QL_HELP[i].syntax);
+ if ( all_help ) {
+ printf("\n");
+ }
+ else {
+ break;
+ }
+ }
+ }
+ if (i == numCmds && ! all_help)
+ printf("command not found, try \\h with no arguments to see available help\n");
+ }
+ status = 1;
+ break;
+ }
+ case 'l': /* \l is list database */
+ listAllDbs(db,settings);
+ status = 1;
+ break;
+ case 'o':
+ settings->queryFout = setFout(optarg);
+ break;
+ case 'p':
+ if (query) {
+ fputs(query, stdout);
+ fputc('\n', stdout);
+ }
+ break;
+ case 'q': /* \q is quit */
+ status = 2;
+ break;
+ case 's': /* \s is save history to a file */
+ {
+ char* fname;
+
+ if (!optarg) {
+ fprintf(stderr,"\\s must be followed by a file name\n");
+ status = 1;
+ break;
+ }
+
+ fname = optarg;
+ if (write_history(fname) != 0)
+ {
+ fprintf(stderr,"cannot write history to %s\n",fname);
+ }
+ status = 1;
+ break;
+ }
+ case 't':
+ if ( settings->printHeader )
+ settings->printHeader = 0;
+ else
+ settings->printHeader = 1;
+ if (!settings->quiet)
+ fprintf(stderr,"turning %s printing of field headers\n",
+ (settings->printHeader) ? "on" : "off" );
+ break;
+ case '!':
+ if (!optarg) {
+ char sys[256];
+ char *shellName;
+ shellName = getenv("SHELL");
+ if (shellName == NULL)
+ shellName = DEFAULT_SHELL;
+ sprintf(sys,"exec %s", shellName);
+ system(sys);
+ }
+ else
+ system(optarg);
+ break;
+ default:
+ case '?': /* \? is help */
+ slashUsage();
+ status = 1;
+ break;
+ }
+ return status;
+}
+
+/*
+ MainLoop: main processing loop for reading lines of input
+ and sending them to the backend
+
+ this loop is re-entrant. May be called by \i command
+ which reads input from a file
+
+ *db_ptr must be initialized and set
+*/
+int
+MainLoop(PGconn** db_ptr,
+ FILE* source,
+ PsqlSettings *settings)
+{
+ char* prompt; /* readline prompt */
+ char* line; /* line of input*/
+ int len; /* length of the line */
+ char query[MAX_QUERY_BUFFER]; /* multi-line query storage */
+ PGconn* db = *db_ptr;
+ char* dbname = PQdb(db);
+ int exitStatus = 0;
+
+ int slashCmdStatus = 0;
+ /* slashCmdStatus can be:
+ 0 - send currently constructed query to backend (i.e. we got a \g)
+ 1 - skip processing of this line, continue building up query
+ 2 - terminate processing of this query entirely
+ */
+
+ int send_query = 0;
+ int interactive;
+ READ_ROUTINE GetNextLine;
+
+ interactive = (source == stdin);
+
+ if (interactive) {
+ prompt = malloc(strlen(dbname) + 10);
+ if (settings->quiet)
+ prompt[0] = '\0';
+ else
+ sprintf(prompt,"%s=> ", dbname);
+ if (settings->useReadline) {
+ using_history();
+ GetNextLine = gets_readline;
+ } else
+ GetNextLine = gets_noreadline;
+
+ }
+ else
+ GetNextLine = gets_fromFile;
+
+ query[0] = '\0';
+
+ /* main loop for getting queries and executing them */
+ while ((line = GetNextLine(prompt, source)) != NULL)
+ {
+ exitStatus = 0;
+ line = rightTrim(line); /* remove whitespaces on the right, incl. \n's */
+
+ if (line[0] == '\0') {
+ free(line);
+ continue;
+ }
+
+ /* filter out comment lines that begin with --,
+ this could be incorrect if -- is part of a quoted string.
+ But we won't go through the trouble of detecting that. If you have
+ -- in your quoted string, be careful and don't start a line with it*/
+ if (line[0] == '-' && line[1] == '-') {
+ if (settings->singleStep) /* in single step mode, show comments */
+ fprintf(stdout,"%s\n",line);
+ free(line);
+ continue;
+ }
+
+ len = strlen(line);
+
+ if (interactive && settings->useReadline)
+ add_history(line); /* save non-empty lines in history */
+
+ /* do the query immediately if we are doing single line queries
+ or if the last character is a semicolon */
+ send_query = settings->singleLineMode || (line[len-1] == ';') ;
+
+ /* normally, \ commands have to be start the line,
+ but for backwards compatibility with monitor,
+ check for \g at the end of line */
+ if (len > 2 && !send_query)
+ {
+ if (line[len-1]=='g' && line[len-2]=='\\')
+ {
+ send_query = 1;
+ line[len-2]='\0';
+ }
+ }
+
+ /* slash commands have to be on their own line */
+ if (line[0] == '\\') {
+ slashCmdStatus = HandleSlashCmds(db_ptr,
+ line,
+ &prompt,
+ query,
+ settings);
+ db = *db_ptr; /* in case \c changed the database */
+ if (slashCmdStatus == 1)
+ continue;
+ if (slashCmdStatus == 2)
+ break;
+ if (slashCmdStatus == 0)
+ send_query = 1;
+ }
+ else
+ if (strlen(query) + len > MAX_QUERY_BUFFER)
+ {
+ fprintf(stderr,"query buffer max length of %d exceeded\n",MAX_QUERY_BUFFER);
+ fprintf(stderr,"query line ignored\n");
+ }
+ else
+ if (query[0]!='\0') {
+ strcat(query,"\n");
+ strcat(query,line);
+ }
+ else
+ strcpy(query,line);
+
+ if (send_query && query[0] != '\0')
+ {
+ /* echo the line read from the file,
+ unless we are in single_step mode, because single_step mode
+ will echo anyway */
+ if (!interactive && !settings->singleStep)
+ fprintf(stderr,"%s\n",query);
+
+ exitStatus = SendQuery(db, query, settings);
+ query[0] = '\0';
+ }
+
+ free(line); /* free storage malloc'd by GetNextLine */
+ } /* while */
+ return exitStatus;
+}
+
+int
+main(int argc, char** argv)
+{
+ extern char* optarg;
+ extern int optind, opterr;
+
+ PGconn *db;
+ char* dbname = NULL;
+ char* host = NULL;
+ char* port = NULL;
+ char* qfilename = NULL;
+ char errbuf[ERROR_MSG_LENGTH];
+
+ PsqlSettings settings;
+
+ char* singleQuery = NULL;
+
+ int listDatabases = 0 ;
+ int exitStatus = 0;
+ int singleSlashCmd = 0;
+ int c;
+
+
+#ifdef NOREADLINE
+ settings.useReadline = 0;
+#else
+ settings.useReadline = 1;
+#endif
+
+ settings.quiet = 0;
+ settings.fillAlign = 1;
+ settings.printHeader = 1;
+ settings.echoQuery = 0;
+ settings.singleStep = 0;
+ settings.singleLineMode = 0;
+ settings.queryFout = stdout;
+ strcpy(settings.fieldSep, DEFAULT_FIELD_SEP);
+
+ while ((c = getopt(argc, argv, "Aa:c:d:ef:F:lhH:nso:p:qST")) != EOF) {
+ switch (c) {
+ case 'A':
+ settings.fillAlign = 0;
+ break;
+ case 'a':
+ fe_setauthsvc(optarg, errbuf);
+ break;
+ case 'c':
+ singleQuery = optarg;
+ if ( singleQuery[0] == '\\' ) {
+ singleSlashCmd=1;
+ }
+ break;
+ case 'd':
+ dbname = optarg;
+ break;
+ case 'e':
+ settings.echoQuery = 1;
+ break;
+ case 'f':
+ qfilename = optarg;
+ break;
+ case 'F':
+ strncpy(settings.fieldSep,optarg,MAX_FIELD_SEP_LENGTH);
+ break;
+ case 'l':
+ listDatabases = 1;
+ break;
+ case 'H':
+ host = optarg;
+ break;
+ case 'n':
+ settings.useReadline = 0;
+ break;
+ case 'o':
+ settings.queryFout = setFout(optarg);
+ break;
+ case 'p':
+ port = optarg;
+ break;
+ case 'q':
+ settings.quiet = 1;
+ break;
+ case 's':
+ settings.singleStep = 1;
+ break;
+ case 'S':
+ settings.singleLineMode = 1;
+ break;
+ case 'T':
+ settings.printHeader = 0;
+ break;
+ case 'h':
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+ /* if we still have an argument, use it as the database name */
+ if (argc - optind == 1)
+ dbname = argv[optind];
+
+ if (listDatabases)
+ dbname = "template1";
+
+ db = PQsetdb(host, port, NULL, NULL, dbname);
+ dbname = PQdb(db);
+
+ if (PQstatus(db) == CONNECTION_BAD) {
+ fprintf(stderr,"Connection to database '%s' failed.\n", dbname);
+ fprintf(stderr,"%s",PQerrorMessage(db));
+ exit(1);
+ }
+ if (listDatabases) {
+ exit(listAllDbs(db,&settings));
+ }
+
+ if (!settings.quiet && !singleQuery && !qfilename) {
+ printf("Welcome to the POSTGRES95 interactive sql monitor:\n");
+ printf(" Please read the file COPYRIGHT for copyright terms of POSTGRES95\n\n");
+ printf(" type \\? for help on slash commands\n");
+ printf(" type \\q to quit\n");
+ printf(" type \\g or terminate with semicolon to execute query\n");
+ printf(" You are currently connected to the database: %s\n\n", dbname);
+ }
+
+ if (qfilename || singleSlashCmd) {
+ /* read in a file full of queries instead of reading in queries
+ interactively */
+ char *line;
+ char prompt[100];
+
+ if ( singleSlashCmd ) {
+ /* Not really a query, but "Do what I mean, not what I say." */
+ line = singleQuery;
+ }
+ else {
+ line = malloc(strlen(qfilename) + 5);
+ sprintf(line,"\\i %s", qfilename);
+ }
+ HandleSlashCmds(&db, line, (char**)prompt, "", &settings);
+
+ } else {
+ if (singleQuery) {
+ exitStatus = SendQuery(db, singleQuery, &settings);
+ }
+ else
+ exitStatus = MainLoop(&db, stdin, &settings);
+ }
+
+ PQfinish(db);
+
+ return exitStatus;
+}
+
+
+static void
+handleCopyOut(PGresult *res, int quiet)
+{
+ bool copydone = false;
+ char copybuf[COPYBUFSIZ];
+ int ret;
+
+ if (!quiet)
+ fprintf(stdout, "Copy command returns...\n");
+
+ while (!copydone) {
+ ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
+
+ if (copybuf[0] == '.' && copybuf[1] =='\0') {
+ copydone = true; /* don't print this... */
+ } else {
+ fputs(copybuf, stdout);
+ switch (ret) {
+ case EOF:
+ copydone = true;
+ /*FALLTHROUGH*/
+ case 0:
+ fputc('\n', stdout);
+ break;
+ case 1:
+ break;
+ }
+ }
+ }
+ fflush(stdout);
+ PQendcopy(res->conn);
+}
+
+
+static void
+handleCopyIn(PGresult *res, int quiet)
+{
+ bool copydone = false;
+ bool firstload;
+ bool linedone;
+ char copybuf[COPYBUFSIZ];
+ char *s;
+ int buflen;
+ int c;
+
+ if (!quiet) {
+ fputs("Enter info followed by a newline\n", stdout);
+ fputs("End with a dot on a line by itself.\n", stdout);
+ }
+
+ /*
+ * eat extra newline still in input buffer
+ *
+ */
+ fflush(stdin);
+ if ((c = getc(stdin)) != '\n' && c != EOF) {
+ (void) ungetc(c, stdin);
+ }
+
+ while (!copydone) { /* for each input line ... */
+ if (!quiet) {
+ fputs(">> ", stdout);
+ fflush(stdout);
+ }
+ firstload = true;
+ linedone = false;
+ while (!linedone) { /* for each buffer ... */
+ s = copybuf;
+ buflen = COPYBUFSIZ;
+ for (; buflen > 1 &&
+ !(linedone = (c = getc(stdin)) == '\n' || c == EOF);
+ --buflen) {
+ *s++ = c;
+ }
+ if (c == EOF) {
+ /* reading from stdin, but from a file */
+ PQputline(res->conn, ".");
+ copydone = true;
+ break;
+ }
+ *s = '\0';
+ PQputline(res->conn, copybuf);
+ if (firstload) {
+ if (!strcmp(copybuf, ".")) {
+ copydone = true;
+ }
+ firstload = false;
+ }
+ }
+ PQputline(res->conn, "\n");
+ }
+ PQendcopy(res->conn);
+}
+
+
+/* try to open fname and return a FILE*,
+ if it fails, use stdout, instead */
+FILE*
+setFout(char *fname)
+{
+ FILE *queryFout;
+
+ if (!fname)
+ queryFout = stdout;
+ else {
+ queryFout = fopen(fname, "w");
+ if (!queryFout) {
+ perror(fname);
+ queryFout = stdout;
+ }
+ }
+
+ return queryFout;
+}
+
diff --git a/src/bin/psql/psqlHelp.h b/src/bin/psql/psqlHelp.h
new file mode 100644
index 00000000000..e0d5077bc3b
--- /dev/null
+++ b/src/bin/psql/psqlHelp.h
@@ -0,0 +1,168 @@
+/*-------------------------------------------------------------------------
+ *
+ * psqlHelp.h--
+ * Help for query language syntax
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: psqlHelp.h,v 1.1.1.1 1996/07/09 06:22:15 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+struct _helpStruct {
+ char* cmd; /* the command name */
+ char* help; /* the help associated with it */
+ char* syntax; /* the syntax associated with it */
+} ;
+
+static struct _helpStruct QL_HELP[] = {
+ { "abort",
+ "abort the current transaction",
+ "abort [transaction];"},
+ { "abort transaction",
+ "abort the current transaction",
+ "abort [transaction];"},
+ { "alter table",
+ "add/rename attributes, rename tables",
+ "alter table <relname> [*] add column <attr> <type>;\n\talter table <relname> [*] rename [column] <attr1> to <attr2>;\n\talter table <relname1> rename to <relname2>"},
+ { "begin",
+ "begin a new transaction",
+ "begin [transaction|work];"},
+ { "begin transaction",
+ "begin a new transaction",
+ "begin [transaction|work];"},
+ { "begin work",
+ "begin a new transaction",
+ "begin [transaction|work];"},
+ { "cluster",
+ "create a clustered index (from an existing index)",
+ "cluster <index_name> on <relation_name>"},
+ { "close",
+ "close an existing cursor (portal)",
+ "close <portalname>;"},
+ { "commit",
+ "commit a transaction",
+ "commit [work]"},
+ { "commit work",
+ "commit a transaction",
+ "commit [work]"},
+ { "copy",
+ "copy data to and from a table",
+ "copy [binary] [nonulls] <relname>\n\t{to|from} {<filename>|stdin|stdout} [using delimiters <delim>];"},
+ { "create",
+ "Please more be specific:",
+ "\tcreate aggregate\n\tcreate database\n\tcreate function\n\tcreate index\n\tcreate operator\n\tcreate rule\n\tcreate table\n\tcreate type\n\tcreate view"},
+ { "create aggregate",
+ "define an aggregate function",
+ "create aggregate <agg_name> [as] (basetype = <data_type>, \n\t[sfunc1 = <sfunc_1>, stype1 = <sfunc1_return_type>]\n\t[sfunc2 = <sfunc_2>, stype2 = <sfunc2_return_type>]\n\t[,finalfunc = <final-function>]\n\t[,initcond1 = <initial-cond1>][,initcond2 = <initial-cond2>]);"},
+ { "create database",
+ "create a database",
+ "create database <dbname>"},
+ { "create function",
+ "create a user-defined function",
+ "create function <function_name> ([<type1>,...<typeN>]) returns <return_type>\n\tas '<object_filename>'|'<sql-queries>'\n\tlanguage 'c'|'sql'|'internal';"},
+ { "create index",
+ "construct an index",
+ "create index <indexname> on <relname> using <access_method> (<attr1>|<funcname>(<attr1>,...) <type_class1>);"},
+ { "create operator",
+ "create a user-defined operator",
+ "create operator <operator_name> (\n\t[leftarg = <type1>][,rightarg = <type2>]\n\t,procedure = <func_name>,\n\t[,commutator = <com_op>][,negator = <neg_op>]\n\t[,restrict = <res_proc>][,hashes]\n\t[,join = <join_proc>][,sort = <sort_op1>...<sort_opN>]);"},
+ { "create rule",
+ "define a new rule",
+ "create rule <rule_name> as on\n\t[select|update|delete|insert]\n\tto <object> [where <qual>]\n\tdo [instead] [<action>|nothing| [<actions>]];"},
+ { "create table",
+ "create a new table",
+ "create table <relname> ( <attr1> <type1>,... <attrN> <typeN>)\n\t[inherits (<relname1>,...<relnameN>\n\tarchive=<archive_mode>\n\tstore=<smgr_name>\n\tarch_store=<smgr_name>];"},
+ { "create type",
+ "create a new user-defined base data type",
+ "create type <typename> (\n\tinternallength = (<number> | variable),\n\t[externallength = (<number>|variable),]\n\tinput=<input_function>, output = <output_function>\n\t[,element = <typename>][,delimiter=<character>][,default=\'<string>\']\n\t[,send = <send_function>][,receive = <receive_function>][,passedbyvalue]);"},
+ { "create view",
+ "create a view",
+ "create view <view_name> as select <expr1>[as <attr1>][,... <exprN>[as <attrN>]] [from <from_list>] [where <qual>];"},
+ { "declare",
+ "set up a cursor (portal)",
+ "declare <portalname> [binary] cursor for\n\tselect [distinct]\n\t<expr1> [as <attr1>],...<exprN> [as <attrN>]\n\t[from <from_list>] [where <qual>]\n\t[order by <attr1> [using <op1>],... <attrN> [using <opN>]];"},
+ { "delete",
+ "delete tuples",
+ "delete from <relname> [where <qual>];"},
+ { "drop",
+ "Please more be specific:",
+ "\tdrop aggregate\n\tdrop database\n\tdrop function\n\tdrop index\n\tdrop operator\n\tdrop rule\n\tdrop table\n\tdrop type\n\tdrop view"},
+ { "drop aggregate",
+ "remove an aggregate function",
+ "drop aggregate <agg_name>;"},
+ { "drop database",
+ "remove a database",
+ "drop database <dbname>"},
+ { "drop function",
+ "remove a user-defined function",
+ "drop function <funcname> ([<type1>,....<typeN>]);"},
+ { "drop index",
+ "remove an existing index",
+ "drop index <indexname>;"},
+ { "drop operator",
+ "remove a user-defined operator",
+ "drop operator <operator_name> ([<ltype>|none],[<rtype>|none]);"},
+ { "drop rule",
+ "remove a rule",
+ "drop rule <rulename>;"},
+ { "drop table",
+ "remove a table",
+ "drop table <relname>[,...<relnameN];"},
+ { "drop type",
+ "remove a user-defined base type",
+ "drop type <typename>;"},
+ { "drop view",
+ "remove a view",
+ "drop view <view_name>"},
+ { "end",
+ "end the current transaction",
+ "end [transaction];"},
+ { "end transaction",
+ "end the current transaction",
+ "end [transaction];"},
+ { "explain",
+ "explain the query execution plan",
+ "explain [with {cost|full_plan}] <query>"},
+ { "extend index",
+ "extend a partial index",
+ "extend index <indexname> [where <qual>];"},
+ { "fetch",
+ "retrieve tuples from a cursor (portal)",
+ "fetch [forward|backward] [<number>|all] [in <portalname>];"},
+ { "grant",
+ "grant access control to a user or group",
+ "grant <privilege[,privilege,...]> on <rel1>[,...<reln>] to \n[public | group <group> | <username>]\n\t privilege is {ALL | SELECT | INSERT | UPDATE | DELETE | RULE}"},
+ { "insert",
+ "insert tuples",
+ "insert into <relname> [(<attr1>...<attrN>)]\n\t[values (<expr1>...<exprN>); |\n\tselect <expr1>,...<exprN> [from <from_clause>] [where <qual>];"},
+ { "listen",
+ "listen for notification on a relation",
+ "listen <relname>"},
+ { "load",
+ "dynamically load a module",
+ "load <filename>;"},
+ { "notify",
+ "signal all frontends and backends listening on a relation",
+ "notify <relname>"},
+ { "purge",
+ "purge historical data",
+ "purge <relname> [before <abstime>] [after <reltime>];"},
+ { "revoke",
+ "revoke access control from a user or group",
+ "revoke <privilege[,privilege,...]> on <rel1>[,...<reln>] from \n[public | group <group> | <username>]\n\t privilege is {ALL | SELECT | INSERT | UPDATE | DELETE | RULE}"},
+ { "rollback",
+ "abort a transaction",
+ "rollback [work]"},
+ { "select",
+ "retrieve tuples",
+ "select [distinct on <attr>] <expr1> [as <attr1>], ... <exprN> [as <attrN>]\n\t[into table <relname>] [from <from_list>]\n\t[where <qual>]\n\t[order by <attr1>\n\t\t[using <op1>],..<attrN> [[using <opN>] | ASC | DESC]];" },
+ { "update",
+ "update tuples",
+ "update <relname> set <attr1>=<expr1>,...<attrN>=<exprN> [from <from_clause>] [where <qual>];"},
+ { "vacuum",
+ "vacuum the database, i.e. cleans out deleted records, updates statistics",
+ "vacuum;"},
+ { NULL, NULL, NULL} /* important to keep a NULL terminator here! */
+};
diff --git a/src/bin/psql/rlstubs.c b/src/bin/psql/rlstubs.c
new file mode 100644
index 00000000000..2640d3ce094
--- /dev/null
+++ b/src/bin/psql/rlstubs.c
@@ -0,0 +1,41 @@
+/*-------------------------------------------------------------------------
+ *
+ * rlstubs.c--
+ * stub routines when compiled without readline and history libraries
+ *
+ * Copyright (c) 1994-5, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/bin/psql/Attic/rlstubs.c,v 1.1.1.1 1996/07/09 06:22:15 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdio.h>
+
+char *
+readline(char *prompt)
+{
+ static char buf[500];
+
+ printf("%s");
+ return fgets(buf, 500, stdin);
+}
+
+int
+write_history()
+{
+ return 0;
+}
+
+int
+using_history()
+{
+ return 0;
+}
+
+int
+add_history()
+{
+ return 0;
+}
diff --git a/src/bin/psql/stringutils.c b/src/bin/psql/stringutils.c
new file mode 100644
index 00000000000..0a9043c6337
--- /dev/null
+++ b/src/bin/psql/stringutils.c
@@ -0,0 +1,104 @@
+/*-------------------------------------------------------------------------
+ *
+ * stringutils.c--
+ * simple string manipulation routines
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/bin/psql/stringutils.c,v 1.1.1.1 1996/07/09 06:22:15 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "stringutils.h"
+
+/* all routines assume null-terminated strings! */
+
+/* removes whitespaces from the left, right and both sides of a string */
+/* MODIFIES the string passed in and returns the head of it */
+char* leftTrim(char* s)
+{
+ char* s2 = s;
+ int shift=0;
+ int j=0;
+
+ while (isspace(*s))
+ { s++; shift++;}
+ if (shift > 0)
+ {
+ while ( (s2[j] = s2[j+shift]) !='\0')
+ j++;
+ }
+
+ return s2;
+}
+
+char* rightTrim(char* s)
+{
+ char* sEnd;
+ sEnd = s+strlen(s)-1;
+ while (isspace(*sEnd))
+ sEnd--;
+ if (sEnd < s)
+ s[0]='\0';
+ else
+ s[sEnd-s+1]='\0';
+ return s;
+}
+
+char* doubleTrim(char* s)
+{
+ strcpy(s,leftTrim(rightTrim(s)));
+ return s;
+}
+
+/* dupstr : copies a string, while allocating space for it.
+ the CALLER is responsible for freeing the space
+ returns NULL if the argument is NULL*/
+char* dupstr(char *s)
+{
+ char* result;
+
+ if (s == NULL)
+ return NULL;
+
+ result = (char*)malloc(strlen(s)+1);
+ strcpy(result, s);
+ return result;
+}
+
+
+#ifdef STRINGUTILS_TEST
+void testStringUtils()
+{
+ static char* tests[] = {" goodbye \n", /* space on both ends */
+ "hello world", /* no spaces to trim */
+ "", /* empty string */
+ "a", /* string with one char*/
+ " ", /* string with one whitespace*/
+ NULL_STR};
+
+ int i=0;
+ while (tests[i]!=NULL_STR)
+ {
+ char* t;
+ t = dupstr(tests[i]);
+ printf("leftTrim(%s) = ",t);
+ printf("%sEND\n", leftTrim(t));
+ t = dupstr(tests[i]);
+ printf("rightTrim(%s) = ",t);
+ printf("%sEND\n", rightTrim(t));
+ t = dupstr(tests[i]);
+ printf("doubleTrim(%s) = ",t);
+ printf("%sEND\n", doubleTrim(t));
+ i++;
+ }
+
+}
+
+#endif
diff --git a/src/bin/psql/stringutils.h b/src/bin/psql/stringutils.h
new file mode 100644
index 00000000000..d8564a02d08
--- /dev/null
+++ b/src/bin/psql/stringutils.h
@@ -0,0 +1,51 @@
+/*-------------------------------------------------------------------------
+ *
+ * stringutils.h--
+ *
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ * $Id: stringutils.h,v 1.1.1.1 1996/07/09 06:22:16 scrappy Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef STRINGUTILS_H
+#define STRINGUTILS_H
+
+/* use this for memory checking of alloc and free using Tcl's memory check
+ package*/
+#ifdef TCL_MEM_DEBUG
+#include <tcl.h>
+#define malloc(x) ckalloc(x)
+#define free(x) ckfree(x)
+#define realloc(x,y) ckrealloc(x,y)
+#endif
+
+/* string fiddling utilties */
+
+/* all routines assume null-terminated strings! as arguments */
+
+/* removes whitespaces from the left, right and both sides of a string */
+/* MODIFIES the string passed in and returns the head of it */
+extern char* leftTrim(char* s);
+extern char* rightTrim(char* s);
+extern char* doubleTrim(char* s);
+
+/* dupstr : copies a string, while making room for it */
+/* the CALLER is responsible for freeing the space */
+/* returns NULL if the argument is NULL */
+extern char* dupstr(char *s);
+
+#ifdef STRINGUTILS_TEST
+extern void testStringUtils();
+#endif
+
+#ifndef NULL_STR
+#define NULL_STR (char*)0
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#endif /* STRINGUTILS_H */