
patch is applied: Rewrite rules on relation level work fine now. Event qualifications on insert/update/delete rules work fine now. I added the new keyword OLD to reference the CURRENT tuple. CURRENT will be removed in 6.5. Update rules can reference NEW and OLD in the rule qualification and the actions. Insert/update/delete rules on views can be established to let them behave like real tables. For insert/update/delete rules multiple actions are supported now. The actions can also be surrounded by parantheses to make psql happy. Multiple actions are required if update to a view requires updates to multiple tables. Regular users are permitted to create/drop rules on tables they have RULE permissions for (DefineQueryRewrite() is now able to get around the access restrictions on pg_rewrite). This enables view creation for regular users too. This required an extra boolean parameter to pg_parse_and_plan() that tells to set skipAcl on all rangetable entries of the resulting queries. There is a new function pg_exec_query_acl_override() that could be used by backend utilities to use this facility. All rule actions (not only views) inherit the permissions of the event relations owner. Sample: User A creates tables T1 and T2, creates rules that log INSERT/UPDATE/DELETE on T1 in T2 (like in the regression tests for rules I created) and grants ALL but RULE on T1 to user B. User B can now fully access T1 and the logging happens in T2. But user B cannot access T2 at all, only the rule actions can. And due to missing RULE permissions on T1, user B cannot disable logging. Rules on the attribute level are disabled (they don't work properly and since regular users are now permitted to create rules I decided to disable them). Rules on select must have exactly one action that is a select (so select rules must be a view definition). UPDATE NEW/OLD rules are disabled (still broken, but triggers can do it). There are two new system views (pg_rule and pg_view) that show the definition of the rules or views so the db admin can see what the users do. They use two new functions pg_get_ruledef() and pg_get_viewdef() that are builtins. The functions pg_get_ruledef() and pg_get_viewdef() could be used to implement rule and view support in pg_dump. PostgreSQL is now the only database system I know, that has rewrite rules on the query level. All others (where I found a rule statement at all) use stored database procedures or the like (triggers as we call them) for active rules (as some call them). Future of the rule system: The now disabled parts of the rule system (attribute level, multiple actions on select and update new stuff) require a complete new rewrite handler from scratch. The old one is too badly wired up. After 6.4 I'll start to work on a new rewrite handler, that fully supports the attribute level rules, multiple actions on select and update new. This will be available for 6.5 so we get full rewrite rule capabilities. Jan
477 lines
16 KiB
Bash
477 lines
16 KiB
Bash
#!/bin/sh
|
|
#-------------------------------------------------------------------------
|
|
#
|
|
# initdb.sh--
|
|
# Create (initialize) a Postgres database system.
|
|
#
|
|
# A database system is a collection of Postgres databases all managed
|
|
# by the same postmaster.
|
|
#
|
|
# To create the database system, we create the directory that contains
|
|
# all its data, create the files that hold the global classes, create
|
|
# a few other control files for it, and create one database: the
|
|
# template database.
|
|
#
|
|
# The template database is an ordinary Postgres database. Its data
|
|
# never changes, though. It exists to make it easy for Postgres to
|
|
# create other databases -- it just copies.
|
|
#
|
|
# Optionally, we can skip creating the database system and just create
|
|
# (or replace) the template database.
|
|
#
|
|
# To create all those classes, we run the postgres (backend) program and
|
|
# feed it data from bki files that are in the Postgres library directory.
|
|
#
|
|
# Copyright (c) 1994, Regents of the University of California
|
|
#
|
|
#
|
|
# IDENTIFICATION
|
|
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.54 1998/08/24 01:38:06 momjian Exp $
|
|
#
|
|
#-------------------------------------------------------------------------
|
|
|
|
# ----------------
|
|
# The OPT_..._PARAM gets set when the script is built (with make)
|
|
# from parameters set in the make file.
|
|
#
|
|
# ----------------
|
|
|
|
CMDNAME=`basename $0`
|
|
MULTIBYTEID=0
|
|
|
|
MULTIBYTE=__MULTIBYTE__
|
|
if [ -n "$MULTIBYTE" ];then
|
|
MULTIBYTEID=`pg_encoding $MULTIBYTE`
|
|
fi
|
|
|
|
# Find the default PGLIB directory (the directory that contains miscellaneous
|
|
# files that are part of Postgres). The user-written program postconfig
|
|
# outputs variable settings like "PGLIB=/usr/lib/whatever". If it doesn't
|
|
# output a PGLIB value, then there is no default and the user must
|
|
# specify the pglib option. Postconfig may validly not exist, in which case
|
|
# our invocation of it silently fails.
|
|
|
|
# The 2>/dev/null is to swallow the "postconfig: not found" message if there
|
|
# is no postconfig.
|
|
|
|
postconfig_result="`sh -c postconfig 2>/dev/null`"
|
|
if [ ! -z "$postconfig_result" ]; then
|
|
set -a # Make the following variable assignment exported to environment
|
|
eval "$postconfig_result"
|
|
set +a # back to normal
|
|
fi
|
|
|
|
# Set defaults:
|
|
debug=0
|
|
noclean=0
|
|
template_only=0
|
|
POSTGRES_SUPERUSERNAME=$USER
|
|
|
|
while [ "$#" -gt 0 ]
|
|
do
|
|
# ${ARG#--username=} is not reliable or available on all platforms
|
|
|
|
case "$1" in
|
|
--debug|-d)
|
|
debug=1
|
|
echo "Running with debug mode on."
|
|
;;
|
|
--noclean|-n)
|
|
noclean=1
|
|
echo "Running with noclean mode on. "
|
|
"Mistakes will not be cleaned up."
|
|
;;
|
|
--template|-t)
|
|
template_only=1
|
|
echo "updating template1 database only."
|
|
;;
|
|
--username=*)
|
|
POSTGRES_SUPERUSERNAME="`echo $1 | sed 's/^--username=//'`"
|
|
;;
|
|
-u)
|
|
shift
|
|
POSTGRES_SUPERUSERNAME="$1"
|
|
;;
|
|
-u*)
|
|
POSTGRES_SUPERUSERNAME="`echo $1 | sed 's/^-u//'`"
|
|
;;
|
|
--pgdata=*)
|
|
PGDATA="`echo $1 | sed 's/^--pgdata=//'`"
|
|
;;
|
|
-r)
|
|
shift
|
|
PGDATA="$1"
|
|
;;
|
|
-r*)
|
|
PGDATA="`echo $1 | sed 's/^-r//'`"
|
|
;;
|
|
--pglib=*)
|
|
PGLIB="`echo $1 | sed 's/^--pglib=//'`"
|
|
;;
|
|
-l)
|
|
shift
|
|
PGLIB="$1"
|
|
;;
|
|
-l*)
|
|
PGLIB="`echo $1 | sed 's/^-l//'`"
|
|
;;
|
|
|
|
--pgencoding=*)
|
|
if [ -z "$MULTIBYTE" ];then
|
|
echo "MULTIBYTE support seems to be disabled"
|
|
exit 100
|
|
fi
|
|
mb="`echo $1 | sed 's/^--pgencoding=//'`"
|
|
MULTIBYTEID=`pg_encoding $mb`
|
|
if [ -z "$MULTIBYTEID" ];then
|
|
echo "$mb is not a valid encoding name"
|
|
exit 100
|
|
fi
|
|
;;
|
|
-e)
|
|
if [ -z "$MULTIBYTE" ];then
|
|
echo "MULTIBYTE support seems to be disabled"
|
|
exit 100
|
|
fi
|
|
shift
|
|
MULTIBYTEID=`pg_encoding $1`
|
|
if [ -z "$MULTIBYTEID" ];then
|
|
echo "$1 is not a valid encoding name"
|
|
exit 100
|
|
fi
|
|
;;
|
|
-e*)
|
|
if [ -z "$MULTIBYTE" ];then
|
|
echo "MULTIBYTE support seems to be disabled"
|
|
exit 100
|
|
fi
|
|
mb="`echo $1 | sed 's/^-e//'`"
|
|
MULTIBYTEID=`pg_encoding $mb`
|
|
if [ -z "$MULTIBYTEID" ];then
|
|
echo "$mb is not a valid encoding name"
|
|
exit 100
|
|
fi
|
|
;;
|
|
*)
|
|
echo "Unrecognized option '$1'. Syntax is:"
|
|
if [ -z "$MULTIBYTE" ];then
|
|
echo "initdb [-t | --template] [-d | --debug]" \
|
|
"[-n | --noclean]" \
|
|
"[-u SUPERUSER | --username=SUPERUSER]" \
|
|
"[-r DATADIR | --pgdata=DATADIR]" \
|
|
"[-l LIBDIR | --pglib=LIBDIR]"
|
|
else
|
|
echo "initdb [-t | --template] [-d | --debug]" \
|
|
"[-n | --noclean]" \
|
|
"[-u SUPERUSER | --username=SUPERUSER]" \
|
|
"[-r DATADIR | --pgdata=DATADIR]" \
|
|
"[-l LIBDIR | --pglib=LIBDIR]" \
|
|
"[-e ENCODING | --pgencoding=ENCODING]"
|
|
fi
|
|
exit 100
|
|
esac
|
|
shift
|
|
done
|
|
|
|
#-------------------------------------------------------------------------
|
|
# Make sure he told us where to find the Postgres files.
|
|
#-------------------------------------------------------------------------
|
|
if [ -z "$PGLIB" ]; then
|
|
echo "$CMDNAME does not know where to find the files that make up "
|
|
echo "Postgres (the PGLIB directory). You must identify the PGLIB "
|
|
echo "directory either with a --pglib invocation option, or by "
|
|
echo "setting the PGLIB environment variable, or by having a program "
|
|
echo "called 'postconfig' in your search path that outputs an asignment "
|
|
echo "for PGLIB."
|
|
exit 20
|
|
fi
|
|
|
|
#-------------------------------------------------------------------------
|
|
# Make sure he told us where to build the database system
|
|
#-------------------------------------------------------------------------
|
|
|
|
if [ -z "$PGDATA" ]; then
|
|
echo "$CMDNAME: You must identify the PGDATA directory, where the data"
|
|
echo "for this database system will reside. Do this with either a"
|
|
echo "--pgdata invocation option or a PGDATA environment variable."
|
|
echo
|
|
exit 20
|
|
fi
|
|
|
|
TEMPLATE=$PGLIB/local1_template1.bki.source
|
|
GLOBAL=$PGLIB/global1.bki.source
|
|
TEMPLATE_DESCR=$PGLIB/local1_template1.description
|
|
GLOBAL_DESCR=$PGLIB/global1.description
|
|
PG_HBA_SAMPLE=$PGLIB/pg_hba.conf.sample
|
|
PG_GEQO_SAMPLE=$PGLIB/pg_geqo.sample
|
|
|
|
|
|
#-------------------------------------------------------------------------
|
|
# Find the input files
|
|
#-------------------------------------------------------------------------
|
|
|
|
for PREREQ_FILE in $TEMPLATE $GLOBAL $PG_HBA_SAMPLE; do
|
|
if [ ! -f $PREREQ_FILE ]; then
|
|
echo "$CMDNAME does not find the file '$PREREQ_FILE'."
|
|
echo "This means you have identified an invalid PGLIB directory."
|
|
echo "You specify a PGLIB directory with a --pglib invocation "
|
|
echo "option, a PGLIB environment variable, or a postconfig program."
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
[ "$debug" -ne 0 ] && echo "$CMDNAME: using $TEMPLATE as input to create the template database."
|
|
if [ $template_only -eq 0 ]; then
|
|
[ "$debug" -ne 0 ] && echo "$CMDNAME: using $GLOBAL as input to create the global classes."
|
|
[ "$debug" -ne 0 ] && echo "$CMDNAME: using $PG_HBA_SAMPLE as the host-based authentication" \
|
|
"control file."
|
|
echo
|
|
fi
|
|
|
|
#---------------------------------------------------------------------------
|
|
# Figure out who the Postgres superuser for the new database system will be.
|
|
#---------------------------------------------------------------------------
|
|
|
|
if [ -z "$POSTGRES_SUPERUSERNAME" ]; then
|
|
echo "Can't tell what username to use. You don't have the USER"
|
|
echo "environment variable set to your username and didn't specify the "
|
|
echo "--username option"
|
|
exit 1
|
|
fi
|
|
|
|
POSTGRES_SUPERUID=`pg_id $POSTGRES_SUPERUSERNAME`
|
|
|
|
if [ ${POSTGRES_SUPERUID:=-1} -eq -1 ]; then
|
|
echo "Unable to determine a valid username. If you are running"
|
|
echo "initdb without an explicit username specified, then there"
|
|
echo "may be a problem with finding the Postgres shared library"
|
|
echo "and/or the pg_id utility."
|
|
exit 10
|
|
fi
|
|
|
|
if [ $POSTGRES_SUPERUID = NOUSER ]; then
|
|
echo "Valid username not given. You must specify the username for "
|
|
echo "the Postgres superuser for the database system you are "
|
|
echo "initializing, either with the --username option or by default "
|
|
echo "to the USER environment variable."
|
|
exit 10
|
|
fi
|
|
|
|
if [ $POSTGRES_SUPERUID -ne `pg_id` -a `pg_id` -ne 0 ]; then
|
|
echo "Only the unix superuser may initialize a database with a different"
|
|
echo "Postgres superuser. (You must be able to create files that belong"
|
|
echo "to the specified unix user)."
|
|
exit 2
|
|
fi
|
|
|
|
echo "We are initializing the database system with username" \
|
|
"$POSTGRES_SUPERUSERNAME (uid=$POSTGRES_SUPERUID)."
|
|
echo "This user will own all the files and must also own the server process."
|
|
echo
|
|
|
|
# -----------------------------------------------------------------------
|
|
# Create the data directory if necessary
|
|
# -----------------------------------------------------------------------
|
|
|
|
# umask must disallow access to group, other for files and dirs
|
|
umask 077
|
|
|
|
if [ -f "$PGDATA/PG_VERSION" ]; then
|
|
if [ $template_only -eq 0 ]; then
|
|
echo "$CMDNAME: error: File $PGDATA/PG_VERSION already exists."
|
|
echo "This probably means initdb has already been run and the "
|
|
echo "database system already exists."
|
|
echo
|
|
echo "If you want to create a new database system, either remove "
|
|
echo "the directory $PGDATA or run initdb with a --pgdata option "
|
|
echo "other than $PGDATA."
|
|
exit 1
|
|
fi
|
|
else
|
|
if [ ! -d $PGDATA ]; then
|
|
echo "Creating Postgres database system directory $PGDATA"
|
|
echo
|
|
mkdir $PGDATA
|
|
if [ $? -ne 0 ]; then exit 5; fi
|
|
fi
|
|
if [ ! -d $PGDATA/base ]; then
|
|
echo "Creating Postgres database system directory $PGDATA/base"
|
|
echo
|
|
mkdir $PGDATA/base
|
|
if [ $? -ne 0 ]; then exit 5; fi
|
|
fi
|
|
fi
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Create the template1 database
|
|
#----------------------------------------------------------------------------
|
|
|
|
rm -rf $PGDATA/base/template1
|
|
mkdir $PGDATA/base/template1
|
|
|
|
if [ "$debug" -eq 1 ]; then
|
|
BACKEND_TALK_ARG="-d"
|
|
else
|
|
BACKEND_TALK_ARG="-Q"
|
|
fi
|
|
|
|
BACKENDARGS="-boot -C -F -D$PGDATA $BACKEND_TALK_ARG"
|
|
|
|
echo "Creating template database in $PGDATA/base/template1"
|
|
[ "$debug" -ne 0 ] && echo "Running: postgres $BACKENDARGS template1"
|
|
|
|
cat $TEMPLATE \
|
|
| sed -e "s/postgres PGUID/$POSTGRES_SUPERUSERNAME $POSTGRES_SUPERUID/" \
|
|
-e "s/PGUID/$POSTGRES_SUPERUID/" \
|
|
| postgres $BACKENDARGS template1
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "$CMDNAME: could not create template database"
|
|
if [ $noclean -eq 0 ]; then
|
|
echo "$CMDNAME: cleaning up by wiping out $PGDATA/base/template1"
|
|
rm -rf $PGDATA/base/template1
|
|
else
|
|
echo "$CMDNAME: cleanup not done because noclean options was used."
|
|
fi
|
|
exit 1;
|
|
fi
|
|
|
|
echo
|
|
|
|
pg_version $PGDATA/base/template1
|
|
|
|
#----------------------------------------------------------------------------
|
|
# Create the global classes, if requested.
|
|
#----------------------------------------------------------------------------
|
|
|
|
if [ $template_only -eq 0 ]; then
|
|
echo "Creating global classes in $PGDATA/base"
|
|
[ "$debug" -ne 0 ] && echo "Running: postgres $BACKENDARGS template1"
|
|
|
|
cat $GLOBAL \
|
|
| sed -e "s/postgres PGUID/$POSTGRES_SUPERUSERNAME $POSTGRES_SUPERUID/" \
|
|
-e "s/PGUID/$POSTGRES_SUPERUID/" \
|
|
| postgres $BACKENDARGS template1
|
|
|
|
if (test $? -ne 0)
|
|
then
|
|
echo "$CMDNAME: could not create global classes."
|
|
if (test $noclean -eq 0); then
|
|
echo "$CMDNAME: cleaning up."
|
|
rm -rf $PGDATA
|
|
else
|
|
echo "$CMDNAME: cleanup not done (noclean mode set)."
|
|
fi
|
|
exit 1;
|
|
fi
|
|
|
|
echo
|
|
|
|
pg_version $PGDATA
|
|
|
|
cp $PG_HBA_SAMPLE $PGDATA/pg_hba.conf
|
|
cp $PG_GEQO_SAMPLE $PGDATA/pg_geqo.sample
|
|
|
|
echo "Adding template1 database to pg_database..."
|
|
|
|
echo "open pg_database" > /tmp/create.$$
|
|
echo "insert (template1 $POSTGRES_SUPERUID $MULTIBYTEID template1)" >> /tmp/create.$$
|
|
#echo "show" >> /tmp/create.$$
|
|
echo "close pg_database" >> /tmp/create.$$
|
|
|
|
[ "$debug" -ne 0 ] && echo "Running: postgres $BACKENDARGS template1 < /tmp/create.$$"
|
|
|
|
postgres $BACKENDARGS template1 < /tmp/create.$$
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "$CMDNAME: could not log template database"
|
|
if [ $noclean -eq 0 ]; then
|
|
echo "$CMDNAME: cleaning up."
|
|
rm -rf $PGDATA
|
|
else
|
|
echo "$CMDNAME: cleanup not done (noclean mode set)."
|
|
fi
|
|
exit 1;
|
|
fi
|
|
rm -f /tmp/create.$$
|
|
fi
|
|
|
|
echo
|
|
|
|
PGSQL_OPT="-o /dev/null -F -Q -D$PGDATA"
|
|
|
|
# If the COPY is first, the VACUUM generates an error, so we vacuum first
|
|
echo "Vacuuming template1"
|
|
echo "vacuum" | postgres $PGSQL_OPT template1 > /dev/null
|
|
|
|
echo "COPY pg_shadow TO '$PGDATA/pg_pwd' USING DELIMITERS '\\t'" | \
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
|
|
echo "Creating public pg_user view"
|
|
echo "CREATE TABLE xpg_user ( \
|
|
usename name, \
|
|
usesysid int4, \
|
|
usecreatedb bool, \
|
|
usetrace bool, \
|
|
usesuper bool, \
|
|
usecatupd bool, \
|
|
passwd text, \
|
|
valuntil abstime);" | postgres $PGSQL_OPT template1 > /dev/null
|
|
|
|
#move it into pg_user
|
|
echo "UPDATE pg_class SET relname = 'pg_user' WHERE relname = 'xpg_user';" |\
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
echo "UPDATE pg_type SET typname = 'pg_user' WHERE typname = 'xpg_user';" |\
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
mv $PGDATA/base/template1/xpg_user $PGDATA/base/template1/pg_user
|
|
|
|
echo "CREATE RULE _RETpg_user AS ON SELECT TO pg_user DO INSTEAD \
|
|
SELECT usename, usesysid, usecreatedb, usetrace, \
|
|
usesuper, usecatupd, '********'::text as passwd, \
|
|
valuntil FROM pg_shadow;" | \
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
echo "REVOKE ALL on pg_shadow FROM public" | \
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
|
|
echo "Creating view pg_rule"
|
|
echo "CREATE TABLE xpg_rule ( \
|
|
rulename name, \
|
|
definition text);" | postgres $PGSQL_OPT template1 > /dev/null
|
|
#move it into pg_rule
|
|
echo "UPDATE pg_class SET relname = 'pg_rule' WHERE relname = 'xpg_rule';" |\
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
echo "UPDATE pg_type SET typname = 'pg_rule' WHERE typname = 'xpg_rule';" |\
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
mv $PGDATA/base/template1/xpg_rule $PGDATA/base/template1/pg_rule
|
|
|
|
echo "CREATE RULE _RETpg_rule AS ON SELECT TO pg_rule DO INSTEAD \
|
|
SELECT rulename, pg_get_ruledef(rulename) AS definition \
|
|
FROM pg_rewrite;" | postgres $PGSQL_OPT template1 > /dev/null
|
|
|
|
echo "Creating view pg_view"
|
|
echo "CREATE TABLE xpg_view ( \
|
|
viewname name, \
|
|
definition text);" | postgres $PGSQL_OPT template1 > /dev/null
|
|
#move it into pg_view
|
|
echo "UPDATE pg_class SET relname = 'pg_view' WHERE relname = 'xpg_view';" |\
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
echo "UPDATE pg_type SET typname = 'pg_view' WHERE typname = 'xpg_view';" |\
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
mv $PGDATA/base/template1/xpg_view $PGDATA/base/template1/pg_view
|
|
|
|
echo "CREATE RULE _RETpg_view AS ON SELECT TO pg_view DO INSTEAD \
|
|
SELECT relname AS viewname, \
|
|
pg_get_viewdef(relname) AS definition \
|
|
FROM pg_class WHERE relhasrules AND \
|
|
pg_get_viewdef(relname) != 'Not a view';" | \
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
|
|
echo "Loading pg_description"
|
|
echo "copy pg_description from '$TEMPLATE_DESCR'" | \
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
echo "copy pg_description from '$GLOBAL_DESCR'" | \
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
echo "vacuum analyze" | \
|
|
postgres $PGSQL_OPT template1 > /dev/null
|
|
|