2 # $PostgreSQL: pgsql/src/test/regress/pg_regress.sh,v 1.58 2005/06/25 23:04:06 tgl Exp $
6 TMPFILE=$TMPDIR/pg_regress.$$
9 PostgreSQL regression test driver
11 Usage: $me [options...] [extra tests...]
14 --dbname=DB use database DB (default \`regression')
15 --debug turn on debug mode in programs that are run
16 --inputdir=DIR take input files from DIR (default \`.')
17 --load-language=lang load the named language before running the
18 tests; can appear multiple times
19 --max-connections=N maximum number of concurrent connections
20 (default is 0 meaning unlimited)
21 --multibyte=ENCODING use ENCODING as the multibyte encoding, and
22 also run a test by the same name
23 --outputdir=DIR place output files in DIR (default \`.')
24 --schedule=FILE use test ordering schedule from FILE
25 (may be used multiple times to concatenate)
26 --temp-install[=DIR] create a temporary installation (in DIR)
28 Options for \`temp-install' mode:
29 --top-builddir=DIR (relative) path to top level build directory
31 Options for using an existing installation:
32 --host=HOST use postmaster running on HOST
33 --port=PORT use postmaster running at PORT
34 --user=USER connect as USER
36 The exit status is 0 if all tests passed, 1 if some tests failed, and 2
37 if the tests could not be run for some reason.
39 Report bugs to <pgsql-bugs@postgresql.org>."
43 _dashes='==============' # 14
45 _msg=`echo "$1$_spaces" | cut -c 1-38`
46 echo "$_dashes $_msg $_dashes"
51 # Unset locale settings
54 unset LC_COLLATE LC_CTYPE LC_MONETARY LC_MESSAGES LC_NUMERIC LC_TIME LC_ALL LANG LANGUAGE
56 # On Windows the default locale may not be English, so force it
57 case $host_platform in
58 *-*-cygwin*|*-*-mingw32*)
66 # Check for echo -n vs echo \c
69 if echo '\c' | grep c >/dev/null 2>&1; then
79 # Initialize default settings
86 pkglibdir='@pkglibdir@'
89 host_platform='@host_tuple@'
90 enable_shared='@enable_shared@'
93 if [ "$GCC" = yes ]; then
115 # Parse command line options
125 echo "pg_regress (PostgreSQL @VERSION@)"
128 dbname=`expr "x$1" : "x--dbname=\(.*\)"`
134 inputdir=`expr "x$1" : "x--inputdir=\(.*\)"`
137 lang=`expr "x$1" : "x--load-language=\(.*\)"`
138 load_langs="$load_langs $lang"
142 multibyte=`expr "x$1" : "x--multibyte=\(.*\)"`
145 temp_install=./tmp_check
148 temp_install=`expr "x$1" : "x--temp-install=\(.*\)"`
151 maxconnections=`expr "x$1" : "x--max-connections=\(.*\)"`
154 outputdir=`expr "x$1" : "x--outputdir=\(.*\)"`
157 foo=`expr "x$1" : "x--schedule=\(.*\)"`
158 schedule="$schedule $foo"
161 top_builddir=`expr "x$1" : "x--top-builddir=\(.*\)"`
164 PGHOST=`expr "x$1" : "x--host=\(.*\)"`
169 PGPORT=`expr "x$1" : "x--port=\(.*\)"`
173 PGUSER=`expr "x$1" : "x--user=\(.*\)"`
177 echo "$me: invalid argument $1" 1>&2
180 extra_tests="$extra_tests $1"
186 # warn of Cygwin likely failure if maxconnections = 0
187 # and we are running parallel tests
190 case $host_platform in
194 if [ $maxconnections -eq 0 ] ; then
195 echo Using unlimited parallel connections is likely to fail or hang on Cygwin.
196 echo Try \"$me --max-connections=n\" or \"gmake MAX_CONNECTIONS=n check\"
197 echo with n = 5 or 10 if this happens.
207 # On some platforms we can't use Unix sockets.
209 case $host_platform in
210 *-*-cygwin* | *-*-mingw32* | *-*-qnx* | *beos*)
218 # Set up diff to ignore horizontal white space differences.
221 case $host_platform in
222 *-*-qnx* | *-*-sco3.2v5*)
230 # Set backend timezone and datestyle explicitly
232 # To pass the horology test in its current form, the postmaster must be
233 # started with PGDATESTYLE=ISO, while the frontend must be started with
234 # PGDATESTYLE=Postgres. We set the postmaster values here and change
235 # to the frontend settings after the postmaster has been started.
238 PGTZ='PST8PDT'; export PGTZ
239 PGDATESTYLE='ISO, MDY'; export PGDATESTYLE
243 # Exit trap to remove temp file and shut down postmaster
246 # Note: There are some stupid shells (even among recent ones) that
247 # ignore the argument to exit (as in `exit 1') if there is an exit
248 # trap. The trap (and thus the shell script) will then always exit
249 # with the result of the last shell command before the `exit'. Hence
250 # we have to write `(exit x); exit' below this point.
254 if [ -n "$postmaster_pid" ]; then
255 kill -2 "$postmaster_pid"
256 wait "$postmaster_pid"
259 rm -f "$TMPFILE" && exit $savestatus
262 trap 'exit_trap $?' 0
266 echo; echo "caught signal"
267 if [ -n "$postmaster_pid" ]; then
268 echo "signalling fast shutdown to postmaster with pid $postmaster_pid"
269 kill -2 "$postmaster_pid"
270 wait "$postmaster_pid"
273 (exit $savestatus); exit
276 trap 'sig_trap $?' 1 2 13 15
281 # Scan resultmap file to find which platform-specific expected files to use.
282 # The format of each line of the file is
283 # testname/hostplatformpattern=substitutefile
284 # where the hostplatformpattern is evaluated per the rules of expr(1),
285 # namely, it is a standard regular expression with an implicit ^ at the start.
286 # What hostplatformpattern will be matched against is the config.guess output
287 # followed by either ':gcc' or ':cc' (independent of the actual name of the
288 # compiler executable).
290 # The tempfile hackery is needed because some shells will run the loop
291 # inside a subshell, whereupon shell variables set therein aren't seen
292 # outside the loop :-(
295 cat /dev/null >$TMPFILE
296 if [ -f "$inputdir/resultmap" ]
300 HOSTPAT=`expr "$LINE" : '.*/\(.*\)='`
301 if [ `expr "$host_platform:$compiler" : "$HOSTPAT"` -ne 0 ]
303 # remove hostnamepattern from line so that there are no shell
304 # wildcards in SUBSTLIST; else later 'for' could expand them!
305 TESTNAME=`expr "$LINE" : '\(.*\)/'`
306 SUBST=`echo "$LINE" | sed 's/^.*=//'`
307 echo "$TESTNAME=$SUBST" >> $TMPFILE
309 done <"$inputdir/resultmap"
311 SUBSTLIST=`cat $TMPFILE`
315 LOGDIR=$outputdir/log
317 if [ x"$temp_install" != x"" ]
319 if echo x"$temp_install" | grep -v '^x/' >/dev/null 2>&1; then
320 case $host_platform in
322 pkglibdir="`pwd -W`/$temp_install/install/$pkglibdir"
323 temp_install="`pwd`/$temp_install"
326 temp_install="`pwd`/$temp_install"
327 pkglibdir=$temp_install/install/$pkglibdir
332 bindir=$temp_install/install/$bindir
333 libdir=$temp_install/install/$libdir
334 datadir=$temp_install/install/$datadir
335 PGDATA=$temp_install/data
337 if [ "$unix_sockets" = no ]; then
348 # Get rid of environment stuff that might cause psql to misbehave
349 # while contacting our temp installation
350 unset PGDATABASE PGUSER PGSERVICE PGSSLMODE PGREQUIRESSL PGCONNECT_TIMEOUT
353 # Set up shared library paths, needed by psql and pg_encoding
354 # (if you run multibyte). LD_LIBRARY_PATH covers many platforms.
355 # DYLD_LIBRARY_PATH works on Darwin, and maybe other Mach-based systems.
356 # Feel free to account for others as well.
359 if [ -n "$LD_LIBRARY_PATH" ]; then
360 LD_LIBRARY_PATH="$libdir:$LD_LIBRARY_PATH"
362 LD_LIBRARY_PATH=$libdir
364 export LD_LIBRARY_PATH
366 if [ -n "$DYLD_LIBRARY_PATH" ]; then
367 DYLD_LIBRARY_PATH="$libdir:$DYLD_LIBRARY_PATH"
369 DYLD_LIBRARY_PATH=$libdir
371 export DYLD_LIBRARY_PATH
374 # Windows needs shared libraries in PATH. (Only those linked into
375 # executables, not dlopen'ed ones)
377 case $host_platform in
378 *-*-cygwin*|*-*-mingw32*)
384 if [ -d "$temp_install" ]; then
385 message "removing existing temp installation"
386 rm -rf "$temp_install"
389 message "creating temporary installation"
390 if [ ! -d "$LOGDIR" ]; then
391 mkdir -p "$LOGDIR" || { (exit 2); exit; }
393 $GMAKE -C "$top_builddir" DESTDIR="$temp_install/install" install with_perl=no with_python=no >"$LOGDIR/install.log" 2>&1
398 echo "$me: installation failed"
399 echo "Examine $LOGDIR/install.log for the reason."
404 # fix conversion shared objs path
405 conv=$datadir/conversion_create.sql
408 sed -e "s@\$libdir@$pkglibdir@g" $backup > $conv
411 message "initializing database system"
412 [ "$debug" = yes ] && initdb_options='--debug'
413 "$bindir/initdb" -D "$PGDATA" -L "$datadir" --noclean $initdb_options >"$LOGDIR/initdb.log" 2>&1
418 echo "$me: initdb failed"
419 echo "Examine $LOGDIR/initdb.log for the reason."
429 message "starting postmaster"
430 [ "$debug" = yes ] && postmaster_options="$postmaster_options -d 5"
431 if [ "$unix_sockets" = no ]; then
432 postmaster_options="$postmaster_options -c listen_addresses=$hostname"
434 postmaster_options="$postmaster_options -c listen_addresses="
436 "$bindir/postmaster" -D "$PGDATA" -F $postmaster_options >"$LOGDIR/postmaster.log" 2>&1 &
439 # Wait till postmaster is able to accept connections (normally only
440 # a second or so, but Cygwin is reportedly *much* slower). Don't
441 # wait forever, however.
444 until "$bindir/psql" -X $psql_options postgres </dev/null 2>/dev/null
451 if kill -0 $postmaster_pid >/dev/null 2>&1
460 if kill -0 $postmaster_pid >/dev/null 2>&1
462 echo "running on port $PGPORT with pid $postmaster_pid"
465 echo "$me: postmaster did not start"
466 echo "Examine $LOGDIR/postmaster.log for the reason."
471 else # not temp-install
474 # Windows needs shared libraries in PATH. (Only those linked into
475 # executables, not dlopen'ed ones)
477 case $host_platform in
478 *-*-cygwin*|*-*-mingw32*)
484 if [ -n "$PGPORT" ]; then
485 port_info="port $PGPORT"
487 port_info="default port"
490 if [ -n "$PGHOST" ]; then
491 echo "(using postmaster on $PGHOST, $port_info)"
493 if [ "$unix_sockets" = no ]; then
494 echo "(using postmaster on localhost, $port_info)"
496 echo "(using postmaster on Unix socket, $port_info)"
500 message "dropping database \"$dbname\""
501 "$bindir/dropdb" $psql_options "$dbname"
502 # errors can be ignored
507 # Set up SQL shell for the test.
510 PSQL="$bindir/psql -a -q -X $psql_options"
514 # Set frontend timezone and datestyle explicitly
517 PGTZ='PST8PDT'; export PGTZ
518 PGDATESTYLE='Postgres, MDY'; export PGDATESTYLE
522 # Set up multibyte environment
525 if [ -n "$multibyte" ]; then
526 PGCLIENTENCODING=$multibyte
527 export PGCLIENTENCODING
528 encoding_opt="-E $multibyte"
530 unset PGCLIENTENCODING
535 # Create the regression database
536 # We use template0 so that any installation-local cruft in template1
537 # will not mess up the tests.
540 message "creating database \"$dbname\""
541 "$bindir/createdb" $encoding_opt $psql_options --template template0 "$dbname"
542 if [ $? -ne 0 ]; then
543 echo "$me: createdb failed"
547 "$bindir/psql" -q -X $psql_options -c "\
548 alter database \"$dbname\" set lc_messages to 'C';
549 alter database \"$dbname\" set lc_monetary to 'C';
550 alter database \"$dbname\" set lc_numeric to 'C';
551 alter database \"$dbname\" set lc_time to 'C';" "$dbname"
552 if [ $? -ne 0 ]; then
553 echo "$me: could not set database default locales"
559 # Remove regressuser* and regressgroup* user accounts.
562 message "dropping regression test user accounts"
563 "$bindir/psql" -q -X $psql_options -c 'DROP GROUP regressgroup1; DROP GROUP regressgroup2; DROP USER regressuser1, regressuser2, regressuser3, regressuser4;' $dbname 2>/dev/null
564 if [ $? -eq 2 ]; then
565 echo "$me: could not drop user accounts"
571 # Install any requested PL languages
574 if [ "$enable_shared" = yes ]; then
575 for lang in xyzzy $load_langs ; do
576 if [ "$lang" != "xyzzy" ]; then
577 message "installing $lang"
578 "$bindir/createlang" -L "$pkglibdir" $psql_options $lang $dbname
579 if [ $? -ne 0 ] && [ $? -ne 2 ]; then
580 echo "$me: createlang $lang failed"
592 message "running regression test queries"
594 if [ ! -d "$outputdir/results" ]; then
595 mkdir -p "$outputdir/results" || { (exit 2); exit; }
597 result_summary_file=$outputdir/regression.out
598 diff_file=$outputdir/regression.diffs
600 cat /dev/null >"$result_summary_file"
601 cat /dev/null >"$diff_file"
605 [ "$enable_shared" != yes ] && echo "ignore: plpgsql"
606 cat $schedule </dev/null
607 for x in $extra_tests; do
610 ) | sed 's/[ ]*#.*//g' | \
615 [ -z "$line" ] && continue
619 if [ x"$1" = x"ignore:" ]; then
621 ignore_list="$ignore_list $@"
623 elif [ x"$1" != x"test:" ]; then
624 echo "$me:$schedule:$lno: syntax error"
634 if [ $# -eq 1 ]; then
636 formatted=`echo $1 | awk '{printf "%-20.20s", $1;}'`
637 $ECHO_N "test $formatted ... $ECHO_C"
638 ( $PSQL -d "$dbname" <"$inputdir/sql/$1.sql" >"$outputdir/results/$1.out" 2>&1 )&
641 # Start a parallel group
642 $ECHO_N "parallel group ($# tests): $ECHO_C"
643 if [ $maxconnections -gt 0 ] ; then
645 test $# -gt $maxconnections && $ECHO_N "(in groups of $maxconnections) $ECHO_C"
649 $PSQL -d "$dbname" <"$inputdir/sql/$name.sql" >"$outputdir/results/$name.out" 2>&1
650 $ECHO_N " $name$ECHO_C"
652 if [ $maxconnections -gt 0 ] ; then
653 connnum=`expr \( $connnum + 1 \) % $maxconnections`
654 test $connnum -eq 0 && wait
663 # (We do not want to run the diffs immediately after each test,
664 # because they would certainly get corrupted if run in parallel
669 if [ $# -ne 1 ]; then
670 formatted=`echo "$name" | awk '{printf "%-20.20s", $1;}'`
671 $ECHO_N " $formatted ... $ECHO_C"
674 # Check list extracted from resultmap to see if we should compare
675 # to a system-specific expected file.
676 # There shouldn't be multiple matches, but take the last if there are.
678 EXPECTED="$inputdir/expected/${name}"
679 for LINE in $SUBSTLIST
681 if [ `expr "$LINE" : "$name="` -ne 0 ]
683 SUBST=`echo "$LINE" | sed 's/^.*=//'`
684 EXPECTED="$inputdir/expected/${SUBST}"
688 # If there are multiple equally valid result files, loop to get the right one.
689 # If none match, diff against the closest one.
694 for thisfile in $EXPECTED.out ${EXPECTED}_[0-9].out; do
695 [ ! -r "$thisfile" ] && continue
696 diff $DIFFFLAGS $thisfile $outputdir/results/${name}.out >/dev/null 2>&1
700 1) thisdiff=`diff $DIFFFLAGS $thisfile $outputdir/results/${name}.out | wc -l`
701 if [ -z "$bestdiff" ] || [ "$thisdiff" -lt "$bestdiff" ]; then
702 bestdiff=$thisdiff; bestfile=$thisfile
709 # Now print the result.
715 ( diff $DIFFFLAGS -C3 $bestfile $outputdir/results/${name}.out
717 echo "======================================================================"
718 echo ) >> "$diff_file"
719 if echo " $ignore_list " | grep " $name " >/dev/null 2>&1 ; then
720 echo "failed (ignored)"
731 done | tee "$result_summary_file" 2>&1
739 if [ -n "$postmaster_pid" ]; then
740 message "shutting down postmaster"
741 "$bindir/pg_ctl" -s -D "$PGDATA" stop
742 wait "$postmaster_pid"
753 count_total=`cat "$result_summary_file" | grep '\.\.\.' | wc -l | sed 's/ //g'`
754 count_ok=`cat "$result_summary_file" | grep '\.\.\. ok' | wc -l | sed 's/ //g'`
755 count_failed=`cat "$result_summary_file" | grep '\.\.\. FAILED' | wc -l | sed 's/ //g'`
756 count_ignored=`cat "$result_summary_file" | grep '\.\.\. failed (ignored)' | wc -l | sed 's/ //g'`
759 if [ $count_total -eq $count_ok ]; then
760 msg="All $count_total tests passed."
762 elif [ $count_failed -eq 0 ]; then
763 msg="$count_ok of $count_total tests passed, $count_ignored failed test(s) ignored."
765 elif [ $count_ignored -eq 0 ]; then
766 msg="$count_failed of $count_total tests failed."
769 msg="`expr $count_failed + $count_ignored` of $count_total tests failed, $count_ignored of these failures ignored."
773 dashes=`echo " $msg " | sed 's/./=/g'`
779 if [ -s "$diff_file" ]; then
780 echo "The differences that caused some tests to fail can be viewed in the"
781 echo "file \`$diff_file'. A copy of the test summary that you see"
782 echo "above is saved in the file \`$result_summary_file'."
785 rm -f "$diff_file" "$result_summary_file"