prepared statements) (Tom)
Assume NaN value to be larger than any other value in MIN()/MAX() (Tom)
Prevent interval from supressing ':00' seconds display
+New pg_get_triggerdef(prettyprint) and pg_constraint_is_visible() functions
_________________________________________________________________
just a preformatted message (Tom, Sean Chittenden)
Allow control SSL negotiation with sslmode values "disable", "allow",
"Prefer", and "require" (Jon Jensen)
+Allow new error codes and levels of text (Tom)
+Allow access to the underlying table and column of a query result (Tom)
+Allow access to the current transaction status (Tom)
+Add ability to pass binary data directly to the backend (Tom)
_________________________________________________________________
dnl @synopsis AC_FUNC_ACCEPT_ARGTYPES
dnl
dnl Checks the data types of the three arguments to accept(). Results are
-dnl placed into the symbols ACCEPT_TYPE_ARG[123], consistent with the
-dnl following example:
+dnl placed into the symbols ACCEPT_TYPE_RETURN and ACCEPT_TYPE_ARG[123],
+dnl consistent with the following example:
dnl
+dnl #define ACCEPT_TYPE_RETURN int
dnl #define ACCEPT_TYPE_ARG1 int
dnl #define ACCEPT_TYPE_ARG2 struct sockaddr *
dnl #define ACCEPT_TYPE_ARG3 socklen_t
# Solaris 7 and 8 have arg3 as 'void *' (disguised as 'Psocklen_t'
# which is *not* 'socklen_t *'). If we detect that, then we assume
# 'int' as the result, because that ought to work best.
+#
+# On Win32, accept() returns 'unsigned int PASCAL'
AC_DEFUN([AC_FUNC_ACCEPT_ARGTYPES],
[AC_MSG_CHECKING([types of arguments for accept()])
- AC_CACHE_VAL(ac_cv_func_accept_arg1,dnl
- [AC_CACHE_VAL(ac_cv_func_accept_arg2,dnl
- [AC_CACHE_VAL(ac_cv_func_accept_arg3,dnl
- [for ac_cv_func_accept_arg1 in 'int' 'unsigned int'; do
- for ac_cv_func_accept_arg2 in 'struct sockaddr *' 'const struct sockaddr *' 'void *'; do
- for ac_cv_func_accept_arg3 in 'int' 'size_t' 'socklen_t' 'unsigned int' 'void'; do
- AC_TRY_COMPILE(
+ AC_CACHE_VAL(ac_cv_func_accept_return,dnl
+ [AC_CACHE_VAL(ac_cv_func_accept_arg1,dnl
+ [AC_CACHE_VAL(ac_cv_func_accept_arg2,dnl
+ [AC_CACHE_VAL(ac_cv_func_accept_arg3,dnl
+ [for ac_cv_func_accept_return in 'int' 'unsigned int PASCAL'; do
+ for ac_cv_func_accept_arg1 in 'int' 'unsigned int'; do
+ for ac_cv_func_accept_arg2 in 'struct sockaddr *' 'const struct sockaddr *' 'void *'; do
+ for ac_cv_func_accept_arg3 in 'int' 'size_t' 'socklen_t' 'unsigned int' 'void'; do
+ AC_TRY_COMPILE(
[#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
-extern int accept ($ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *);],
- [], [ac_not_found=no; break 3], [ac_not_found=yes])
+extern $ac_cv_func_accept_return accept ($ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *);],
+ [], [ac_not_found=no; break 4], [ac_not_found=yes])
+ done
done
done
done
if test "$ac_cv_func_accept_arg3" = "void"; then
ac_cv_func_accept_arg3=int
fi
+ ])dnl AC_CACHE_VAL
])dnl AC_CACHE_VAL
])dnl AC_CACHE_VAL
])dnl AC_CACHE_VAL
- AC_MSG_RESULT([$ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *])
+ AC_MSG_RESULT([$ac_cv_func_accept_return, $ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *])
+ AC_DEFINE_UNQUOTED(ACCEPT_TYPE_RETURN, $ac_cv_func_accept_return,
+ [Define to the return type of 'accept'])
AC_DEFINE_UNQUOTED(ACCEPT_TYPE_ARG1, $ac_cv_func_accept_arg1,
[Define to the type of arg 1 of 'accept'])
AC_DEFINE_UNQUOTED(ACCEPT_TYPE_ARG2, $ac_cv_func_accept_arg2,
python_prefix=`${PYTHON} -c "import sys; print sys.prefix"`
python_execprefix=`${PYTHON} -c "import sys; print sys.exec_prefix"`
python_configdir="${python_execprefix}/lib/python${python_version}/config"
-python_moduledir="${python_prefix}/lib/python${python_version}/site-packages"
-python_moduleexecdir="${python_execprefix}/lib/python${python_version}/site-packages"
python_includespec="-I${python_prefix}/include/python${python_version}"
if test "$python_prefix" != "$python_execprefix"; then
python_includespec="-I${python_execprefix}/include/python${python_version} $python_includespec"
fi
-AC_SUBST(python_version)[]dnl
AC_SUBST(python_prefix)[]dnl
AC_SUBST(python_execprefix)[]dnl
AC_SUBST(python_configdir)[]dnl
-AC_SUBST(python_moduledir)[]dnl
-AC_SUBST(python_moduleexecdir)[]dnl
AC_SUBST(python_includespec)[]dnl
# This should be enough of a message.
if test "$python_prefix" != "$python_execprefix"; then
])# _PGAC_CHECK_PYTHON_DIRS
-# PGAC_CHECK_PYTHON_MODULE_SETUP
-# ------------------------------
-# Finds things required to build a Python extension module.
-# This used to do more, that's why it's separate.
-#
-# It would be nice if we could check whether the current setup allows
-# the build of the shared module. Future project.
-AC_DEFUN([PGAC_CHECK_PYTHON_MODULE_SETUP],
-[
- AC_REQUIRE([_PGAC_CHECK_PYTHON_DIRS])
-])# PGAC_CHECK_PYTHON_MODULE_SETUP
-
-
# PGAC_CHECK_PYTHON_EMBED_SETUP
# -----------------------------
# Courtesy of the INN 2.3.1 package...
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.53 for PostgreSQL 7.4beta1.
+# Generated by GNU Autoconf 2.53 for PostgreSQL 7.4beta2.
#
#
# Identity of this package.
PACKAGE_NAME='PostgreSQL'
PACKAGE_TARNAME='postgresql'
-PACKAGE_VERSION='7.4beta1'
-PACKAGE_STRING='PostgreSQL 7.4beta1'
+PACKAGE_VERSION='7.4beta2'
+PACKAGE_STRING='PostgreSQL 7.4beta2'
ac_unique_file="src/backend/access/common/heaptuple.c"
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures PostgreSQL 7.4beta1 to adapt to many kinds of systems.
+\`configure' configures PostgreSQL 7.4beta2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of PostgreSQL 7.4beta1:";;
+ short | recursive ) echo "Configuration of PostgreSQL 7.4beta2:";;
esac
cat <<\_ACEOF
--with-tclconfig=DIR tclConfig.sh and tkConfig.sh are in DIR
--with-tkconfig=DIR tkConfig.sh is in DIR
--with-perl build Perl modules (PL/Perl)
- --with-python build Python interface module
+ --with-python build Python modules (PL/Python)
--with-java build JDBC interface and Java tools
--with-krb4[=DIR] build with Kerberos 4 support [/usr/athena]
--with-krb5[=DIR] build with Kerberos 5 support [/usr/athena]
test -n "$ac_init_help" && exit 0
if $ac_init_version; then
cat <<\_ACEOF
-PostgreSQL configure 7.4beta1
+PostgreSQL configure 7.4beta2
generated by GNU Autoconf 2.53
Copyright 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by PostgreSQL $as_me 7.4beta1, which was
+It was created by PostgreSQL $as_me 7.4beta2, which was
generated by GNU Autoconf 2.53. Invocation command line was
$ $0 $@
{ echo "$as_me:$LINENO: using CFLAGS=$CFLAGS" >&5
echo "$as_me: using CFLAGS=$CFLAGS" >&6;}
+# We already have this in Makefile.win32, but configure needs it too
+if test "$PORTNAME" = "win32"
+then
+ CPPFLAGS="$CPPFLAGS -Isrc/include/port/win32"
+fi
+
# Check if the compiler still works with the template settings
echo "$as_me:$LINENO: checking whether the C compiler still works" >&5
echo $ECHO_N "checking whether the C compiler still works... $ECHO_C" >&6
#
-# Optionally build Python interface module
+# Optionally build Python modules (PL/Python)
#
echo "$as_me:$LINENO: checking whether to build Python modules" >&5
echo $ECHO_N "checking whether to build Python modules... $ECHO_C" >&6
python_prefix=`${PYTHON} -c "import sys; print sys.prefix"`
python_execprefix=`${PYTHON} -c "import sys; print sys.exec_prefix"`
python_configdir="${python_execprefix}/lib/python${python_version}/config"
-python_moduledir="${python_prefix}/lib/python${python_version}/site-packages"
-python_moduleexecdir="${python_execprefix}/lib/python${python_version}/site-packages"
python_includespec="-I${python_prefix}/include/python${python_version}"
if test "$python_prefix" != "$python_execprefix"; then
python_includespec="-I${python_execprefix}/include/python${python_version} $python_includespec"
fi
-
-
-
echo "$as_me:$LINENO: checking how to link an embedded Python application" >&5
echo $ECHO_N "checking how to link an embedded Python application... $ECHO_C" >&6
fi
echo "$as_me:$LINENO: checking types of arguments for accept()" >&5
echo $ECHO_N "checking types of arguments for accept()... $ECHO_C" >&6
- if test "${ac_cv_func_accept_arg1+set}" = set; then
+ if test "${ac_cv_func_accept_return+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
- if test "${ac_cv_func_accept_arg2+set}" = set; then
+ if test "${ac_cv_func_accept_arg1+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
- if test "${ac_cv_func_accept_arg3+set}" = set; then
+ if test "${ac_cv_func_accept_arg2+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
- for ac_cv_func_accept_arg1 in 'int' 'unsigned int'; do
- for ac_cv_func_accept_arg2 in 'struct sockaddr *' 'const struct sockaddr *' 'void *'; do
- for ac_cv_func_accept_arg3 in 'int' 'size_t' 'socklen_t' 'unsigned int' 'void'; do
- cat >conftest.$ac_ext <<_ACEOF
+ if test "${ac_cv_func_accept_arg3+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ for ac_cv_func_accept_return in 'int' 'unsigned int PASCAL'; do
+ for ac_cv_func_accept_arg1 in 'int' 'unsigned int'; do
+ for ac_cv_func_accept_arg2 in 'struct sockaddr *' 'const struct sockaddr *' 'void *'; do
+ for ac_cv_func_accept_arg3 in 'int' 'size_t' 'socklen_t' 'unsigned int' 'void'; do
+ cat >conftest.$ac_ext <<_ACEOF
#line $LINENO "configure"
#include "confdefs.h"
#ifdef HAVE_SYS_TYPES_H
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
-extern int accept ($ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *);
+extern $ac_cv_func_accept_return accept ($ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *);
#ifdef F77_DUMMY_MAIN
# ifdef __cplusplus
extern "C"
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
- ac_not_found=no; break 3
+ ac_not_found=no; break 4
else
echo "$as_me: failed program was:" >&5
cat conftest.$ac_ext >&5
ac_not_found=yes
fi
rm -f conftest.$ac_objext conftest.$ac_ext
+ done
done
done
done
fi
fi
- echo "$as_me:$LINENO: result: $ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *" >&5
-echo "${ECHO_T}$ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *" >&6
+
+fi
+ echo "$as_me:$LINENO: result: $ac_cv_func_accept_return, $ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *" >&5
+echo "${ECHO_T}$ac_cv_func_accept_return, $ac_cv_func_accept_arg1, $ac_cv_func_accept_arg2, $ac_cv_func_accept_arg3 *" >&6
+
+cat >>confdefs.h <<_ACEOF
+#define ACCEPT_TYPE_RETURN $ac_cv_func_accept_return
+_ACEOF
+
cat >>confdefs.h <<_ACEOF
#define ACCEPT_TYPE_ARG1 $ac_cv_func_accept_arg1
+HAVE_IPV6=no
echo "$as_me:$LINENO: checking for struct sockaddr_in6" >&5
echo $ECHO_N "checking for struct sockaddr_in6... $ECHO_C" >&6
if test "${ac_cv_type_struct_sockaddr_in6+set}" = set; then
#define HAVE_IPV6 1
_ACEOF
+ HAVE_IPV6=yes
fi
fi
+
echo "$as_me:$LINENO: checking for PS_STRINGS" >&5
echo $ECHO_N "checking for PS_STRINGS... $ECHO_C" >&6
if test "${pgac_cv_var_PS_STRINGS+set}" = set; then
#
# For each platform, we need to know about any special compile and link
# libraries, and whether the normal C function names are thread-safe.
+# See the comment at the top of src/port/thread.c for more information.
#
if test "$enable_thread_safety" = yes; then
if test "${ac_cv_header_pthread_h+set}" = set; then
if test $ac_cv_header_pthread_h = yes; then
:
else
- { { echo "$as_me:$LINENO: error: pthread.h not found, required for --with-threads" >&5
-echo "$as_me: error: pthread.h not found, required for --with-threads" >&2;}
+ { { echo "$as_me:$LINENO: error: pthread.h not found, required for --enable-thread-safetys" >&5
+echo "$as_me: error: pthread.h not found, required for --enable-thread-safetys" >&2;}
{ (exit 1); exit 1; }; }
fi
Please report your platform threading info to the PostgreSQL mailing lists
so it can be added to the next release. Report all compile flags, link flags,
functions, or libraries required for threading support.
+See the comment at the top of src/port/thread.c for more information.
" >&5
echo "$as_me: error:
Cannot enable threads on your platform.
Please report your platform threading info to the PostgreSQL mailing lists
so it can be added to the next release. Report all compile flags, link flags,
functions, or libraries required for threading support.
+See the comment at the top of src/port/thread.c for more information.
" >&2;}
{ (exit 1); exit 1; }; }
fi
_LIBS="$LIBS"
CFLAGS="$CFLAGS $THREAD_CFLAGS"
LIBS="$LIBS $THREAD_LIBS"
+echo "$as_me:$LINENO: checking for strerror_r" >&5
+echo $ECHO_N "checking for strerror_r... $ECHO_C" >&6
+if test "${ac_cv_func_strerror_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char strerror_r (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char strerror_r ();
+char (*f) ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_strerror_r) || defined (__stub___strerror_r)
+choke me
+#else
+f = strerror_r;
+#endif
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_strerror_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_func_strerror_r=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_strerror_r" >&5
+echo "${ECHO_T}$ac_cv_func_strerror_r" >&6
+if test $ac_cv_func_strerror_r = yes; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: strerror_r not found, required on this platform for --enable-thread-safety" >&5
+echo "$as_me: error: strerror_r not found, required on this platform for --enable-thread-safety" >&2;}
+ { (exit 1); exit 1; }; }
+fi
-for ac_func in strerror_r getpwuid_r gethostbyname_r
-do
-as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
-echo "$as_me:$LINENO: checking for $ac_func" >&5
-echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6
-if eval "test \"\${$as_ac_var+set}\" = set"; then
+echo "$as_me:$LINENO: checking for getpwuid_r" >&5
+echo $ECHO_N "checking for getpwuid_r... $ECHO_C" >&6
+if test "${ac_cv_func_getpwuid_r+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
cat >conftest.$ac_ext <<_ACEOF
#line $LINENO "configure"
#include "confdefs.h"
/* System header to define __stub macros and hopefully few prototypes,
- which can conflict with char $ac_func (); below. */
+ which can conflict with char getpwuid_r (); below. */
#include <assert.h>
/* Override any gcc2 internal prototype to avoid an error. */
#ifdef __cplusplus
#endif
/* We use char because int might match the return type of a gcc2
builtin and then its argument prototype would still apply. */
-char $ac_func ();
+char getpwuid_r ();
char (*f) ();
#ifdef F77_DUMMY_MAIN
/* The GNU C library defines this for functions which it implements
to always fail with ENOSYS. Some functions are actually named
something starting with __ and the normal name is an alias. */
-#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+#if defined (__stub_getpwuid_r) || defined (__stub___getpwuid_r)
choke me
#else
-f = $ac_func;
+f = getpwuid_r;
#endif
;
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
- eval "$as_ac_var=yes"
+ ac_cv_func_getpwuid_r=yes
else
echo "$as_me: failed program was:" >&5
cat conftest.$ac_ext >&5
-eval "$as_ac_var=no"
+ac_cv_func_getpwuid_r=no
fi
rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
fi
-echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5
-echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6
-if test `eval echo '${'$as_ac_var'}'` = yes; then
- cat >>confdefs.h <<_ACEOF
-#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
-_ACEOF
+echo "$as_me:$LINENO: result: $ac_cv_func_getpwuid_r" >&5
+echo "${ECHO_T}$ac_cv_func_getpwuid_r" >&6
+if test $ac_cv_func_getpwuid_r = yes; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: getpwuid_r not found, required on this platform for --enable-thread-safety" >&5
+echo "$as_me: error: getpwuid_r not found, required on this platform for --enable-thread-safety" >&2;}
+ { (exit 1); exit 1; }; }
+fi
+
+echo "$as_me:$LINENO: checking for gethostbyname_r" >&5
+echo $ECHO_N "checking for gethostbyname_r... $ECHO_C" >&6
+if test "${ac_cv_func_gethostbyname_r+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char gethostbyname_r (); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+#ifdef __cplusplus
+extern "C"
+#endif
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char gethostbyname_r ();
+char (*f) ();
+#ifdef F77_DUMMY_MAIN
+# ifdef __cplusplus
+ extern "C"
+# endif
+ int F77_DUMMY_MAIN() { return 1; }
+#endif
+int
+main ()
+{
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_gethostbyname_r) || defined (__stub___gethostbyname_r)
+choke me
+#else
+f = gethostbyname_r;
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -s conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_cv_func_gethostbyname_r=yes
+else
+ echo "$as_me: failed program was:" >&5
+cat conftest.$ac_ext >&5
+ac_cv_func_gethostbyname_r=no
+fi
+rm -f conftest.$ac_objext conftest$ac_exeext conftest.$ac_ext
+fi
+echo "$as_me:$LINENO: result: $ac_cv_func_gethostbyname_r" >&5
+echo "${ECHO_T}$ac_cv_func_gethostbyname_r" >&6
+if test $ac_cv_func_gethostbyname_r = yes; then
+ :
+else
+ { { echo "$as_me:$LINENO: error: gethostbyname_r not found, required on this platform for --enable-thread-safety" >&5
+echo "$as_me: error: gethostbyname_r not found, required on this platform for --enable-thread-safety" >&2;}
+ { (exit 1); exit 1; }; }
fi
-done
CFLAGS="$_CFLAGS"
LIBS="$_LIBS"
} >&5
cat >&5 <<_CSEOF
-This file was extended by PostgreSQL $as_me 7.4beta1, which was
+This file was extended by PostgreSQL $as_me 7.4beta2, which was
generated by GNU Autoconf 2.53. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
cat >>$CONFIG_STATUS <<_ACEOF
ac_cs_version="\\
-PostgreSQL config.status 7.4beta1
+PostgreSQL config.status 7.4beta2
configured by $0, generated by GNU Autoconf 2.53,
with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\"
s,@perl_useshrplib@,$perl_useshrplib,;t t
s,@perl_embed_ldflags@,$perl_embed_ldflags,;t t
s,@PYTHON@,$PYTHON,;t t
-s,@python_version@,$python_version,;t t
s,@python_prefix@,$python_prefix,;t t
s,@python_execprefix@,$python_execprefix,;t t
s,@python_configdir@,$python_configdir,;t t
-s,@python_moduledir@,$python_moduledir,;t t
-s,@python_moduleexecdir@,$python_moduleexecdir,;t t
s,@python_includespec@,$python_includespec,;t t
s,@python_libspec@,$python_libspec,;t t
s,@LIBOBJS@,$LIBOBJS,;t t
+s,@HAVE_IPV6@,$HAVE_IPV6,;t t
s,@THREAD_CFLAGS@,$THREAD_CFLAGS,;t t
s,@THREAD_LIBS@,$THREAD_LIBS,;t t
s,@HAVE_POSIX_SIGNALS@,$HAVE_POSIX_SIGNALS,;t t
dnl Texinfo. Use this sorcery to use "docdir" instead of "infodir".
m4_define([info], [doc])
m4_define([infodir], [docdir])
m4_undefine([infodir])
m4_undefine([info])
AC_SUBST(docdir)
fi
AC_MSG_NOTICE([using CFLAGS=$CFLAGS])
+# We already have this in Makefile.win32, but configure needs it too
+if test "$PORTNAME" = "win32"
+then
+ CPPFLAGS="$CPPFLAGS -Isrc/include/port/win32"
+fi
+
# Check if the compiler still works with the template settings
AC_MSG_CHECKING([whether the C compiler still works])
AC_TRY_LINK([], [return 0;],
AC_SUBST(with_perl)
#
-# Optionally build Python interface module
+# Optionally build Python modules (PL/Python)
#
AC_MSG_CHECKING([whether to build Python modules])
-PGAC_ARG_BOOL(with, python, no, [ --with-python build Python interface module])
+PGAC_ARG_BOOL(with, python, no, [ --with-python build Python modules (PL/Python)])
AC_MSG_RESULT([$with_python])
AC_SUBST(with_python)
if test "$with_python" = yes; then
PGAC_PATH_PYTHON
- PGAC_CHECK_PYTHON_MODULE_SETUP
PGAC_CHECK_PYTHON_EMBED_SETUP
fi
AC_CHECK_DECLS(fdatasync, [], [], [#include <unistd.h>])
+HAVE_IPV6=no
AC_CHECK_TYPE([struct sockaddr_in6],
[AC_CHECK_FUNC(inet_ntop,
- [AC_DEFINE(HAVE_IPV6, 1, [Define to 1 if you have support for IPv6.])])],
+ [AC_DEFINE(HAVE_IPV6, 1, [Define to 1 if you have support for IPv6.])
+ HAVE_IPV6=yes])],
[],
[$ac_includes_default
#include <netinet/in.h>])
+AC_SUBST(HAVE_IPV6)
AC_CACHE_CHECK([for PS_STRINGS], [pgac_cv_var_PS_STRINGS],
[AC_TRY_LINK(
#
# For each platform, we need to know about any special compile and link
# libraries, and whether the normal C function names are thread-safe.
+# See the comment at the top of src/port/thread.c for more information.
#
if test "$enable_thread_safety" = yes; then
-AC_CHECK_HEADER(pthread.h, [], [AC_MSG_ERROR([pthread.h not found, required for --with-threads])])
+AC_CHECK_HEADER(pthread.h, [], [AC_MSG_ERROR([pthread.h not found, required for --enable-thread-safetys])])
if test "$SUPPORTS_THREADS" != yes; then
AC_MSG_ERROR([
Please report your platform threading info to the PostgreSQL mailing lists
so it can be added to the next release. Report all compile flags, link flags,
functions, or libraries required for threading support.
+See the comment at the top of src/port/thread.c for more information.
])
fi
else
_LIBS="$LIBS"
CFLAGS="$CFLAGS $THREAD_CFLAGS"
LIBS="$LIBS $THREAD_LIBS"
-AC_CHECK_FUNCS([strerror_r getpwuid_r gethostbyname_r])
+AC_CHECK_FUNC(strerror_r,
+ [], [AC_MSG_ERROR([strerror_r not found, required on this platform for --enable-thread-safety])])
+AC_CHECK_FUNC(getpwuid_r,
+ [], [AC_MSG_ERROR([getpwuid_r not found, required on this platform for --enable-thread-safety])])
+AC_CHECK_FUNC(gethostbyname_r,
+ [], [AC_MSG_ERROR([gethostbyname_r not found, required on this platform for --enable-thread-safety])])
CFLAGS="$_CFLAGS"
LIBS="$_LIBS"
fi
uninstall:
ifneq (,$(DATA)$(DATA_built))
- rm -f $(addprefix $(DESTDIR)$(datadir)/contrib/, $(DATA) $(DATA_built))
+ rm -f $(addprefix $(DESTDIR)$(datadir)/contrib/, $(notdir $(DATA) $(DATA_built)))
endif
ifdef MODULES
rm -f $(addprefix $(DESTDIR)$(pkglibdir)/, $(addsuffix $(DLSUFFIX), $(MODULES)))
int tokenlen;
int tsearch_yylex(void);
void start_parse_str(char *, int);
-void start_parse_fh(FILE *, int);
void end_parse(void);
#endif
YY_BUFFER_STATE buf = NULL; /* buffer to parse; it need for parse from string */
-int lrlimit = -1; /* for limiting read from filehandle ( -1 - unlimited read ) */
-int bytestoread = 0; /* for limiting read from filehandle */
-
-/* redefine macro for read limited length */
-#define YY_INPUT(buf,result,max_size) \
- if ( yy_current_buffer->yy_is_interactive ) { \
- int c = '*', n; \
- for ( n = 0; n < max_size && \
- (c = getc( tsearch_yyin )) != EOF && c != '\n'; ++n ) \
- buf[n] = (char) c; \
- if ( c == '\n' ) \
- buf[n++] = (char) c; \
- if ( c == EOF && ferror( tsearch_yyin ) ) \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- result = n; \
- } else { \
- if ( lrlimit == 0 ) \
- result=YY_NULL; \
- else { \
- if ( lrlimit>0 ) { \
- bytestoread = ( lrlimit > max_size ) ? max_size : lrlimit; \
- lrlimit -= bytestoread; \
- } else \
- bytestoread = max_size; \
- if ( ((result = fread( buf, 1, bytestoread, tsearch_yyin )) == 0) \
- && ferror( tsearch_yyin ) ) \
- YY_FATAL_ERROR( "input in flex scanner failed" ); \
- } \
- }
-
%}
%option 8bit
BEGIN INITIAL;
}
-/* start parse from filehandle */
-void start_parse_fh( FILE* fh, int limit ) {
- if (buf) end_parse();
- lrlimit = ( limit ) ? limit : -1;
- buf = tsearch_yy_create_buffer( fh, YY_BUF_SIZE );
- tsearch_yy_switch_to_buffer( buf );
- BEGIN INITIAL;
-}
-
--- /dev/null
+# $Header$
+
+subdir = contrib/tsearch2
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+
+
+MODULE_big = tsearch2
+OBJS = dict_ex.o dict.o snmap.o stopword.o common.o prs_dcfg.o \
+ dict_snowball.o dict_ispell.o dict_syn.o \
+ wparser.o wparser_def.o \
+ ts_cfg.o tsvector.o rewrite.o crc32.o query.o gistidx.o \
+ tsvector_op.o rank.o ts_stat.o
+
+SUBDIRS := snowball ispell wordparser
+SUBDIROBJS := $(SUBDIRS:%=%/SUBSYS.o)
+
+OBJS:= $(OBJS) $(SUBDIROBJS)
+
+$(SUBDIROBJS): $(SUBDIRS:%=%-recursive) ;
+
+$(SUBDIRS:%=%-recursive):
+ $(MAKE) -C $(subst -recursive,,$@) SUBSYS.o
+
+PG_CPPFLAGS = -I$(srcdir)/snowball -I$(srcdir)/ispell -I$(srcdir)/wordparser
+
+DATA = stopword/english.stop stopword/russian.stop
+DATA_built = tsearch2.sql untsearch2.sql
+DOCS = README.tsearch2
+REGRESS = tsearch2
+
+SHLIB_LINK := -lm
+
+tsearch2.sql: tsearch.sql.in
+ sed -e 's,MODULE_PATHNAME,$$libdir/$(MODULE_big),g' \
+ -e 's,DATA_PATH,$(datadir)/contrib,g' $< >$@
+
+untsearch2.sql: untsearch.sql.in
+ cp $< $@
+
+.PHONY: subclean
+clean: subclean
+
+subclean:
+ for dir in $(SUBDIRS); do $(MAKE) -C $$dir clean || exit; done
+
+include $(top_srcdir)/contrib/contrib-global.mk
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title>tsearch-v2-intro</title>
+
+<link type="text/css" rel="stylesheet" href="tsearch-V2-intro_files/tsearch.txt"></head>
+
+
+<body>
+ <div class="content">
+ <h2>Tsearch2 - Introduction</h2>
+
+ <p><a href="http://www.sai.msu.su/%7Emegera/postgres/gist/tsearch/V2/docs/tsearch-V2-intro.html">
+ [Online version]</a> of this document is available.</p>
+
+ <p>The tsearch2 module is available to add as an extension to
+ the PostgreSQL database to allow for Full Text Indexing. This
+ document is an introduction to installing, configuring, using
+ and maintaining the database with the tsearch2 module
+ activated.</p>
+
+ <p>Please, note, tsearch2 module is fully incompatible with old
+ tsearch, which is deprecated in 7.4 and will be obsoleted in
+ 7.5.</p>
+
+ <h3>USING TSEARCH2 AND POSTGRESQL FOR A WEB BASED SEARCH
+ ENGINE</h3>
+
+ <p>This documentation is provided as a short guide on how to
+ quickly get up and running with tsearch2 and PostgreSQL, for
+ those who want to implement a full text indexed based search
+ engine. It is not meant to be a complete in-depth guide into
+ the full ins and outs of the contrib/tsearch2 module, and is
+ primarily aimed at beginners who want to speed up searching of
+ large text fields, or those migrating from other database
+ systems such as MS-SQL.</p>
+
+ <p>The README.tsearch2 file included in the contrib/tsearch2
+ directory contains a brief overview and history behind tsearch.
+ This can also be found online <a href="http://www.sai.msu.su/%7Emegera/postgres/gist/tsearch/V2/">[right
+ here]</a>.</p>
+
+ <p>Further in depth documentation such as a full function
+ reference, and user guide can be found online at the <a href="http://www.sai.msu.su/%7Emegera/postgres/gist/tsearch/V2/docs/">[tsearch
+ documentation home]</a>.</p>
+
+ <h3>ACKNOWLEDGEMENTS</h3>
+
+ <p>Robert John Shepherd originally wrote this documentation for
+ the previous version of tsearch module (v1) included with the
+ postgres release. I took his documentation and updated it to
+ comply with the tsearch2 modifications.</p>
+
+ <p>Robert's original acknowledgements:</p>
+
+ <p>"Thanks to Oleg Bartunov for taking the time to answer many
+ of my questions regarding this module, and also to Teodor
+ Sigaev for clearing up the process of making your own
+ dictionaries. Plus of course a big thanks to the pair of them
+ for writing this module in the first place!"</p>
+
+ <p>I would also like to extend my thanks to the developers, and
+ Oleg Bartunov for all of his direction and help with the new
+ features of tsearch2.</p>
+
+ <h3>OVERVIEW</h3>
+
+ <p>MS-SQL provides a full text indexing (FTI) system which
+ enables the fast searching of text based fields, very useful
+ for websites (and other applications) that require a results
+ set based on key words. PostgreSQL ships with a contributed
+ module called tsearch2, which implements a special type of
+ index that can also be used for full text indexing. Further
+ more, unlike MS' offering which requires regular incremental
+ rebuilds of the text indexes themselves, tsearch2 indexes are
+ always up-to-date and keeping them so induces very little
+ overhead.</p>
+
+ <p>Before we get into the details, it is recommended that you
+ have installed and tested PostgreSQL, are reasonably familiar
+ with databases, the SQL query language and also understand the
+ basics of connecting to PostgreSQL from the local shell. This
+ document isn't intended for the complete PostgreSQL newbie, but
+ anyone with a reasonable grasp of the basics should be able to
+ follow it.</p>
+
+ <h3>INSTALLATION</h3>
+
+ <p>Starting with PostgreSQL version 7.4 tsearch2 is now
+ included in the contrib directory with the PostgreSQL sources.
+ contrib/tsearch2 is where you will find everything needed to
+ install and use tsearch2. Please note that tsearch2 will also
+ work with PostgreSQL version 7.3.x, but it is not the module
+ included with the source distribution. You will have to
+ download the module separately and install it in the same
+ fashion.</p>
+
+ <p>I installed the tsearch2 module to a PostgreSQL 7.3 database
+ from the contrib directory without squashing the original (old)
+ tsearch module. What I did was move the modules tsearch src
+ driectory into the contrib tree under the name tsearchV2.</p>
+
+ <p>Step one is to download the tsearch V2 module :</p>
+
+ <p><a href="http://www.sai.msu.su/%7Emegera/postgres/gist/tsearch/V2/">[http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/]</a>
+ (check Development History for latest stable version !)</p>
+ <pre> tar -zxvf tsearch-v2.tar.gz
+ mv tsearch2 PGSQL_SRC/contrib/
+ cd PGSQL_SRC/contrib/tsearch2
+</pre>
+
+ <p>If you are installing from PostgreSQL version 7.4 or higher,
+ you can skip those steps and just change to the
+ contrib/tsearch2 directory in the source tree and continue from
+ there.</p>
+
+ <p>Then continue with the regular building and installation
+ process</p>
+ <pre> gmake
+ gmake install
+ gmake installcheck
+</pre>
+
+ <p>That is pretty much all you have to do, unless of course you
+ get errors. However if you get those, you better go check with
+ the mailing lists over at <a href="http://www.postgresql.org/">http://www.postgresql.org</a> or
+ <a href="http://openfts.sourceforge.net/">http://openfts.sourceforge.net/</a>
+ since its never failed for me.</p>
+
+ <p>The directory in the contib/ and the directory from the
+ archive is called tsearch2. Tsearch2 is completely incompatible
+ with the previous version of tsearch. This means that both
+ versions can be installed into a single database, and migration
+ the new version may be much easier.</p>
+
+ <p>NOTE: the previous version of tsearch found in the
+ contrib/tsearch directory is depricated. ALthough it is still
+ available and included within PostgreSQL version 7.4. It will
+ be removed in version 7.5.</p>
+
+ <h3>ADDING TSEARCH2 FUNCTIONALITY TO A DATABASE</h3>
+
+ <p>We should create a database to use as an example for the
+ remainder of this file. We can call the database "ftstest". You
+ can create it from the command line like this:</p>
+ <pre> #createdb ftstest
+</pre>
+
+ <p>If you thought installation was easy, this next bit is even
+ easier. Change to the PGSQL_SRC/contrib/tsearch2 directory and
+ type:</p>
+ <pre> psql ftstest < tsearch2.sql
+</pre>
+
+ <p>The file "tsearch2.sql" holds all the wonderful little
+ goodies you need to do full text indexing. It defines numerous
+ functions and operators, and creates the needed tables in the
+ database. There will be 4 new tables created after running the
+ tsearch2.sql file : pg_ts_dict, pg_ts_parser, pg_ts_cfg,
+ pg_ts_cfgmap are added.</p>
+
+ <p>You can check out the tables if you like:</p>
+ <pre> #psql ftstest
+ ftstest=# \d
+ List of relations
+ Schema | Name | Type | Owner
+ --------+--------------+-------+----------
+ public | pg_ts_cfg | table | kopciuch
+ public | pg_ts_cfgmap | table | kopciuch
+ public | pg_ts_dict | table | kopciuch
+ public | pg_ts_parser | table | kopciuch
+ (4 rows)
+</pre>
+
+ <h3>TYPES AND FUNCTIONS PROVIDED BY TSEARCH2</h3>
+
+ <p>The first thing we can do is try out some of the types that
+ are provided for us. Lets look at the tsvector type provided
+ for us:</p>
+ <pre> SELECT 'Our first string used today'::tsvector;
+ tsvector
+ ---------------------------------------
+ 'Our' 'used' 'first' 'today' 'string'
+ (1 row)
+</pre>
+
+ <p>The results are the words used within our string. Notice
+ they are not in any particular order. The tsvector type returns
+ a string of space separated words.</p>
+ <pre> SELECT 'Our first string used today first string'::tsvector;
+ tsvector
+ -----------------------------------------------
+ 'Our' 'used' 'again' 'first' 'today' 'string'
+ (1 row)
+</pre>
+
+ <p>Notice the results string has each unique word ('first' and
+ 'string' only appear once in the tsvector value). Which of
+ course makes sense if you are searching the full text ... you
+ only need to know each unique word in the text.</p>
+
+ <p>Those examples were just casting a text field to that of
+ type tsvector. Lets check out one of the new functions created
+ by the tsearch2 module.</p>
+
+ <p>The function to_tsvector has 3 possible signatures:</p>
+ <pre> to_tsvector(oid, text);
+ to_tsvector(text, text);
+ to_tsvector(text);
+</pre>
+
+ <p>We will use the second method using two text fields. The
+ overloaded methods provide us with a way to specifiy the way
+ the searchable text is broken up into words (Stemming process).
+ Right now we will specify the 'default' configuration. See the
+ section on TSEARCH2 CONFIGURATION to learn more about this.</p>
+ <pre> SELECT to_tsvector('default',
+ 'Our first string used today first string');
+ to_tsvector
+ --------------------------------------------
+ 'use':4 'first':2,6 'today':5 'string':3,7
+ (1 row)
+</pre>
+
+ <p>The result returned from this function is of type tsvector.
+ The results came about by this reasoning: All of the words in
+ the text passed in are stemmed, or not used because they are
+ stop words defined in our configuration. Each lower case
+ morphed word is returned with all of the positons in the
+ text.</p>
+
+ <p>In this case the word "Our" is a stop word in the default
+ configuration. That means it will not be included in the
+ result. The word "first" is found at positions 2 and 6
+ (although "Our" is a stop word, it's position is maintained).
+ The word(s) positioning is maintained exactly as in the
+ original string. The word "used" is morphed to the word "use"
+ based on the default configuration for word stemming, and is
+ found at position 4. The rest of the results follow the same
+ logic. Just a reminder again ... the order of the 'word'
+ position in the output is not in any kind of order. (ie 'use':4
+ appears first)</p>
+
+ <p>If you want to view the output of the tsvector fields
+ without their positions, you can do so with the function
+ "strip(tsvector)".</p>
+ <pre> SELECT strip(to_tsvector('default',
+ 'Our first string used today first string'));
+ strip
+ --------------------------------
+ 'use' 'first' 'today' 'string'
+</pre>
+
+ <p>If you wish to know the number of unique words returned in
+ the tsvector you can do so by using the function
+ "length(tsvector)"</p>
+ <pre> SELECT length(to_tsvector('default',
+ 'Our first string used today first string'));
+ length
+ --------
+ 4
+ (1 row)
+</pre>
+
+ <p>Lets take a look at the function to_tsquery. It also has 3
+ signatures which follow the same rational as the to_tsvector
+ function:</p>
+ <pre> to_tsquery(oid, text);
+ to_tsquery(text, text);
+ to_tsquery(text);
+</pre>
+
+ <p>Lets try using the function with a single word :</p>
+ <pre> SELECT to_tsquery('default', 'word');
+ to_tsquery
+ -----------
+ 'word'
+ (1 row)
+</pre>
+
+ <p>I call the function the same way I would a to_tsvector
+ function, specifying the 'default' configuration for morphing,
+ and the result is the stemmed output 'word'.</p>
+
+ <p>Lets attempt to use the function with a string of multiple
+ words:</p>
+ <pre> SELECT to_tsquery('default', 'this is many words');
+ ERROR: Syntax error
+</pre>
+
+ <p>The function can not accept a space separated string. The
+ intention of the to_tsquery function is to return a type of
+ "tsquery" used for searching a tsvector field. What we need to
+ do is search for one to many words with some kind of logic (for
+ now simple boolean).</p>
+ <pre> SELECT to_tsquery('default', 'searching|sentence');
+ to_tsquery
+ ----------------------
+ 'search' | 'sentenc'
+ (1 row)
+</pre>
+
+ <p>Notice that the words are separated by the boolean logic
+ "OR", the text could contain boolean operators &,|,!,()
+ with their usual meaning.</p>
+
+ <p>You can not use words defined as being a stop word in your
+ configuration. The function will not fail ... you will just get
+ no result, and a NOTICE like this:</p>
+ <pre> SELECT to_tsquery('default', 'a|is&not|!the');
+ NOTICE: Query contains only stopword(s)
+ or doesn't contain lexem(s), ignored
+ to_tsquery
+ -----------
+ (1 row)
+</pre>
+
+ <p>That is a beginning to using the types, and functions
+ defined in the tsearch2 module. There are numerous more
+ functions that I have not touched on. You can read through the
+ tsearch2.sql file built when compiling to get more familiar
+ with what is included.</p>
+
+ <h3>INDEXING FIELDS IN A TABLE</h3>
+
+ <p>The next stage is to add a full text index to an existing
+ table. In this example we already have a table defined as
+ follows:</p>
+ <pre> CREATE TABLE tblMessages
+ (
+ intIndex int4,
+ strTopic varchar(100),
+ strMessage text
+ );
+</pre>
+
+ <p>We are assuming there are several rows with some kind of
+ data in them. Any data will do, just do several inserts with
+ test strings for a topic, and a message. here is some test data
+ I inserted. (yes I know it's completely useless stuff ;-) but
+ it will serve our purpose right now).</p>
+ <pre> INSERT INTO tblMessages
+ VALUES ('1', 'Testing Topic', 'Testing message data input');
+ INSERT INTO tblMessages
+ VALUES ('2', 'Movie', 'Breakfast at Tiffany\'s');
+ INSERT INTO tblMessages
+ VALUES ('3', 'Famous Author', 'Stephen King');
+ INSERT INTO tblMessages
+ VALUES ('4', 'Political Topic',
+ 'Nelson Mandella is released from prison');
+ INSERT INTO tblMessages
+ VALUES ('5', 'Nursery rhyme phrase',
+ 'Little jack horner sat in a corner');
+ INSERT INTO tblMessages
+ VALUES ('6', 'Gettysburg address quotation',
+ 'Four score and seven years ago'
+ ' our fathers brought forth on this'
+ ' continent a new nation, conceived in'
+ ' liberty and dedicated to the proposition'
+ ' that all men are created equal');
+ INSERT INTO tblMessages
+ VALUES ('7', 'Classic Rock Bands',
+ 'Led Zeppelin Grateful Dead and The Sex Pistols');
+ INSERT INTO tblMessages
+ VALUES ('8', 'My birth address',
+ '18 Sommervile road, Regina, Saskatchewan');
+ INSERT INTO tblMessages
+ VALUES ('9', 'Joke', 'knock knock : who\'s there?'
+ ' I will not finish this joke');
+ INSERT INTO tblMessages
+ VALUES ('10', 'Computer information',
+ 'My computer is a pentium III 400 mHz'
+ ' with 192 megabytes of RAM');
+</pre>
+
+ <p>The next stage is to create a special text index which we
+ will use for FTI, so we can search our table of messages for
+ words or a phrase. We do this using the SQL command:</p>
+ <pre> ALTER TABLE tblMessages ADD COLUMN idxFTI tsvector;
+</pre>
+
+ <p>Note that unlike traditional indexes, this is actually a new
+ field in the same table, which is then used (through the magic
+ of the tsearch2 operators and functions) by a special index we
+ will create in a moment.</p>
+
+ <p>The general rule for the initial insertion of data will
+ follow four steps:</p>
+ <pre> 1. update table
+ 2. vacuum full analyze
+ 3. create index
+ 4. vacuum full analyze
+</pre>
+
+ <p>The data can be updated into the table, the vacuum full
+ analyze will reclaim unused space. The index can be created on
+ the table after the data has been inserted. Having the index
+ created prior to the update will slow down the process. It can
+ be done in that manner, this way is just more efficient. After
+ the index has been created on the table, vacuum full analyze is
+ run again to update postgres's statistics (ie having the index
+ take effect).</p>
+ <pre> UPDATE tblMessages SET idxFTI=to_tsvector('default', strMessage);
+ VACUUM FULL ANALYZE;
+</pre>
+
+ <p>Note that this only inserts the field strMessage as a
+ tsvector, so if you want to also add strTopic to the
+ information stored, you should instead do the following, which
+ effectively concatenates the two fields into one before being
+ inserted into the table:</p>
+ <pre> UPDATE tblMessages
+ SET idxFTI=to_tsvector('default',coalesce(strTopic,'') ||' '|| coalesce(strMessage,''));
+ VACUUM FULL ANALYZE;
+</pre>
+
+ <p><strong>Using the coalesce function makes sure this
+ concatenation also works with NULL fields.</strong></p>
+
+ <p>We need to create the index on the column idxFTI. Keep in
+ mind that the database will update the index when some action
+ is taken. In this case we _need_ the index (The whole point of
+ Full Text INDEXINGi ;-)), so don't worry about any indexing
+ overhead. We will create an index based on the gist function.
+ GiST is an index structure for Generalized Search Tree.</p>
+ <pre> CREATE INDEX idxFTI_idx ON tblMessages USING gist(idxFTI);
+ VACUUM FULL ANALYZE;
+</pre>
+
+ <p>After you have converted all of your data and indexed the
+ column, you can select some rows to see what actually happened.
+ I will not display output here but you can play around
+ yourselves and see what happened.</p>
+
+ <p>The last thing to do is set up a trigger so every time a row
+ in this table is changed, the text index is automatically
+ updated. This is easily done using:</p>
+ <pre> CREATE TRIGGER tsvectorupdate BEFORE UPDATE OR INSERT ON tblMessages
+ FOR EACH ROW EXECUTE PROCEDURE tsearch2(idxFTI, strMessage);
+</pre>
+
+ <p>Or if you are indexing both strMessage and strTopic you
+ should instead do:</p>
+ <pre> CREATE TRIGGER tsvectorupdate BEFORE UPDATE OR INSERT ON tblMessages
+ FOR EACH ROW EXECUTE PROCEDURE
+ tsearch2(idxFTI, strTopic, strMessage);
+</pre>
+
+ <p>Before you ask, the tsearch2 function accepts multiple
+ fields as arguments so there is no need to concatenate the two
+ into one like we did before.</p>
+
+ <p>If you want to do something specific with columns, you may
+ write your very own trigger function using plpgsql or other
+ procedural languages (but not SQL, unfortunately) and use it
+ instead of <em>tsearch2</em> trigger.</p>
+
+ <p>You could however call other stored procedures from within
+ the tsearch2 function. Lets say we want to create a function to
+ remove certain characters (like the @ symbol from all
+ text).</p>
+ <pre> CREATE FUNCTION dropatsymbol(text)
+ RETURNS text AS 'select replace($1, \'@\', \' \');' LANGUAGE SQL;
+</pre>
+
+ <p>Now we can use this function within the tsearch2 function on
+ the trigger.</p>
+ <pre> DROP TRIGGER tsvectorupdate ON tblmessages;
+ CREATE TRIGGER tsvectorupdate BEFORE UPDATE OR INSERT ON tblMessages
+ FOR EACH ROW EXECUTE PROCEDURE tsearch2(idxFTI, dropatsymbol, strMessage);
+ INSERT INTO tblmessages VALUES (69, 'Attempt for dropatsymbol', '
[email protected]');
+</pre>
+
+ <p>If at this point you receive an error stating: ERROR: Can't
+ find tsearch config by locale</p>
+
+ <p>Do not worry. You have done nothing wrong. And tsearch2 is
+ not broken. All that has happened here is that the
+ configuration is setup to use a configuration based on the
+ locale of the server. All you have to do is change your default
+ configuration, or add a new one for your specific locale. See
+ the section on TSEARCH2 CONFIGURATION.</p>
+ <pre class="real"> SELECT * FROM tblmessages WHERE intindex = 69;
+
+ intindex | strtopic | strmessage | idxfti
+ ----------+--------------------------+---------------+-----------------------
+ (1 row)
+</pre>Notice that the string content was passed throught the stored
+procedure dropatsymbol. The '@' character was replaced with a
+single space ... and the output from the procedure was then stored
+in the tsvector column.
+
+ <p>This could be useful for removing other characters from
+ indexed text, or any kind of preprocessing needed to be done on
+ the text prior to insertion into the index.</p>
+
+ <h3>QUERYING A TABLE</h3>
+
+ <p>There are some examples in the README.tsearch2 file for
+ querying a table. One major difference between tsearch and
+ tsearch2 is the operator ## is no longer available. Only the
+ operator @@ is defined, using the types tsvector on one side
+ and tsquery on the other side.</p>
+
+ <p>Lets search the indexed data for the word "Test". I indexed
+ based on the the concatenation of the strTopic, and the
+ strMessage:</p>
+ <pre> SELECT intindex, strtopic FROM tblmessages
+ WHERE idxfti @@ 'test'::tsquery;
+ intindex | strtopic
+ ----------+---------------
+ 1 | Testing Topic
+ (1 row)
+</pre>
+
+ <p>The only result that matched was the row with a topic
+ "Testing Topic". Notice that the word I search for was all
+ lowercase. Let's see what happens when I query for uppercase
+ "Test".</p>
+ <pre> SELECT intindex, strtopic FROM tblmessages
+ WHERE idxfti @@ 'Test'::tsquery;
+ intindex | strtopic
+ ----------+----------
+ (0 rows)
+</pre>
+
+ <p>We get zero rows returned. The reason is because when the
+ text was inserted, it was morphed to my default configuration
+ (because of the call to to_tsvector in the UPDATE statement).
+ If there was no morphing done, and the tsvector field(s)
+ contained the word 'Text', a match would have been found.</p>
+
+ <p>Most likely the best way to query the field is to use the
+ to_tsquery function on the right hand side of the @@ operator
+ like this:</p>
+ <pre> SELECT intindex, strtopic FROM tblmessages
+ WHERE idxfti @@ to_tsquery('default', 'Test | Zeppelin');
+ intindex | strtopic
+ ----------+--------------------
+ 1 | Testing Topic
+ 7 | Classic Rock Bands
+ (2 rows)
+</pre>
+
+ <p>That query searched for all instances of "Test" OR
+ "Zeppelin". It returned two rows: the "Testing Topic" row, and
+ the "Classic Rock Bands" row. The to_tsquery function performed
+ the correct morphology upon the parameters, and searched the
+ tsvector field appropriately.</p>
+
+ <p>The last example here relates to searching for a phrase, for
+ example "minority report". This poses a problem with regard to
+ tsearch2, as it doesn't index phrases, only words. But there is
+ a way around which doesn't appear to have a significant impact
+ on query time, and that is to use a query such as the
+ following:</p>
+ <pre> SELECT intindex, strTopic FROM tblmessages
+ WHERE idxfti @@ to_tsquery('default', 'gettysburg & address')
+ AND strMessage ~* '.*men are created equal.*';
+ intindex | strtopic
+ ----------+------------------------------
+ 6 | Gettysburg address quotation
+ (1 row)
+ SELECT intindex, strTopic FROM tblmessages
+ WHERE idxfti @@ to_tsquery('default', 'gettysburg & address')
+ AND strMessage ~* '.*something that does not exist.*';
+ intindex | strtopic
+ ----------+----------
+ (0 rows)
+</pre>
+
+ <p>Of course if your indexing both strTopic and strMessage, and
+ want to search for this phrase on both, then you will have to
+ get out the brackets and extend this query a little more.</p>
+
+ <h3>TSEARCH2 CONFIGURATION</h3>
+
+ <p>Some words such as "and", "the", and "who" are automatically
+ not indexed, since they belong to a pre-existing dictionary of
+ "Stop Words" which tsearch2 does not perform indexing on. If
+ someone needs to search for "The Who" in your database, they
+ are going to have a tough time coming up with any results,
+ since both are ignored in the indexes. But there is a
+ solution.</p>
+
+ <p>Lets say we want to add a word into the stop word list for
+ english stemming. We could edit the file
+ :'/usr/local/pgsql/share/english.stop' and add a word to the
+ list. I edited mine to exclude my name from indexing:</p>
+ <pre> - Edit /usr/local/pgsql/share/english.stop
+ - Add 'andy' to the list
+ - Save the file.
+</pre>
+
+ <p>When you connect to the database, the dict_init procedure is
+ run during initialization. And in my configuration it will read
+ the stop words from the file I just edited. If you were
+ connected to the DB while editing the stop words, you will need
+ to end the current session and re-connect. When you re-connect
+ to the database, 'andy' is no longer indexed:</p>
+ <pre> SELECT to_tsvector('default', 'Andy');
+ to_tsvector
+ ------------
+ (1 row)
+</pre>
+
+ <p>Originally I would get the result :</p>
+ <pre> SELECT to_tsvector('default', 'Andy');
+ to_tsvector
+ ------------
+ 'andi':1
+ (1 row)
+</pre>
+
+ <p>But since I added it as a stop word, it would be ingnored on
+ the indexing. The stop word added was used in the dictionary
+ "en_stem". If I were to use a different configuration such as
+ 'simple', the results would be different. There are no stop
+ words for the simple dictionary. It will just convert to lower
+ case, and index every unique word.</p>
+ <pre> SELECT to_tsvector('simple', 'Andy andy The the in out');
+ to_tsvector
+ -------------------------------------
+ 'in':5 'out':6 'the':3,4 'andy':1,2
+ (1 row)
+</pre>
+
+ <p>All this talk about which configuration to use is leading us
+ into the actual configuration of tsearch2. In the examples in
+ this document the configuration has always been specified when
+ using the tsearch2 functions:</p>
+ <pre> SELECT to_tsvector('default', 'Testing the default config');
+ SELECT to_tsvector('simple', 'Example of simple Config');
+</pre>
+
+ <p>The pg_ts_cfg table holds each configuration you can use
+ with the tsearch2 functions. As you can see the ts_name column
+ contains both the 'default' configurations based on the 'C'
+ locale. And the 'simple' configuration which is not based on
+ any locale.</p>
+ <pre> SELECT * from pg_ts_cfg;
+ ts_name | prs_name | locale
+ -----------------+----------+--------------
+ default | default | C
+ default_russian | default | ru_RU.KOI8-R
+ simple | default |
+ (3 rows)
+</pre>
+
+ <p>Each row in the pg_ts_cfg table contains the name of the
+ tsearch2 configuration, the name of the parser to use, and the
+ locale mapped to the configuration. There is only one parser to
+ choose from the table pg_ts_parser called 'default'. More
+ parsers could be written, but for our needs we will use the
+ default.</p>
+
+ <p>There are 3 configurations installed by tsearch2 initially.
+ If your locale is set to 'en_US' for example (like my laptop),
+ then as you can see there is currently no dictionary configured
+ to use with that locale. You can either set up a new
+ configuration or just use one that already exists. If I do not
+ specify which configuration to use in the to_tsvector function,
+ I receive the following error.</p>
+ <pre> SELECT to_tsvector('learning tsearch is like going to school');
+ ERROR: Can't find tsearch config by locale
+</pre>
+
+ <p>We will create a new configuration for use with the server
+ encoding 'en_US'. The first step is to add a new configuration
+ into the pg_ts_cfg table. We will call the configuration
+ 'default_english', with the default parser and use the locale
+ 'en_US'.</p>
+ <pre> INSERT INTO pg_ts_cfg (ts_name, prs_name, locale)
+ VALUES ('default_english', 'default', 'en_US');
+</pre>
+
+ <p>We have only declared that there is a configuration called
+ 'default_english'. We need to set the configuration of how
+ 'default_english' will work. The next step is creating a new
+ dictionary to use. The configuration of the dictionary is
+ completlely different in tsearch2. In the prior versions to
+ make changes, you would have to re-compile your changes into
+ the tsearch.so. All of the configuration has now been moved
+ into the system tables created by executing the SQL code from
+ tsearch2.sql</p>
+
+ <p>Lets take a first look at the pg_ts_dict table</p>
+ <pre> ftstest=# \d pg_ts_dict
+ Table "public.pg_ts_dict"
+ Column | Type | Modifiers
+ -----------------+---------+-----------
+ dict_name | text | not null
+ dict_init | oid |
+ dict_initoption | text |
+ dict_lexize | oid | not null
+ dict_comment | text |
+ Indexes: pg_ts_dict_idx unique btree (dict_name)
+</pre>
+
+ <p>The dict_name column is the name of the dictionary, for
+ example 'simple', 'en_stem' or 'ru_stem'. The dict_init column
+ is an OID of a stored procedure to run for initialization of
+ that dictionary, for example 'snb_en_init' or 'snb_ru_init'.
+ The dict_init option is used for options passed to the init
+ function for the stored procedure. In the cases of 'en_stem' or
+ 'ru_stem' it is a path to a stopword file for that dictionary,
+ for example '/usr/local/pgsql/share/english.stop'. This is
+ however dictated by the dictionary. ISpell dictionaries may
+ require different options. The dict_lemmatize column is another
+ OID of a stored procedure to the function used to lemmitize,
+ for example 'snb_lemmatize'. The dict_comment column is just a
+ comment.</p>
+
+ <p>Next we will configure the use of a new dictionary based on
+ ISpell. We will assume you have ISpell installed on you
+ machine. (in /usr/local/lib)</p>
+
+ <p>There has been some confusion in the past as to which files
+ are used from ISpell. ISpell operates using a hash file. This
+ is a binary file created by the ISpell command line utility
+ "buildhash". This utility accepts a file containing the words
+ from the dictionary, and the affixes file and the output is the
+ hash file. The default installation of ISPell installs the
+ english hash file english.hash, which is the exact same file as
+ american.hash. ISpell uses this as the fallback dictionary to
+ use.</p>
+
+ <p>This hash file is not what tsearch2 requires as the ISpell
+ interface. The file(s) needed are those used to create the
+ hash. Tsearch uses the dictionary words for morphology, so the
+ listing is needed not spellchecking. Regardless, these files
+ are included in the ISpell sources, and you can use them to
+ integrate into tsearch2. This is not complicated, but is not
+ very obvious to begin with. The tsearch2 ISpell interface needs
+ only the listing of dictionary words, it will parse and load
+ those words, and use the ISpell dictionary for lexem
+ processing.</p>
+
+ <p>I found the ISPell make system to be very finicky. Their
+ documentation actually states this to be the case. So I just
+ did things the command line way. In the ISpell source tree
+ under langauges/english there are several files in this
+ directory. For a complete description, please read the ISpell
+ README. Basically for the english dictionary there is the
+ option to create the small, medium, large and extra large
+ dictionaries. The medium dictionary is recommended. If the make
+ system is configured correctly, it would build and install the
+ english.has file from the medium size dictionary. Since we are
+ only concerned with the dictionary word listing ... it can be
+ created from the /languages/english directory with the
+ following command:</p>
+ <pre> sort -u -t/ +0f -1 +0 -T /usr/tmp -o english.med english.0 english.1
+</pre>
+
+ <p>This will create a file called english.med. You can copy
+ this file to whever you like. I place mine in /usr/local/lib so
+ it coincides with the ISpell hash files. You can now add the
+ tsearch2 configuration entry for the ISpell english dictionary.
+ We will also continue to use the english word stop file that
+ was installed for the en_stem dictionary. You could use a
+ different one if you like. The ISpell configuration is based on
+ the "ispell_template" dictionary installed by default with
+ tsearch2. We will use the OIDs to the stored procedures from
+ the row where the dict_name = 'ispell_template'.</p>
+ <pre> INSERT INTO pg_ts_dict
+ (SELECT 'en_ispell',
+ dict_init,
+ 'DictFile="/usr/local/lib/english.med",'
+ 'AffFile="/usr/local/lib/english.aff",'
+ 'StopFile="/usr/local/pgsql/share/english.stop"',
+ dict_lexize
+ FROM pg_ts_dict
+ WHERE dict_name = 'ispell_template');
+</pre>
+
+ <p>Now that we have a dictionary we can specify it's use in a
+ query to get a lexem. For this we will use the lexize function.
+ The lexize function takes the name of the dictionary to use as
+ an argument. Just as the other tsearch2 functions operate.</p>
+ <pre> SELECT lexize('en_ispell', 'program');
+ lexize
+ -----------
+ {program}
+ (1 row)
+</pre>
+
+ <p>If you wanted to always use the ISpell english dictionary
+ you have installed, you can configure tsearch2 to always use a
+ specific dictionary.</p>
+ <pre> SELCECT set_curdict('en_ispell');
+</pre>
+
+ <p>Lexize is meant to turn a word into a lexem. It is possible
+ to receive more than one lexem returned for a single word.</p>
+ <pre> SELECT lexize('en_ispell', 'conditionally');
+ lexize
+ -----------------------------
+ {conditionally,conditional}
+ (1 row)
+</pre>
+
+ <p>The lexize function is not meant to take a full string as an
+ argument to return lexems for. If you passed in an entire
+ sentence, it attempts to find that entire sentence in the
+ dictionary. SInce the dictionary contains only words, you will
+ receive an empty result set back.</p>
+ <pre> SELECT lexize('en_ispell', 'This is a senctece to lexize');
+ lexize
+ --------
+
+ (1 row)
+
+If you parse a lexem from a word not in the dictionary, then you will receive an empty result. This makes sense because the word "tsearch" is not int the english dictionary. You can create your own additions to the dictionary if you like. This may be useful for scientific or technical glossaries that need to be indexed. SELECT lexize('en_ispell', 'tsearch'); lexize -------- (1 row)
+</pre>
+
+ <p>This is not to say that tsearch will be ignored when adding
+ text information to the the tsvector index column. This will be
+ explained in greater detail with the table pg_ts_cfgmap.</p>
+
+ <p>Next we need to set up the configuration for mapping the
+ dictionay use to the lexxem parsings. This will be done by
+ altering the pg_ts_cfgmap table. We will insert several rows,
+ specifying to using the new dictionary we installed and
+ configured for use within tsearch2. There are several type of
+ lexims we would be concerned with forcing the use of the ISpell
+ dictionary.</p>
+ <pre> INSERT INTO pg_ts_cfgmap (ts_name, tok_alias, dict_name)
+ VALUES ('default_english', 'lhword', '{en_ispell,en_stem}');
+ INSERT INTO pg_ts_cfgmap (ts_name, tok_alias, dict_name)
+ VALUES ('default_english', 'lpart_hword', '{en_ispell,en_stem}');
+ INSERT INTO pg_ts_cfgmap (ts_name, tok_alias, dict_name)
+ VALUES ('default_english', 'lword', '{en_ispell,en_stem}');
+</pre>
+
+ <p>We have just inserted 3 records to the configuration
+ mapping, specifying that the lexem types for "lhword,
+ lpart_hword and lword" are to be stemmed using the 'en_ispell'
+ dictionary we added into pg_ts_dict, when using the
+ configuration ' default_english' which we added to
+ pg_ts_cfg.</p>
+
+ <p>There are several other lexem types used that we do not need
+ to specify as using the ISpell dictionary. We can simply insert
+ values using the 'simple' stemming process dictionary.</p>
+ <pre> INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'url', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'host', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'sfloat', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'uri', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'int', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'float', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'email', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'word', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'hword', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'nlword', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'nlpart_hword', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'part_hword', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'nlhword', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'file', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'uint', '{simple}');
+ INSERT INTO pg_ts_cfgmap
+ VALUES ('default_english', 'version', '{simple}');
+</pre>
+
+ <p>Our addition of a configuration for 'default_english' is now
+ complete. We have successfully created a new tsearch2
+ configuration. At the same time we have also set the new
+ configuration to be our default for en_US locale.</p>
+ <pre> SELECT to_tsvector('default_english',
+ 'learning tsearch is like going to school');
+ to_tsvector
+ --------------------------------------------------
+ 'go':5 'like':4 'learn':1 'school':7 'tsearch':2
+ SELECT to_tsvector('learning tsearch is like going to school');
+ to_tsvector
+ --------------------------------------------------
+ 'go':5 'like':4 'learn':1 'school':7 'tsearch':2
+ (1 row)
+</pre>
+
+ <p>Notice here that words like "tsearch" are still parsed and
+ indexed in the tsvector column. There is a lexem returned for
+ the word becuase in the configuration mapping table, we specify
+ words to be used from the 'en_ispell' dictionary first, but as
+ a fallback to use the 'en_stem' dictionary. Therefore a lexem
+ is not returned from en_ispell, but is returned from en_stem,
+ and added to the tsvector.</p>
+ <pre> SELECT to_tsvector('learning tsearch is like going to computer school');
+ to_tsvector
+ ---------------------------------------------------------------------------
+ 'go':5 'like':4 'learn':1 'school':8 'compute':7 'tsearch':2 'computer':7
+ (1 row)
+</pre>
+
+ <p>Notice in this last example I added the word "computer" to
+ the text to be converted into a tsvector. Because we have setup
+ our default configuration to use the ISpell english dictionary,
+ the words are lexized, and computer returns 2 lexems at the
+ same position. 'compute':7 and 'computer':7 are now both
+ indexed for the word computer.</p>
+
+ <p>You can create additional dictionarynlists, or use the extra
+ large dictionary from ISpell. You can read through the ISpell
+ documents, and source tree to make modifications as you see
+ fit.</p>
+
+ <p>In the case that you already have a configuration set for
+ the locale, and you are changing it to your new dictionary
+ configuration. You will have to set the old locale to NULL. If
+ we are using the 'C' locale then we would do this:</p>
+ <pre> UPDATE pg_ts_cfg SET locale=NULL WHERE locale = 'C';
+</pre>
+
+ <p>That about wraps up the configuration of tsearch2. There is
+ much more you can do with the tables provided. This was just an
+ introduction to get things working rather quickly.</p>
+
+ <h3>ADDING NEW DICTIONARIES TO TSEARCH2</h3>
+
+ <p>To aid in the addition of new dictionaries to the tsearch2
+ module you can use another additional module in combination
+ with tsearch2. The gendict module is included into tsearch2
+ distribution and is available from gendict/ subdirectory.</p>
+
+ <p>I will not go into detail about installation and
+ instructions on how to use gendict to it's fullest extent right
+ now. You can read the README.gendict ... it has all of the
+ instructions and information you will need.</p>
+
+ <h3>BACKING UP AND RESTORING DATABASES THAT FEATURE
+ TSEARCH2</h3>
+
+ <p>Believe it or not, this isn't as straight forward as it
+ should be, and you will have problems trying to backup and
+ restore any database which uses tsearch2 unless you take the
+ steps shown below. And before you ask using pg_dumpall will
+ result in failure every time. These took a lot of trial and
+ error to get working, but the process as laid down below has
+ been used a dozen times now in live production environments so
+ it should work fine.</p>
+
+ <p>HOWEVER never rely on anyone elses instructions to backup
+ and restore a database system, always develop and understand
+ your own methodology, and test it numerous times before you
+ need to do it for real.</p>
+
+ <p>To Backup a PostgreSQL database that uses the tsearch2
+ module:</p>
+
+ <p>1) Backup any global database objects such as users and
+ groups (this step is usually only necessary when you will be
+ restoring to a virgin system)</p>
+ <pre> pg_dumpall -g > GLOBALobjects.sql
+</pre>
+
+ <p>2) Backup the full database schema using pg_dump</p>
+ <pre> pg_dump -s DATABASE > DATABASEschema.sql
+</pre>
+
+ <p>3) Backup the full database using pg_dump</p>
+ <pre> pg_dump -Fc DATABASE > DATABASEdata.tar
+</pre>
+
+ <p>To Restore a PostgreSQL database that uses the tsearch2
+ module:</p>
+
+ <p>1) Create the blank database</p>
+ <pre> createdb DATABASE
+</pre>
+
+ <p>2) Restore any global database objects such as users and
+ groups (this step is usually only necessary when you will be
+ restoring to a virgin system)</p>
+ <pre> psql DATABASE < GLOBALobjects.sql
+</pre>
+
+ <p>3) Create the tsearch2 objects, functions and operators</p>
+ <pre> psql DATABASE < tsearch2.sql
+</pre>
+
+ <p>4) Edit the backed up database schema and delete all SQL
+ commands which create tsearch2 related functions, operators and
+ data types, BUT NOT fields in table definitions that specify
+ tsvector types. If your not sure what these are, they are the
+ ones listed in tsearch2.sql. Then restore the edited schema to
+ the database</p>
+ <pre> psql DATABASE < DATABASEschema.sql
+</pre>
+
+ <p>5) Restore the data for the database</p>
+ <pre> pg_restore -N -a -d DATABASE DATABASEdata.tar
+</pre>
+
+ <p>If you get any errors in step 4, it will most likely be
+ because you forgot to remove an object that was created in
+ tsearch2.sql. Any errors in step 5 will mean the database
+ schema was probably restored wrongly.</p>
+ </div>
+</body></html>
\ No newline at end of file
--- /dev/null
+--
+-- first, define the datatype. Turn off echoing so that expected file
+-- does not depend on contents of seg.sql.
+--
+\set ECHO none
+psql:tsearch2.sql:13: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "pg_ts_dict_pkey" for table "pg_ts_dict"
+psql:tsearch2.sql:145: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "pg_ts_parser_pkey" for table "pg_ts_parser"
+psql:tsearch2.sql:244: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "pg_ts_cfg_pkey" for table "pg_ts_cfg"
+psql:tsearch2.sql:251: NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "pg_ts_cfgmap_pkey" for table "pg_ts_cfgmap"
+psql:tsearch2.sql:339: NOTICE: type "tsvector" is not yet defined
+DETAIL: Creating a shell type definition.
+psql:tsearch2.sql:344: NOTICE: argument type tsvector is only a shell
+psql:tsearch2.sql:398: NOTICE: type "tsquery" is not yet defined
+DETAIL: Creating a shell type definition.
+psql:tsearch2.sql:403: NOTICE: argument type tsquery is only a shell
+psql:tsearch2.sql:545: NOTICE: type "gtsvector" is not yet defined
+DETAIL: Creating a shell type definition.
+psql:tsearch2.sql:550: NOTICE: argument type gtsvector is only a shell
+--tsvector
+SELECT '1'::tsvector;
+ tsvector
+----------
+ '1'
+(1 row)
+
+SELECT '1 '::tsvector;
+ tsvector
+----------
+ '1'
+(1 row)
+
+SELECT ' 1'::tsvector;
+ tsvector
+----------
+ '1'
+(1 row)
+
+SELECT ' 1 '::tsvector;
+ tsvector
+----------
+ '1'
+(1 row)
+
+SELECT '1 2'::tsvector;
+ tsvector
+----------
+ '1' '2'
+(1 row)
+
+SELECT '\'1 2\''::tsvector;
+ tsvector
+----------
+ '1 2'
+(1 row)
+
+SELECT '\'1 \\\'2\''::tsvector;
+ tsvector
+----------
+ '1 \'2'
+(1 row)
+
+SELECT '\'1 \\\'2\'3'::tsvector;
+ tsvector
+-------------
+ '3' '1 \'2'
+(1 row)
+
+SELECT '\'1 \\\'2\' 3'::tsvector;
+ tsvector
+-------------
+ '3' '1 \'2'
+(1 row)
+
+SELECT '\'1 \\\'2\' \' 3\' 4 '::tsvector;
+ tsvector
+------------------
+ '4' ' 3' '1 \'2'
+(1 row)
+
+select '\'w\':4A,3B,2C,1D,5 a:8';
+ ?column?
+-----------------------
+ 'w':4A,3B,2C,1D,5 a:8
+(1 row)
+
+select 'a:3A b:2a'::tsvector || 'ba:1234 a:1B';
+ ?column?
+----------------------------
+ 'a':3A,4B 'b':2A 'ba':1237
+(1 row)
+
+select setweight('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd zxc:81,567,222A'::tsvector, 'c');
+ setweight
+----------------------------------------------------------
+ 'a':1C,3C 'w':5C,6C,12C,13C 'asd':1C 'zxc':81C,222C,567C
+(1 row)
+
+select strip('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd'::tsvector);
+ strip
+---------------
+ 'a' 'w' 'asd'
+(1 row)
+
+--tsquery
+SELECT '1'::tsquery;
+ tsquery
+---------
+ '1'
+(1 row)
+
+SELECT '1 '::tsquery;
+ tsquery
+---------
+ '1'
+(1 row)
+
+SELECT ' 1'::tsquery;
+ tsquery
+---------
+ '1'
+(1 row)
+
+SELECT ' 1 '::tsquery;
+ tsquery
+---------
+ '1'
+(1 row)
+
+SELECT '\'1 2\''::tsquery;
+ tsquery
+---------
+ '1 2'
+(1 row)
+
+SELECT '\'1 \\\'2\''::tsquery;
+ tsquery
+---------
+ '1 \'2'
+(1 row)
+
+SELECT '!1'::tsquery;
+ tsquery
+---------
+ !'1'
+(1 row)
+
+SELECT '1|2'::tsquery;
+ tsquery
+-----------
+ '1' | '2'
+(1 row)
+
+SELECT '1|!2'::tsquery;
+ tsquery
+------------
+ '1' | !'2'
+(1 row)
+
+SELECT '!1|2'::tsquery;
+ tsquery
+------------
+ !'1' | '2'
+(1 row)
+
+SELECT '!1|!2'::tsquery;
+ tsquery
+-------------
+ !'1' | !'2'
+(1 row)
+
+SELECT '!(!1|!2)'::tsquery;
+ tsquery
+------------------
+ !( !'1' | !'2' )
+(1 row)
+
+SELECT '!(!1|2)'::tsquery;
+ tsquery
+-----------------
+ !( !'1' | '2' )
+(1 row)
+
+SELECT '!(1|!2)'::tsquery;
+ tsquery
+-----------------
+ !( '1' | !'2' )
+(1 row)
+
+SELECT '!(1|2)'::tsquery;
+ tsquery
+----------------
+ !( '1' | '2' )
+(1 row)
+
+SELECT '1&2'::tsquery;
+ tsquery
+-----------
+ '1' & '2'
+(1 row)
+
+SELECT '!1&2'::tsquery;
+ tsquery
+------------
+ !'1' & '2'
+(1 row)
+
+SELECT '1&!2'::tsquery;
+ tsquery
+------------
+ '1' & !'2'
+(1 row)
+
+SELECT '!1&!2'::tsquery;
+ tsquery
+-------------
+ !'1' & !'2'
+(1 row)
+
+SELECT '(1&2)'::tsquery;
+ tsquery
+-----------
+ '1' & '2'
+(1 row)
+
+SELECT '1&(2)'::tsquery;
+ tsquery
+-----------
+ '1' & '2'
+(1 row)
+
+SELECT '!(1)&2'::tsquery;
+ tsquery
+------------
+ !'1' & '2'
+(1 row)
+
+SELECT '!(1&2)'::tsquery;
+ tsquery
+----------------
+ !( '1' & '2' )
+(1 row)
+
+SELECT '1|2&3'::tsquery;
+ tsquery
+-----------------
+ '1' | '2' & '3'
+(1 row)
+
+SELECT '1|(2&3)'::tsquery;
+ tsquery
+-----------------
+ '1' | '2' & '3'
+(1 row)
+
+SELECT '(1|2)&3'::tsquery;
+ tsquery
+---------------------
+ ( '1' | '2' ) & '3'
+(1 row)
+
+SELECT '1|2&!3'::tsquery;
+ tsquery
+------------------
+ '1' | '2' & !'3'
+(1 row)
+
+SELECT '1|!2&3'::tsquery;
+ tsquery
+------------------
+ '1' | !'2' & '3'
+(1 row)
+
+SELECT '!1|2&3'::tsquery;
+ tsquery
+------------------
+ !'1' | '2' & '3'
+(1 row)
+
+SELECT '!1|(2&3)'::tsquery;
+ tsquery
+------------------
+ !'1' | '2' & '3'
+(1 row)
+
+SELECT '!(1|2)&3'::tsquery;
+ tsquery
+----------------------
+ !( '1' | '2' ) & '3'
+(1 row)
+
+SELECT '(!1|2)&3'::tsquery;
+ tsquery
+----------------------
+ ( !'1' | '2' ) & '3'
+(1 row)
+
+SELECT '1|(2|(4|(5|6)))'::tsquery;
+ tsquery
+-----------------------------------------
+ '1' | ( '2' | ( '4' | ( '5' | '6' ) ) )
+(1 row)
+
+SELECT '1|2|4|5|6'::tsquery;
+ tsquery
+-----------------------------------------
+ ( ( ( '1' | '2' ) | '4' ) | '5' ) | '6'
+(1 row)
+
+SELECT '1&(2&(4&(5&6)))'::tsquery;
+ tsquery
+-----------------------------
+ '1' & '2' & '4' & '5' & '6'
+(1 row)
+
+SELECT '1&2&4&5&6'::tsquery;
+ tsquery
+-----------------------------
+ '1' & '2' & '4' & '5' & '6'
+(1 row)
+
+SELECT '1&(2&(4&(5|6)))'::tsquery;
+ tsquery
+---------------------------------
+ '1' & '2' & '4' & ( '5' | '6' )
+(1 row)
+
+SELECT '1&(2&(4&(5|!6)))'::tsquery;
+ tsquery
+----------------------------------
+ '1' & '2' & '4' & ( '5' | !'6' )
+(1 row)
+
+SELECT '1&(\'2\'&(\' 4\'&(\\|5 | \'6 \\\' !|&\')))'::tsquery;
+ tsquery
+------------------------------------------
+ '1' & '2' & ' 4' & ( '|5' | '6 \' !|&' )
+(1 row)
+
+SELECT '\'the wether\':dc & \' sKies \':BC & a:d b:a';
+ ?column?
+------------------------------------------
+ 'the wether':dc & ' sKies ':BC & a:d b:a
+(1 row)
+
+select lexize('simple', 'ASD56 hsdkf');
+ lexize
+-----------------
+ {"asd56 hsdkf"}
+(1 row)
+
+select lexize('en_stem', 'SKIES Problems identity');
+ lexize
+--------------------------
+ {"skies problems ident"}
+(1 row)
+
+select * from token_type('default');
+ tokid | alias | descr
+-------+--------------+-----------------------------------
+ 1 | lword | Latin word
+ 2 | nlword | Non-latin word
+ 3 | word | Word
+ 4 | email | Email
+ 5 | url | URL
+ 6 | host | Host
+ 7 | sfloat | Scientific notation
+ 8 | version | VERSION
+ 9 | part_hword | Part of hyphenated word
+ 10 | nlpart_hword | Non-latin part of hyphenated word
+ 11 | lpart_hword | Latin part of hyphenated word
+ 12 | blank | Space symbols
+ 13 | tag | HTML Tag
+ 14 | http | HTTP head
+ 15 | hword | Hyphenated word
+ 16 | lhword | Latin hyphenated word
+ 17 | nlhword | Non-latin hyphenated word
+ 18 | uri | URI
+ 19 | file | File or path name
+ 20 | float | Decimal notation
+ 21 | int | Signed integer
+ 22 | uint | Unsigned integer
+ 23 | entity | HTML Entity
+(23 rows)
+
+select * from parse('default', '345
[email protected] \' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe 234.435 455 5.005
[email protected] qwe-wer asdf <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>">
+/usr/local/fff /awdf/dwqe/4325 rewt/ewr wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234
+<i <b> wow < jqw <> qwerty');
+ tokid | token
+-------+--------------------------------------
+ 22 | 345
+ 12 |
+ 12 |
+ 12 | '
+ 12 |
+ 14 | http://
+ 6 | www.com
+ 12 | /
+ 12 |
+ 14 | http://
+ 5 | aew.werc.ewr/?ad=qwe&dw
+ 6 | aew.werc.ewr
+ 18 | /?ad=qwe&dw
+ 12 |
+ 5 | 1aew.werc.ewr/?ad=qwe&dw
+ 6 | 1aew.werc.ewr
+ 18 | /?ad=qwe&dw
+ 12 |
+ 6 | 2aew.werc.ewr
+ 12 |
+ 14 | http://
+ 5 | 3aew.werc.ewr/?ad=qwe&dw
+ 6 | 3aew.werc.ewr
+ 18 | /?ad=qwe&dw
+ 12 |
+ 14 | http://
+ 6 | 4aew.werc.ewr
+ 12 |
+ 14 | http://
+ 5 | 5aew.werc.ewr:8100/?
+ 6 | 5aew.werc.ewr
+ 18 | :8100/?
+ 12 |
+ 1 | ad
+ 12 | =
+ 1 | qwe
+ 12 | &
+ 1 | dw
+ 12 |
+ 5 | 6aew.werc.ewr:8100/?ad=qwe&dw
+ 6 | 6aew.werc.ewr
+ 18 | :8100/?ad=qwe&dw
+ 12 |
+ 5 | 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32
+ 6 | 7aew.werc.ewr
+ 18 | :8100/?ad=qwe&dw=%20%32
+ 12 |
+ 7 | +4.0e-10
+ 12 |
+ 1 | qwe
+ 12 |
+ 1 | qwe
+ 12 |
+ 1 | qwqwe
+ 12 |
+ 20 | 234.435
+ 12 |
+ 22 | 455
+ 12 |
+ 20 | 5.005
+ 12 |
+ 12 |
+ 16 | qwe-wer
+ 11 | qwe
+ 12 | -
+ 11 | wer
+ 12 |
+ 1 | asdf
+ 12 |
+ 13 |
+ 1 | qwer
+ 12 |
+ 1 | jf
+ 12 |
+ 1 | sdjk
+ 13 |
+ 12 |
+ 3 | ewr1
+ 12 | >
+ 12 |
+ 3 | ewri2
+ 12 |
+ 13 |
+ 12 |
+
+ 19 | /usr/local/fff
+ 12 |
+ 19 | /awdf/dwqe/4325
+ 12 |
+ 19 | rewt/ewr
+ 12 |
+ 1 | wefjn
+ 12 |
+ 19 | /wqe-324/ewr
+ 12 |
+ 6 | gist.h
+ 12 |
+ 6 | gist.h.c
+ 12 |
+ 6 | gist.c
+ 12 | .
+ 12 |
+ 1 | readline
+ 12 |
+ 20 | 4.2
+ 12 |
+ 20 | 4.2
+ 12 | .
+ 12 |
+ 20 | 4.2
+ 12 | ,
+ 12 |
+ 15 | readline-4
+ 11 | readline
+ 12 | -
+ 20 | 4.2
+ 12 |
+ 15 | readline-4
+ 11 | readline
+ 12 | -
+ 20 | 4.2
+ 12 | .
+ 12 |
+ 22 | 234
+ 12 |
+
+ 13 |
+ 12 |
+ 1 | wow
+ 12 |
+ 12 | <
+ 12 |
+ 1 | jqw
+ 12 |
+ 12 | <
+ 12 | >
+ 12 |
+ 1 | qwerty
+(138 rows)
+
+SELECT to_tsvector('default', '345
[email protected] \' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe 234.435 455 5.005
[email protected] qwe-wer asdf <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>">
+/usr/local/fff /awdf/dwqe/4325 rewt/ewr wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234
+<i <b> wow < jqw <> qwerty');
+ to_tsvector
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ 'ad':18 'dw':20 'jf':40 '234':62 '345':1 '4.2':53,54,55,58,61 '455':32 'jqw':64 'qwe':19,28,29,36 'wer':37 'wow':63 'asdf':38 'ewr1':42 'qwer':39 'sdjk':41 '5.005':33 'ewri2':43 'qwqwe':30 'wefjn':47 'gist.c':51 'gist.h':49 'qwerti':65 '234.435':31 ':8100/?':17 'qwe-wer':35 'readlin':52,57,60 'www.com':3 '+4.0e-10':27 'gist.h.c':50 'rewt/ewr':46 '
[email protected]':2 'readline-4':56,59 '/?ad=qwe&dw':6,9,13 '/wqe-324/ewr':48 'aew.werc.ewr':5 '1aew.werc.ewr':8 '2aew.werc.ewr':10 '3aew.werc.ewr':12 '4aew.werc.ewr':14 '5aew.werc.ewr':16 '6aew.werc.ewr':22 '7aew.werc.ewr':25 '/usr/local/fff':44 '/awdf/dwqe/4325':45 ':8100/?ad=qwe&dw':23 '
[email protected]':34 '5aew.werc.ewr:8100/?':15 ':8100/?ad=qwe&dw=%20%32':26 'aew.werc.ewr/?ad=qwe&dw':4 '1aew.werc.ewr/?ad=qwe&dw':7 '3aew.werc.ewr/?ad=qwe&dw':11 '6aew.werc.ewr:8100/?ad=qwe&dw':21 '7aew.werc.ewr:8100/?ad=qwe&dw=%20%32':24
+(1 row)
+
+SELECT length(to_tsvector('default', '345 qw'));
+ length
+--------
+ 2
+(1 row)
+
+SELECT length(to_tsvector('default', '345
[email protected] \' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe 234.435 455 5.005
[email protected] qwe-wer asdf <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>">
+/usr/local/fff /awdf/dwqe/4325 rewt/ewr wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234
+<i <b> wow < jqw <> qwerty'));
+ length
+--------
+ 53
+(1 row)
+
+select to_tsquery('default', 'qwe & sKies ');
+ to_tsquery
+---------------
+ 'qwe' & 'sky'
+(1 row)
+
+select to_tsquery('simple', 'qwe & sKies ');
+ to_tsquery
+-----------------
+ 'qwe' & 'skies'
+(1 row)
+
+select to_tsquery('default', '\'the wether\':dc & \' sKies \':BC ');
+ to_tsquery
+------------------------
+ 'wether':CD & 'sky':BC
+(1 row)
+
+select to_tsquery('asd&(and|fghj)');
+ to_tsquery
+----------------
+ 'asd' & 'fghj'
+(1 row)
+
+select to_tsquery('(asd&and)|fghj');
+ to_tsquery
+----------------
+ 'asd' | 'fghj'
+(1 row)
+
+select to_tsquery('(asd&!and)|fghj');
+ to_tsquery
+----------------
+ 'asd' | 'fghj'
+(1 row)
+
+select to_tsquery('(the|and&(i&1))&fghj');
+ to_tsquery
+--------------
+ '1' & 'fghj'
+(1 row)
+
+select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca';
+ ?column?
+----------
+ t
+(1 row)
+
+select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca:B';
+ ?column?
+----------
+ t
+(1 row)
+
+select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca:A';
+ ?column?
+----------
+ t
+(1 row)
+
+select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca:C';
+ ?column?
+----------
+ f
+(1 row)
+
+select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca:CB';
+ ?column?
+----------
+ t
+(1 row)
+
+CREATE TABLE test_tsvector( t text, a tsvector );
+\copy test_tsvector from 'data/test_tsearch.data'
+SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh';
+ count
+-------
+ 158
+(1 row)
+
+SELECT count(*) FROM test_tsvector WHERE a @@ 'wr&qh';
+ count
+-------
+ 17
+(1 row)
+
+SELECT count(*) FROM test_tsvector WHERE a @@ 'eq&yt';
+ count
+-------
+ 6
+(1 row)
+
+SELECT count(*) FROM test_tsvector WHERE a @@ 'eq|yt';
+ count
+-------
+ 98
+(1 row)
+
+SELECT count(*) FROM test_tsvector WHERE a @@ '(eq&yt)|(wr&qh)';
+ count
+-------
+ 23
+(1 row)
+
+SELECT count(*) FROM test_tsvector WHERE a @@ '(eq|yt)&(wr|qh)';
+ count
+-------
+ 39
+(1 row)
+
+create index wowidx on test_tsvector using gist (a);
+set enable_seqscan=off;
+SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh';
+ count
+-------
+ 158
+(1 row)
+
+SELECT count(*) FROM test_tsvector WHERE a @@ 'wr&qh';
+ count
+-------
+ 17
+(1 row)
+
+SELECT count(*) FROM test_tsvector WHERE a @@ 'eq&yt';
+ count
+-------
+ 6
+(1 row)
+
+SELECT count(*) FROM test_tsvector WHERE a @@ 'eq|yt';
+ count
+-------
+ 98
+(1 row)
+
+SELECT count(*) FROM test_tsvector WHERE a @@ '(eq&yt)|(wr&qh)';
+ count
+-------
+ 23
+(1 row)
+
+SELECT count(*) FROM test_tsvector WHERE a @@ '(eq|yt)&(wr|qh)';
+ count
+-------
+ 39
+(1 row)
+
+select set_curcfg('default');
+ set_curcfg
+------------
+
+(1 row)
+
+CREATE TRIGGER tsvectorupdate
+BEFORE UPDATE OR INSERT ON test_tsvector
+FOR EACH ROW EXECUTE PROCEDURE tsearch2(a, t);
+SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty');
+ count
+-------
+ 0
+(1 row)
+
+INSERT INTO test_tsvector (t) VALUES ('345 qwerty');
+SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty');
+ count
+-------
+ 1
+(1 row)
+
+UPDATE test_tsvector SET t = null WHERE t = '345 qwerty';
+SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty');
+ count
+-------
+ 0
+(1 row)
+
+drop trigger tsvectorupdate on test_tsvector;
+create function wow(text) returns text as 'select $1 || \' copyright\'; ' language sql;
+create trigger tsvectorupdate before update or insert on test_tsvector
+for each row execute procedure tsearch2(a, wow, t);
+insert into test_tsvector (t) values ('345 qwerty');
+select count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty');
+ count
+-------
+ 1
+(1 row)
+
+select count(*) FROM test_tsvector WHERE a @@ to_tsquery('copyright');
+ count
+-------
+ 1
+(1 row)
+
+select rank(' a:1 s:2C d g'::tsvector, 'a | s');
+ rank
+------
+ 0.28
+(1 row)
+
+select rank(' a:1 s:2B d g'::tsvector, 'a | s');
+ rank
+------
+ 0.46
+(1 row)
+
+select rank(' a:1 s:2 d g'::tsvector, 'a | s');
+ rank
+------
+ 0.19
+(1 row)
+
+select rank(' a:1 s:2C d g'::tsvector, 'a & s');
+ rank
+----------
+ 0.140153
+(1 row)
+
+select rank(' a:1 s:2B d g'::tsvector, 'a & s');
+ rank
+----------
+ 0.198206
+(1 row)
+
+select rank(' a:1 s:2 d g'::tsvector, 'a & s');
+ rank
+-----------
+ 0.0991032
+(1 row)
+
+insert into test_tsvector (t) values ('foo bar foo the over foo qq bar');
+select * from stat('select a from test_tsvector') order by ndoc desc, nentry desc, word;
+ word | ndoc | nentry
+-----------+------+--------
+ qq | 109 | 109
+ qt | 102 | 102
+ qe | 100 | 100
+ qh | 98 | 98
+ qw | 98 | 98
+ qa | 97 | 97
+ ql | 94 | 94
+ qs | 94 | 94
+ qi | 92 | 92
+ qr | 92 | 92
+ qj | 91 | 91
+ qd | 87 | 87
+ qz | 87 | 87
+ qc | 86 | 86
+ qn | 86 | 86
+ qv | 85 | 85
+ qo | 84 | 84
+ qy | 84 | 84
+ wp | 84 | 84
+ qf | 81 | 81
+ qk | 80 | 80
+ wt | 80 | 80
+ qu | 79 | 79
+ qg | 78 | 78
+ wb | 78 | 78
+ qx | 77 | 77
+ wr | 77 | 77
+ ws | 73 | 73
+ wy | 73 | 73
+ wa | 72 | 72
+ wf | 70 | 70
+ wg | 70 | 70
+ wi | 70 | 70
+ wu | 70 | 70
+ wc | 69 | 69
+ wj | 69 | 69
+ qp | 68 | 68
+ wh | 68 | 68
+ wv | 68 | 68
+ qb | 66 | 66
+ eu | 65 | 65
+ we | 65 | 65
+ wl | 65 | 65
+ wq | 65 | 65
+ wk | 64 | 64
+ ee | 63 | 63
+ eo | 63 | 63
+ qm | 63 | 63
+ wn | 63 | 63
+ ef | 62 | 62
+ eh | 62 | 62
+ ex | 62 | 62
+ re | 62 | 62
+ rl | 62 | 62
+ rr | 62 | 62
+ eb | 61 | 61
+ ek | 61 | 61
+ ww | 61 | 61
+ ea | 60 | 60
+ ei | 60 | 60
+ em | 60 | 60
+ eq | 60 | 60
+ ew | 60 | 60
+ ro | 60 | 60
+ rw | 60 | 60
+ tl | 60 | 60
+ eg | 59 | 59
+ en | 59 | 59
+ ez | 59 | 59
+ rj | 59 | 59
+ ry | 59 | 59
+ tw | 59 | 59
+ tx | 59 | 59
+ ej | 58 | 58
+ es | 58 | 58
+ ra | 58 | 58
+ rd | 58 | 58
+ rg | 58 | 58
+ rx | 58 | 58
+ tb | 58 | 58
+ wd | 58 | 58
+ ed | 57 | 57
+ tc | 57 | 57
+ wx | 57 | 57
+ er | 56 | 56
+ wm | 56 | 56
+ wo | 56 | 56
+ yw | 56 | 56
+ ep | 55 | 55
+ rk | 55 | 55
+ rp | 55 | 55
+ rz | 55 | 55
+ ta | 55 | 55
+ rq | 54 | 54
+ yn | 54 | 54
+ ec | 53 | 53
+ el | 53 | 53
+ ru | 53 | 53
+ rv | 53 | 53
+ tz | 53 | 53
+ un | 53 | 53
+ wz | 53 | 53
+ ys | 53 | 53
+ oe | 52 | 52
+ tn | 52 | 52
+ tq | 52 | 52
+ ty | 52 | 52
+ uq | 52 | 52
+ yg | 52 | 52
+ ym | 52 | 52
+ oi | 51 | 51
+ to | 51 | 51
+ yi | 51 | 51
+ pn | 50 | 50
+ rb | 50 | 50
+ ri | 50 | 50
+ rn | 50 | 50
+ ti | 50 | 50
+ tv | 50 | 50
+ um | 50 | 50
+ ut | 50 | 50
+ ya | 50 | 50
+ et | 49 | 49
+ ix | 49 | 49
+ ox | 49 | 49
+ q3 | 49 | 49
+ yf | 49 | 49
+ yl | 49 | 49
+ yo | 49 | 49
+ yr | 49 | 49
+ ev | 48 | 48
+ ey | 48 | 48
+ ot | 48 | 48
+ rc | 48 | 48
+ rm | 48 | 48
+ th | 48 | 48
+ uo | 48 | 48
+ ia | 47 | 47
+ q1 | 47 | 47
+ rh | 47 | 47
+ yq | 47 | 47
+ yz | 47 | 47
+ av | 46 | 46
+ im | 46 | 46
+ os | 46 | 46
+ tk | 46 | 46
+ yy | 46 | 46
+ ir | 45 | 45
+ iv | 45 | 45
+ iw | 45 | 45
+ oj | 45 | 45
+ pl | 45 | 45
+ pv | 45 | 45
+ te | 45 | 45
+ tu | 45 | 45
+ uv | 45 | 45
+ ux | 45 | 45
+ yd | 45 | 45
+ yx | 45 | 45
+ ij | 44 | 44
+ pa | 44 | 44
+ se | 44 | 44
+ tg | 44 | 44
+ ue | 44 | 44
+ yb | 44 | 44
+ yt | 44 | 44
+ if | 43 | 43
+ ik | 43 | 43
+ in | 43 | 43
+ ph | 43 | 43
+ pj | 43 | 43
+ q5 | 43 | 43
+ rt | 43 | 43
+ ub | 43 | 43
+ ud | 43 | 43
+ uh | 43 | 43
+ uj | 43 | 43
+ w7 | 43 | 43
+ ye | 43 | 43
+ yv | 43 | 43
+ db | 42 | 42
+ do | 42 | 42
+ id | 42 | 42
+ ie | 42 | 42
+ ii | 42 | 42
+ of | 42 | 42
+ pr | 42 | 42
+ q4 | 42 | 42
+ rf | 42 | 42
+ td | 42 | 42
+ uk | 42 | 42
+ up | 42 | 42
+ yh | 42 | 42
+ yk | 42 | 42
+ io | 41 | 41
+ it | 41 | 41
+ pb | 41 | 41
+ q0 | 41 | 41
+ q7 | 41 | 41
+ rs | 41 | 41
+ tj | 41 | 41
+ ur | 41 | 41
+ ig | 40 | 40
+ iu | 40 | 40
+ iy | 40 | 40
+ od | 40 | 40
+ q6 | 40 | 40
+ tt | 40 | 40
+ ug | 40 | 40
+ ul | 40 | 40
+ us | 40 | 40
+ uu | 40 | 40
+ uz | 40 | 40
+ ah | 39 | 39
+ ar | 39 | 39
+ as | 39 | 39
+ dl | 39 | 39
+ dt | 39 | 39
+ hk | 39 | 39
+ iq | 39 | 39
+ is | 39 | 39
+ oc | 39 | 39
+ ov | 39 | 39
+ oy | 39 | 39
+ uf | 39 | 39
+ ui | 39 | 39
+ aa | 38 | 38
+ ad | 38 | 38
+ fh | 38 | 38
+ gm | 38 | 38
+ ic | 38 | 38
+ jd | 38 | 38
+ om | 38 | 38
+ or | 38 | 38
+ oz | 38 | 38
+ pm | 38 | 38
+ q8 | 38 | 38
+ sf | 38 | 38
+ sm | 38 | 38
+ sv | 38 | 38
+ uc | 38 | 38
+ ak | 37 | 37
+ aq | 37 | 37
+ di | 37 | 37
+ e4 | 37 | 37
+ fi | 37 | 37
+ fx | 37 | 37
+ ha | 37 | 37
+ hp | 37 | 37
+ ih | 37 | 37
+ og | 37 | 37
+ po | 37 | 37
+ pw | 37 | 37
+ sn | 37 | 37
+ su | 37 | 37
+ sw | 37 | 37
+ w6 | 37 | 37
+ yj | 37 | 37
+ yu | 37 | 37
+ ag | 36 | 36
+ am | 36 | 36
+ at | 36 | 36
+ e1 | 36 | 36
+ ff | 36 | 36
+ gx | 36 | 36
+ he | 36 | 36
+ hj | 36 | 36
+ ib | 36 | 36
+ iz | 36 | 36
+ lm | 36 | 36
+ ok | 36 | 36
+ pk | 36 | 36
+ pp | 36 | 36
+ pu | 36 | 36
+ sp | 36 | 36
+ tf | 36 | 36
+ tm | 36 | 36
+ ay | 35 | 35
+ dy | 35 | 35
+ fu | 35 | 35
+ ku | 35 | 35
+ lh | 35 | 35
+ lq | 35 | 35
+ o6 | 35 | 35
+ ob | 35 | 35
+ on | 35 | 35
+ op | 35 | 35
+ pd | 35 | 35
+ ps | 35 | 35
+ si | 35 | 35
+ sl | 35 | 35
+ sx | 35 | 35
+ tp | 35 | 35
+ tr | 35 | 35
+ w3 | 35 | 35
+ y1 | 35 | 35
+ al | 34 | 34
+ ap | 34 | 34
+ az | 34 | 34
+ dc | 34 | 34
+ dd | 34 | 34
+ dz | 34 | 34
+ e0 | 34 | 34
+ fj | 34 | 34
+ fp | 34 | 34
+ gd | 34 | 34
+ gg | 34 | 34
+ gk | 34 | 34
+ go | 34 | 34
+ ho | 34 | 34
+ jc | 34 | 34
+ oa | 34 | 34
+ oh | 34 | 34
+ oo | 34 | 34
+ pe | 34 | 34
+ px | 34 | 34
+ sd | 34 | 34
+ sq | 34 | 34
+ sy | 34 | 34
+ ab | 33 | 33
+ ae | 33 | 33
+ af | 33 | 33
+ aw | 33 | 33
+ e5 | 33 | 33
+ fk | 33 | 33
+ gu | 33 | 33
+ gy | 33 | 33
+ hb | 33 | 33
+ hm | 33 | 33
+ hy | 33 | 33
+ jl | 33 | 33
+ jr | 33 | 33
+ ls | 33 | 33
+ oq | 33 | 33
+ pt | 33 | 33
+ sa | 33 | 33
+ sh | 33 | 33
+ sj | 33 | 33
+ so | 33 | 33
+ sz | 33 | 33
+ t7 | 33 | 33
+ uw | 33 | 33
+ w8 | 33 | 33
+ y0 | 33 | 33
+ yp | 33 | 33
+ dh | 32 | 32
+ dp | 32 | 32
+ dq | 32 | 32
+ e7 | 32 | 32
+ fn | 32 | 32
+ fo | 32 | 32
+ fr | 32 | 32
+ ga | 32 | 32
+ gq | 32 | 32
+ hh | 32 | 32
+ il | 32 | 32
+ ip | 32 | 32
+ jv | 32 | 32
+ lc | 32 | 32
+ ol | 32 | 32
+ pc | 32 | 32
+ q9 | 32 | 32
+ ds | 31 | 31
+ e9 | 31 | 31
+ fd | 31 | 31
+ fe | 31 | 31
+ ft | 31 | 31
+ gs | 31 | 31
+ hl | 31 | 31
+ hs | 31 | 31
+ jb | 31 | 31
+ kc | 31 | 31
+ kw | 31 | 31
+ mj | 31 | 31
+ q2 | 31 | 31
+ r3 | 31 | 31
+ sb | 31 | 31
+ sk | 31 | 31
+ ts | 31 | 31
+ ua | 31 | 31
+ yc | 31 | 31
+ zw | 31 | 31
+ ao | 30 | 30
+ du | 30 | 30
+ fw | 30 | 30
+ gj | 30 | 30
+ hu | 30 | 30
+ kh | 30 | 30
+ kl | 30 | 30
+ kv | 30 | 30
+ ld | 30 | 30
+ lf | 30 | 30
+ pq | 30 | 30
+ py | 30 | 30
+ sc | 30 | 30
+ sr | 30 | 30
+ uy | 30 | 30
+ vg | 30 | 30
+ w2 | 30 | 30
+ xg | 30 | 30
+ xo | 30 | 30
+ au | 29 | 29
+ cx | 29 | 29
+ fv | 29 | 29
+ gh | 29 | 29
+ gl | 29 | 29
+ gt | 29 | 29
+ hw | 29 | 29
+ ji | 29 | 29
+ km | 29 | 29
+ la | 29 | 29
+ ou | 29 | 29
+ r0 | 29 | 29
+ w0 | 29 | 29
+ y9 | 29 | 29
+ zm | 29 | 29
+ zs | 29 | 29
+ zy | 29 | 29
+ ax | 28 | 28
+ cd | 28 | 28
+ dj | 28 | 28
+ dn | 28 | 28
+ dr | 28 | 28
+ ht | 28 | 28
+ jf | 28 | 28
+ lo | 28 | 28
+ lr | 28 | 28
+ na | 28 | 28
+ ng | 28 | 28
+ r8 | 28 | 28
+ ss | 28 | 28
+ xt | 28 | 28
+ y6 | 28 | 28
+ aj | 27 | 27
+ ca | 27 | 27
+ cg | 27 | 27
+ df | 27 | 27
+ dg | 27 | 27
+ dv | 27 | 27
+ gc | 27 | 27
+ gn | 27 | 27
+ gr | 27 | 27
+ hd | 27 | 27
+ i8 | 27 | 27
+ jn | 27 | 27
+ jt | 27 | 27
+ lp | 27 | 27
+ o9 | 27 | 27
+ ow | 27 | 27
+ r9 | 27 | 27
+ t8 | 27 | 27
+ u5 | 27 | 27
+ w4 | 27 | 27
+ xm | 27 | 27
+ zz | 27 | 27
+ a2 | 26 | 26
+ ac | 26 | 26
+ ai | 26 | 26
+ cm | 26 | 26
+ cu | 26 | 26
+ cw | 26 | 26
+ dk | 26 | 26
+ e2 | 26 | 26
+ fc | 26 | 26
+ fg | 26 | 26
+ fl | 26 | 26
+ fs | 26 | 26
+ ge | 26 | 26
+ gv | 26 | 26
+ hc | 26 | 26
+ hi | 26 | 26
+ hx | 26 | 26
+ jj | 26 | 26
+ jm | 26 | 26
+ kg | 26 | 26
+ kk | 26 | 26
+ kn | 26 | 26
+ ko | 26 | 26
+ kt | 26 | 26
+ ln | 26 | 26
+ mx | 26 | 26
+ pg | 26 | 26
+ r4 | 26 | 26
+ t6 | 26 | 26
+ u1 | 26 | 26
+ u4 | 26 | 26
+ vi | 26 | 26
+ vr | 26 | 26
+ w1 | 26 | 26
+ w9 | 26 | 26
+ xk | 26 | 26
+ xs | 26 | 26
+ zf | 26 | 26
+ bb | 25 | 25
+ dm | 25 | 25
+ dw | 25 | 25
+ e8 | 25 | 25
+ fb | 25 | 25
+ gw | 25 | 25
+ h8 | 25 | 25
+ hf | 25 | 25
+ hg | 25 | 25
+ hn | 25 | 25
+ hv | 25 | 25
+ i0 | 25 | 25
+ i3 | 25 | 25
+ jg | 25 | 25
+ jo | 25 | 25
+ jx | 25 | 25
+ kq | 25 | 25
+ lw | 25 | 25
+ lx | 25 | 25
+ o3 | 25 | 25
+ p7 | 25 | 25
+ pf | 25 | 25
+ pi | 25 | 25
+ pz | 25 | 25
+ r2 | 25 | 25
+ r5 | 25 | 25
+ t9 | 25 | 25
+ u7 | 25 | 25
+ ve | 25 | 25
+ vu | 25 | 25
+ y5 | 25 | 25
+ y8 | 25 | 25
+ zt | 25 | 25
+ an | 24 | 24
+ bj | 24 | 24
+ dx | 24 | 24
+ fm | 24 | 24
+ fz | 24 | 24
+ gb | 24 | 24
+ gi | 24 | 24
+ gp | 24 | 24
+ hr | 24 | 24
+ hz | 24 | 24
+ i5 | 24 | 24
+ jq | 24 | 24
+ kb | 24 | 24
+ ke | 24 | 24
+ kf | 24 | 24
+ kp | 24 | 24
+ lv | 24 | 24
+ lz | 24 | 24
+ o8 | 24 | 24
+ r1 | 24 | 24
+ s7 | 24 | 24
+ sg | 24 | 24
+ u3 | 24 | 24
+ vj | 24 | 24
+ vt | 24 | 24
+ w5 | 24 | 24
+ zj | 24 | 24
+ be | 23 | 23
+ bi | 23 | 23
+ bn | 23 | 23
+ cn | 23 | 23
+ cy | 23 | 23
+ da | 23 | 23
+ e6 | 23 | 23
+ fa | 23 | 23
+ js | 23 | 23
+ ki | 23 | 23
+ kz | 23 | 23
+ li | 23 | 23
+ mt | 23 | 23
+ mz | 23 | 23
+ nu | 23 | 23
+ o2 | 23 | 23
+ p5 | 23 | 23
+ p8 | 23 | 23
+ r7 | 23 | 23
+ t0 | 23 | 23
+ t1 | 23 | 23
+ t3 | 23 | 23
+ vm | 23 | 23
+ xh | 23 | 23
+ xx | 23 | 23
+ zp | 23 | 23
+ zr | 23 | 23
+ a3 | 22 | 22
+ bg | 22 | 22
+ de | 22 | 22
+ e3 | 22 | 22
+ fq | 22 | 22
+ i2 | 22 | 22
+ i7 | 22 | 22
+ ja | 22 | 22
+ jk | 22 | 22
+ jy | 22 | 22
+ kr | 22 | 22
+ kx | 22 | 22
+ ly | 22 | 22
+ nb | 22 | 22
+ nh | 22 | 22
+ ns | 22 | 22
+ s3 | 22 | 22
+ u2 | 22 | 22
+ vn | 22 | 22
+ xe | 22 | 22
+ y4 | 22 | 22
+ zh | 22 | 22
+ zo | 22 | 22
+ zq | 22 | 22
+ a1 | 21 | 21
+ bl | 21 | 21
+ bo | 21 | 21
+ cb | 21 | 21
+ ch | 21 | 21
+ co | 21 | 21
+ cq | 21 | 21
+ cv | 21 | 21
+ d7 | 21 | 21
+ g8 | 21 | 21
+ je | 21 | 21
+ jp | 21 | 21
+ jz | 21 | 21
+ lg | 21 | 21
+ me | 21 | 21
+ nc | 21 | 21
+ p4 | 21 | 21
+ st | 21 | 21
+ vb | 21 | 21
+ vw | 21 | 21
+ vz | 21 | 21
+ xj | 21 | 21
+ xq | 21 | 21
+ xu | 21 | 21
+ xy | 21 | 21
+ zb | 21 | 21
+ bv | 20 | 20
+ bz | 20 | 20
+ cj | 20 | 20
+ cp | 20 | 20
+ cs | 20 | 20
+ d8 | 20 | 20
+ ju | 20 | 20
+ k0 | 20 | 20
+ ks | 20 | 20
+ ky | 20 | 20
+ l1 | 20 | 20
+ lb | 20 | 20
+ lj | 20 | 20
+ lu | 20 | 20
+ nm | 20 | 20
+ nw | 20 | 20
+ nz | 20 | 20
+ o7 | 20 | 20
+ p6 | 20 | 20
+ vh | 20 | 20
+ vp | 20 | 20
+ vs | 20 | 20
+ xb | 20 | 20
+ xr | 20 | 20
+ z3 | 20 | 20
+ zv | 20 | 20
+ bq | 19 | 19
+ br | 19 | 19
+ by | 19 | 19
+ cl | 19 | 19
+ d2 | 19 | 19
+ f1 | 19 | 19
+ f4 | 19 | 19
+ gf | 19 | 19
+ hq | 19 | 19
+ k9 | 19 | 19
+ ka | 19 | 19
+ kd | 19 | 19
+ kj | 19 | 19
+ md | 19 | 19
+ mi | 19 | 19
+ ml | 19 | 19
+ my | 19 | 19
+ nj | 19 | 19
+ ny | 19 | 19
+ o1 | 19 | 19
+ s4 | 19 | 19
+ s8 | 19 | 19
+ t5 | 19 | 19
+ u0 | 19 | 19
+ xl | 19 | 19
+ zg | 19 | 19
+ zi | 19 | 19
+ a5 | 18 | 18
+ b9 | 18 | 18
+ bh | 18 | 18
+ bx | 18 | 18
+ d3 | 18 | 18
+ fy | 18 | 18
+ g2 | 18 | 18
+ i4 | 18 | 18
+ i6 | 18 | 18
+ i9 | 18 | 18
+ jw | 18 | 18
+ lk | 18 | 18
+ mb | 18 | 18
+ mv | 18 | 18
+ nd | 18 | 18
+ nr | 18 | 18
+ nt | 18 | 18
+ t2 | 18 | 18
+ xf | 18 | 18
+ xv | 18 | 18
+ zc | 18 | 18
+ zd | 18 | 18
+ a7 | 17 | 17
+ bc | 17 | 17
+ bd | 17 | 17
+ ce | 17 | 17
+ cf | 17 | 17
+ cr | 17 | 17
+ g9 | 17 | 17
+ j0 | 17 | 17
+ j5 | 17 | 17
+ mp | 17 | 17
+ mr | 17 | 17
+ mw | 17 | 17
+ nk | 17 | 17
+ no | 17 | 17
+ o0 | 17 | 17
+ o4 | 17 | 17
+ s0 | 17 | 17
+ s1 | 17 | 17
+ t4 | 17 | 17
+ u9 | 17 | 17
+ vf | 17 | 17
+ vx | 17 | 17
+ x3 | 17 | 17
+ xi | 17 | 17
+ xn | 17 | 17
+ xz | 17 | 17
+ zl | 17 | 17
+ zn | 17 | 17
+ a0 | 16 | 16
+ bu | 16 | 16
+ bw | 16 | 16
+ ci | 16 | 16
+ ck | 16 | 16
+ d0 | 16 | 16
+ d4 | 16 | 16
+ d6 | 16 | 16
+ f5 | 16 | 16
+ g1 | 16 | 16
+ gz | 16 | 16
+ h4 | 16 | 16
+ jh | 16 | 16
+ l4 | 16 | 16
+ lt | 16 | 16
+ mg | 16 | 16
+ mh | 16 | 16
+ mo | 16 | 16
+ ni | 16 | 16
+ nl | 16 | 16
+ nq | 16 | 16
+ p2 | 16 | 16
+ u8 | 16 | 16
+ v9 | 16 | 16
+ vl | 16 | 16
+ vo | 16 | 16
+ xp | 16 | 16
+ y3 | 16 | 16
+ y7 | 16 | 16
+ z7 | 16 | 16
+ za | 16 | 16
+ zx | 16 | 16
+ bf | 15 | 15
+ bp | 15 | 15
+ cc | 15 | 15
+ g0 | 15 | 15
+ j2 | 15 | 15
+ j9 | 15 | 15
+ l6 | 15 | 15
+ le | 15 | 15
+ ll | 15 | 15
+ m8 | 15 | 15
+ ma | 15 | 15
+ mu | 15 | 15
+ nf | 15 | 15
+ r6 | 15 | 15
+ s5 | 15 | 15
+ vd | 15 | 15
+ vk | 15 | 15
+ xa | 15 | 15
+ xw | 15 | 15
+ y2 | 15 | 15
+ z8 | 15 | 15
+ ze | 15 | 15
+ zu | 15 | 15
+ a6 | 14 | 14
+ bk | 14 | 14
+ bt | 14 | 14
+ c0 | 14 | 14
+ f8 | 14 | 14
+ g3 | 14 | 14
+ g4 | 14 | 14
+ g7 | 14 | 14
+ h6 | 14 | 14
+ h7 | 14 | 14
+ h9 | 14 | 14
+ i1 | 14 | 14
+ k1 | 14 | 14
+ k2 | 14 | 14
+ k6 | 14 | 14
+ k7 | 14 | 14
+ mc | 14 | 14
+ nn | 14 | 14
+ p9 | 14 | 14
+ u6 | 14 | 14
+ xd | 14 | 14
+ z6 | 14 | 14
+ zk | 14 | 14
+ a4 | 13 | 13
+ a9 | 13 | 13
+ bm | 13 | 13
+ cz | 13 | 13
+ f2 | 13 | 13
+ f3 | 13 | 13
+ f6 | 13 | 13
+ g6 | 13 | 13
+ h2 | 13 | 13
+ j1 | 13 | 13
+ k5 | 13 | 13
+ m1 | 13 | 13
+ mf | 13 | 13
+ mq | 13 | 13
+ np | 13 | 13
+ nx | 13 | 13
+ o5 | 13 | 13
+ p0 | 13 | 13
+ p1 | 13 | 13
+ s6 | 13 | 13
+ s9 | 13 | 13
+ v6 | 13 | 13
+ va | 13 | 13
+ vc | 13 | 13
+ xc | 13 | 13
+ z0 | 13 | 13
+ c9 | 12 | 12
+ d1 | 12 | 12
+ h0 | 12 | 12
+ h1 | 12 | 12
+ j8 | 12 | 12
+ k4 | 12 | 12
+ l5 | 12 | 12
+ l9 | 12 | 12
+ m2 | 12 | 12
+ m6 | 12 | 12
+ m9 | 12 | 12
+ n7 | 12 | 12
+ nv | 12 | 12
+ p3 | 12 | 12
+ vq | 12 | 12
+ vy | 12 | 12
+ x1 | 12 | 12
+ x2 | 12 | 12
+ z5 | 12 | 12
+ c1 | 11 | 11
+ c3 | 11 | 11
+ ct | 11 | 11
+ f9 | 11 | 11
+ g5 | 11 | 11
+ j6 | 11 | 11
+ l8 | 11 | 11
+ n1 | 11 | 11
+ v7 | 11 | 11
+ vv | 11 | 11
+ x5 | 11 | 11
+ x8 | 11 | 11
+ z2 | 11 | 11
+ b0 | 10 | 10
+ b2 | 10 | 10
+ b8 | 10 | 10
+ c6 | 10 | 10
+ f0 | 10 | 10
+ f7 | 10 | 10
+ h5 | 10 | 10
+ j3 | 10 | 10
+ j4 | 10 | 10
+ j7 | 10 | 10
+ l7 | 10 | 10
+ m0 | 10 | 10
+ m7 | 10 | 10
+ mm | 10 | 10
+ mn | 10 | 10
+ n8 | 10 | 10
+ v1 | 10 | 10
+ x0 | 10 | 10
+ x6 | 10 | 10
+ x7 | 10 | 10
+ x9 | 10 | 10
+ a8 | 9 | 9
+ b1 | 9 | 9
+ b4 | 9 | 9
+ b5 | 9 | 9
+ b6 | 9 | 9
+ ba | 9 | 9
+ bs | 9 | 9
+ c5 | 9 | 9
+ d5 | 9 | 9
+ k8 | 9 | 9
+ l0 | 9 | 9
+ m5 | 9 | 9
+ mk | 9 | 9
+ ms | 9 | 9
+ n3 | 9 | 9
+ n4 | 9 | 9
+ n6 | 9 | 9
+ ne | 9 | 9
+ v0 | 9 | 9
+ v3 | 9 | 9
+ v5 | 9 | 9
+ v8 | 9 | 9
+ b3 | 8 | 8
+ b7 | 8 | 8
+ c2 | 8 | 8
+ c7 | 8 | 8
+ c8 | 8 | 8
+ d9 | 8 | 8
+ k3 | 8 | 8
+ l3 | 8 | 8
+ m3 | 8 | 8
+ m4 | 8 | 8
+ n0 | 8 | 8
+ n5 | 8 | 8
+ v4 | 8 | 8
+ x4 | 8 | 8
+ z1 | 8 | 8
+ z9 | 8 | 8
+ l2 | 7 | 7
+ s2 | 7 | 7
+ z4 | 7 | 7
+ 1l | 6 | 6
+ 1o | 6 | 6
+ 1t | 6 | 6
+ 2e | 6 | 6
+ 2o | 6 | 6
+ c4 | 6 | 6
+ h3 | 6 | 6
+ n2 | 6 | 6
+ n9 | 6 | 6
+ v2 | 6 | 6
+ 2l | 5 | 5
+ 2u | 5 | 5
+ 3k | 5 | 5
+ 4p | 5 | 5
+ 18 | 4 | 4
+ 1a | 4 | 4
+ 1i | 4 | 4
+ 2s | 4 | 4
+ 3q | 4 | 4
+ 3y | 4 | 4
+ 5y | 4 | 4
+ 1f | 3 | 3
+ 1h | 3 | 3
+ 1m | 3 | 3
+ 1p | 3 | 3
+ 1s | 3 | 3
+ 1v | 3 | 3
+ 1x | 3 | 3
+ 27 | 3 | 3
+ 2a | 3 | 3
+ 2b | 3 | 3
+ 2h | 3 | 3
+ 2n | 3 | 3
+ 2p | 3 | 3
+ 2v | 3 | 3
+ 2y | 3 | 3
+ 3d | 3 | 3
+ 3w | 3 | 3
+ 3z | 3 | 3
+ 4a | 3 | 3
+ 4d | 3 | 3
+ 4v | 3 | 3
+ 4z | 3 | 3
+ 5e | 3 | 3
+ 5i | 3 | 3
+ 5k | 3 | 3
+ 5o | 3 | 3
+ 5t | 3 | 3
+ 6b | 3 | 3
+ 6d | 3 | 3
+ 6o | 3 | 3
+ 6w | 3 | 3
+ 7a | 3 | 3
+ 7h | 3 | 3
+ 7r | 3 | 3
+ 93 | 3 | 3
+ 10 | 2 | 2
+ 12 | 2 | 2
+ 15 | 2 | 2
+ 16 | 2 | 2
+ 19 | 2 | 2
+ 1b | 2 | 2
+ 1d | 2 | 2
+ 1g | 2 | 2
+ 1j | 2 | 2
+ 1n | 2 | 2
+ 1r | 2 | 2
+ 1u | 2 | 2
+ 1w | 2 | 2
+ 1y | 2 | 2
+ 20 | 2 | 2
+ 25 | 2 | 2
+ 2d | 2 | 2
+ 2i | 2 | 2
+ 2j | 2 | 2
+ 2k | 2 | 2
+ 2q | 2 | 2
+ 2r | 2 | 2
+ 2t | 2 | 2
+ 2w | 2 | 2
+ 2z | 2 | 2
+ 3b | 2 | 2
+ 3f | 2 | 2
+ 3h | 2 | 2
+ 3o | 2 | 2
+ 3p | 2 | 2
+ 3r | 2 | 2
+ 3s | 2 | 2
+ 3v | 2 | 2
+ 42 | 2 | 2
+ 43 | 2 | 2
+ 4f | 2 | 2
+ 4g | 2 | 2
+ 4h | 2 | 2
+ 4j | 2 | 2
+ 4m | 2 | 2
+ 4r | 2 | 2
+ 4s | 2 | 2
+ 4t | 2 | 2
+ 4u | 2 | 2
+ 5c | 2 | 2
+ 5f | 2 | 2
+ 5h | 2 | 2
+ 5p | 2 | 2
+ 5q | 2 | 2
+ 5z | 2 | 2
+ 6a | 2 | 2
+ 6h | 2 | 2
+ 6q | 2 | 2
+ 6r | 2 | 2
+ 6t | 2 | 2
+ 6y | 2 | 2
+ 70 | 2 | 2
+ 7c | 2 | 2
+ 7g | 2 | 2
+ 7k | 2 | 2
+ 7o | 2 | 2
+ 7u | 2 | 2
+ 8j | 2 | 2
+ 8w | 2 | 2
+ 9f | 2 | 2
+ 9y | 2 | 2
+ copyright | 2 | 2
+ foo | 1 | 3
+ bar | 1 | 2
+ 0e | 1 | 1
+ 0h | 1 | 1
+ 0p | 1 | 1
+ 0w | 1 | 1
+ 0z | 1 | 1
+ 11 | 1 | 1
+ 13 | 1 | 1
+ 14 | 1 | 1
+ 17 | 1 | 1
+ 1k | 1 | 1
+ 1q | 1 | 1
+ 1z | 1 | 1
+ 24 | 1 | 1
+ 26 | 1 | 1
+ 28 | 1 | 1
+ 2f | 1 | 1
+ 30 | 1 | 1
+ 345 | 1 | 1
+ 37 | 1 | 1
+ 39 | 1 | 1
+ 3a | 1 | 1
+ 3e | 1 | 1
+ 3g | 1 | 1
+ 3i | 1 | 1
+ 3m | 1 | 1
+ 3t | 1 | 1
+ 3u | 1 | 1
+ 40 | 1 | 1
+ 41 | 1 | 1
+ 44 | 1 | 1
+ 45 | 1 | 1
+ 48 | 1 | 1
+ 4b | 1 | 1
+ 4c | 1 | 1
+ 4i | 1 | 1
+ 4k | 1 | 1
+ 4n | 1 | 1
+ 4o | 1 | 1
+ 4q | 1 | 1
+ 4w | 1 | 1
+ 4y | 1 | 1
+ 51 | 1 | 1
+ 55 | 1 | 1
+ 56 | 1 | 1
+ 5a | 1 | 1
+ 5d | 1 | 1
+ 5g | 1 | 1
+ 5j | 1 | 1
+ 5l | 1 | 1
+ 5s | 1 | 1
+ 5u | 1 | 1
+ 5x | 1 | 1
+ 64 | 1 | 1
+ 68 | 1 | 1
+ 6c | 1 | 1
+ 6f | 1 | 1
+ 6g | 1 | 1
+ 6i | 1 | 1
+ 6k | 1 | 1
+ 6n | 1 | 1
+ 6p | 1 | 1
+ 6s | 1 | 1
+ 6u | 1 | 1
+ 6x | 1 | 1
+ 72 | 1 | 1
+ 7f | 1 | 1
+ 7j | 1 | 1
+ 7n | 1 | 1
+ 7p | 1 | 1
+ 7w | 1 | 1
+ 7y | 1 | 1
+ 7z | 1 | 1
+ 80 | 1 | 1
+ 82 | 1 | 1
+ 85 | 1 | 1
+ 8d | 1 | 1
+ 8i | 1 | 1
+ 8l | 1 | 1
+ 8n | 1 | 1
+ 8p | 1 | 1
+ 8t | 1 | 1
+ 8x | 1 | 1
+ 95 | 1 | 1
+ 97 | 1 | 1
+ 9a | 1 | 1
+ 9e | 1 | 1
+ 9h | 1 | 1
+ 9r | 1 | 1
+ 9w | 1 | 1
+ qwerti | 1 | 1
+(1146 rows)
+
+select reset_tsearch();
+NOTICE: TSearch cache cleaned
+ reset_tsearch
+---------------
+
+(1 row)
+
+select to_tsquery('default', 'skies & books');
+ to_tsquery
+----------------
+ 'sky' & 'book'
+(1 row)
+
+select rank_cd(to_tsvector('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+'), to_tsquery('sea&thousand&years'));
+ rank_cd
+---------
+ 1.2
+(1 row)
+
+select rank_cd(to_tsvector('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+'), to_tsquery('granite&sea'));
+ rank_cd
+----------
+ 0.880303
+(1 row)
+
+select rank_cd(to_tsvector('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+'), to_tsquery('sea'));
+ rank_cd
+---------
+ 2
+(1 row)
+
+select get_covers(to_tsvector('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+'), to_tsquery('sea&thousand&years'));
+ get_covers
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ eros took {1 sea thousand year }1 {2 thousand year trace granit featur cliff crag scarp base took sea }2 hour one night hour storm place sculptur granit seam upon woman face e j pratt 1882 1964
+(1 row)
+
+select get_covers(to_tsvector('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+'), to_tsquery('granite&sea'));
+ get_covers
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ eros took {1 sea thousand year thousand year trace {2 granit }1 featur cliff crag scarp base took {3 sea }2 hour one night hour storm place sculptur granit }3 seam upon woman face e j pratt 1882 1964
+(1 row)
+
+select get_covers(to_tsvector('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+'), to_tsquery('sea'));
+ get_covers
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ eros took {1 sea }1 thousand year thousand year trace granit featur cliff crag scarp base took {2 sea }2 hour one night hour storm place sculptur granit seam upon woman face e j pratt 1882 1964
+(1 row)
+
+select headline('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+', to_tsquery('sea&thousand&years'));
+ headline
+-----------------------------------------------------------------------------------------------------------------------
+ <b>sea</b> a <b>thousand</b> <b>years</b>,
+A <b>thousand</b> <b>years</b> to trace
+The granite features of this cliff
+(1 row)
+
+
+select headline('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+', to_tsquery('granite&sea'));
+ headline
+----------------------------------------------------------------------------------------------
+ <b>sea</b> an hour one night
+An hour of storm to place
+The sculpture of these <b>granite</b>
+(1 row)
+
+
+select headline('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+', to_tsquery('sea'));
+ headline
+-------------------------------------------------------------------------------------------
+ <b>sea</b> a thousand years,
+A thousand years to trace
+The granite features of this cliff
+(1 row)
+
+--check debug
+select * from ts_debug('Tsearch module for PostgreSQL 7.3.3');
+ ts_name | tok_type | description | token | dict_name | tsvector
+---------+----------+-------------+------------+-----------+--------------
+ default | lword | Latin word | Tsearch | {en_stem} | 'tsearch'
+ default | lword | Latin word | module | {en_stem} | 'modul'
+ default | lword | Latin word | for | {en_stem} |
+ default | lword | Latin word | PostgreSQL | {en_stem} | 'postgresql'
+ default | version | VERSION | 7.3.3 | {simple} | '7.3.3'
+(5 rows)
+
--- /dev/null
+# $Header$
+
+subdir = contrib/tsearch2/ispell
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+
+PG_CPPFLAGS = -I$(srcdir)/.. $(CPPFLAGS)
+override CFLAGS += $(CFLAGS_SL)
+
+SUBOBJS = spell.o
+
+all: SUBSYS.o
+
+SUBSYS.o: $(SUBOBJS)
+ $(LD) $(LDREL) $(LDOUT) $@ $^
+
+EXTRA_CLEAN = SUBSYS.o $(SUBOBJS)
+
+include $(top_srcdir)/contrib/contrib-global.mk
--- /dev/null
+/*
+ * IO definitions for tsquery and mtsquery. This type
+ * are identical, but for parsing mtsquery used parser for text
+ * and also morphology is used.
+ * Internal structure:
+ * query tree, then string with original value.
+ * Query tree with plain view. It's means that in array of nodes
+ * right child is always next and left position = item+item->left
+ */
+#include "postgres.h"
+
+#include <float.h>
+#include <ctype.h>
+
+#include "access/gist.h"
+#include "access/itup.h"
+#include "access/rtree.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "storage/bufpage.h"
+
+#include "ts_cfg.h"
+#include "tsvector.h"
+#include "crc32.h"
+#include "query.h"
+#include "rewrite.h"
+#include "common.h"
+
+
+PG_FUNCTION_INFO_V1(tsquery_in);
+Datum tsquery_in(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(tsquery_out);
+Datum tsquery_out(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(exectsq);
+Datum exectsq(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(rexectsq);
+Datum rexectsq(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(tsquerytree);
+Datum tsquerytree(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(to_tsquery);
+Datum to_tsquery(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(to_tsquery_name);
+Datum to_tsquery_name(PG_FUNCTION_ARGS);
+
+PG_FUNCTION_INFO_V1(to_tsquery_current);
+Datum to_tsquery_current(PG_FUNCTION_ARGS);
+
+/* parser's states */
+#define WAITOPERAND 1
+#define WAITOPERATOR 2
+
+/*
+ * node of query tree, also used
+ * for storing polish notation in parser
+ */
+typedef struct NODE
+{
+ int2 weight;
+ int2 type;
+ int4 val;
+ int2 distance;
+ int2 length;
+ struct NODE *next;
+} NODE;
+
+typedef struct
+{
+ char *buf;
+ int4 state;
+ int4 count;
+ /* reverse polish notation in list (for temprorary usage) */
+ NODE *str;
+ /* number in str */
+ int4 num;
+
+ /* user-friendly operand */
+ int4 lenop;
+ int4 sumlen;
+ char *op;
+ char *curop;
+
+ /* state for value's parser */
+ TI_IN_STATE valstate;
+
+ /* tscfg */
+ int cfg_id;
+} QPRS_STATE;
+
+static char *
+get_weight(char *buf, int2 *weight)
+{
+ *weight = 0;
+
+ if (*buf != ':')
+ return buf;
+
+ buf++;
+ while (*buf)
+ {
+ switch (tolower(*buf))
+ {
+ case 'a':
+ *weight |= 1 << 3;
+ break;
+ case 'b':
+ *weight |= 1 << 2;
+ break;
+ case 'c':
+ *weight |= 1 << 1;
+ break;
+ case 'd':
+ *weight |= 1;
+ break;
+ default:
+ return buf;
+ }
+ buf++;
+ }
+
+ return buf;
+}
+
+/*
+ * get token from query string
+ */
+static int4
+gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, int2 *weight)
+{
+ while (1)
+ {
+ switch (state->state)
+ {
+ case WAITOPERAND:
+ if (*(state->buf) == '!')
+ {
+ (state->buf)++;
+ *val = (int4) '!';
+ return OPR;
+ }
+ else if (*(state->buf) == '(')
+ {
+ state->count++;
+ (state->buf)++;
+ return OPEN;
+ }
+ else if (*(state->buf) == ':')
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("error at start of operand")));
+ }
+ else if (*(state->buf) != ' ')
+ {
+ state->valstate.prsbuf = state->buf;
+ state->state = WAITOPERATOR;
+ if (gettoken_tsvector(&(state->valstate)))
+ {
+ *strval = state->valstate.word;
+ *lenval = state->valstate.curpos - state->valstate.word;
+ state->buf = get_weight(state->valstate.prsbuf, weight);
+ return VAL;
+ }
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("no operand")));
+ }
+ break;
+ case WAITOPERATOR:
+ if (*(state->buf) == '&' || *(state->buf) == '|')
+ {
+ state->state = WAITOPERAND;
+ *val = (int4) *(state->buf);
+ (state->buf)++;
+ return OPR;
+ }
+ else if (*(state->buf) == ')')
+ {
+ (state->buf)++;
+ state->count--;
+ return (state->count < 0) ? ERR : CLOSE;
+ }
+ else if (*(state->buf) == '\0')
+ return (state->count) ? ERR : END;
+ else if (*(state->buf) != ' ')
+ return ERR;
+ break;
+ default:
+ return ERR;
+ break;
+ }
+ (state->buf)++;
+ }
+ return END;
+}
+
+/*
+ * push new one in polish notation reverse view
+ */
+static void
+pushquery(QPRS_STATE * state, int4 type, int4 val, int4 distance, int4 lenval, int2 weight)
+{
+ NODE *tmp = (NODE *) palloc(sizeof(NODE));
+
+ tmp->weight = weight;
+ tmp->type = type;
+ tmp->val = val;
+ if (distance >= MAXSTRPOS)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("value is too big")));
+ if (lenval >= MAXSTRLEN)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("operand is too long")));
+ tmp->distance = distance;
+ tmp->length = lenval;
+ tmp->next = state->str;
+ state->str = tmp;
+ state->num++;
+}
+
+/*
+ * This function is used for tsquery parsing
+ */
+static void
+pushval_asis(QPRS_STATE * state, int type, char *strval, int lenval, int2 weight)
+{
+ if (lenval >= MAXSTRLEN)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("word is too long")));
+
+ pushquery(state, type, crc32_sz((uint8 *) strval, lenval),
+ state->curop - state->op, lenval, weight);
+
+ while (state->curop - state->op + lenval + 1 >= state->lenop)
+ {
+ int4 tmp = state->curop - state->op;
+
+ state->lenop *= 2;
+ state->op = (char *) repalloc((void *) state->op, state->lenop);
+ state->curop = state->op + tmp;
+ }
+ memcpy((void *) state->curop, (void *) strval, lenval);
+ state->curop += lenval;
+ *(state->curop) = '\0';
+ state->curop++;
+ state->sumlen += lenval + 1;
+ return;
+}
+
+/*
+ * This function is used for morph parsing
+ */
+static void
+pushval_morph(QPRS_STATE * state, int typeval, char *strval, int lenval, int2 weight)
+{
+ int4 count = 0;
+ PRSTEXT prs;
+
+ prs.lenwords = 32;
+ prs.curwords = 0;
+ prs.pos = 0;
+ prs.words = (WORD *) palloc(sizeof(WORD) * prs.lenwords);
+
+ parsetext_v2(findcfg(state->cfg_id), &prs, strval, lenval);
+
+ for (count = 0; count < prs.curwords; count++)
+ {
+ pushval_asis(state, VAL, prs.words[count].word, prs.words[count].len, weight);
+ pfree(prs.words[count].word);
+ if (count)
+ pushquery(state, OPR, (int4) '&', 0, 0, 0);
+ }
+ pfree(prs.words);
+
+ /* XXX */
+ if (prs.curwords == 0)
+ pushval_asis(state, VALSTOP, 0, 0, 0);
+}
+
+#define STACKDEPTH 32
+/*
+ * make polish notaion of query
+ */
+static int4
+makepol(QPRS_STATE * state, void (*pushval) (QPRS_STATE *, int, char *, int, int2))
+{
+ int4 val,
+ type;
+ int4 lenval;
+ char *strval;
+ int4 stack[STACKDEPTH];
+ int4 lenstack = 0;
+ int2 weight;
+
+ while ((type = gettoken_query(state, &val, &lenval, &strval, &weight)) != END)
+ {
+ switch (type)
+ {
+ case VAL:
+ (*pushval) (state, VAL, strval, lenval, weight);
+ while (lenstack && (stack[lenstack - 1] == (int4) '&' ||
+ stack[lenstack - 1] == (int4) '!'))
+ {
+ lenstack--;
+ pushquery(state, OPR, stack[lenstack], 0, 0, 0);
+ }
+ break;
+ case OPR:
+ if (lenstack && val == (int4) '|')
+ pushquery(state, OPR, val, 0, 0, 0);
+ else
+ {
+ if (lenstack == STACKDEPTH)
+ /* internal error */
+ elog(ERROR, "stack too short");
+ stack[lenstack] = val;
+ lenstack++;
+ }
+ break;
+ case OPEN:
+ if (makepol(state, pushval) == ERR)
+ return ERR;
+ if (lenstack && (stack[lenstack - 1] == (int4) '&' ||
+ stack[lenstack - 1] == (int4) '!'))
+ {
+ lenstack--;
+ pushquery(state, OPR, stack[lenstack], 0, 0, 0);
+ }
+ break;
+ case CLOSE:
+ while (lenstack)
+ {
+ lenstack--;
+ pushquery(state, OPR, stack[lenstack], 0, 0, 0);
+ };
+ return END;
+ break;
+ case ERR:
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("syntax error")));
+ return ERR;
+
+ }
+ }
+ while (lenstack)
+ {
+ lenstack--;
+ pushquery(state, OPR, stack[lenstack], 0, 0, 0);
+ };
+ return END;
+}
+
+typedef struct
+{
+ WordEntry *arrb;
+ WordEntry *arre;
+ char *values;
+ char *operand;
+} CHKVAL;
+
+/*
+ * compare 2 string values
+ */
+static int4
+ValCompare(CHKVAL * chkval, WordEntry * ptr, ITEM * item)
+{
+ if (ptr->len == item->length)
+ return strncmp(
+ &(chkval->values[ptr->pos]),
+ &(chkval->operand[item->distance]),
+ item->length);
+
+ return (ptr->len > item->length) ? 1 : -1;
+}
+
+/*
+ * check weight info
+ */
+static bool
+checkclass_str(CHKVAL * chkval, WordEntry * val, ITEM * item)
+{
+ WordEntryPos *ptr = (WordEntryPos *) (chkval->values + val->pos + SHORTALIGN(val->len) + sizeof(uint16));
+ uint16 len = *((uint16 *) (chkval->values + val->pos + SHORTALIGN(val->len)));
+
+ while (len--)
+ {
+ if (item->weight & (1 << ptr->weight))
+ return true;
+ ptr++;
+ }
+ return false;
+}
+
+/*
+ * is there value 'val' in array or not ?
+ */
+static bool
+checkcondition_str(void *checkval, ITEM * val)
+{
+ WordEntry *StopLow = ((CHKVAL *) checkval)->arrb;
+ WordEntry *StopHigh = ((CHKVAL *) checkval)->arre;
+ WordEntry *StopMiddle;
+ int difference;
+
+ /* Loop invariant: StopLow <= val < StopHigh */
+
+ while (StopLow < StopHigh)
+ {
+ StopMiddle = StopLow + (StopHigh - StopLow) / 2;
+ difference = ValCompare((CHKVAL *) checkval, StopMiddle, val);
+ if (difference == 0)
+ return (val->weight && StopMiddle->haspos) ?
+ checkclass_str((CHKVAL *) checkval, StopMiddle, val) : true;
+ else if (difference < 0)
+ StopLow = StopMiddle + 1;
+ else
+ StopHigh = StopMiddle;
+ }
+
+ return (false);
+}
+
+/*
+ * check for boolean condition
+ */
+bool
+TS_execute(ITEM * curitem, void *checkval, bool calcnot, bool (*chkcond) (void *checkval, ITEM * val))
+{
+ if (curitem->type == VAL)
+ return (*chkcond) (checkval, curitem);
+ else if (curitem->val == (int4) '!')
+ {
+ return (calcnot) ?
+ ((TS_execute(curitem + 1, checkval, calcnot, chkcond)) ? false : true)
+ : true;
+ }
+ else if (curitem->val == (int4) '&')
+ {
+ if (TS_execute(curitem + curitem->left, checkval, calcnot, chkcond))
+ return TS_execute(curitem + 1, checkval, calcnot, chkcond);
+ else
+ return false;
+ }
+ else
+ { /* |-operator */
+ if (TS_execute(curitem + curitem->left, checkval, calcnot, chkcond))
+ return true;
+ else
+ return TS_execute(curitem + 1, checkval, calcnot, chkcond);
+ }
+ return false;
+}
+
+/*
+ * boolean operations
+ */
+Datum
+rexectsq(PG_FUNCTION_ARGS)
+{
+ return DirectFunctionCall2(
+ exectsq,
+ PG_GETARG_DATUM(1),
+ PG_GETARG_DATUM(0)
+ );
+}
+
+Datum
+exectsq(PG_FUNCTION_ARGS)
+{
+ tsvector *val = (tsvector *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
+ QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
+ CHKVAL chkval;
+ bool result;
+
+ if (!val->size || !query->size)
+ {
+ PG_FREE_IF_COPY(val, 0);
+ PG_FREE_IF_COPY(query, 1);
+ PG_RETURN_BOOL(false);
+ }
+
+ chkval.arrb = ARRPTR(val);
+ chkval.arre = chkval.arrb + val->size;
+ chkval.values = STRPTR(val);
+ chkval.operand = GETOPERAND(query);
+ result = TS_execute(
+ GETQUERY(query),
+ &chkval,
+ true,
+ checkcondition_str
+ );
+
+ PG_FREE_IF_COPY(val, 0);
+ PG_FREE_IF_COPY(query, 1);
+ PG_RETURN_BOOL(result);
+}
+
+/*
+ * find left operand in polish notation view
+ */
+static void
+findoprnd(ITEM * ptr, int4 *pos)
+{
+#ifdef BS_DEBUG
+ elog(DEBUG3, (ptr[*pos].type == OPR) ?
+ "%d %c" : "%d %d", *pos, ptr[*pos].val);
+#endif
+ if (ptr[*pos].type == VAL || ptr[*pos].type == VALSTOP)
+ {
+ ptr[*pos].left = 0;
+ (*pos)++;
+ }
+ else if (ptr[*pos].val == (int4) '!')
+ {
+ ptr[*pos].left = 1;
+ (*pos)++;
+ findoprnd(ptr, pos);
+ }
+ else
+ {
+ ITEM *curitem = &ptr[*pos];
+ int4 tmp = *pos;
+
+ (*pos)++;
+ findoprnd(ptr, pos);
+ curitem->left = *pos - tmp;
+ findoprnd(ptr, pos);
+ }
+}
+
+
+/*
+ * input
+ */
+static QUERYTYPE *
+ queryin(char *buf, void (*pushval) (QPRS_STATE *, int, char *, int, int2), int cfg_id)
+{
+ QPRS_STATE state;
+ int4 i;
+ QUERYTYPE *query;
+ int4 commonlen;
+ ITEM *ptr;
+ NODE *tmp;
+ int4 pos = 0;
+
+#ifdef BS_DEBUG
+ char pbuf[16384],
+ *cur;
+#endif
+
+ /* init state */
+ state.buf = buf;
+ state.state = WAITOPERAND;
+ state.count = 0;
+ state.num = 0;
+ state.str = NULL;
+ state.cfg_id = cfg_id;
+
+ /* init value parser's state */
+ state.valstate.oprisdelim = true;
+ state.valstate.len = 32;
+ state.valstate.word = (char *) palloc(state.valstate.len);
+
+ /* init list of operand */
+ state.sumlen = 0;
+ state.lenop = 64;
+ state.curop = state.op = (char *) palloc(state.lenop);
+ *(state.curop) = '\0';
+
+ /* parse query & make polish notation (postfix, but in reverse order) */
+ makepol(&state, pushval);
+ pfree(state.valstate.word);
+ if (!state.num)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("empty query")));
+
+ /* make finish struct */
+ commonlen = COMPUTESIZE(state.num, state.sumlen);
+ query = (QUERYTYPE *) palloc(commonlen);
+ query->len = commonlen;
+ query->size = state.num;
+ ptr = GETQUERY(query);
+
+ /* set item in polish notation */
+ for (i = 0; i < state.num; i++)
+ {
+ ptr[i].weight = state.str->weight;
+ ptr[i].type = state.str->type;
+ ptr[i].val = state.str->val;
+ ptr[i].distance = state.str->distance;
+ ptr[i].length = state.str->length;
+ tmp = state.str->next;
+ pfree(state.str);
+ state.str = tmp;
+ }
+
+ /* set user friendly-operand view */
+ memcpy((void *) GETOPERAND(query), (void *) state.op, state.sumlen);
+ pfree(state.op);
+
+ /* set left operand's position for every operator */
+ pos = 0;
+ findoprnd(ptr, &pos);
+
+#ifdef BS_DEBUG
+ cur = pbuf;
+ *cur = '\0';
+ for (i = 0; i < query->size; i++)
+ {
+ if (ptr[i].type == OPR)
+ sprintf(cur, "%c(%d) ", ptr[i].val, ptr[i].left);
+ else
+ sprintf(cur, "%d(%s) ", ptr[i].val, GETOPERAND(query) + ptr[i].distance);
+ cur = strchr(cur, '\0');
+ }
+ elog(DEBUG3, "POR: %s", pbuf);
+#endif
+
+ return query;
+}
+
+/*
+ * in without morphology
+ */
+Datum
+tsquery_in(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_POINTER(queryin((char *) PG_GETARG_POINTER(0), pushval_asis, 0));
+}
+
+/*
+ * out function
+ */
+typedef struct
+{
+ ITEM *curpol;
+ char *buf;
+ char *cur;
+ char *op;
+ int4 buflen;
+} INFIX;
+
+#define RESIZEBUF(inf,addsize) \
+while( ( inf->cur - inf->buf ) + addsize + 1 >= inf->buflen ) \
+{ \
+ int4 len = inf->cur - inf->buf; \
+ inf->buflen *= 2; \
+ inf->buf = (char*) repalloc( (void*)inf->buf, inf->buflen ); \
+ inf->cur = inf->buf + len; \
+}
+
+/*
+ * recursive walk on tree and print it in
+ * infix (human-readable) view
+ */
+static void
+infix(INFIX * in, bool first)
+{
+ if (in->curpol->type == VAL)
+ {
+ char *op = in->op + in->curpol->distance;
+
+ RESIZEBUF(in, in->curpol->length * 2 + 2 + 5);
+ *(in->cur) = '\'';
+ in->cur++;
+ while (*op)
+ {
+ if (*op == '\'')
+ {
+ *(in->cur) = '\\';
+ in->cur++;
+ }
+ *(in->cur) = *op;
+ op++;
+ in->cur++;
+ }
+ *(in->cur) = '\'';
+ in->cur++;
+ if (in->curpol->weight)
+ {
+ *(in->cur) = ':';
+ in->cur++;
+ if (in->curpol->weight & (1 << 3))
+ {
+ *(in->cur) = 'A';
+ in->cur++;
+ }
+ if (in->curpol->weight & (1 << 2))
+ {
+ *(in->cur) = 'B';
+ in->cur++;
+ }
+ if (in->curpol->weight & (1 << 1))
+ {
+ *(in->cur) = 'C';
+ in->cur++;
+ }
+ if (in->curpol->weight & 1)
+ {
+ *(in->cur) = 'D';
+ in->cur++;
+ }
+ }
+ *(in->cur) = '\0';
+ in->curpol++;
+ }
+ else if (in->curpol->val == (int4) '!')
+ {
+ bool isopr = false;
+
+ RESIZEBUF(in, 1);
+ *(in->cur) = '!';
+ in->cur++;
+ *(in->cur) = '\0';
+ in->curpol++;
+ if (in->curpol->type == OPR)
+ {
+ isopr = true;
+ RESIZEBUF(in, 2);
+ sprintf(in->cur, "( ");
+ in->cur = strchr(in->cur, '\0');
+ }
+ infix(in, isopr);
+ if (isopr)
+ {
+ RESIZEBUF(in, 2);
+ sprintf(in->cur, " )");
+ in->cur = strchr(in->cur, '\0');
+ }
+ }
+ else
+ {
+ int4 op = in->curpol->val;
+ INFIX nrm;
+
+ in->curpol++;
+ if (op == (int4) '|' && !first)
+ {
+ RESIZEBUF(in, 2);
+ sprintf(in->cur, "( ");
+ in->cur = strchr(in->cur, '\0');
+ }
+
+ nrm.curpol = in->curpol;
+ nrm.op = in->op;
+ nrm.buflen = 16;
+ nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
+
+ /* get right operand */
+ infix(&nrm, false);
+
+ /* get & print left operand */
+ in->curpol = nrm.curpol;
+ infix(in, false);
+
+ /* print operator & right operand */
+ RESIZEBUF(in, 3 + (nrm.cur - nrm.buf));
+ sprintf(in->cur, " %c %s", op, nrm.buf);
+ in->cur = strchr(in->cur, '\0');
+ pfree(nrm.buf);
+
+ if (op == (int4) '|' && !first)
+ {
+ RESIZEBUF(in, 2);
+ sprintf(in->cur, " )");
+ in->cur = strchr(in->cur, '\0');
+ }
+ }
+}
+
+
+Datum
+tsquery_out(PG_FUNCTION_ARGS)
+{
+ QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
+ INFIX nrm;
+
+ if (query->size == 0)
+ {
+ char *b = palloc(1);
+
+ *b = '\0';
+ PG_RETURN_POINTER(b);
+ }
+ nrm.curpol = GETQUERY(query);
+ nrm.buflen = 32;
+ nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
+ *(nrm.cur) = '\0';
+ nrm.op = GETOPERAND(query);
+ infix(&nrm, true);
+
+ PG_FREE_IF_COPY(query, 0);
+ PG_RETURN_POINTER(nrm.buf);
+}
+
+/*
+ * debug function, used only for view query
+ * which will be executed in non-leaf pages in index
+ */
+Datum
+tsquerytree(PG_FUNCTION_ARGS)
+{
+ QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
+ INFIX nrm;
+ text *res;
+ ITEM *q;
+ int4 len;
+
+
+ if (query->size == 0)
+ {
+ res = (text *) palloc(VARHDRSZ);
+ VARATT_SIZEP(res) = VARHDRSZ;
+ PG_RETURN_POINTER(res);
+ }
+
+ q = clean_NOT_v2(GETQUERY(query), &len);
+
+ if (!q)
+ {
+ res = (text *) palloc(1 + VARHDRSZ);
+ VARATT_SIZEP(res) = 1 + VARHDRSZ;
+ *((char *) VARDATA(res)) = 'T';
+ }
+ else
+ {
+ nrm.curpol = q;
+ nrm.buflen = 32;
+ nrm.cur = nrm.buf = (char *) palloc(sizeof(char) * nrm.buflen);
+ *(nrm.cur) = '\0';
+ nrm.op = GETOPERAND(query);
+ infix(&nrm, true);
+
+ res = (text *) palloc(nrm.cur - nrm.buf + VARHDRSZ);
+ VARATT_SIZEP(res) = nrm.cur - nrm.buf + VARHDRSZ;
+ strncpy(VARDATA(res), nrm.buf, nrm.cur - nrm.buf);
+ pfree(q);
+ }
+
+ PG_FREE_IF_COPY(query, 0);
+
+ PG_RETURN_POINTER(res);
+}
+
+Datum
+to_tsquery(PG_FUNCTION_ARGS)
+{
+ text *in = PG_GETARG_TEXT_P(1);
+ char *str;
+ QUERYTYPE *query;
+ ITEM *res;
+ int4 len;
+
+ str = text2char(in);
+ PG_FREE_IF_COPY(in, 1);
+
+ query = queryin(str, pushval_morph, PG_GETARG_INT32(0));
+ res = clean_fakeval_v2(GETQUERY(query), &len);
+ if (!res)
+ {
+ query->len = HDRSIZEQT;
+ query->size = 0;
+ PG_RETURN_POINTER(query);
+ }
+ memcpy((void *) GETQUERY(query), (void *) res, len * sizeof(ITEM));
+ pfree(res);
+ PG_RETURN_POINTER(query);
+}
+
+Datum
+to_tsquery_name(PG_FUNCTION_ARGS)
+{
+ text *name = PG_GETARG_TEXT_P(0);
+ Datum res = DirectFunctionCall2(
+ to_tsquery,
+ Int32GetDatum(name2id_cfg(name)),
+ PG_GETARG_DATUM(1)
+ );
+
+ PG_FREE_IF_COPY(name, 1);
+ PG_RETURN_DATUM(res);
+}
+
+Datum
+to_tsquery_current(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_DATUM(DirectFunctionCall2(
+ to_tsquery,
+ Int32GetDatum(get_currcfg()),
+ PG_GETARG_DATUM(0)
+ ));
+}
--- /dev/null
+#ifndef __QUERY_H__
+#define __QUERY_H__
+/*
+#define BS_DEBUG
+*/
+
+
+/*
+ * item in polish notation with back link
+ * to left operand
+ */
+typedef struct ITEM
+{
+ int8 type;
+ int8 weight;
+ int2 left;
+ int4 val;
+ /* user-friendly value, must correlate with WordEntry */
+ uint32
+ unused:1,
+ length:11,
+ distance:20;
+} ITEM;
+
+/*
+ *Storage:
+ * (len)(size)(array of ITEM)(array of operand in user-friendly form)
+ */
+typedef struct
+{
+ int4 len;
+ int4 size;
+ char data[1];
+} QUERYTYPE;
+
+#define HDRSIZEQT ( 2*sizeof(int4) )
+#define COMPUTESIZE(size,lenofoperand) ( HDRSIZEQT + size * sizeof(ITEM) + lenofoperand )
+#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
+#define GETOPERAND(x) ( (char*)GETQUERY(x) + ((QUERYTYPE*)x)->size * sizeof(ITEM) )
+
+#define ISOPERATOR(x) ( (x)=='!' || (x)=='&' || (x)=='|' || (x)=='(' || (x)==')' )
+
+#define END 0
+#define ERR 1
+#define VAL 2
+#define OPR 3
+#define OPEN 4
+#define CLOSE 5
+#define VALSTOP 6 /* for stop words */
+
+bool TS_execute(ITEM * curitem, void *checkval,
+ bool calcnot, bool (*chkcond) (void *checkval, ITEM * val));
+
+#endif
--- /dev/null
+/*
+ * Rewrite routines of query tree
+ */
+
+#include "postgres.h"
+
+#include <float.h>
+
+#include "access/gist.h"
+#include "access/itup.h"
+#include "access/rtree.h"
+#include "storage/bufpage.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+
+#include "query.h"
+#include "rewrite.h"
+
+typedef struct NODE
+{
+ struct NODE *left;
+ struct NODE *right;
+ ITEM *valnode;
+} NODE;
+
+/*
+ * make query tree from plain view of query
+ */
+static NODE *
+maketree(ITEM * in)
+{
+ NODE *node = (NODE *) palloc(sizeof(NODE));
+
+ node->valnode = in;
+ node->right = node->left = NULL;
+ if (in->type == OPR)
+ {
+ node->right = maketree(in + 1);
+ if (in->val != (int4) '!')
+ node->left = maketree(in + in->left);
+ }
+ return node;
+}
+
+typedef struct
+{
+ ITEM *ptr;
+ int4 len;
+ int4 cur;
+} PLAINTREE;
+
+static void
+plainnode(PLAINTREE * state, NODE * node)
+{
+ if (state->cur == state->len)
+ {
+ state->len *= 2;
+ state->ptr = (ITEM *) repalloc((void *) state->ptr, state->len * sizeof(ITEM));
+ }
+ memcpy((void *) &(state->ptr[state->cur]), (void *) node->valnode, sizeof(ITEM));
+ if (node->valnode->type == VAL)
+ state->cur++;
+ else if (node->valnode->val == (int4) '!')
+ {
+ state->ptr[state->cur].left = 1;
+ state->cur++;
+ plainnode(state, node->right);
+ }
+ else
+ {
+ int4 cur = state->cur;
+
+ state->cur++;
+ plainnode(state, node->right);
+ state->ptr[cur].left = state->cur - cur;
+ plainnode(state, node->left);
+ }
+ pfree(node);
+}
+
+/*
+ * make plain view of tree from 'normal' view of tree
+ */
+static ITEM *
+plaintree(NODE * root, int4 *len)
+{
+ PLAINTREE pl;
+
+ pl.cur = 0;
+ pl.len = 16;
+ if (root && (root->valnode->type == VAL || root->valnode->type == OPR))
+ {
+ pl.ptr = (ITEM *) palloc(pl.len * sizeof(ITEM));
+ plainnode(&pl, root);
+ }
+ else
+ pl.ptr = NULL;
+ *len = pl.cur;
+ return pl.ptr;
+}
+
+static void
+freetree(NODE * node)
+{
+ if (!node)
+ return;
+ if (node->left)
+ freetree(node->left);
+ if (node->right)
+ freetree(node->right);
+ pfree(node);
+}
+
+/*
+ * clean tree for ! operator.
+ * It's usefull for debug, but in
+ * other case, such view is used with search in index.
+ * Operator ! always return TRUE
+ */
+static NODE *
+clean_NOT_intree(NODE * node)
+{
+ if (node->valnode->type == VAL)
+ return node;
+
+ if (node->valnode->val == (int4) '!')
+ {
+ freetree(node);
+ return NULL;
+ }
+
+ /* operator & or | */
+ if (node->valnode->val == (int4) '|')
+ {
+ if ((node->left = clean_NOT_intree(node->left)) == NULL ||
+ (node->right = clean_NOT_intree(node->right)) == NULL)
+ {
+ freetree(node);
+ return NULL;
+ }
+ }
+ else
+ {
+ NODE *res = node;
+
+ node->left = clean_NOT_intree(node->left);
+ node->right = clean_NOT_intree(node->right);
+ if (node->left == NULL && node->right == NULL)
+ {
+ pfree(node);
+ res = NULL;
+ }
+ else if (node->left == NULL)
+ {
+ res = node->right;
+ pfree(node);
+ }
+ else if (node->right == NULL)
+ {
+ res = node->left;
+ pfree(node);
+ }
+ return res;
+ }
+ return node;
+}
+
+ITEM *
+clean_NOT_v2(ITEM * ptr, int4 *len)
+{
+ NODE *root = maketree(ptr);
+
+ return plaintree(clean_NOT_intree(root), len);
+}
+
+#define V_UNKNOWN 0
+#define V_TRUE 1
+#define V_FALSE 2
+#define V_STOP 3
+
+/*
+ * Clean query tree from values which is always in
+ * text (stopword)
+ */
+static NODE *
+clean_fakeval_intree(NODE * node, char *result)
+{
+ char lresult = V_UNKNOWN,
+ rresult = V_UNKNOWN;
+
+ if (node->valnode->type == VAL)
+ return node;
+ else if (node->valnode->type == VALSTOP)
+ {
+ pfree(node);
+ *result = V_STOP;
+ return NULL;
+ }
+
+
+ if (node->valnode->val == (int4) '!')
+ {
+ node->right = clean_fakeval_intree(node->right, &rresult);
+ if (!node->right)
+ {
+ *result = V_STOP;
+ freetree(node);
+ return NULL;
+ }
+ }
+ else
+ {
+ NODE *res = node;
+
+ node->left = clean_fakeval_intree(node->left, &lresult);
+ node->right = clean_fakeval_intree(node->right, &rresult);
+ if (lresult == V_STOP && rresult == V_STOP)
+ {
+ freetree(node);
+ *result = V_STOP;
+ return NULL;
+ }
+ else if (lresult == V_STOP)
+ {
+ res = node->right;
+ pfree(node);
+ }
+ else if (rresult == V_STOP)
+ {
+ res = node->left;
+ pfree(node);
+ }
+ return res;
+ }
+ return node;
+}
+
+ITEM *
+clean_fakeval_v2(ITEM * ptr, int4 *len)
+{
+ NODE *root = maketree(ptr);
+ char result = V_UNKNOWN;
+ NODE *resroot;
+
+ resroot = clean_fakeval_intree(root, &result);
+ if (result != V_UNKNOWN)
+ {
+ elog(NOTICE, "Query contains only stopword(s) or doesn't contain lexem(s), ignored");
+ *len = 0;
+ return NULL;
+ }
+
+ return plaintree(resroot, len);
+}
--- /dev/null
+# $Header$
+
+subdir = contrib/tsearch2/snowball
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+
+PG_CPPFLAGS = -I$(srcdir)/..
+override CFLAGS += $(CFLAGS_SL)
+
+SUBOBJS = english_stem.o api.o russian_stem.o utilities.o
+
+all: SUBSYS.o
+
+SUBSYS.o: $(SUBOBJS)
+ $(LD) $(LDREL) $(LDOUT) $@ $^
+
+EXTRA_CLEAN = SUBSYS.o $(SUBOBJS)
+
+include $(top_srcdir)/contrib/contrib-global.mk
--- /dev/null
+--
+-- first, define the datatype. Turn off echoing so that expected file
+-- does not depend on contents of seg.sql.
+--
+\set ECHO none
+\i tsearch2.sql
+\set ECHO all
+
+--tsvector
+SELECT '1'::tsvector;
+SELECT '1 '::tsvector;
+SELECT ' 1'::tsvector;
+SELECT ' 1 '::tsvector;
+SELECT '1 2'::tsvector;
+SELECT '\'1 2\''::tsvector;
+SELECT '\'1 \\\'2\''::tsvector;
+SELECT '\'1 \\\'2\'3'::tsvector;
+SELECT '\'1 \\\'2\' 3'::tsvector;
+SELECT '\'1 \\\'2\' \' 3\' 4 '::tsvector;
+select '\'w\':4A,3B,2C,1D,5 a:8';
+select 'a:3A b:2a'::tsvector || 'ba:1234 a:1B';
+select setweight('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd zxc:81,567,222A'::tsvector, 'c');
+select strip('w:12B w:13* w:12,5,6 a:1,3* a:3 w asd:1dc asd'::tsvector);
+
+
+--tsquery
+SELECT '1'::tsquery;
+SELECT '1 '::tsquery;
+SELECT ' 1'::tsquery;
+SELECT ' 1 '::tsquery;
+SELECT '\'1 2\''::tsquery;
+SELECT '\'1 \\\'2\''::tsquery;
+SELECT '!1'::tsquery;
+SELECT '1|2'::tsquery;
+SELECT '1|!2'::tsquery;
+SELECT '!1|2'::tsquery;
+SELECT '!1|!2'::tsquery;
+SELECT '!(!1|!2)'::tsquery;
+SELECT '!(!1|2)'::tsquery;
+SELECT '!(1|!2)'::tsquery;
+SELECT '!(1|2)'::tsquery;
+SELECT '1&2'::tsquery;
+SELECT '!1&2'::tsquery;
+SELECT '1&!2'::tsquery;
+SELECT '!1&!2'::tsquery;
+SELECT '(1&2)'::tsquery;
+SELECT '1&(2)'::tsquery;
+SELECT '!(1)&2'::tsquery;
+SELECT '!(1&2)'::tsquery;
+SELECT '1|2&3'::tsquery;
+SELECT '1|(2&3)'::tsquery;
+SELECT '(1|2)&3'::tsquery;
+SELECT '1|2&!3'::tsquery;
+SELECT '1|!2&3'::tsquery;
+SELECT '!1|2&3'::tsquery;
+SELECT '!1|(2&3)'::tsquery;
+SELECT '!(1|2)&3'::tsquery;
+SELECT '(!1|2)&3'::tsquery;
+SELECT '1|(2|(4|(5|6)))'::tsquery;
+SELECT '1|2|4|5|6'::tsquery;
+SELECT '1&(2&(4&(5&6)))'::tsquery;
+SELECT '1&2&4&5&6'::tsquery;
+SELECT '1&(2&(4&(5|6)))'::tsquery;
+SELECT '1&(2&(4&(5|!6)))'::tsquery;
+SELECT '1&(\'2\'&(\' 4\'&(\\|5 | \'6 \\\' !|&\')))'::tsquery;
+SELECT '\'the wether\':dc & \' sKies \':BC & a:d b:a';
+
+select lexize('simple', 'ASD56 hsdkf');
+select lexize('en_stem', 'SKIES Problems identity');
+
+select * from token_type('default');
+select * from parse('default', '345
[email protected] \' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe 234.435 455 5.005
[email protected] qwe-wer asdf <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>">
+/usr/local/fff /awdf/dwqe/4325 rewt/ewr wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234
+<i <b> wow < jqw <> qwerty');
+
+SELECT to_tsvector('default', '345
[email protected] \' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe 234.435 455 5.005
[email protected] qwe-wer asdf <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>">
+/usr/local/fff /awdf/dwqe/4325 rewt/ewr wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234
+<i <b> wow < jqw <> qwerty');
+
+SELECT length(to_tsvector('default', '345 qw'));
+
+SELECT length(to_tsvector('default', '345
[email protected] \' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe 234.435 455 5.005
[email protected] qwe-wer asdf <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>">
+/usr/local/fff /awdf/dwqe/4325 rewt/ewr wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234
+<i <b> wow < jqw <> qwerty'));
+
+
+select to_tsquery('default', 'qwe & sKies ');
+select to_tsquery('simple', 'qwe & sKies ');
+select to_tsquery('default', '\'the wether\':dc & \' sKies \':BC ');
+select to_tsquery('asd&(and|fghj)');
+select to_tsquery('(asd&and)|fghj');
+select to_tsquery('(asd&!and)|fghj');
+select to_tsquery('(the|and&(i&1))&fghj');
+select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca';
+select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca:B';
+select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca:A';
+select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca:C';
+select 'a b:89 ca:23A,64b d:34c'::tsvector @@ 'd:AC & ca:CB';
+
+CREATE TABLE test_tsvector( t text, a tsvector );
+
+\copy test_tsvector from 'data/test_tsearch.data'
+
+SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh';
+SELECT count(*) FROM test_tsvector WHERE a @@ 'wr&qh';
+SELECT count(*) FROM test_tsvector WHERE a @@ 'eq&yt';
+SELECT count(*) FROM test_tsvector WHERE a @@ 'eq|yt';
+SELECT count(*) FROM test_tsvector WHERE a @@ '(eq&yt)|(wr&qh)';
+SELECT count(*) FROM test_tsvector WHERE a @@ '(eq|yt)&(wr|qh)';
+
+create index wowidx on test_tsvector using gist (a);
+set enable_seqscan=off;
+
+SELECT count(*) FROM test_tsvector WHERE a @@ 'wr|qh';
+SELECT count(*) FROM test_tsvector WHERE a @@ 'wr&qh';
+SELECT count(*) FROM test_tsvector WHERE a @@ 'eq&yt';
+SELECT count(*) FROM test_tsvector WHERE a @@ 'eq|yt';
+SELECT count(*) FROM test_tsvector WHERE a @@ '(eq&yt)|(wr&qh)';
+SELECT count(*) FROM test_tsvector WHERE a @@ '(eq|yt)&(wr|qh)';
+
+select set_curcfg('default');
+
+CREATE TRIGGER tsvectorupdate
+BEFORE UPDATE OR INSERT ON test_tsvector
+FOR EACH ROW EXECUTE PROCEDURE tsearch2(a, t);
+
+SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty');
+
+INSERT INTO test_tsvector (t) VALUES ('345 qwerty');
+
+SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty');
+
+UPDATE test_tsvector SET t = null WHERE t = '345 qwerty';
+
+SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty');
+
+drop trigger tsvectorupdate on test_tsvector;
+create function wow(text) returns text as 'select $1 || \' copyright\'; ' language sql;
+create trigger tsvectorupdate before update or insert on test_tsvector
+for each row execute procedure tsearch2(a, wow, t);
+insert into test_tsvector (t) values ('345 qwerty');
+select count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty');
+select count(*) FROM test_tsvector WHERE a @@ to_tsquery('copyright');
+
+select rank(' a:1 s:2C d g'::tsvector, 'a | s');
+select rank(' a:1 s:2B d g'::tsvector, 'a | s');
+select rank(' a:1 s:2 d g'::tsvector, 'a | s');
+select rank(' a:1 s:2C d g'::tsvector, 'a & s');
+select rank(' a:1 s:2B d g'::tsvector, 'a & s');
+select rank(' a:1 s:2 d g'::tsvector, 'a & s');
+
+insert into test_tsvector (t) values ('foo bar foo the over foo qq bar');
+select * from stat('select a from test_tsvector') order by ndoc desc, nentry desc, word;
+
+select reset_tsearch();
+select to_tsquery('default', 'skies & books');
+
+select rank_cd(to_tsvector('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+'), to_tsquery('sea&thousand&years'));
+
+select rank_cd(to_tsvector('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+'), to_tsquery('granite&sea'));
+
+select rank_cd(to_tsvector('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+'), to_tsquery('sea'));
+
+select get_covers(to_tsvector('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+'), to_tsquery('sea&thousand&years'));
+
+select get_covers(to_tsvector('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+'), to_tsquery('granite&sea'));
+
+select get_covers(to_tsvector('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+'), to_tsquery('sea'));
+
+select headline('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+', to_tsquery('sea&thousand&years'));
+
+select headline('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+', to_tsquery('granite&sea'));
+
+select headline('Erosion It took the sea a thousand years,
+A thousand years to trace
+The granite features of this cliff
+In crag and scarp and base.
+It took the sea an hour one night
+An hour of storm to place
+The sculpture of these granite seams,
+Upon a woman s face. E. J. Pratt (1882 1964)
+', to_tsquery('sea'));
+
+--check debug
+select * from ts_debug('Tsearch module for PostgreSQL 7.3.3');
--- /dev/null
+# $Header$
+
+subdir = contrib/tsearch2/wordparser
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+
+PG_CPPFLAGS = -I$(srcdir)/..
+override CFLAGS += $(CFLAGS_SL)
+
+SUBOBJS = parser.o deflex.o
+
+all: SUBSYS.o
+
+parser.c: parser.l
+ifdef FLEX
+ $(FLEX) $(FLEXFLAGS) -8 -Ptsearch2_yy -o'$@' $<
+else
+ @$(missing) flex $< $@
+endif
+
+SUBSYS.o: $(SUBOBJS)
+ $(LD) $(LDREL) $(LDOUT) $@ $^
+
+EXTRA_CLEAN = SUBSYS.o $(SUBOBJS) parser.c
+
+include $(top_srcdir)/contrib/contrib-global.mk
--- /dev/null
+#ifndef __PARSER_H__
+#define __PARSER_H__
+
+char *token;
+int tokenlen;
+int tsearch2_yylex(void);
+void start_parse_str(char *, int);
+void end_parse(void);
+
+#endif
--- /dev/null
+%{
+#include "postgres.h"
+
+#include "deflex.h"
+#include "parser.h"
+#include "common.h"
+
+/* Avoid exit() on fatal scanner errors */
+#define fprintf(file, fmt, msg) ts_error(ERROR, fmt, msg)
+
+/* postgres allocation function */
+#define free pfree
+#define malloc palloc
+#define realloc repalloc
+
+#ifdef strdup
+#undef strdup
+#endif
+#define strdup pstrdup
+
+char *token = NULL; /* pointer to token */
+char *s = NULL; /* to return WHOLE hyphenated-word */
+
+YY_BUFFER_STATE buf = NULL; /* buffer to parse; it need for parse from string */
+
+%}
+
+%option 8bit
+%option never-interactive
+%option nounput
+%option noyywrap
+
+/* parser's state for parsing hyphenated-word */
+%x DELIM
+/* parser's state for parsing URL*/
+%x URL
+%x SERVER
+
+/* parser's state for parsing TAGS */
+%x INTAG
+%x QINTAG
+%x INCOMMENT
+%x INSCRIPT
+
+/* cyrillic koi8 char */
+CYRALNUM [0-9\200-\377]
+CYRALPHA [\200-\377]
+ALPHA [a-zA-Z\200-\377]
+ALNUM [0-9a-zA-Z\200-\377]
+
+
+HOSTNAME ([-_[:alnum:]]+\.)+[[:alpha:]]+
+URI [-_[:alnum:]/%,\.;=&?#]+
+
+%%
+
+"<"[Ss][Cc][Rr][Ii][Pp][Tt] { BEGIN INSCRIPT; }
+
+<INSCRIPT>"</"[Ss][Cc][Rr][Ii][Pp][Tt]">" {
+ BEGIN INITIAL;
+ *tsearch2_yytext=' '; *(tsearch2_yytext+1) = '\0';
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return SPACE;
+}
+
+"<!--" { BEGIN INCOMMENT; }
+
+<INCOMMENT>"-->" {
+ BEGIN INITIAL;
+ *tsearch2_yytext=' '; *(tsearch2_yytext+1) = '\0';
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return SPACE;
+}
+
+
+"<"[\![:alpha:]] { BEGIN INTAG; }
+
+"</"[[:alpha:]] { BEGIN INTAG; }
+
+<INTAG>"\"" { BEGIN QINTAG; }
+
+<QINTAG>"\\\"" ;
+
+<QINTAG>"\"" { BEGIN INTAG; }
+
+<INTAG>">" {
+ BEGIN INITIAL;
+ token = tsearch2_yytext;
+ *tsearch2_yytext=' ';
+ token = tsearch2_yytext;
+ tokenlen = 1;
+ return TAG;
+}
+
+<QINTAG,INTAG,INCOMMENT,INSCRIPT>.|\n ;
+
+\&(quot|amp|nbsp|lt|gt)\; {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return HTMLENTITY;
+}
+
+\&\#[0-9][0-9]?[0-9]?\; {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return HTMLENTITY;
+}
+
+[-_\.[:alnum:]]+@{HOSTNAME} /* Emails */ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return EMAIL;
+}
+
+[+-]?[0-9]+(\.[0-9]+)?[eEdD][+-]?[0-9]+ /* float */ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return SCIENTIFIC;
+}
+
+[0-9]+\.[0-9]+\.[0-9\.]*[0-9] {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return VERSIONNUMBER;
+}
+
+[+-]?[0-9]+\.[0-9]+ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return DECIMAL;
+}
+
+[+-][0-9]+ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return SIGNEDINT;
+}
+
+<DELIM,INITIAL>[0-9]+ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return UNSIGNEDINT;
+}
+
+http"://" {
+ BEGIN URL;
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return HTTP;
+}
+
+ftp"://" {
+ BEGIN URL;
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return HTTP;
+}
+
+<URL,INITIAL>{HOSTNAME}[/:]{URI} {
+ BEGIN SERVER;
+ if (s) { free(s); s=NULL; }
+ s = strdup( tsearch2_yytext );
+ tokenlen = tsearch2_yyleng;
+ yyless( 0 );
+ token = s;
+ return FURL;
+}
+
+<SERVER,URL,INITIAL>{HOSTNAME} {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return HOST;
+}
+
+<SERVER>[/:]{URI} {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return URI;
+}
+
+[[:alnum:]\./_-]+"/"[[:alnum:]\./_-]+ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return FILEPATH;
+}
+
+({CYRALPHA}+-)+{CYRALPHA}+ /* composite-word */ {
+ BEGIN DELIM;
+ if (s) { free(s); s=NULL; }
+ s = strdup( tsearch2_yytext );
+ tokenlen = tsearch2_yyleng;
+ yyless( 0 );
+ token = s;
+ return CYRHYPHENWORD;
+}
+
+([[:alpha:]]+-)+[[:alpha:]]+ /* composite-word */ {
+ BEGIN DELIM;
+ if (s) { free(s); s=NULL; }
+ s = strdup( tsearch2_yytext );
+ tokenlen = tsearch2_yyleng;
+ yyless( 0 );
+ token = s;
+ return LATHYPHENWORD;
+}
+
+({ALNUM}+-)+{ALNUM}+ /* composite-word */ {
+ BEGIN DELIM;
+ if (s) { free(s); s=NULL; }
+ s = strdup( tsearch2_yytext );
+ tokenlen = tsearch2_yyleng;
+ yyless( 0 );
+ token = s;
+ return HYPHENWORD;
+}
+
+<DELIM>[0-9]+\.[0-9]+\.[0-9\.]*[0-9] {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return VERSIONNUMBER;
+}
+
+<DELIM>\+?[0-9]+\.[0-9]+ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return DECIMAL;
+}
+
+<DELIM>{CYRALPHA}+ /* one word in composite-word */ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return CYRPARTHYPHENWORD;
+}
+
+<DELIM>[[:alpha:]]+ /* one word in composite-word */ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return LATPARTHYPHENWORD;
+}
+
+<DELIM>{ALNUM}+ /* one word in composite-word */ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return PARTHYPHENWORD;
+}
+
+<DELIM>- {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return SPACE;
+}
+
+<DELIM,SERVER,URL>.|\n /* return in basic state */ {
+ BEGIN INITIAL;
+ yyless( 0 );
+}
+
+{CYRALPHA}+ /* normal word */ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return CYRWORD;
+}
+
+[[:alpha:]]+ /* normal word */ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return LATWORD;
+}
+
+{ALNUM}+ /* normal word */ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return UWORD;
+}
+
+[ \r\n\t]+ {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return SPACE;
+}
+
+. {
+ token = tsearch2_yytext;
+ tokenlen = tsearch2_yyleng;
+ return SPACE;
+}
+
+%%
+
+/* clearing after parsing from string */
+void end_parse() {
+ if (s) { free(s); s=NULL; }
+ tsearch2_yy_delete_buffer( buf );
+ buf = NULL;
+}
+
+/* start parse from string */
+void start_parse_str(char* str, int limit) {
+ if (buf) end_parse();
+ buf = tsearch2_yy_scan_bytes( str, limit );
+ tsearch2_yy_switch_to_buffer( buf );
+ BEGIN INITIAL;
+}
+
+
+
Frequently Asked Questions (FAQ) for PostgreSQL
- Last updated: Fri Jul 25 18:07:30 EDT 2003
+ Last updated: Fri Sep 5 12:42:57 EDT 2003
A native port to MS Win NT/2000/XP is currently being worked on. For
more details on the current status of PostgreSQL on Windows see
- http://techdocs.postgresql.org/guides/Windows.
+ http://techdocs.postgresql.org/guides/Windows and
+ http://candle.pha.pa.us/main/writings/pgsql/win32.html.
There is also a Novell Netware 6 port at http://forge.novell.com.
Finally, you could use the OID returned from the INSERT statement to
look up the default value, though this is probably the least portable
- approach. In Perl, using DBI with Edmund Mergl's DBD::Pg module, the
+ approach, and the oid value will wrap around when it reaches 4
+ billion. In Perl, using DBI with Edmund Mergl's DBD::Pg module, the
oid value is made available via $sth->{pg_oid_status} after
$sth->execute().
- Letzte Aktualisierung der deutschen Übersetzung: Di., den 22.07.2003,
- 16:20 CET
+ Letzte Aktualisierung der deutschen Übersetzung: Di., den 02.09.2003,
+ 10:00 CET
Die aktuellste Version dieses Dokuments liegt auf der PostgreSQL
Website:
Schließlich besteht noch die Möglichkeit, den von einer
INSERT-Anweisung zurückgelieferten OID-Wert als einmaligen Wert zu
- verwenden. In Perl mit dem DBD::Pg-Modul von Edmund Mergl wird der
- OID-Wert nach einem $sth->excute() über $sth->{pg_oid_status}
- zurückgeliefert.
+ verwenden. Dieser Ansatz ist allerdings PostgreSQL-spezifisch;
+ außerdem wird nach ca. 4 Milliarden Einträgen der OID-Wert wieder auf
+ eine kleine Zahl gesetzt, ist also nicht garantiert einmalig.
+
+ In Perl mit dem DBD::Pg-Modul wird der OID-Wert nach einem
+ $sth->excute() über $sth->{pg_oid_status} zurückgeliefert.
4.15.3) Führen currval() und nextval() zu einer Race-Condition mit anderen
Nutzern?
4.28) Welche Möglichkeiten zur Verschlüsselung gibt es?
* contrib/pgcrypto enthält diverse Funktionen für die Benützung mit
- SQL-Abfragen;
- * die einzige Möglichkeit, Kommunikationen zwischen Client und
- Server zu verschlüsseln, ist durch die Anwendung von hostssl in
- pg_hba.conf;
+ SQL-Abfragen.
+ * Um Verbindungen zwischen dem Server und Client-Anwendungen zu
+ verschlüsseln, muss in der Server-Konfigurationsdatei
+ postgresql.conf die ssl-Option auf true (Voreinstellung: false)
+ gesetzt werden und ein passender host- bzw. hostssl-Eintrag muss
+ in pg_hba.conf vorhanden sein. Zudem muss die sslmode-Einstellung
+ beim Client nicht auf disable gesetzt werden. (Bitte beachten Sie
+ auch, daß neben der eingebauten SSL-Unterstützung verschlüsselte
+ Verbindungen auch über externe Anwendungen wie stunnel oder ssh
+ aufgebaut werden können).
* Die Passwörter der Datenbanknutzer werden ab Version 7.3
automatisch verschlüsselt (in früheren Versionen muß der Parameter
PASSWORD_ENCRYPTION in postgresql.conf explizit eingeschaltet
- werden);
- * der Server läuft auf einem verschlüsselten Dateisystem.
+ werden).
+ * Betrieb des Servers auf einem verschlüsselten Dateisystem.
_________________________________________________________________
PostgreSQL erweitern
Die englische Vorlage dieser FAQ wird ständig überarbeitet. Daher
liegt die Übersetzung nicht immer auf dem aktuellsten Stand.
+ Die aktuellste Version der deutschen Übersetzung befindet sich immer
+ unter http://sql-info.de/postgresql/FAQ_german.html. Diese
+ "Arbeitsversion" enthält eventuell Änderungen, die noch nicht auf der
+ PostgreSQL-Website eingebunden worden sind.
+
Über Verbesserungshinweise und Korrekturvorschläge sowie
Verständnisfragen zum Inhalt der FAQ freue ich mich. Ich nehme auch
- allgemeine Fragen zu PostgreSQL gerne entgegen, kann aber leider keine
- zeitige Antwort garantieren.
+ allgemeine Fragen zu PostgreSQL gerne entgegen, verweise jedoch auf
+ die Mailing-Listen als schnelle und zuverlässige Anlaufstellen.
Diese Übersetzung basiert teilweise auf einer früheren Übersetzung von
TODO list for PostgreSQL
========================
-Last updated: Tue Aug 12 18:04:15 EDT 2003
+Last updated: Fri Sep 5 15:52:01 EDT 2003
* Allow configuration files to be specified in a different directory
* -Add start time to pg_stat_activity
* Allow limits on per-db/user connections
-* Have standalone backend read postgresql.conf
+* -Have standalone backend read postgresql.conf (Tom)
* Add group object ownership, so groups can rename/drop/grant on objects,
so we can implement roles
* Add the concept of dataspaces/tablespaces [tablespaces]
* Allow server log information to be output as INSERT statements
* Prevent default re-use of sysids for dropped users and groups
* Prevent dropping user that still owns objects, or auto-drop the objects
+* Allow pooled connections to query prepared queries
+* Allow pooled connections to close all open WITH HOLD cursors
from making invalid dates valid
* -Prevent month/day swapping of ISO dates to make invalid dates valid
* Have initdb set DateStyle based on locale?
+* Add pg_get_acldef(), pg_get_typedefault(), and pg_get_attrdef()
+* Add ALTER DOMAIN, AGGREGATE, CONVERSION, SEQUENCE ... OWNER TO
+* Allow to_char to print localized month names (Karel)
+
* ARRAYS
o Allow nulls in arrays
* Prevent mismatch of frontend/backend encodings from converting bytea
data from being interpreted as encoded strings
* -Remove Cyrillic recode support
+* Fix upper()/lower() to work for multibyte encodings
+
Views / Rules
INSERT INTO inherit_table (unique_index_col) VALUES (dup) should fail
[inheritance]
* Add UNIQUE capability to non-btree indexes
-* Add btree index support for reltime, tinterval, regproc
+* -Add btree index support for reltime, tinterval, regproc (Tom)
* Add rtree index support for line, lseg, path, point
* -Certain indexes will not shrink, e.g. indexes on ever-increasing
columns and indexes with many duplicate keys
float4, numeric/decimal too [optimizer]
* Add FILLFACTOR to btree index creation
* Add concurrency to GIST
-* Improve concurrency of hash indexes (Neil)
+* -Improve concurrency of hash indexes (Tom)
* Allow a single index to index multiple tables (for inheritance and subtables)
* -Have SELECT '13 minutes'::interval display zero seconds in ISO datestyle
* Prevent COMMENT ON DATABASE from using a database name
* Add GUC variable to prevent waiting on locks
+* Allow TRUNCATE ... CASCADE/RESTRICT
+* Allow PREPARE of cursors
* ALTER
o Allow ALTER TABLE to modify column lengths and change to binary
compatible types
o Add ALTER DATABASE ... OWNER TO newowner
+ o Allow ALTER TABLE ... ALTER CONSTRAINT ... RENAME
* CLUSTER
o Automatically maintain clustering on a table
* -Allow psql to show transaction status if backend protocol changes made
* -Add schema, cast, and conversion backslash commands to psql (Christopher)
* -Allow pg_dump to dump a specific schema (Neil Conway)
-* Allow psql to do table completion for SELECT * FROM schema_part and
+* -Allow psql to do table completion for SELECT * FROM schema_part and
table completion for SELECT * FROM schema_name.
* Add XML capability to pg_dump and COPY, when backend XML capability
* -Allow SSL-enabled clients to turn off SSL transfers
* Allow psql \du to show groups, and add \dg for groups
* Allow clients to query WITH HOLD cursors and prepared statements
* Prevent unneeded quoting in psql \d output using fmtId()
+* Add a libpq function to support Parse/DescribeStatement capability
* JDBC
* Support triggers on columns (Neil)
* Have AFTER triggers execute after the appropriate SQL statement in a
function, not at the end of the function
-
+* Print table names with constraint names in error messages, or make constraint
+ names unique within a schema
Dependency Checking
===================
* Provide automatic running of vacuum in the background in backend
rather than in /contrib [vacuum]
* Allow free space map to be auto-sized or warn when it is too small
+* Maintain a map of recently-expired of pages so vacuum can reclaim
+ free space without a sequential scan
Locking
alink="#0000ff">
<H1>Frequently Asked Questions (FAQ) for PostgreSQL</H1>
- <P>Last updated: Fri Jul 25 18:07:30 EDT 2003</P>
+ <P>Last updated: Fri Sep 5 12:42:57 EDT 2003</P>
<P>Current maintainer: Bruce Momjian (<A href=
<p>A native port to MS Win NT/2000/XP is currently being worked
on. For more details on the current status of PostgreSQL on Windows see
<a href="http://techdocs.postgresql.org/guides/Windows">
- http://techdocs.postgresql.org/guides/Windows</a>.</p>
+ http://techdocs.postgresql.org/guides/Windows</a> and
+ <a href="http://candle.pha.pa.us/main/writings/pgsql/win32.html">
+ http://candle.pha.pa.us/main/writings/pgsql/win32.html</a>.</p>
<p>There is also a Novell Netware 6 port at
<a href="http://forge.novell.com">http://forge.novell.com</a>.</p>
Finally, you could use the <A href="#4.16"><SMALL>OID</SMALL></A>
returned from the <SMALL>INSERT</SMALL> statement to look up the
- default value, though this is probably the least portable approach.
+ default value, though this is probably the least portable approach,
+ and the oid value will wrap around when it reaches 4 billion.
In Perl, using DBI with Edmund Mergl's DBD::Pg module, the oid
value is made available via <I>$sth->{pg_oid_status}</I> after
<I>$sth->execute()</I>.
- <p>Letzte Aktualisierung der deutschen Übersetzung: Di., den 22.07.2003, 16:20 CET</p>
+ <p>Letzte Aktualisierung der deutschen Übersetzung: Di., den 02.09.2003, 10:00 CET</p>
<p>Die aktuellste Version dieses Dokuments liegt auf der PostgreSQL Website:</p>
<ul>
new_id = output of execute("SELECT currval('person_id_seq')");
</pre>
<p>Schließlich besteht noch die Möglichkeit, den von einer <small>INSERT</small>-Anweisung
- zurückgelieferten <small>OID</small>-Wert als einmaligen Wert zu verwenden.
- In Perl mit dem <em>DBD::Pg</em>-Modul von Edmund Mergl wird der OID-Wert nach einem
+ zurückgelieferten <a href="#4.16"><small>OID</small></a>-Wert als einmaligen Wert zu verwenden.
+ Dieser Ansatz ist allerdings PostgreSQL-spezifisch; außerdem wird nach
+ ca. 4 Milliarden Einträgen der <small>OID</small>-Wert wieder auf eine kleine Zahl
+ gesetzt, ist also nicht garantiert einmalig.</p>
+
+ <p>In Perl mit dem <em>DBD::Pg</em>-Modul wird der OID-Wert nach einem
<em>$sth->excute()</em> über <em>$sth->{pg_oid_status}</em> zurückgeliefert.</p>
<h4><a name="4.15.3">4.15.3</a>) Führen <em>currval()</em> und <em>nextval()</em> zu einer Race-Condition mit anderen
<ul>
<li><em>contrib/pgcrypto</em> enthält diverse Funktionen für die Benützung mit
- SQL-Abfragen;</li>
- <li>die einzige Möglichkeit, Kommunikationen zwischen Client und Server
- zu verschlüsseln, ist durch die Anwendung von <em>hostssl</em> in <em>pg_hba.conf</em>;</li>
+ SQL-Abfragen.</li>
+
+ <li>Um Verbindungen zwischen dem Server und Client-Anwendungen zu
+ verschlüsseln, muss in der Server-Konfigurationsdatei <em>postgresql.conf</em>
+ die <em>ssl</em>-Option auf <em>true</em> (Voreinstellung: <em>false</em>) gesetzt werden
+ und ein passender <em>host</em>- bzw. <em>hostssl</em>-Eintrag muss in
+ <em>pg_hba.conf</em> vorhanden sein. Zudem muss die <em>sslmode</em>-Einstellung
+ beim Client nicht auf <em>disable</em> gesetzt werden. (Bitte beachten Sie auch,
+ daß neben der eingebauten SSL-Unterstützung verschlüsselte Verbindungen
+ auch über externe Anwendungen wie <em>stunnel</em> oder <em>ssh</em> aufgebaut werden können).</li>
+
<li>Die Passwörter der Datenbanknutzer werden ab Version 7.3 automatisch
verschlüsselt (in früheren Versionen muß der Parameter <em>PASSWORD_ENCRYPTION</em>
- in <em>postgresql.conf</em> explizit eingeschaltet werden);</li>
- <li>der Server läuft auf einem verschlüsselten Dateisystem.</li>
+ in <em>postgresql.conf</em> explizit eingeschaltet werden).</li>
+ <li>Betrieb des Servers auf einem verschlüsselten Dateisystem.</li>
</ul>
<hr />
<p>Die englische Vorlage dieser FAQ wird ständig überarbeitet. Daher liegt
die Übersetzung nicht immer auf dem aktuellsten Stand.</p>
+ <p>Die aktuellste Version der deutschen Übersetzung befindet sich immer unter
+ <a href="http://sql-info.de/postgresql/FAQ_german.html">http://sql-info.de/postgresql/FAQ_german.html</a>.
+ Diese "Arbeitsversion" enthält eventuell Änderungen, die noch nicht auf der
+ PostgreSQL-Website eingebunden worden sind.</p>
+
<p>Über Verbesserungshinweise und Korrekturvorschläge sowie Verständnisfragen
zum Inhalt der FAQ freue ich mich. Ich nehme auch allgemeine Fragen zu PostgreSQL gerne
- entgegen, kann aber leider keine zeitige Antwort garantieren.</p>
+ entgegen, verweise jedoch auf die Mailing-Listen als schnelle und zuverlässige
+ Anlaufstellen.</p>
<p>Diese Übersetzung basiert teilweise auf einer früheren Übersetzung von Karsten
# Enable draft mode during development
ifneq (,$(findstring devel, $(VERSION)))
-JADEFLAGS += -V draft-mode
+override JADEFLAGS += -V draft-mode
endif
$(JADE) $(JADEFLAGS) $(SGMLINCLUDE) $(CATALOG) -d stylesheet.dsl -i output-html -t sgml $<
-COLLATEINDEX := $(PERL) $(COLLATEINDEX) -f -g
+COLLATEINDEX := LC_ALL=C $(PERL) $(COLLATEINDEX) -f -g
ifeq (,$(wildcard HTML.index))
bookindex.sgml:
<title>Transactions</title>
<indexterm zone="tutorial-transactions">
- <primary>transactions</primary>
+ <primary>transaction</primary>
</indexterm>
<para>
<title>Arrays</title>
<indexterm>
- <primary>arrays</primary>
+ <primary>array</primary>
</indexterm>
<para>
expression syntax is discussed in more detail in <xref
linkend="sql-syntax-array-constructors">.
</para>
-
</sect2>
<sect2>
<literal>||</literal>.
<programlisting>
SELECT ARRAY[1,2] || ARRAY[3,4];
- ?column?
----------------
- {{1,2},{3,4}}
+ ?column?
+-----------
+ {1,2,3,4}
(1 row)
SELECT ARRAY[5,6] || ARRAY[[1,2],[3,4]];
{{5,6},{1,2},{3,4}}
(1 row)
</programlisting>
+ </para>
+ <para>
The concatenation operator allows a single element to be pushed on to the
beginning or end of a one-dimensional array. It also accepts two
<replaceable>N</>-dimensional arrays, or an <replaceable>N</>-dimensional
- and an <replaceable>N+1</>-dimensional array. In the former case, the two
- <replaceable>N</>-dimension arrays become outer elements of an
- <replaceable>N+1</>-dimensional array. In the latter, the
- <replaceable>N</>-dimensional array is added as either the first or last
- outer element of the <replaceable>N+1</>-dimensional array.
-
- When extending an array by concatenation, the subscripts of its existing
- elements are preserved. For example, when pushing
- onto the beginning of an array with one-based subscripts, the resulting
- array has zero-based subscripts:
+ and an <replaceable>N+1</>-dimensional array.
+ </para>
+ <para>
+ When a single element is pushed on to the beginning of a one-dimensional
+ array, the result is an array with a lower bound subscript equal to
+ the righthand operand's lower bound subscript, minus one. When a single
+ element is pushed on to the end of a one-dimensional array, the result is
+ an array retaining the lower bound of the lefthand operand. For example:
<programlisting>
SELECT array_dims(1 || ARRAY[2,3]);
array_dims
------------
[0:2]
(1 row)
+
+SELECT array_dims(ARRAY[1,2] || 3);
+ array_dims
+------------
+ [1:3]
+(1 row)
+</programlisting>
+ </para>
+
+ <para>
+ When two arrays with an equal number of dimensions are concatenated, the
+ result retains the lower bound subscript of the lefthand operand's outer
+ dimension. The result is an array comprising every element of the lefthand
+ operand followed by every element of the righthand operand. For example:
+<programlisting>
+SELECT array_dims(ARRAY[1,2] || ARRAY[3,4,5]);
+ array_dims
+------------
+ [1:5]
+(1 row)
+
+SELECT array_dims(ARRAY[[1,2],[3,4]] || ARRAY[[5,6],[7,8],[9,0]]);
+ array_dims
+------------
+ [1:5][1:2]
+(1 row)
+</programlisting>
+ </para>
+
+ <para>
+ When an <replaceable>N</>-dimensional array is pushed on to the beginning
+ or end of an <replaceable>N+1</>-dimensional array, the result is
+ analogous to the element-array case above. Each <replaceable>N</>-dimensional
+ sub-array is essentially an element of the <replaceable>N+1</>-dimensional
+ array's outer dimension. For example:
+<programlisting>
+SELECT array_dims(ARRAY[1,2] || ARRAY[[3,4],[5,6]]);
+ array_dims
+------------
+ [0:2][1:2]
+(1 row)
</programlisting>
</para>
(1 row)
SELECT array_cat(ARRAY[1,2], ARRAY[3,4]);
- array_cat
----------------
- {{1,2},{3,4}}
+ array_cat
+-----------
+ {1,2,3,4}
(1 row)
SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]);
</para>
</important>
+ <tip>
+ <para>
+ Restore performance can be improved by increasing <literal>SORT_MEM</>
+ (see <xref linkend="runtime-config-resource-memory">).
+ </para>
+ </tip>
</sect2>
<sect2 id="backup-dump-all">
</para>
<para>
- For reasons of backward compatibility, <application>pg_dump</> does
- not dump large objects by default. To dump large objects you must use
- either the custom or the TAR output format, and use the <option>-b</> option in
- <application>pg_dump</>. See the reference pages for details.
- The directory <filename>contrib/pg_dumplo</> of the
- <productname>PostgreSQL</> source tree also contains a program that can
- dump large objects.
+ For reasons of backward compatibility, <application>pg_dump</>
+ does not dump large objects by default.<indexterm><primary>large
+ object</primary><secondary>backup</secondary></indexterm> To dump
+ large objects you must use either the custom or the TAR output
+ format, and use the <option>-b</> option in
+ <application>pg_dump</>. See the reference pages for details. The
+ directory <filename>contrib/pg_dumplo</> of the
+ <productname>PostgreSQL</> source tree also contains a program
+ that can dump large objects.
</para>
<para>
<sect1 id="migration">
<title>Migration between releases</title>
- <indexterm zone="migration"><primary>upgrading</></>
+
+ <indexterm zone="migration">
+ <primary>upgrading</primary>
+ </indexterm>
+
+ <indexterm zone="migration">
+ <primary>version</primary>
+ <secondary>compatibility</secondary>
+ </indexterm>
<para>
As a general rule, the internal data storage format is subject to
<listitem>
<para>
Sort order in queries using <command>ORDER BY</>
- <indexterm><primary>ORDER BY</></>
+ <indexterm><primary>ORDER BY</><secondary>and locales</></indexterm>
</para>
</listitem>
<programlisting>
(<replaceable>actual-IP-address</replaceable> xor <replaceable>IP-address-field</replaceable>) and <replaceable>IP-mask-field</replaceable>
</programlisting>
- must be zero for the record to match. (Of course IP addresses
- can be spoofed but this consideration is beyond the scope of
- <productname>PostgreSQL</productname>.) If you machine supports
- IPv6, the default <filename>pg_hba.conf</> file will have an
- IPv6 entry for <literal>localhost</>. You can add your own IPv6
- entries to the file. IPv6 entries are used only for IPv6
- connections.
+ must be zero for the record to match.
+ </para>
+
+ <para>
+ An IP address given in IPv4 format will match IPv6 connections that
+ have the corresponding address, for example <literal>127.0.0.1</>
+ will match the IPv6 address <literal>::ffff:127.0.0.1</>. An entry
+ given in IPv6 format will match only IPv6 connections, even if the
+ represented address is in the IPv4-in-IPv6 range. Note that entries
+ in IPv6 format will be rejected if the system's C library does not have
+ support for IPv6 addresses.
</para>
<para>
<term><replaceable>CIDR-mask</replaceable></term>
<listitem>
<para>
- This is an integer specifying the number of significant bits
- to set in the mask, and is an alternative to using the
- <replaceable>IP-mask</replaceable> notation. The number must
+ This field may be used as an alternative to the
+ <replaceable>IP-mask</replaceable> notation. It is an
+ integer specifying the number of high-order bits
+ to set in the mask. The number must
be between 0 and 32 (in the case of an IPv4 address) or 128
(in the case of an IPv6 address) inclusive. 0 will match any
address, while 32/128 will match only the exact host specified.
# TYPE DATABASE USER IP-ADDRESS IP-MASK METHOD
host all all 127.0.0.1 255.255.255.255 trust
+# The same as the last line but using a CIDR mask
+#
+# TYPE DATABASE USER IP-ADDRESS/CIDR-mask METHOD
+host all all 127.0.0.1/32 trust
+
# Allow any user from any host with IP address 192.168.93.x to connect
# to database "template1" as the same user name that ident reports for
# the connection (typically the Unix user name).
# TYPE DATABASE USER IP-ADDRESS IP-MASK METHOD
host template1 all 192.168.93.0 255.255.255.0 ident sameuser
+# The same as the last line but using a CIDR mask
+#
+# TYPE DATABASE USER IP-ADDRESS/CIDR-mask METHOD
+host template1 all 192.168.93.0/24 ident sameuser
+
# Allow a user from host 192.168.12.10 to connect to database
# "template1" if the user's password is correctly supplied.
#
</indexterm>
<indexterm>
<primary>password</primary>
+ <secondary>authentication</secondary>
</indexterm>
<para>
<para>
<productname>Kerberos</productname> is an industry-standard secure
- authentication system suitable for distributed computing over a
- public network. A description of the
- <productname>Kerberos</productname> system is far beyond the scope
- of this document; in all generality it can be quite complex (yet
- powerful). The <ulink
+ authentication system suitable for distributed computing over a public
+ network. A description of the <productname>Kerberos</productname> system
+ is far beyond the scope of this document; in all generality it can be
+ quite complex (yet powerful). The <ulink
url="http://www.nrl.navy.mil/CCS/people/kenh/kerberos-faq.html">Kerberos
- <acronym>FAQ</></ulink> or <ulink
- url="ftp://athena-dist.mit.edu">MIT Project Athena</ulink> can be
- a good starting point for exploration. Several sources for
- <productname>Kerberos</> distributions exist.
+ <acronym>FAQ</></ulink> or <ulink url="ftp://athena-dist.mit.edu">MIT
+ Project Athena</ulink> can be a good starting point for exploration.
+ Several sources for <productname>Kerberos</> distributions exist.
+ </para>
+
+ <para>
+ While <productname>PostgreSQL</> supports both Kerberos 4 and
+ Kerberos 5, only Kerberos 5 is recommended. Kerberos 4 is
+ considered insecure and no longer recommended for general
+ use.
</para>
<para>
<sect2 id="auth-pam">
<title>PAM Authentication</title>
+ <indexterm zone="auth-pam">
+ <primary>PAM</primary>
+ </indexterm>
+
<para>
This authentication method operates similarly to
<literal>password</literal> except that it uses PAM (Pluggable
<title id="datatype-title">Data Types</title>
<indexterm zone="datatype">
- <primary>data types</primary>
+ <primary>data type</primary>
</indexterm>
<indexterm>
- <primary>types</primary>
- <see>data types</see>
+ <primary>type</primary>
+ <see>data type</see>
</indexterm>
<para>
<title>Numeric Types</title>
<indexterm zone="datatype-numeric">
- <primary>data types</primary>
+ <primary>data type</primary>
<secondary>numeric</secondary>
</indexterm>
- <indexterm zone="datatype-numeric">
- <primary>integer</primary>
- </indexterm>
-
- <indexterm zone="datatype-numeric">
- <primary>smallint</primary>
- </indexterm>
-
- <indexterm zone="datatype-numeric">
- <primary>bigint</primary>
- </indexterm>
-
- <indexterm>
- <primary>int4</primary>
- <see>integer</see>
- </indexterm>
-
- <indexterm>
- <primary>int2</primary>
- <see>smallint</see>
- </indexterm>
-
- <indexterm>
- <primary>int8</primary>
- <see>bigint</see>
- </indexterm>
-
- <indexterm zone="datatype-numeric">
- <primary>numeric (data type)</primary>
- </indexterm>
-
- <indexterm>
- <primary>decimal</primary>
- <see>numeric</see>
- </indexterm>
-
- <indexterm zone="datatype-numeric">
- <primary>real</primary>
- </indexterm>
-
- <indexterm zone="datatype-numeric">
- <primary>double precision</primary>
- </indexterm>
-
- <indexterm>
- <primary>float4</primary>
- <see>real</see>
- </indexterm>
-
- <indexterm>
- <primary>float8</primary>
- <see>double precision</see>
- </indexterm>
-
- <indexterm zone="datatype-numeric">
- <primary>floating point</primary>
- </indexterm>
-
<para>
Numeric types consist of two-, four-, and eight-byte integers,
four- and eight-byte floating-point numbers, and fixed-precision
<sect2 id="datatype-int">
<title>Integer Types</title>
+ <indexterm zone="datatype-int">
+ <primary>integer</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-int">
+ <primary>smallint</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-int">
+ <primary>bigint</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>int4</primary>
+ <see>integer</see>
+ </indexterm>
+
+ <indexterm>
+ <primary>int2</primary>
+ <see>smallint</see>
+ </indexterm>
+
+ <indexterm>
+ <primary>int8</primary>
+ <see>bigint</see>
+ </indexterm>
+
<para>
The types <type>smallint</type>, <type>integer</type>, and
<type>bigint</type> store whole numbers, that is, numbers without
<sect2 id="datatype-numeric-decimal">
<title>Arbitrary Precision Numbers</title>
+ <indexterm zone="datatype-numeric-decimal">
+ <primary>numeric (data type)</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>decimal</primary>
+ <see>numeric</see>
+ </indexterm>
+
<para>
The type <type>numeric</type> can store numbers with up to 1000
digits of precision and perform calculations exactly. It is
<sect2 id="datatype-float">
<title>Floating-Point Types</title>
+ <indexterm zone="datatype-float">
+ <primary>real</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-float">
+ <primary>double precision</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>float4</primary>
+ <see>real</see>
+ </indexterm>
+
+ <indexterm>
+ <primary>float8</primary>
+ <see>double precision</see>
+ </indexterm>
+
+ <indexterm zone="datatype-float">
+ <primary>floating point</primary>
+ </indexterm>
+
<para>
The data types <type>real</type> and <type>double
precision</type> are inexact, variable-precision numeric types.
</indexterm>
<indexterm>
- <primary>sequences</primary>
+ <primary>sequence</primary>
<secondary>and serial type</secondary>
</indexterm>
<title>Character Types</title>
<indexterm zone="datatype-character">
- <primary>character strings</primary>
+ <primary>character string</primary>
<secondary>data types</secondary>
</indexterm>
<indexterm>
- <primary>strings</primary>
- <see>character strings</see>
+ <primary>string</primary>
+ <see>character string</see>
</indexterm>
- <indexterm>
+ <indexterm zone="datatype-character">
+ <primary>character</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-character">
+ <primary>character varying</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-character">
<primary>text</primary>
- <see>character strings</see>
+ </indexterm>
+
+ <indexterm zone="datatype-character">
+ <primary>char</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-character">
+ <primary>varchar</primary>
</indexterm>
<table id="datatype-character-table">
<sect1 id="datatype-binary">
<title>Binary Data Types</title>
+
+ <indexterm zone="datatype-binary">
+ <primary>binary data</primary>
+ </indexterm>
+
+ <indexterm zone="datatype-binary">
+ <primary>bytea</primary>
+ </indexterm>
+
<para>
The <type>bytea</type> data type allows storage of binary strings;
see <xref linkend="datatype-binary-table">.
<sect1 id="datatype-datetime">
<title>Date/Time Types</title>
+ <indexterm zone="datatype-datetime">
+ <primary>date</primary>
+ </indexterm>
+ <indexterm zone="datatype-datetime">
+ <primary>time</primary>
+ </indexterm>
+ <indexterm zone="datatype-datetime">
+ <primary>time without time zone</primary>
+ </indexterm>
+ <indexterm zone="datatype-datetime">
+ <primary>time with time zone</primary>
+ </indexterm>
+ <indexterm zone="datatype-datetime">
+ <primary>timestamp</primary>
+ </indexterm>
+ <indexterm zone="datatype-datetime">
+ <primary>timestamp with time zone</primary>
+ </indexterm>
+ <indexterm zone="datatype-datetime">
+ <primary>timestamp without time zone</primary>
+ </indexterm>
+ <indexterm zone="datatype-datetime">
+ <primary>interval</primary>
+ </indexterm>
+ <indexterm zone="datatype-datetime">
+ <primary>time span</primary>
+ </indexterm>
+
<para>
<productname>PostgreSQL</productname> supports the full set of
<acronym>SQL</acronym> date and time types, shown in <xref
<indexterm>
<primary>date</primary>
- <secondary>data type</secondary>
</indexterm>
<para>
<indexterm>
<primary>time</primary>
- <secondary>data type</secondary>
</indexterm>
<indexterm>
<primary>time without time zone</primary>
- <secondary>time</secondary>
</indexterm>
<indexterm>
<primary>time with time zone</primary>
- <secondary>data type</secondary>
</indexterm>
<para>
<indexterm>
<primary>timestamp</primary>
- <secondary>data type</secondary>
</indexterm>
<indexterm>
<primary>timestamp with time zone</primary>
- <secondary>data type</secondary>
</indexterm>
<indexterm>
<primary>timestamp without time zone</primary>
- <secondary>data type</secondary>
</indexterm>
<para>
<indexterm>
<primary>date</primary>
<secondary>output format</secondary>
- <seealso>Formatting</seealso>
+ <seealso>formatting</seealso>
</indexterm>
<indexterm>
<primary>time</primary>
<secondary>output format</secondary>
- <seealso>Formatting</seealso>
+ <seealso>formatting</seealso>
</indexterm>
<para>
<title>Time Zones</title>
<indexterm zone="datatype-timezones">
- <primary>time zones</primary>
+ <primary>time zone</primary>
</indexterm>
<para>
<title>Line Segments</title>
<indexterm>
- <primary>line</primary>
+ <primary>lseg</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>line segment</primary>
</indexterm>
<para>
<primary>box (data type)</primary>
</indexterm>
+ <indexterm>
+ <primary>rectangle</primary>
+ </indexterm>
+
<para>
Boxes are represented by pairs of points that are opposite
corners of the box.
<indexterm zone="datatype-net-types">
<primary>network</primary>
- <secondary>addresses</secondary>
+ <secondary>data types</secondary>
</indexterm>
<para>
<title>Bit String Types</title>
<indexterm zone="datatype-bit">
- <primary>bit strings</primary>
+ <primary>bit string</primary>
<secondary>data type</secondary>
</indexterm>
</thead>
<tbody>
- <row>
- <entry><type>record</></entry>
- <entry>Identifies a function returning an unspecified row type.</entry>
- </row>
-
<row>
<entry><type>any</></entry>
<entry>Indicates that a function accepts any input data type whatever.</entry>
<row>
<entry><type>anyarray</></entry>
<entry>Indicates that a function accepts any array data type
- (see <xref linkend="types-polymorphic">).</entry>
+ (see <xref linkend="extend-types-polymorphic">).</entry>
</row>
<row>
<entry><type>anyelement</></entry>
<entry>Indicates that a function accepts any data type
- (see <xref linkend="types-polymorphic">).</entry>
+ (see <xref linkend="extend-types-polymorphic">).</entry>
</row>
<row>
- <entry><type>void</></entry>
- <entry>Indicates that a function returns no value.</entry>
+ <entry><type>cstring</></entry>
+ <entry>Indicates that a function accepts or returns a null-terminated C string.</entry>
</row>
<row>
- <entry><type>trigger</></entry>
- <entry>A trigger function is declared to return <type>trigger.</></entry>
+ <entry><type>internal</></entry>
+ <entry>Indicates that a function accepts or returns a server-internal
+ data type.</entry>
</row>
<row>
</row>
<row>
- <entry><type>cstring</></entry>
- <entry>Indicates that a function accepts or returns a null-terminated C string.</entry>
+ <entry><type>record</></entry>
+ <entry>Identifies a function returning an unspecified row type.</entry>
</row>
<row>
- <entry><type>internal</></entry>
- <entry>Indicates that a function accepts or returns a server-internal
- data type.</entry>
+ <entry><type>trigger</></entry>
+ <entry>A trigger function is declared to return <type>trigger.</></entry>
+ </row>
+
+ <row>
+ <entry><type>void</></entry>
+ <entry>Indicates that a function returns no value.</entry>
</row>
<row>
</para>
<indexterm>
- <primary>time zones</primary>
+ <primary>time zone</primary>
+ <secondary>abbreviations</secondary>
</indexterm>
<para>
<entry>+07:00</entry>
<entry>Christmas (Island) Time</entry>
</row>
-<!--
- Conflicts with China Coastal Time
- <row>
- <entry>CCT</entry>
- <entry>+06:30</entry>
- <entry>Cocos Island Time</entry>
- </row>
--->
<row>
<entry>MMT</entry>
<entry>+06:30</entry>
- <entry>Myannar Time</entry>
+ <entry>Myanmar Time</entry>
</row>
<row>
<entry>ALMT</entry>
<entry>-01:00</entry>
<entry>West Africa Time</entry>
</row>
+ <row>
+ <entry>FNST</entry>
+ <entry>-01:00</entry>
+ <entry>Fernando de Noronha Summer Time</entry>
+ </row>
+ <row>
+ <entry>FNT</entry>
+ <entry>-02:00</entry>
+ <entry>Fernando de Noronha Time</entry>
+ </row>
+ <row>
+ <entry>BRST</entry>
+ <entry>-02:00</entry>
+ <entry>Brasilia Summer Time</entry>
+ </row>
<row>
<entry>NDT</entry>
<entry>-02:30</entry>
<entry>-03:00</entry>
<entry>(unknown)</entry>
</row>
+ <row>
+ <entry>BRT</entry>
+ <entry>-03:00</entry>
+ <entry>Brasilia Time</entry>
+ </row>
<row>
<entry>NFT</entry>
<entry>-03:30</entry>
<entry>-04:00</entry>
<entry>Atlantic/Porto Acre Summer Time</entry>
</row>
- <row>
- <entry>ACT</entry>
- <entry>-05:00</entry>
- <entry>Atlantic/Porto Acre Standard Time</entry>
- </row>
<row>
<entry>EDT</entry>
<entry>-04:00</entry>
<entry>GMT +4 hours</entry>
</row>
-->
+ <row>
+ <entry>ACT</entry>
+ <entry>-05:00</entry>
+ <entry>Atlantic/Porto Acre Standard Time</entry>
+ </row>
<row>
<entry>CDT</entry>
<entry>-05:00</entry>
<sect1 id="ddl-basics">
<title>Table Basics</title>
+ <indexterm zone="ddl-basics">
+ <primary>table</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>row</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>column</primary>
+ </indexterm>
+
<para>
A table in a relational database is much like a table on paper: It
consists of rows and columns. The number and order of the columns
containing both date and time.
</para>
+ <indexterm>
+ <primary>table</primary>
+ <secondary>creating</secondary>
+ </indexterm>
+
<para>
To create a table, you use the aptly named <literal>CREATE
TABLE</literal> command. In this command you specify at least a
highly unusual and often a questionable design.
</para>
+ <indexterm>
+ <primary>table</primary>
+ <secondary>removing</secondary>
+ </indexterm>
+
<para>
If you no longer need a table, you can remove it using the
<command>DROP TABLE</command> command. For example:
</para>
<indexterm>
- <primary>columns</primary>
- <secondary>system columns</secondary>
+ <primary>column</primary>
+ <secondary>system column</secondary>
</indexterm>
<variablelist>
<para>
<indexterm>
<primary>OID</primary>
+ <secondary>column</secondary>
</indexterm>
The object identifier (object ID) of a row. This is a serial
number that is automatically added by
<varlistentry>
<term><structfield>tableoid</></term>
<listitem>
+ <indexterm>
+ <primary>tableoid</primary>
+ </indexterm>
+
<para>
The OID of the table containing this row. This column is
particularly handy for queries that select from inheritance
<varlistentry>
<term><structfield>xmin</></term>
<listitem>
+ <indexterm>
+ <primary>xmin</primary>
+ </indexterm>
+
<para>
The identity (transaction ID) of the inserting transaction for
this tuple. (Note: In this context, a tuple is an individual
<varlistentry>
<term><structfield>cmin</></term>
<listitem>
+ <indexterm>
+ <primary>cmin</primary>
+ </indexterm>
+
<para>
The command identifier (starting at zero) within the inserting
transaction.
<varlistentry>
<term><structfield>xmax</></term>
<listitem>
+ <indexterm>
+ <primary>xmax</primary>
+ </indexterm>
+
<para>
The identity (transaction ID) of the deleting transaction, or
zero for an undeleted tuple. It is possible for this column to
<varlistentry>
<term><structfield>cmax</></term>
<listitem>
+ <indexterm>
+ <primary>cmax</primary>
+ </indexterm>
+
<para>
The command identifier within the deleting transaction, or zero.
</para>
<varlistentry>
<term><structfield>ctid</></term>
<listitem>
+ <indexterm>
+ <primary>ctid</primary>
+ </indexterm>
+
<para>
The physical location of the tuple within its table. Note that
although the <structfield>ctid</structfield> can be used to
<sect1 id="ddl-default">
<title>Default Values</title>
+ <indexterm zone="ddl-default">
+ <primary>default value</primary>
+ </indexterm>
+
<para>
A column can be assigned a default value. When a new row is
created and no values are specified for some of the columns, the
</para>
<para>
+ <indexterm><primary>null value</primary><secondary>default value</secondary></indexterm>
If no default value is declared explicitly, the null value is the
default value. This usually makes sense because a null value can
be thought to represent unknown data.
<sect1 id="ddl-constraints">
<title>Constraints</title>
+ <indexterm zone="ddl-constraints">
+ <primary>constraint</primary>
+ </indexterm>
+
<para>
Data types are a way to limit the kind of data that can be stored
in a table. For many applications, however, the constraint they
<sect2>
<title>Check Constraints</title>
+ <indexterm>
+ <primary>check constraint</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>constraint</primary>
+ <secondary>check</secondary>
+ </indexterm>
+
<para>
A check constraint is the most generic constraint type. It allows
you to specify that the value in a certain column must satisfy an
would not make too much sense.
</para>
+ <indexterm>
+ <primary>constraint</primary>
+ <secondary>name</secondary>
+ </indexterm>
+
<para>
You can also give the constraint a separate name. This clarifies
error messages and allows you to refer to the constraint when you
It's a matter of taste.
</para>
+ <indexterm>
+ <primary>null value</primary>
+ <secondary sortas="check constraints">with check constraints</secondary>
+ </indexterm>
+
<para>
It should be noted that a check constraint is satisfied if the
check expression evaluates to true or the null value. Since most
<sect2>
<title>Not-Null Constraints</title>
+ <indexterm>
+ <primary>not-null constraint</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>constraint</primary>
+ <secondary>NOT NULL</secondary>
+ </indexterm>
+
<para>
A not-null constraint simply specifies that a column must not
assume the null value. A syntax example:
<sect2>
<title>Unique Constraints</title>
+ <indexterm>
+ <primary>unique constraint</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>constraint</primary>
+ <secondary>unique</secondary>
+ </indexterm>
+
<para>
Unique constraints ensure that the data contained in a column or a
group of columns is unique with respect to all the rows in the
</programlisting>
</para>
+ <indexterm>
+ <primary>null value</primary>
+ <secondary sortas="unique constraints">with unique constraints</secondary>
+ </indexterm>
+
<para>
In general, a unique constraint is violated when there are (at
least) two rows in the table where the values of each of the
<sect2>
<title>Primary Keys</title>
+ <indexterm>
+ <primary>primary key</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>constraint</primary>
+ <secondary>primary key</secondary>
+ </indexterm>
+
<para>
Technically, a primary key constraint is simply a combination of a
unique constraint and a not-null constraint. So, the following
<sect2 id="ddl-constraints-fk">
<title>Foreign Keys</title>
+ <indexterm>
+ <primary>foreign key</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>constraint</primary>
+ <secondary>foreign key</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>referential integrity</primary>
+ </indexterm>
+
<para>
A foreign key constraint specifies that the values in a column (or
a group of columns) must match the values appearing in some row
the last table.
</para>
+ <indexterm>
+ <primary>CASCADE</primary>
+ <secondary>foreign key action</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>RESTRICT</primary>
+ <secondary>foreign key action</secondary>
+ </indexterm>
+
<para>
We know that the foreign keys disallow creation of orders that
do not relate to any products. But what if a product is removed
<sect1 id="ddl-alter">
<title>Modifying Tables</title>
+ <indexterm zone="ddl-alter">
+ <primary>table</primary>
+ <secondary>modifying</secondary>
+ </indexterm>
+
<para>
When you create a table and you realize that you made a mistake, or
the requirements of the application changed, then you can drop the
<sect2>
<title>Adding a Column</title>
+ <indexterm>
+ <primary>column</primary>
+ <secondary>adding</secondary>
+ </indexterm>
+
<para>
To add a column, use this command:
<programlisting>
<sect2>
<title>Removing a Column</title>
+ <indexterm>
+ <primary>column</primary>
+ <secondary>removing</secondary>
+ </indexterm>
+
<para>
To remove a column, use this command:
<programlisting>
<sect2>
<title>Adding a Constraint</title>
+ <indexterm>
+ <primary>constraint</primary>
+ <secondary>adding</secondary>
+ </indexterm>
+
<para>
To add a constraint, the table constraint syntax is used. For example:
<programlisting>
<sect2>
<title>Removing a Constraint</title>
+ <indexterm>
+ <primary>constraint</primary>
+ <secondary>removing</secondary>
+ </indexterm>
+
<para>
To remove a constraint you need to know its name. If you gave it
a name then that's easy. Otherwise the system assigned a
<sect2>
<title>Changing the Default</title>
+ <indexterm>
+ <primary>default value</primary>
+ <secondary>changing</secondary>
+ </indexterm>
+
<para>
To set a new default for a column, use a command like this:
<programlisting>
<sect2>
<title>Renaming a Column</title>
+ <indexterm>
+ <primary>column</primary>
+ <secondary>renaming</secondary>
+ </indexterm>
+
<para>
To rename a column:
<programlisting>
<sect2>
<title>Renaming a Table</title>
+ <indexterm>
+ <primary>table</primary>
+ <secondary>renaming</secondary>
+ </indexterm>
+
<para>
To rename a table:
<programlisting>
<sect1 id="ddl-priv">
<title>Privileges</title>
+ <indexterm zone="ddl-priv">
+ <primary>privilege</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>permission</primary>
+ <see>privilege</see>
+ </indexterm>
+
<para>
When you create a database object, you become its owner. By
default, only the owner of an object can do anything with the
<sect1 id="ddl-schemas">
<title>Schemas</title>
- <indexterm>
- <primary>schemas</primary>
- </indexterm>
-
- <indexterm>
- <primary>namespaces</primary>
+ <indexterm zone="ddl-schemas">
+ <primary>schema</primary>
</indexterm>
<para>
<sect2 id="ddl-schemas-create">
<title>Creating a Schema</title>
+ <indexterm zone="ddl-schemas-create">
+ <primary>schema</primary>
+ <secondary>creating</secondary>
+ </indexterm>
+
<para>
To create a separate schema, use the command <literal>CREATE
SCHEMA</literal>. Give the schema a name of your choice. For
</para>
<indexterm>
- <primary>qualified names</primary>
+ <primary>qualified name</primary>
</indexterm>
<indexterm>
- <primary>names</primary>
+ <primary>name</primary>
<secondary>qualified</secondary>
</indexterm>
the following chapters.
</para>
+ <indexterm>
+ <primary>schema</primary>
+ <secondary>removing</secondary>
+ </indexterm>
+
<para>
To drop a schema if it's empty (all objects in it have been
dropped), use
<sect2 id="ddl-schemas-public">
<title>The Public Schema</title>
+ <indexterm zone="ddl-schemas-public">
+ <primary>schema</primary>
+ <secondary>public</secondary>
+ </indexterm>
+
<para>
In the previous sections we created tables without specifying any
schema names. By default, such tables (and other objects) are
</indexterm>
<indexterm>
- <primary>unqualified names</primary>
+ <primary>unqualified name</primary>
</indexterm>
<indexterm>
- <primary>names</primary>
+ <primary>name</primary>
<secondary>unqualified</secondary>
</indexterm>
in other schemas in the database.
</para>
+ <indexterm>
+ <primary>schema</primary>
+ <secondary>current</secondary>
+ </indexterm>
+
<para>
The first schema named in the search path is called the current schema.
Aside from being the first schema searched, it is also the schema in
command does not specify a schema name.
</para>
+ <indexterm>
+ <primary>search_path</primary>
+ </indexterm>
+
<para>
To show the current search path, use the following command:
<programlisting>
<sect2 id="ddl-schemas-priv">
<title>Schemas and Privileges</title>
+ <indexterm zone="ddl-schemas-priv">
+ <primary>privilege</primary>
+ <secondary sortas="schemas">for schemas</secondary>
+ </indexterm>
+
<para>
By default, users cannot see the objects in schemas they do not
own. To allow that, the owner of the schema needs to grant the
</para>
</sect2>
- <sect2>
+ <sect2 id="ddl-schemas-catalog">
<title>The System Catalog Schema</title>
+ <indexterm zone="ddl-schemas-catalog">
+ <primary>system catalog</primary>
+ <secondary>schema</secondary>
+ </indexterm>
+
<para>
In addition to <literal>public</> and user-created schemas, each
database contains a <literal>pg_catalog</> schema, which contains
<sect1 id="ddl-depend">
<title>Dependency Tracking</title>
+ <indexterm zone="ddl-depend">
+ <primary>CASCADE</primary>
+ <secondary sortas="DROP">with DROP</secondary>
+ </indexterm>
+
+ <indexterm zone="ddl-depend">
+ <primary>RESTRICT</primary>
+ <secondary sortas="DROP">with DROP</secondary>
+ </indexterm>
+
<para>
When you create complex database structures involving many tables
with foreign key constraints, views, triggers, functions, etc. you
<para>
Before you are able to use your
<productname>PostgreSQL</productname> extension functions written in
- C, they must be compiled and linked in a special way to produce a file
- that can be dynamically loaded by the server. To be
- precise, a <firstterm>shared library</firstterm> needs to be created.
+ C, they must be compiled and linked in a special way to produce a
+ file that can be dynamically loaded by the server. To be precise, a
+ <firstterm>shared library</firstterm> needs to be
+ created.<indexterm><primary>shared library</></indexterm>
+
</para>
<para>
</para>
<para>
- <indexterm><primary>PIC</></>
- Creating shared libraries is generally analogous to linking
- executables: first the source files are compiled into object files,
- then the object files are linked together. The object files need to
- be created as <firstterm>position-independent code</firstterm>
- (<acronym>PIC</acronym>), which conceptually means that they can be
- placed at an arbitrary location in memory when they are loaded by the
- executable. (Object files intended for executables are usually not compiled
- that way.) The command to link a shared library contains special
- flags to distinguish it from linking an executable. --- At least
- this is the theory. On some systems the practice is much uglier.
+ <indexterm><primary>PIC</></> Creating shared libraries is generally
+ analogous to linking executables: first the source files are
+ compiled into object files, then the object files are linked
+ together. The object files need to be created as
+ <firstterm>position-independent code</firstterm>
+ (<acronym>PIC</acronym>),<indexterm><primary>PIC</></> which
+ conceptually means that they can be placed at an arbitrary location
+ in memory when they are loaded by the executable. (Object files
+ intended for executables are usually not compiled that way.) The
+ command to link a shared library contains special flags to
+ distinguish it from linking an executable. --- At least this is the
+ theory. On some systems the practice is much uglier.
</para>
<para>
<variablelist>
<varlistentry>
<term><systemitem class="osname">BSD/OS</></term>
- <indexterm><primary>BSD/OS</></>
+ <indexterm><primary>BSD/OS</><secondary>shared library</></>
<listitem>
<para>
The compiler flag to create <acronym>PIC</acronym> is
<varlistentry>
<term><systemitem class="osname">FreeBSD</></term>
- <indexterm><primary>FreeBSD</></>
+ <indexterm><primary>FreeBSD</><secondary>shared library</></>
<listitem>
<para>
The compiler flag to create <acronym>PIC</acronym> is
<varlistentry>
<term><systemitem class="osname">HP-UX</></term>
- <indexterm><primary>HP-UX</></>
+ <indexterm><primary>HP-UX</><secondary>shared library</></>
<listitem>
<para>
The compiler flag of the system compiler to create
<varlistentry>
<term><systemitem class="osname">IRIX</></term>
- <indexterm><primary>IRIX</></>
+ <indexterm><primary>IRIX</><secondary>shared library</></>
<listitem>
<para>
<acronym>PIC</acronym> is the default, no special compiler
<varlistentry>
<term><systemitem class="osname">Linux</></term>
- <indexterm><primary>Linux</></>
+ <indexterm><primary>Linux</><secondary>shared library</></>
<listitem>
<para>
The compiler flag to create <acronym>PIC</acronym> is
<varlistentry>
<term><systemitem class="osname">MacOS X</></term>
- <indexterm><primary>MacOS X</></>
+ <indexterm><primary>MacOS X</><secondary>shared library</></>
<listitem>
<para>
Here is an example. It assumes the developer tools are installed.
<varlistentry>
<term><systemitem class="osname">NetBSD</></term>
- <indexterm><primary>NetBSD</></>
+ <indexterm><primary>NetBSD</><secondary>shared library</></>
<listitem>
<para>
The compiler flag to create <acronym>PIC</acronym> is
<varlistentry>
<term><systemitem class="osname">OpenBSD</></term>
- <indexterm><primary>OpenBSD</></>
+ <indexterm><primary>OpenBSD</><secondary>shared library</></>
<listitem>
<para>
The compiler flag to create <acronym>PIC</acronym> is
<varlistentry>
<term><systemitem class="osname">Solaris</></term>
- <indexterm><primary>Solaris</></>
+ <indexterm><primary>Solaris</><secondary>shared library</></>
<listitem>
<para>
The compiler flag to create <acronym>PIC</acronym> is
<varlistentry>
<term><systemitem class="osname">Tru64 UNIX</></term>
- <indexterm><primary>Tru64 UNIX</></>
+ <indexterm><primary>Tru64 UNIX</><secondary>shared library</></>
<indexterm><primary>Digital UNIX</><see>Tru64 UNIX</></>
<listitem>
<para>
<varlistentry>
<term><systemitem class="osname">UnixWare</></term>
- <indexterm><primary>UnixWare</></>
+ <indexterm><primary>UnixWare</><secondary>shared library</></>
<listitem>
<para>
The compiler flag to create <acronym>PIC</acronym> is <option>-K
<sect1 id="dml-insert">
<title>Inserting Data</title>
+ <indexterm zone="dml-insert">
+ <primary>inserting</primary>
+ </indexterm>
+
+ <indexterm zone="dml-insert">
+ <primary>INSERT</primary>
+ </indexterm>
+
<para>
When a table is created, it contains no data. The first thing to
do before a database can be of much use is to insert data. Data is
<sect1 id="dml-update">
<title>Updating Data</title>
+ <indexterm zone="dml-update">
+ <primary>updating</primary>
+ </indexterm>
+
+ <indexterm zone="dml-update">
+ <primary>UPDATE</primary>
+ </indexterm>
+
<para>
The modification of data that is already in the database is
referred to as updating. You can update individual rows, all the
<sect1 id="dml-delete">
<title>Deleting Data</title>
+ <indexterm zone="dml-delete">
+ <primary>deleting</primary>
+ </indexterm>
+
+ <indexterm zone="dml-delete">
+ <primary>DELETE</primary>
+ </indexterm>
+
<para>
So far we have explained how to add data to tables and how to
change data. What remains is to discuss how to remove data that is
<title><application>ECPG</application> - Embedded <acronym>SQL</acronym> in C</title>
<indexterm zone="ecpg"><primary>embedded SQL</primary><secondary>in C</secondary></indexterm>
+ <indexterm zone="ecpg"><primary>C</primary></indexterm>
+ <indexterm zone="ecpg"><primary>ECPG</primary></indexterm>
<para>
This chapter describes the embedded <acronym>SQL</acronym> package
</para>
</sect1>
- <sect1 id="type-system">
+ <sect1 id="extend-type-system">
<title>The <productname>PostgreSQL</productname> Type System</title>
- <indexterm zone="type-system">
- <primary>extending SQL</primary>
- <secondary>types</secondary>
+ <indexterm zone="extend-type-system">
+ <primary>base type</primary>
+ </indexterm>
+
+ <indexterm zone="extend-type-system">
+ <primary>data type</primary>
+ <secondary>base</secondary>
+ </indexterm>
+
+ <indexterm zone="extend-type-system">
+ <primary>composite type</primary>
</indexterm>
- <indexterm zone="type-system">
- <primary>data types</primary>
+ <indexterm zone="extend-type-system">
+ <primary>data type</primary>
+ <secondary>composite</secondary>
</indexterm>
<para>
pseudo-types.
</para>
- <sect2 id="types-polymorphic">
+ <sect2 id="extend-types-polymorphic">
<title>Polymorphic Types and Functions</title>
- <indexterm>
- <primary>polymorphic types</primary>
+ <indexterm zone="extend-types-polymorphic">
+ <primary>polymorphic type</primary>
+ </indexterm>
+
+ <indexterm zone="extend-types-polymorphic">
+ <primary>polymorphic function</primary>
+ </indexterm>
+
+ <indexterm zone="extend-types-polymorphic">
+ <primary>type</primary>
+ <secondary>polymorphic</secondary>
</indexterm>
- <indexterm>
- <primary>polymorphic functions</primary>
+ <indexterm zone="extend-types-polymorphic">
+ <primary>function</primary>
+ <secondary>polymorphic</secondary>
</indexterm>
<para>
<!entity libpgeasy SYSTEM "libpgeasy.sgml">
<!entity libpq SYSTEM "libpq.sgml">
<!entity libpgtcl SYSTEM "libpgtcl.sgml">
-<!entity pygresql SYSTEM "pygresql.sgml">
<!entity lobj SYSTEM "lobj.sgml">
<!entity odbc SYSTEM "odbc.sgml">
<!entity rules SYSTEM "rules.sgml">
<title>Functions and Operators</title>
<indexterm zone="functions">
- <primary>functions</primary>
+ <primary>function</primary>
</indexterm>
<indexterm zone="functions">
- <primary>operators</primary>
+ <primary>operator</primary>
</indexterm>
<para>
<title>Logical Operators</title>
<indexterm zone="functions-logical">
- <primary>operators</primary>
+ <primary>operator</primary>
<secondary>logical</secondary>
</indexterm>
The usual logical operators are available:
<indexterm>
- <primary>and</primary>
- <secondary>operator</secondary>
+ <primary>AND (operator)</primary>
</indexterm>
<indexterm>
- <primary>or</primary>
- <secondary>operator</secondary>
+ <primary>OR (operator)</primary>
</indexterm>
<indexterm>
- <primary>not</primary>
- <secondary>operator</secondary>
+ <primary>NOT (operator)</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>conjunction</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>disjunction</primary>
+ </indexterm>
+
+ <indexterm>
+ <primary>negation</primary>
</indexterm>
<simplelist>
<primary>between</primary>
</indexterm>
In addition to the comparison operators, the special
- <token>BETWEEN</token> construct is available.
+ <token>BETWEEN</token> construct is available.<indexterm><primary>BETWEEN</primary></indexterm>
<synopsis>
<replaceable>a</replaceable> BETWEEN <replaceable>x</replaceable> AND <replaceable>y</replaceable>
</synopsis>
<replaceable>expression</replaceable> ISNULL
<replaceable>expression</replaceable> NOTNULL
</synopsis>
+ <indexterm><primary>null value</primary><secondary>comparing</secondary></indexterm>
</para>
<para>
<entry>
String concatenation
<indexterm>
- <primary>character strings</primary>
+ <primary>character string</primary>
<secondary>concatenation</secondary>
</indexterm>
</entry>
<entry>
Number of characters in string
<indexterm>
- <primary>character strings</primary>
+ <primary>character string</primary>
<secondary>length</secondary>
</indexterm>
<indexterm>
<primary>length</primary>
- <secondary>character strings</secondary>
+ <secondary sortas="character string">of a character string</secondary>
<see>character strings, length</see>
</indexterm>
</entry>
<entry>
Number of characters in string
<indexterm>
- <primary>character strings</primary>
+ <primary>character string</primary>
<secondary>length</secondary>
</indexterm>
<indexterm>
<primary>length</primary>
- <secondary>character strings</secondary>
+ <secondary sortas="character string">of a character string</secondary>
<see>character strings, length</see>
</indexterm>
</entry>
</row>
<row>
- <entry><literal><function>quote_ident</function>(<parameter>string</parameter> text)</literal></entry>
+ <entry><literal><function>quote_ident</function>(<parameter>string</parameter> text)</literal><indexterm><primary>quote_ident</></></entry>
<entry><type>text</type></entry>
<entry>
Return the given string suitably quoted to be used as an identifier
</row>
<row>
- <entry><literal><function>quote_literal</function>(<parameter>string</parameter> text)</literal></entry>
+ <entry><literal><function>quote_literal</function>(<parameter>string</parameter> text)</literal><indexterm><primary>quote_literal</></></entry>
<entry><type>text</type></entry>
<entry>
Return the given string suitably quoted to be used as a string literal
<sect1 id="functions-binarystring">
<title>Binary String Functions and Operators</title>
+ <indexterm zone="functions-binarystring">
+ <primary>binary data</primary>
+ <secondary>functions</secondary>
+ </indexterm>
+
<para>
This section describes functions and operators for examining and
manipulating values of type <type>bytea</type>.
<entry>
String concatenation
<indexterm>
- <primary>binary strings</primary>
+ <primary>binary string</primary>
<secondary>concatenation</secondary>
</indexterm>
</entry>
<entry>
Length of binary string
<indexterm>
- <primary>binary strings</primary>
+ <primary>binary string</primary>
<secondary>length</secondary>
</indexterm>
<indexterm>
<primary>length</primary>
- <secondary>binary strings</secondary>
+ <secondary sortas="binary string">of a binary string</secondary>
<see>binary strings, length</see>
</indexterm>
</entry>
<sect2 id="functions-like">
<title><function>LIKE</function></title>
- <indexterm>
- <primary>like</primary>
+ <indexterm zone="functions-like">
+ <primary>LIKE</primary>
</indexterm>
<synopsis>
Regular Expressions</title>
<indexterm zone="functions-sql99-regexp">
- <primary>regular expressions</primary>
+ <primary>regular expression</primary>
<!-- <seealso>pattern matching</seealso> breaks index build -->
</indexterm>
<indexterm>
- <primary>similar to</primary>
+ <primary>SIMILAR TO</primary>
</indexterm>
<indexterm>
<title><acronym>POSIX</acronym> Regular Expressions</title>
<indexterm zone="functions-posix-regexp">
- <primary>regular expressions</primary>
+ <primary>regular expression</primary>
<seealso>pattern matching</seealso>
</indexterm>
<primary>formatting</primary>
</indexterm>
+ <indexterm zone="functions-formatting">
+ <primary>to_char</primary>
+ </indexterm>
+
<para>
The <productname>PostgreSQL</productname> formatting functions
provide a powerful set of tools for converting various data types
</tgroup>
</table>
+ <para>
+ Warning. <literal><function>to_char</function>(<type>interval</type>, <type>text</type>)</literal>
+ is deprecated and should not be used in newly-written code. Will be removed in the next version.
+ </para>
+
<para>
In an output template string (for <function>to_char</>), there are certain patterns that are
recognized and replaced with appropriately-formatted data from the value
<title>Sequence-Manipulation Functions</title>
<indexterm>
- <primary>sequences</primary>
+ <primary>sequence</primary>
</indexterm>
<indexterm>
<primary>nextval</primary>
<title>Conditional Expressions</title>
<indexterm>
- <primary>case</primary>
+ <primary>CASE</primary>
</indexterm>
<indexterm>
- <primary>conditionals</primary>
+ <primary>conditional expression</primary>
</indexterm>
<para>
<sect2>
<title><literal>COALESCE</></title>
+ <indexterm>
+ <primary>COALESCE</primary>
+ </indexterm>
+
<synopsis>
-<function>COALESCE</function>(<replaceable>value</replaceable> <optional>, ...</optional>)
+<function>coalesce</function>(<replaceable>value</replaceable> <optional>, ...</optional>)
</synopsis>
<para>
<indexterm zone="functions-misc">
<primary>configuration</primary>
- <secondary>server</secondary>
+ <secondary sortas="server">of the server</secondary>
+ <tertiary>functions</tertiary>
</indexterm>
<para>
</programlisting>
</para>
+ <indexterm>
+ <primary>privilege</primary>
+ <secondary>querying</secondary>
+ </indexterm>
+
<para>
<xref linkend="functions-misc-access-table"> lists functions that
allow the user to query object access privileges programmatically.
<primary>col_description</primary>
</indexterm>
+ <indexterm zone="functions-misc">
+ <primary>comment</primary>
+ <secondary sortas="database objects">about database objects</secondary>
+ </indexterm>
+
<para>
The function shown in <xref
linkend="functions-misc-comment-table"> extract comments
<para>
<xref linkend="array-operators-table"> shows the operators
- available for the <type>array</type> types.
+ available for <type>array</type> types.
</para>
<table id="array-operators-table">
<entry> <literal>||</literal> </entry>
<entry>array-to-array concatenation</entry>
<entry><literal>ARRAY[1,2,3] || ARRAY[4,5,6]</literal></entry>
- <entry><literal>{{1,2,3},{4,5,6}}</literal></entry>
+ <entry><literal>{1,2,3,4,5,6}</literal></entry>
</row>
<row>
</tgroup>
</table>
+ <para>
+ See <xref linkend="arrays"> for more details about array operator
+ behavior.
+ </para>
+
<para>
<xref linkend="array-functions-table"> shows the functions
available for use with array types. See <xref linkend="arrays">
for <literal>NULL</literal> inputs
</entry>
<entry><literal>array_cat(ARRAY[1,2,3], ARRAY[4,5,6])</literal></entry>
- <entry><literal>{{1,2,3},{4,5,6}}</literal></entry>
+ <entry><literal>{1,2,3,4,5,6}</literal></entry>
</row>
<row>
<entry>
<sect1 id="functions-aggregate">
<title>Aggregate Functions</title>
+ <indexterm zone="functions-aggregate">
+ <primary>aggregate function</primary>
+ <secondary>built-in</secondary>
+ </indexterm>
+
<para>
<firstterm>Aggregate functions</firstterm> compute a single result
value from a set of input values. <xref
<entry>
<indexterm>
<primary>average</primary>
- <secondary>function</secondary>
</indexterm>
<function>avg(<replaceable class="parameter">expression</replaceable>)</function>
</entry>
<title>Subquery Expressions</title>
<indexterm>
- <primary>exists</primary>
+ <primary>EXISTS</primary>
</indexterm>
<indexterm>
- <primary>in</primary>
+ <primary>IN</primary>
</indexterm>
<indexterm>
- <primary>not in</primary>
+ <primary>NOT IN</primary>
</indexterm>
<indexterm>
- <primary>any</primary>
+ <primary>ANY</primary>
</indexterm>
<indexterm>
- <primary>all</primary>
+ <primary>ALL</primary>
</indexterm>
<indexterm>
- <primary>some</primary>
+ <primary>SOME</primary>
</indexterm>
<indexterm>
- <primary>subqueries</primary>
+ <primary>subquery</primary>
</indexterm>
<para>
<sect2>
<title>Row-wise Comparison</title>
+ <indexterm>
+ <primary>comparison</primary>
+ <secondary>of rows</secondary>
+ </indexterm>
+
<synopsis>
(<replaceable>expression</replaceable> <optional>, <replaceable>expression</replaceable> ...</optional>) <replaceable>operator</replaceable> (<replaceable>subquery</replaceable>)
</synopsis>
<title id="indexes-title">Indexes</title>
<indexterm zone="indexes">
- <primary>indexes</primary>
+ <primary>index</primary>
</indexterm>
<para>
B-tree, R-tree, GiST, and Hash. Each index type is more appropriate for
a particular query type because of the algorithm it uses.
<indexterm>
- <primary>indexes</primary>
+ <primary>index</primary>
<secondary>B-tree</secondary>
</indexterm>
<indexterm>
<primary>B-tree</primary>
- <see>indexes</see>
+ <see>index</see>
</indexterm>
By
default, the <command>CREATE INDEX</command> command will create a
<para>
<indexterm>
- <primary>indexes</primary>
+ <primary>index</primary>
<secondary>R-tree</secondary>
</indexterm>
<indexterm>
<primary>R-tree</primary>
- <see>indexes</see>
+ <see>index</see>
</indexterm>
R-tree indexes are especially suited for spatial data. To create
an R-tree index, use a command of the form
<para>
<indexterm>
- <primary>indexes</primary>
+ <primary>index</primary>
<secondary>hash</secondary>
</indexterm>
<indexterm>
<primary>hash</primary>
- <see>indexes</see>
+ <see>index</see>
</indexterm>
The query planner will consider using a hash index whenever an
indexed column is involved in a comparison using the
<title>Multicolumn Indexes</title>
<indexterm zone="indexes-multicolumn">
- <primary>indexes</primary>
+ <primary>index</primary>
<secondary>multicolumn</secondary>
</indexterm>
<title>Unique Indexes</title>
<indexterm zone="indexes-unique">
- <primary>indexes</primary>
+ <primary>index</primary>
<secondary>unique</secondary>
</indexterm>
<title>Indexes on Expressions</title>
<indexterm zone="indexes-expressional">
- <primary>indexes</primary>
- <secondary>on expressions</secondary>
+ <primary>index</primary>
+ <secondary sortas="expressions">on expressions</secondary>
</indexterm>
<para>
<sect1 id="indexes-opclass">
<title>Operator Classes</title>
+ <indexterm zone="indexes-opclass">
+ <primary>operator class</primary>
+ </indexterm>
+
<para>
An index definition may specify an <firstterm>operator
class</firstterm> for each column of an index.
<title>Partial Indexes</title>
<indexterm zone="indexes-partial">
- <primary>indexes</primary>
+ <primary>index</primary>
<secondary>partial</secondary>
</indexterm>
<sect1 id="indexes-examine">
<title>Examining Index Usage</title>
+ <indexterm zone="indexes-examine">
+ <primary>index</primary>
+ <secondary>examining usage</secondary>
+ </indexterm>
+
<para>
Although indexes in <productname>PostgreSQL</> do not need
maintenance and tuning, it is still important to check
<listitem>
<para>
- To build the Python interface module or the PL/Python server
- programming language, you need a Python installation, including
- the header files.
- Since PL/Python will be a shared library, the
+ To build the PL/Python server programming language, you need a
+ Python installation, including the header files. Since
+ PL/Python will be a shared library, the
<indexterm><primary>libpython</primary></indexterm>
<filename>libpython</filename> library must be a shared library
also on most platforms. This is not the case in a default
<para>
<indexterm>
<primary>pg_dumpall</primary>
+ <secondary>use during upgrade</secondary>
</indexterm>
To back up your database installation, type:
<term><option>--with-python</option></term>
<listitem>
<para>
- Build the Python interface module and the PL/Python
- server-side language. You need to have root access to be able
- to install the Python module at its default place
- (<filename>/usr/lib/python<replaceable>x</>.<replaceable>y</></>).
+ Build the PL/Python server-side language.
</para>
</listitem>
</varlistentry>
<term><option>--with-pam</option></term>
<listitem>
<para>
- Build with <acronym>PAM</> (Pluggable Authentication Modules)
- support.
+ Build with <acronym>PAM</><indexterm><primary>PAM</></>
+ (Pluggable Authentication Modules) support.
</para>
</listitem>
</varlistentry>
possibly can, you will have to do manual work.
</para>
- <para>
- If you built the Python interfaces and you were not the
- root user when you executed the above command then that part of
- the installation probably failed. In that case you should become
- the root user and then do
-<screen>
-<userinput>gmake -C src/interfaces/python install</userinput>
-</screen>
- If you do not have root access you are on your own:
- you can still take the required files and place them in
- other directories where Python can find them, but how to
- do that is left as an exercise.
- </para>
-
<para>
The standard installation provides only the header files needed for client
application development. If you plan to do any server-side program
<title>Shared Libraries</title>
<indexterm>
- <primary>shared libraries</primary>
+ <primary>shared library</primary>
</indexterm>
<para>
<para>
<indexterm>
<primary><envar>MANPATH</envar></primary>
- <seealso>man pages</seealso>
</indexterm>
To enable your system to find the <application>man</>
documentation, you need to add lines like the following to a
<chapter id="jdbc">
<title><acronym>JDBC</acronym> Interface</title>
+ <indexterm zone="jdbc">
+ <primary>JDBC</primary>
+ </indexterm>
+
+ <indexterm zone="jdbc">
+ <primary>Java</primary>
+ </indexterm>
+
<para>
<acronym>JDBC</acronym> is a core <acronym>API</acronym> of Java 1.1 and later.
It provides a standard set of
<sect2 id="jdbc-classpath">
<title>Setting up the Class Path</title>
+ <indexterm zone="jdbc-classpath">
+ <primary>class path</primary>
+ </indexterm>
+
+ <indexterm zone="jdbc-classpath">
+ <primary>CLASSPATH</primary>
+ </indexterm>
+
<para>
To use the driver, the JAR archive (named
<filename>postgresql.jar</filename> if you built from source, otherwise
<sect1 id="jdbc-query">
<title>Issuing a Query and Processing the Result</title>
+ <indexterm zone="jdbc-query">
+ <primary>Statement</primary>
+ </indexterm>
+
+ <indexterm zone="jdbc-query">
+ <primary>PreparedStatement</primary>
+ </indexterm>
+
+ <indexterm zone="jdbc-query">
+ <primary>ResultSet</primary>
+ </indexterm>
+
<para>
Any time you want to issue <acronym>SQL</acronym> statements to
the database, you require a <classname>Statement</classname> or
<sect1 id="jdbc-binary-data">
<title>Storing Binary Data</title>
+ <indexterm zone="jdbc-binary-data">
+ <primary>bytea</primary>
+ <secondary sortas="JDBC">in JDBC</secondary>
+ </indexterm>
+
+ <indexterm zone="jdbc-binary-data">
+ <primary>large object</primary>
+ <secondary sortas="JDBC">in JDBC</secondary>
+ </indexterm>
+
<para>
<application>PostgreSQL</application> provides two distinct ways to
store binary data. Binary data can be stored in a table using
<sect1 id="jdbc-thread">
<title>Using the Driver in a Multithreaded or a Servlet Environment</title>
+ <indexterm zone="jdbc-thread">
+ <primary>threads</primary>
+ <secondary sortas="JDBC">with JDBC</secondary>
+ </indexterm>
+
<para>
A problem with many <acronym>JDBC</acronym> drivers is that only
one thread can use a <classname>Connection</classname> at any one
<sect1 id="jdbc-datasource">
<title>Connection Pools and Data Sources</title>
+ <indexterm zone="jdbc-datasource">
+ <primary>connection pool</primary>
+ <secondary sortas="JDBC">in JDBC</secondary>
+ </indexterm>
+
+ <indexterm zone="jdbc-datasource">
+ <primary>DataSource</primary>
+ </indexterm>
+
<para>
<acronym>JDBC</> 2 introduced standard connection pooling features in an
add-on <acronym>API</> known as the <acronym>JDBC</acronym> 2.0 Optional
</sect2>
<sect2 id="jdbc-jndi">
- <title>Data Sources and <acronym>JNDI</acronym></title>
+ <title>Data Sources and <acronym>JNDI</acronym></title>
+
+ <indexterm zone="jdbc-jndi">
+ <primary>JNDI</primary>
+ </indexterm>
<para>
All the <literal>ConnectionPoolDataSource</literal> and
<title><acronym>SQL</acronym> Key Words</title>
<indexterm zone="sql-keywords-appendix">
- <primary>key words</primary>
+ <primary>key word</primary>
<secondary>list of</secondary>
</indexterm>
<para>
The <function>pg_lo_*</function> commands are interfaces to the
large object features of
- <ProductName>PostgreSQL</ProductName>.<indexterm><primary>Large
- Object</></> The functions are designed to mimic the analogous file
+ <ProductName>PostgreSQL</ProductName>.<indexterm><primary>large
+ object</><secondary>in pgctl</></> The functions are designed to mimic the analogous file
system functions in the standard Unix file system interface. The
<function>pg_lo_*</function> commands should be used within a
<command>BEGIN</command>/<command>COMMIT</command> transaction
message bearing the given name arrives from the server. This
occurs when any <productname>PostgreSQL</productname> client
application issues a
- <command>NOTIFY</command><indexterm><primary>NOTIFY</><secondary>in
- pgtcl</></> command referencing that name. The command string is
- executed from the Tcl idle loop. That is the normal idle state of
- an application written with Tk. In non-Tk Tcl shells, you can
- execute <function>update</function> or <function>vwait</function>
- to cause the idle loop to be entered.
+ <command>NOTIFY</command><indexterm><primary>NOTIFY</><secondary
+ sortas="pgtcl">in pgtcl</></> command referencing that name. The
+ command string is executed from the Tcl idle loop. That is the
+ normal idle state of an application written with Tk. In non-Tk Tcl
+ shells, you can execute <function>update</function> or
+ <function>vwait</function> to cause the idle loop to be entered.
</para>
<para>
<primary>libpq</primary>
</indexterm>
+ <indexterm zone="libpq">
+ <primary>C</primary>
+ </indexterm>
+
<para>
<application>libpq</application> is the <acronym>C</acronym>
application programmer's interface to
</para>
<para>
- Client programs that use <application>libpq</application> must include the
- header file <filename>libpq-fe.h</filename> and must link with the
- <application>libpq</application> library.
+ Client programs that use <application>libpq</application> must
+ include the header file
+ <filename>libpq-fe.h</filename><indexterm><primary>libpq-fe.h</></>
+ and must link with the <application>libpq</application> library.
</para>
<sect1 id="libpq-connect">
application program can have several backend connections open at
one time. (One reason to do that is to access more than one
database.) Each connection is represented by a
- <structname>PGconn</> object which is obtained from the function
- <function>PQconnectdb</> or <function>PQsetdbLogin</>. Note that
- these functions will always return a non-null object pointer,
- unless perhaps there is too little memory even to allocate the
- <structname>PGconn</> object. The <function>PQstatus</> function
- should be called to check whether a connection was successfully
- made before queries are sent via the connection object.
+ <structname>PGconn</><indexterm><primary>PGconn</></> object which
+ is obtained from the function <function>PQconnectdb</> or
+ <function>PQsetdbLogin</>. Note that these functions will always
+ return a non-null object pointer, unless perhaps there is too
+ little memory even to allocate the <structname>PGconn</> object.
+ The <function>PQstatus</> function should be called to check
+ whether a connection was successfully made before queries are sent
+ via the connection object.
<variablelist>
<varlistentry>
- <term><function>PQconnectdb</function></term>
+ <term><function>PQconnectdb</function><indexterm><primary>PQconnectdb</></></term>
<listitem>
<para>
Makes a new connection to the database server.
<term><literal>host</literal></term>
<listitem>
<para>
- Name of host to connect to.
- If this begins with a slash, it specifies Unix-domain communication
- rather than TCP/IP communication; the value is the name of the
- directory in which the socket file is stored.
- The default is to connect to a Unix-domain socket in
- <filename>/tmp</filename>.
+ Name of host to connect to.<indexterm><primary>host name</></>
+ If this begins with a slash, it specifies Unix-domain
+ communication rather than TCP/IP communication; the value is the
+ name of the directory in which the socket file is stored. The
+ default is to connect to a Unix-domain socket in
+ <filename>/tmp</filename>.<indexterm><primary>Unix domain
+ socket</></>
</para>
</listitem>
</varlistentry>
<term><literal>port</literal></term>
<listitem>
<para>
- Port number to connect to at the server host,
- or socket file name extension for Unix-domain connections.
+ Port number to connect to at the server host, or socket file
+ name extension for Unix-domain
+ connections.<indexterm><primary>port</></>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>sslmode</literal></term>
<listitem>
- <para>
- This option determines whether or with what priority an <acronym>SSL</>
- connection will be negotiated with the server. There are four
- modes: <literal>disable</> will attempt only an unencrypted
- <acronym>SSL</> connection; <literal>allow</> will negotiate,
- trying first a non-<acronym>SSL</> connection, then if that fails,
- trying an <acronym>SSL</> connection; <literal>prefer</>
- (the default) will negotiate, trying first an <acronym>SSL</> connection,
- then if that fails, trying a regular non-<acronym>SSL</> connection;
- <literal>require</> will try only an <acronym>SSL</> connection.
- </para>
- <para>
- If <productname>PostgreSQL</> is compiled without SSL support,
- using option <literal>require</> will cause an error, and options
- <literal>allow</> and <literal>prefer</> will be tolerated but
- <application>libpq</> will be unable to negotiate an <acronym>SSL</>
- connection.
- </para>
+ <para>
+ This option determines whether or with what priority an
+ <acronym>SSL</> connection will be negotiated with the
+ server. There are four modes: <literal>disable</> will attempt
+ only an unencrypted <acronym>SSL</> connection;
+ <literal>allow</> will negotiate, trying first a
+ non-<acronym>SSL</> connection, then if that fails, trying an
+ <acronym>SSL</> connection; <literal>prefer</> (the default)
+ will negotiate, trying first an <acronym>SSL</> connection,
+ then if that fails, trying a regular non-<acronym>SSL</>
+ connection; <literal>require</> will try only an
+ <acronym>SSL</> connection.
+ </para>
+
+ <para>
+ If <productname>PostgreSQL</> is compiled without SSL support,
+ using option <literal>require</> will cause an error, and
+ options <literal>allow</> and <literal>prefer</> will be
+ tolerated but <application>libpq</> will be unable to negotiate
+ an <acronym>SSL</>
+ connection.<indexterm><primary>SSL</><secondary
+ sortas="libpq">with libpq</></indexterm>
+ </para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>requiressl</literal></term>
<listitem>
- <para>
- This option is deprecated in favor of the <literal>sslmode</>
- setting.
- </para>
- <para>
- If set to 1, an <acronym>SSL</acronym> connection to the server is required
- (this is equivalent to <literal>sslmode</> <literal>require</>).
- <application>libpq</> will then refuse to connect if the server does not
- accept an <acronym>SSL</acronym> connection.
- If set to 0 (default), <application>libpq</> will negotiate the connection
- type with the server (equivalent to <literal>sslmode</> <literal>prefer</>).
- This option is only available if
- <productname>PostgreSQL</> is compiled with SSL support.
- </para>
+ <para>
+ This option is deprecated in favor of the <literal>sslmode</>
+ setting.
+ </para>
+
+ <para>
+ If set to 1, an <acronym>SSL</acronym> connection to the server
+ is required (this is equivalent to <literal>sslmode</>
+ <literal>require</>). <application>libpq</> will then refuse
+ to connect if the server does not accept an
+ <acronym>SSL</acronym> connection. If set to 0 (default),
+ <application>libpq</> will negotiate the connection type with
+ the server (equivalent to <literal>sslmode</>
+ <literal>prefer</>). This option is only available if
+ <productname>PostgreSQL</> is compiled with SSL support.
+ </para>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
- <term><function>PQsetdbLogin</function></term>
+ <term><function>PQsetdbLogin</function><indexterm><primary>PQsetdbLogin</></></term>
<listitem>
<para>
Makes a new connection to the database server.
</varlistentry>
<varlistentry>
- <term><function>PQsetdb</function></term>
+ <term><function>PQsetdb</function><indexterm><primary>PQsetdb</></></term>
<listitem>
<para>
Makes a new connection to the database server.
</varlistentry>
<varlistentry>
- <term><function>PQconnectStart</function></term>
- <term><function>PQconnectPoll</function></term>
+ <term><function>PQconnectStart</function><indexterm><primary>PQconnectStart</></></term>
+ <term><function>PQconnectPoll</function><indexterm><primary>PQconnectPoll</></></term>
<listitem>
<para>
<indexterm><primary>nonblocking connection</primary></indexterm>
</varlistentry>
<varlistentry>
- <term><function>PQconndefaults</function></term>
+ <term><function>PQconndefaults</function><indexterm><primary>PQconndefaults</></></term>
<listitem>
<para>
Returns the default connection options.
</varlistentry>
<varlistentry>
- <term><function>PQfinish</function></term>
+ <term><function>PQfinish</function><indexterm><primary>PQfinish</></></term>
<listitem>
<para>
Closes the connection to the server. Also frees
</varlistentry>
<varlistentry>
- <term><function>PQreset</function></term>
+ <term><function>PQreset</function><indexterm><primary>PQreset</></></term>
<listitem>
<para>
Resets the communication channel to the server.
</varlistentry>
<varlistentry>
- <term><function>PQresetStart</function></term>
- <term><function>PQresetPoll</function></term>
+ <term><function>PQresetStart</function><indexterm><primary>PQresetStart</></></term>
+ <term><function>PQresetPoll</function><indexterm><primary>PQresetPoll</></></term>
<listitem>
<para>
Reset the communication channel to the server, in a nonblocking manner.
<variablelist>
<varlistentry>
-<term><function>PQdb</function></term>
+<term><function>PQdb</function><indexterm><primary>PQdb</></></term>
<listitem>
<para>
Returns the database name of the connection.
</varlistentry>
<varlistentry>
-<term><function>PQuser</function></term>
+<term><function>PQuser</function><indexterm><primary>PQuser</></></term>
<listitem>
<para>
Returns the user name of the connection.
</varlistentry>
<varlistentry>
-<term><function>PQpass</function></term>
+<term><function>PQpass</function><indexterm><primary>PQpass</></></term>
<listitem>
<para>
Returns the password of the connection.
</varlistentry>
<varlistentry>
-<term><function>PQhost</function></term>
+<term><function>PQhost</function><indexterm><primary>PQhost</></></term>
<listitem>
<para>
Returns the server host name of the connection.
</varlistentry>
<varlistentry>
-<term><function>PQport</function></term>
+<term><function>PQport</function><indexterm><primary>PQport</></></term>
<listitem>
<para>
Returns the port of the connection.
</varlistentry>
<varlistentry>
-<term><function>PQtty</function></term>
+<term><function>PQtty</function><indexterm><primary>PQtty</></></term>
<listitem>
<para>
Returns the debug <acronym>TTY</acronym> of the connection.
- (This is obsolete, since the server no longer pays attention
- to the <acronym>TTY</acronym> setting, but the function remains
- for backwards compatibility.)
+ (This is obsolete, since the server no longer pays attention
+ to the <acronym>TTY</acronym> setting, but the function remains
+ for backwards compatibility.)
<synopsis>
char *PQtty(const PGconn *conn);
</synopsis>
</varlistentry>
<varlistentry>
-<term><function>PQoptions</function></term>
+<term><function>PQoptions</function><indexterm><primary>PQoptions</></></term>
<listitem>
<para>
Returns the command-line options passed in the connection request.
<variablelist>
<varlistentry>
-<term><function>PQstatus</function></term>
+<term><function>PQstatus</function><indexterm><primary>PQstatus</></></term>
<listitem>
<para>
Returns the status of the connection.
</varlistentry>
<varlistentry>
-<term><function>PQtransactionStatus</function></term>
+<term><function>PQtransactionStatus</function><indexterm><primary>PQtransactionStatus</></></term>
<listitem>
<para>
Returns the current in-transaction status of the server.
</varlistentry>
<varlistentry>
-<term><function>PQparameterStatus</function></term>
+<term><function>PQparameterStatus</function><indexterm><primary>PQparameterStatus</></></term>
<listitem>
<para>
Looks up a current parameter setting of the server.
<para>
Parameters reported as of the current release include
<literal>server_version</> (cannot change after startup);
-<literal>server_encoding</> (also not presently changeable after start);
<literal>client_encoding</>,
-<literal>is_superuser</>, and
+<literal>is_superuser</>,
+<literal>session_authorization</literal>, and
<literal>DateStyle</>.
</para>
<para>
-Pre-3.0-protocol servers do not report parameter settings,
-but <application>libpq</> includes logic to obtain values for
-<literal>server_version</>, <literal>server_encoding</>, and
-<literal>client_encoding</>. Applications are encouraged to use
-<function>PQparameterStatus</> rather than ad-hoc code to determine these
-values. (Beware however that on a pre-3.0 connection, changing
-<literal>client_encoding</> via <command>SET</> after connection startup
-will not be reflected by <function>PQparameterStatus</>.)
+Pre-3.0-protocol servers do not report parameter settings, but
+<application>libpq</> includes logic to obtain values for
+<literal>server_version</>, and <literal>client_encoding</>.
+Applications are encouraged to use <function>PQparameterStatus</>
+rather than ad-hoc code to determine these values. (Beware however
+that on a pre-3.0 connection, changing <literal>client_encoding</> via
+<command>SET</> after connection startup will not be reflected by
+<function>PQparameterStatus</>.)
</para>
</listitem>
</varlistentry>
<varlistentry>
-<term><function>PQprotocolVersion</function></term>
+<term><function>PQprotocolVersion</function><indexterm><primary>PQprotocolVersion</></></term>
<listitem>
<para>
Interrogates the frontend/backend protocol being used.
</varlistentry>
<varlistentry>
- <term><function>PQerrorMessage</function></term>
+ <term><function>PQerrorMessage</function><indexterm><primary>PQerrorMessage</></></term>
<listitem>
<para>
<indexterm><primary>error message</></>
</varlistentry>
<varlistentry>
- <term><function>PQsocket</function></term>
+ <term><function>PQsocket</function><indexterm><primary>PQsocket</></></term>
<listitem>
<para>
Obtains the file descriptor number of the connection socket to
</varlistentry>
<varlistentry>
- <term><function>PQbackendPID</function></term>
+ <term><function>PQbackendPID</function><indexterm><primary>PQbackendPID</></></term>
<listitem>
<para>
- Returns the process <acronym>ID</acronym> of the backend server process
- handling this connection.
+ Returns the process <acronym>ID</acronym>
+ (PID)<indexterm><primary>PID</><secondary>determining PID of
+ server process</><tertiary>in libpq</></> of the backend server
+ process handling this connection.
<synopsis>
int PQbackendPID(const PGconn *conn);
</synopsis>
</varlistentry>
<varlistentry>
- <term><function>PQgetssl</function></term>
+ <term><function>PQgetssl</function><indexterm><primary>PQgetssl</></></term>
<listitem>
<para>
- <indexterm><primary>SSL</></>
+ <indexterm><primary>SSL</><secondary sortas="libpq">in libpq</secondary></indexterm>
Returns the SSL structure used in the connection, or null
if SSL is not in use.
<synopsis>
<para>
<variablelist>
<varlistentry>
-<term><function>PQexec</function></term>
+<term><function>PQexec</function><indexterm><primary>PQexec</></></term>
<listitem>
<para>
Submits a command to the server
out-of-memory conditions or serious errors such as inability
to send the command to the server.
If a null pointer is returned, it
- should be treated like a <symbol>PGRES_FATAL_ERROR</symbol> result. Use
- <function>PQerrorMessage</function> to get more information about the error.
+ should be treated like a <symbol>PGRES_FATAL_ERROR</symbol> result. Use
+ <function>PQerrorMessage</function> to get more information about the error.
</para>
</listitem>
</varlistentry>
<para>
<variablelist>
<varlistentry>
-<term><function>PQexecParams</function></term>
+<term><function>PQexecParams</function><indexterm><primary>PQexecParams</></></term>
<listitem>
<para>
Submits a command to the server and waits for the result,
- with the ability to pass parameters separately from the SQL
- command text.
+ with the ability to pass parameters separately from the SQL
+ command text.
<synopsis>
PGresult *PQexecParams(PGconn *conn,
const char *command,
<para>
<variablelist>
<varlistentry>
-<term><function>PQexecPrepared</function></term>
+<term><function>PQexecPrepared</function><indexterm><primary>PQexecPrepared</></></term>
<listitem>
<para>
Sends a request to execute a prepared statement with given
- parameters, and waits for the result.
+ parameters, and waits for the result.
<synopsis>
PGresult *PQexecPrepared(PGconn *conn,
const char *stmtName,
</para>
<para>
-The <structname>PGresult</structname> structure encapsulates the result
-returned by the server.
-<application>libpq</application> application programmers should be careful to
-maintain the <structname>PGresult</structname> abstraction. Use the accessor functions below to get
-at the contents of <structname>PGresult</structname>. Avoid directly referencing the fields of the
-<structname>PGresult</structname> structure because they are subject to change in the future.
+The
+<structname>PGresult</structname><indexterm><primary>PGresult</></>
+structure encapsulates the result returned by the server.
+<application>libpq</application> application programmers should be
+careful to maintain the <structname>PGresult</structname> abstraction.
+Use the accessor functions below to get at the contents of
+<structname>PGresult</structname>. Avoid directly referencing the
+fields of the <structname>PGresult</structname> structure because they
+are subject to change in the future.
<variablelist>
<varlistentry>
-<term><function>PQresultStatus</function></term>
+<term><function>PQresultStatus</function><indexterm><primary>PQresultStatus</></></term>
<listitem>
<para>
Returns the result status of the command.
</varlistentry>
<varlistentry>
-<term><function>PQresStatus</function></term>
+<term><function>PQresStatus</function><indexterm><primary>PQresStatus</></></term>
<listitem>
<para>
- Converts the enumerated type returned by <function>PQresultStatus</> into
- a string constant describing the status code.
+ Converts the enumerated type returned by <function>PQresultStatus</> into
+ a string constant describing the status code.
<synopsis>
char *PQresStatus(ExecStatusType status);
</synopsis>
</varlistentry>
<varlistentry>
-<term><function>PQresultErrorMessage</function></term>
+<term><function>PQresultErrorMessage</function><indexterm><primary>PQresultErrorMessage</></></term>
<listitem>
<para>
Returns the error message associated with the command, or an empty string
</varlistentry>
<varlistentry>
-<term><function>PQresultErrorField</function></term>
+<term><function>PQresultErrorField</function><indexterm><primary>PQresultErrorField</></></term>
<listitem>
<para>
Returns an individual field of an error report.
<synopsis>
char *PQresultErrorField(const PGresult *res, int fieldcode);
</synopsis>
-<parameter>fieldcode</> is an error field identifier defined by the
-<productname>PostgreSQL</> protocol (see <xref
-linkend="protocol-error-fields">), for example <literal>'C'</> for
-the SQLSTATE error code. NULL is returned if the
+<parameter>fieldcode</> is an error field identifier; see the symbols
+listed below. <symbol>NULL</symbol> is returned if the
<structname>PGresult</structname> is not an error or warning result,
or does not include the specified field. Field values will normally
not include a trailing newline.
</para>
<para>
-Errors generated internally by libpq will have severity and primary message,
-but typically no other fields. Errors returned by a pre-3.0-protocol server
-will include severity and primary message, and sometimes a detail message,
-but no other fields.
+The following field codes are available:
+<variablelist>
+
+<varlistentry>
+<term><symbol>PG_DIAG_SEVERITY</></term>
+<listitem>
+<para>
+The severity; the field contents are <literal>ERROR</>,
+<literal>FATAL</>, or <literal>PANIC</> (in an error message), or
+<literal>WARNING</>, <literal>NOTICE</>, <literal>DEBUG</>,
+<literal>INFO</>, or <literal>LOG</> (in a notice message), or a
+localized translation of one of these. Always present.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><symbol>PG_DIAG_SQLSTATE</>
+</term>
+<listitem>
+<para>
+The SQLSTATE code for the error (a 5-character string following SQL
+spec conventions). Not localizable. Always present.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><symbol>PG_DIAG_MESSAGE_PRIMARY</></term>
+<listitem>
+<para>
+The primary human-readable error message (typically one line). Always
+present.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><symbol>PG_DIAG_MESSAGE_DETAIL</></term>
+<listitem>
+<para>
+Detail: an optional secondary error message carrying more detail about
+the problem. May run to multiple lines.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><symbol>PG_DIAG_MESSAGE_HINT</></term>
+<listitem>
+<para>
+Hint: an optional suggestion what to do about the problem. This is
+intended to differ from detail in that it offers advice (potentially
+inappropriate) rather than hard facts. May run to multiple lines.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><symbol>PG_DIAG_STATEMENT_POSITION</></term>
+<listitem>
+<para>
+A string containing a decimal integer indicating an error cursor
+position as an index into the original statement string. The first
+character has index 1, and positions are measured in characters not
+bytes.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><symbol>PG_DIAG_CONTEXT</></term>
+<listitem>
+<para>
+An indication of the context in which the error occurred. Presently
+this includes a call stack traceback of active PL functions. The
+trace is one entry per line, most recent first.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><symbol>PG_DIAG_SOURCE_FILE</></term>
+<listitem>
+<para>
+The file name of the source-code location where the error was
+reported.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><symbol>PG_DIAG_SOURCE_LINE</></term>
+<listitem>
+<para>
+The line number of the source-code location where the error was
+reported.
+</para>
+</listitem>
+</varlistentry>
+
+<varlistentry>
+<term><symbol>PG_DIAG_SOURCE_FUNCTION</></term>
+<listitem>
+<para>
+The name of the source-code function reporting the error.
+</para>
+</listitem>
+</varlistentry>
+</variablelist>
+</para>
+
+<para>
+The client is responsible for formatting displayed information to meet
+its needs; in particular it should break long lines as needed.
+Newline characters appearing in the error message fields should be
+treated as paragraph breaks, not line breaks.
+</para>
+
+<para>
+Errors generated internally by <application>libpq</application> will
+have severity and primary message, but typically no other fields.
+Errors returned by a pre-3.0-protocol server will include severity and
+primary message, and sometimes a detail message, but no other fields.
</para>
<para>
</varlistentry>
<varlistentry>
-<term><function>PQclear</function></term>
+<term><function>PQclear</function><indexterm><primary>PQclear</></></term>
<listitem>
<para>
Frees the storage associated with a <structname>PGresult</structname>.
</varlistentry>
<varlistentry>
-<term><function>PQmakeEmptyPGresult</function></term>
+<term><function>PQmakeEmptyPGresult</function><indexterm><primary>PQmakeEmptyPGresult</></></term>
<listitem>
<para>
Constructs an empty <structname>PGresult</structname> object with the given status.
<variablelist>
<varlistentry>
-<term><function>PQntuples</function></term>
+<term><function>PQntuples</function><indexterm><primary>PQntuples</></></term>
<listitem>
<para>
Returns the number of rows (tuples)
</varlistentry>
<varlistentry>
-<term><function>PQnfields</function></term>
+<term><function>PQnfields</function><indexterm><primary>PQnfields</></></term>
<listitem>
<para>
Returns the number of columns (fields)
</varlistentry>
<varlistentry>
-<term><function>PQfname</function></term>
+<term><function>PQfname</function><indexterm><primary>PQfname</></></term>
<listitem>
<para>
Returns the column name associated with the given column number.
</varlistentry>
<varlistentry>
-<term><function>PQfnumber</function></term>
+<term><function>PQfnumber</function><indexterm><primary>PQfnumber</></></term>
<listitem>
<para>
Returns the column number
</varlistentry>
<varlistentry>
-<term><function>PQftable</function></term>
+<term><function>PQftable</function><indexterm><primary>PQftable</></></term>
<listitem>
<para>
Returns the OID of the table from which the given column was fetched.
</varlistentry>
<varlistentry>
-<term><function>PQftablecol</function></term>
+<term><function>PQftablecol</function><indexterm><primary>PQftablecol</></></term>
<listitem>
<para>
Returns the column number (within its table) of the column making up
</varlistentry>
<varlistentry>
-<term><function>PQfformat</function></term>
+<term><function>PQfformat</function><indexterm><primary>PQfformat</></></term>
<listitem>
<para>
Returns the format code indicating the format of the given column.
</varlistentry>
<varlistentry>
-<term><function>PQftype</function></term>
+<term><function>PQftype</function><indexterm><primary>PQftype</></></term>
<listitem>
<para>
Returns the data type associated with the
</varlistentry>
<varlistentry>
-<term><function>PQfmod</function></term>
+<term><function>PQfmod</function><indexterm><primary>PQfmod</></></term>
<listitem>
<para>
Returns the type modifier of the column
</varlistentry>
<varlistentry>
-<term><function>PQfsize</function></term>
+<term><function>PQfsize</function><indexterm><primary>PQfsize</></></term>
<listitem>
<para>
Returns the size in bytes of the column
</varlistentry>
<varlistentry>
-<term><function>PQbinaryTuples</function></term>
+<term><function>PQbinaryTuples</function><indexterm><primary>PQbinaryTuples</></></term>
<listitem>
<para>
Returns 1 if the <structname>PGresult</> contains binary data
</varlistentry>
<varlistentry>
-<term><function>PQgetvalue</function></term>
+<term><function>PQgetvalue</function><indexterm><primary>PQgetvalue</></></term>
<listitem>
<para>
Returns a single field value of one row
- of a <structname>PGresult</structname>.
+ of a <structname>PGresult</structname>.
Row and column numbers start at 0.
<synopsis>
char* PQgetvalue(const PGresult *res,
</varlistentry>
<varlistentry>
-<term><function>PQgetisnull</function></term>
-<listitem>
+<term><function>PQgetisnull</function><indexterm><primary>PQgetisnull</></></term>
+<indexterm><primary>null value</><secondary sortas="libpq">in libpq</></indexterm><listitem>
<para>
Tests a field for a null value.
Row and column numbers start at 0.
</varlistentry>
<varlistentry>
-<term><function>PQgetlength</function></term>
+<term><function>PQgetlength</function><indexterm><primary>PQgetlength</></></term>
<listitem>
<para>
Returns the actual length of a field value in bytes.
</varlistentry>
<varlistentry>
-<term><function>PQprint</function></term>
+<term><function>PQprint</function><indexterm><primary>PQprint</></></term>
<listitem>
<para>
Prints out all the rows and, optionally, the
<variablelist>
<varlistentry>
-<term><function>PQcmdStatus</function></term>
+<term><function>PQcmdStatus</function><indexterm><primary>PQcmdStatus</></></term>
<listitem>
<para>
Returns the command status tag from the SQL command that
- generated the <structname>PGresult</structname>.
+ generated the <structname>PGresult</structname>.
<synopsis>
char * PQcmdStatus(PGresult *res);
</synopsis>
</varlistentry>
<varlistentry>
-<term><function>PQcmdTuples</function></term>
+<term><function>PQcmdTuples</function><indexterm><primary>PQcmdTuples</></></term>
<listitem>
<para>
- Returns the number of rows affected by the SQL command.
+ Returns the number of rows affected by the SQL command.
<synopsis>
char * PQcmdTuples(PGresult *res);
</synopsis>
<para>
If the <acronym>SQL</acronym> command that generated the
- <structname>PGresult</structname> was <command>INSERT</>,
- <command>UPDATE</>, <command>DELETE</command>, <command>MOVE</>,
- or <command>FETCH</>, this returns a
- string containing the number of rows affected. If the
+ <structname>PGresult</structname> was <command>INSERT</>,
+ <command>UPDATE</>, <command>DELETE</command>, <command>MOVE</>,
+ or <command>FETCH</>, this returns a
+ string containing the number of rows affected. If the
command was anything else, it returns the empty string.
</para>
</listitem>
</varlistentry>
<varlistentry>
-<term><function>PQoidValue</function></term>
+<term><function>PQoidValue</function><indexterm><primary>PQoidValue</></></term>
<listitem>
<para>
- Returns the OID of the inserted row, if the
- <acronym>SQL</acronym> command was an <command>INSERT</command>
- that inserted exactly one row into a table that has OIDs.
- Otherwise, returns <literal>InvalidOid</literal>.
+ Returns the OID<indexterm><primary>OID</><secondary>in
+ libpq</></> of the inserted row, if the
+ <acronym>SQL</acronym> command was an
+ <command>INSERT</command> that inserted exactly one row into
+ a table that has OIDs. Otherwise, returns
+ <literal>InvalidOid</literal>.
<synopsis>
Oid PQoidValue(const PGresult *res);
</synopsis>
</varlistentry>
<varlistentry>
-<term><function>PQoidStatus</function></term>
+<term><function>PQoidStatus</function><indexterm><primary>PQoidStatus</></></term>
<listitem>
<para>
Returns a string with the OID of the inserted row, if the
<sect2 id="libpq-exec-escape-string">
<title>Escaping Strings for Inclusion in SQL Commands</title>
+ <indexterm zone="libpq-exec-escape-string"><primary>PQescapeString</></>
<indexterm zone="libpq-exec-escape-string"><primary>escaping strings</></>
<para>
<sect2 id="libpq-exec-escape-bytea">
<title>Escaping Binary Strings for Inclusion in SQL Commands</title>
+
<indexterm zone="libpq-exec-escape-bytea">
- <primary>escaping binary strings</primary>
+ <primary>bytea</>
+ <secondary sortas="libpq">in libpq</>
</indexterm>
<variablelist>
<varlistentry>
- <term><function>PQescapeBytea</function></term>
+ <term><function>PQescapeBytea</function><indexterm><primary>PQescapeBytea</></></term>
<listitem>
<para>
Escapes binary data for use within an SQL command with the type
</varlistentry>
<varlistentry>
- <term><function>PQunescapeBytea</function></term>
+ <term><function>PQunescapeBytea</function><indexterm><primary>PQunescapeBytea</></></term>
<listitem>
<para>
Converts an escaped string representation of binary data into binary
</varlistentry>
<varlistentry>
- <term><function>PQfreemem</function></term>
+ <term><function>PQfreemem</function><indexterm><primary>PQfreemem</></></term>
<listitem>
<para>
Frees memory allocated by <application>libpq</>.
<variablelist>
<varlistentry>
-<term><function>PQsendQuery</function></term>
+<term><function>PQsendQuery</function><indexterm><primary>PQsendQuery</></></term>
<listitem>
<para>
Submits a command to the server without
- waiting for the result(s). 1 is returned if the command was
- successfully dispatched and 0 if not (in which case, use
- <function>PQerrorMessage</> to get more information about the failure).
+ waiting for the result(s). 1 is returned if the command was
+ successfully dispatched and 0 if not (in which case, use
+ <function>PQerrorMessage</> to get more information about the failure).
<synopsis>
int PQsendQuery(PGconn *conn, const char *command);
</synopsis>
- After successfully calling <function>PQsendQuery</function>, call
+ After successfully calling <function>PQsendQuery</function>, call
<function>PQgetResult</function> one or more
- times to obtain the results. <function>PQsendQuery</function> may not be called
- again (on the same connection) until <function>PQgetResult</function> has returned a null pointer,
- indicating that the command is done.
+ times to obtain the results. <function>PQsendQuery</function> may not be called
+ again (on the same connection) until <function>PQgetResult</function> has returned a null pointer,
+ indicating that the command is done.
</para>
</listitem>
</varlistentry>
<varlistentry>
-<term><function>PQsendQueryParams</function></term>
+<term><function>PQsendQueryParams</function><indexterm><primary>PQsendQueryParams</></></term>
<listitem>
<para>
Submits a command and separate parameters to the server without
- waiting for the result(s).
+ waiting for the result(s).
<synopsis>
int PQsendQueryParams(PGconn *conn,
const char *command,
int resultFormat);
</synopsis>
- This is equivalent to <function>PQsendQuery</function> except that
- query parameters can be specified separately from the query string.
- The function's parameters are handled identically to
- <function>PQexecParams</function>. Like
- <function>PQexecParams</function>, it will not work on 2.0-protocol
- connections, and it allows only one command in the query string.
+ This is equivalent to <function>PQsendQuery</function> except that
+ query parameters can be specified separately from the query string.
+ The function's parameters are handled identically to
+ <function>PQexecParams</function>. Like
+ <function>PQexecParams</function>, it will not work on 2.0-protocol
+ connections, and it allows only one command in the query string.
</para>
</listitem>
</varlistentry>
<varlistentry>
-<term><function>PQsendQueryPrepared</function></term>
+<term><function>PQsendQueryPrepared</function><indexterm><primary>PQsendQueryPrepared</></></term>
<listitem>
<para>
Sends a request to execute a prepared statement with given
- parameters, without waiting for the result(s).
+ parameters, without waiting for the result(s).
<synopsis>
int PQsendQueryPrepared(PGconn *conn,
const char *stmtName,
int resultFormat);
</synopsis>
- This is similar to <function>PQsendQueryParams</function>, but the
- command to be executed is specified by naming a previously-prepared
- statement, instead of giving a query string.
- The function's parameters are handled identically to
- <function>PQexecPrepared</function>. Like
- <function>PQexecPrepared</function>, it will not work on 2.0-protocol
- connections.
+ This is similar to <function>PQsendQueryParams</function>, but the
+ command to be executed is specified by naming a previously-prepared
+ statement, instead of giving a query string.
+ The function's parameters are handled identically to
+ <function>PQexecPrepared</function>. Like
+ <function>PQexecPrepared</function>, it will not work on 2.0-protocol
+ connections.
</para>
</listitem>
</varlistentry>
<varlistentry>
-<term><function>PQgetResult</function></term>
+<term><function>PQgetResult</function><indexterm><primary>PQgetResult</></></term>
<listitem>
<para>
Waits for the next result from a prior
- <function>PQsendQuery</function>,
- <function>PQsendQueryParams</function>, or
- <function>PQsendQueryPrepared</function> call,
- and returns it. A null pointer is returned when the command is complete
- and there will be no more results.
+ <function>PQsendQuery</function>,
+ <function>PQsendQueryParams</function>, or
+ <function>PQsendQueryPrepared</function> call,
+ and returns it. A null pointer is returned when the command is complete
+ and there will be no more results.
<synopsis>
PGresult *PQgetResult(PGconn *conn);
</synopsis>
</para>
<para>
- <function>PQgetResult</function> must be called repeatedly until it returns a null pointer,
- indicating that the command is done. (If called when no command is
- active, <function>PQgetResult</function> will just return a null pointer at once.)
- Each non-null result from <function>PQgetResult</function> should be processed using
- the same <structname>PGresult</> accessor functions previously described.
- Don't forget to free each result object with <function>PQclear</function> when done with it.
- Note that <function>PQgetResult</function> will block only if a command is active and the
- necessary response data has not yet been read by <function>PQconsumeInput</function>.
+ <function>PQgetResult</function> must be called repeatedly until it returns a null pointer,
+ indicating that the command is done. (If called when no command is
+ active, <function>PQgetResult</function> will just return a null pointer at once.)
+ Each non-null result from <function>PQgetResult</function> should be processed using
+ the same <structname>PGresult</> accessor functions previously described.
+ Don't forget to free each result object with <function>PQclear</function> when done with it.
+ Note that <function>PQgetResult</function> will block only if a command is active and the
+ necessary response data has not yet been read by <function>PQconsumeInput</function>.
</para>
</listitem>
</varlistentry>
<variablelist>
<varlistentry>
-<term><function>PQconsumeInput</function></term>
+<term><function>PQconsumeInput</function><indexterm><primary>PQconsumeInput</></></term>
<listitem>
<para>
- If input is available from the server, consume it.
+ If input is available from the server, consume it.
<synopsis>
int PQconsumeInput(PGconn *conn);
</synopsis>
</varlistentry>
<varlistentry>
-<term><function>PQisBusy</function></term>
+<term><function>PQisBusy</function><indexterm><primary>PQisBusy</></></term>
<listitem>
<para>
Returns 1 if a command is busy, that is, <function>PQgetResult</function> would block
</para>
<para>
-A client that uses <function>PQsendQuery</function>/<function>PQgetResult</function>
-can also attempt to cancel a command that is still being processed by the server.
+A client that uses
+<function>PQsendQuery</function>/<function>PQgetResult</function> can
+also attempt to cancel a command that is still being processed by the
+server.<indexterm><primary>canceling</><secondary>SQL command</></>
<variablelist>
<varlistentry>
-<term><function>PQrequestCancel</function></term>
+<term><function>PQrequestCancel</function><indexterm><primary>PQrequestCancel</></></term>
<listitem>
<para>
- Requests that the server abandon
- processing of the current command.
+ Requests that the server abandon
+ processing of the current command.
<synopsis>
int PQrequestCancel(PGconn *conn);
</synopsis>
<variablelist>
<varlistentry>
- <term><function>PQsetnonblocking</function></term>
+ <term><function>PQsetnonblocking</function><indexterm><primary>PQsetnonblocking</></></term>
<listitem>
<para>
Sets the nonblocking status of the connection.
</varlistentry>
<varlistentry>
-<term><function>PQisnonblocking</function></term>
+<term><function>PQisnonblocking</function><indexterm><primary>PQisnonblocking</></></term>
<listitem>
<para>
Returns the blocking status of the database connection.
</varlistentry>
<varlistentry>
-<term><function>PQflush</function></term>
+<term><function>PQflush</function><indexterm><primary>PQflush</></></term>
<listitem>
<para>
Attempts to flush any queued output data to the server.
<sect1 id="libpq-fastpath">
<title>The Fast-Path Interface</title>
+<indexterm zone="libpq-fastpath"><primary>fast path</></>
+
<para>
<productname>PostgreSQL</productname> provides a fast-path interface to send
simple function calls to the server.
</tip>
<para>
-The function <function>PQfn</function> requests execution of a server
-function via the fast-path interface:
+The function <function>PQfn</function><indexterm><primary>PQfn</></>
+requests execution of a server function via the fast-path interface:
<synopsis>
PGresult* PQfn(PGconn* conn,
int fnid,
<sect1 id="libpq-notify">
<title>Asynchronous Notification</title>
- <indexterm zone="libpq-notify"><primary>NOTIFY</primary></indexterm>
+ <indexterm zone="libpq-notify">
+ <primary>NOTIFY</primary>
+ <secondary>in libpq</secondary>
+ </indexterm>
<para>
<productname>PostgreSQL</productname> offers asynchronous notification via the
</para>
<para>
-<application>libpq</application> applications submit <command>LISTEN</command> and <command>UNLISTEN</command>
-commands as ordinary SQL commands. The arrival of <command>NOTIFY</command>
-messages can subsequently be detected by calling <function>PQnotifies</function>.
+<application>libpq</application> applications submit
+<command>LISTEN</command> and <command>UNLISTEN</command> commands as
+ordinary SQL commands. The arrival of <command>NOTIFY</command>
+messages can subsequently be detected by calling
+<function>PQnotifies</function>.<indexterm><primary>PQnotifies</></>
</para>
<para>
returns the next notification from a list of unhandled
notification messages received from the server. It returns a null pointer if
there are no pending notifications. Once a notification is
- returned from <function>PQnotifies</>, it is considered handled and will be
- removed from the list of notifications.
+ returned from <function>PQnotifies</>, it is considered handled and will be
+ removed from the list of notifications.
<synopsis>
PGnotify* PQnotifies(PGconn *conn);
<variablelist>
<varlistentry>
-<term><function>PQnfields</function></term>
+<term><function>PQnfields</function><indexterm><primary>PQnfields</><secondary>with COPY</></></term>
<listitem>
<para>
Returns the number of columns (fields) to be copied.
</varlistentry>
<varlistentry>
-<term><function>PQbinaryTuples</function></term>
+<term><function>PQbinaryTuples</function><indexterm><primary>PQbinaryTuples</><secondary>with COPY</></></term>
<listitem>
<para>
0 indicates the overall copy format is textual (rows
- separated by newlines, columns separated by separator
- characters, etc).
- 1 indicates the overall copy format is binary.
- See <xref linkend="sql-copy" endterm="sql-copy-title">
- for more information.
+ separated by newlines, columns separated by separator
+ characters, etc).
+ 1 indicates the overall copy format is binary.
+ See <xref linkend="sql-copy" endterm="sql-copy-title">
+ for more information.
</para>
</listitem>
</varlistentry>
<varlistentry>
-<term><function>PQfformat</function></term>
+<term><function>PQfformat</function><indexterm><primary>PQfformat</><secondary>with COPY</></></term>
<listitem>
<para>
Returns the format code (0 for text, 1 for binary) associated
- with each column of the copy operation. The per-column format
- codes will always be zero when the overall copy format is textual,
- but the binary format can support both text and binary columns.
- (However, as of the current implementation of <command>COPY</>,
- only binary columns appear in a binary copy; so the per-column
- formats always match the overall format at present.)
+ with each column of the copy operation. The per-column format
+ codes will always be zero when the overall copy format is textual,
+ but the binary format can support both text and binary columns.
+ (However, as of the current implementation of <command>COPY</>,
+ only binary columns appear in a binary copy; so the per-column
+ formats always match the overall format at present.)
</para>
</listitem>
</varlistentry>
<variablelist>
<varlistentry>
-<term><function>PQputCopyData</function></term>
+<term><function>PQputCopyData</function><indexterm><primary>PQputCopyData</></></term>
<listitem>
<para>
Sends data to the server during <literal>COPY_IN</> state.
</varlistentry>
<varlistentry>
-<term><function>PQputCopyEnd</function></term>
+<term><function>PQputCopyEnd</function><indexterm><primary>PQputCopyEnd</></></term>
<listitem>
<para>
Sends end-of-data indication to the server during <literal>COPY_IN</> state.
<variablelist>
<varlistentry>
-<term><function>PQgetCopyData</function></term>
+<term><function>PQgetCopyData</function><indexterm><primary>PQgetCopyData</></></term>
<listitem>
<para>
Receives data from the server during <literal>COPY_OUT</> state.
<variablelist>
<varlistentry>
-<term><function>PQgetline</function></term>
+<term><function>PQgetline</function><indexterm><primary>PQgetline</></></term>
<listitem>
<para>
Reads a newline-terminated line of characters
</varlistentry>
<varlistentry>
-<term><function>PQgetlineAsync</function></term>
+<term><function>PQgetlineAsync</function><indexterm><primary>PQgetlineAsync</></></term>
<listitem>
<para>
Reads a row of COPY data
</varlistentry>
<varlistentry>
-<term><function>PQputline</function></term>
+<term><function>PQputline</function><indexterm><primary>PQputline</></></term>
<listitem>
<para>
Sends a null-terminated string to the server.
</varlistentry>
<varlistentry>
-<term><function>PQputnbytes</function></term>
+<term><function>PQputnbytes</function><indexterm><primary>PQputnbytes</></></term>
<listitem>
<para>
Sends a non-null-terminated string to the server.
</varlistentry>
<varlistentry>
-<term><function>PQendcopy</function></term>
+<term><function>PQendcopy</function><indexterm><primary>PQendcopy</></></term>
<listitem>
<para>
Synchronizes with the server.
<variablelist>
<varlistentry>
-<term><function>PQsetErrorVerbosity</function></term>
+<term><function>PQsetErrorVerbosity</function><indexterm><primary>PQsetErrorVerbosity</></></term>
<listitem>
<para>
Determines the verbosity of messages returned by
</varlistentry>
<varlistentry>
-<term><function>PQtrace</function></term>
+<term><function>PQtrace</function><indexterm><primary>PQtrace</></></term>
<listitem>
<para>
Enables tracing of the client/server communication to a debugging file stream.
</varlistentry>
<varlistentry>
-<term><function>PQuntrace</function></term>
+<term><function>PQuntrace</function><indexterm><primary>PQuntrace</></></term>
<listitem>
<para>
Disables tracing started by <function>PQtrace</function>.
<sect1 id="libpq-notice-processing">
<title>Notice Processing</title>
+<indexterm zone="libpq-notice-processing">
+ <primary>notice processing</primary>
+ <secondary>in libpq</secondary>
+</indexterm>
+
<para>
Notice and warning messages generated by the server are not returned by the
query execution functions, since they do not imply failure of the query.
<para>
The function <function>PQsetNoticeReceiver</function>
-<indexterm><primary>notice receiver</></>
+<indexterm><primary>notice receiver</></><indexterm><primary>PQsetNoticeReceiver</></>
sets or examines the current notice receiver for a connection object.
Similarly, <function>PQsetNoticeProcessor</function>
-<indexterm><primary>notice processor</></>
+<indexterm><primary>notice processor</></><indexterm><primary>PQsetNoticeProcessor</></>
sets or examines the current notice processor.
<synopsis>
<title>Environment Variables</title>
<indexterm zone="libpq-envars">
- <primary>environment variables</primary>
+ <primary>environment variable</primary>
</indexterm>
<para>
</para>
<para>
-<application>libpq</application> applications that use the <literal>crypt</literal>
-authentication method rely on the <literal>crypt()</literal> operating
-system function, which is often not thread-safe. It is better to use the
-<literal>md5</literal> method, which is thread-safe on all
-platforms.
+<application>libpq</application> applications that use the
+<literal>crypt</literal> authentication method rely on the
+<literal>crypt()</literal> operating system function, which is often
+not thread-safe.<indexterm><primary>crypt</><secondary>thread
+safety</></> It is better to use the <literal>md5</literal> method,
+which is thread-safe on all platforms.
</para>
</sect1>
<sect1 id="libpq-build">
<title>Building <application>libpq</application> Programs</title>
+ <indexterm zone="libpq-build">
+ <primary>compiling</primary>
+ <secondary>libpq applications</secondary>
+ </indexterm>
+
<para>
To build (i.e., compile and link) your <application>libpq</application> programs you need to
do all of the following things:
</para>
<para>
- <indexterm><primary>pg_config</></>
If there is any chance that your program might be compiled by
other users then you should not hardcode the directory location
like that. Instead, you can run the utility
- <command>pg_config</command> to find out where the header files
- are on the local system:
+ <command>pg_config</command><indexterm><primary>pg_config</><secondary
+ sortas="libpq">with libpq</></> to find out where the header
+ files are on the local system:
<screen>
<prompt>$</prompt> pg_config --includedir
<computeroutput>/usr/local/include</computeroutput>
/*
* testlibpq.c
*
- * Test the C version of LIBPQ, the POSTGRES frontend library.
+ * Test the C version of LIBPQ, the POSTGRES frontend library.
*/
#include <stdio.h>
#include <stdlib.h>
static void
exit_nicely(PGconn *conn)
{
- PQfinish(conn);
- exit(1);
+ PQfinish(conn);
+ exit(1);
}
int
main(int argc, char **argv)
{
- const char *conninfo;
- PGconn *conn;
- PGresult *res;
- int nFields;
- int i,
- j;
-
- /*
- * If the user supplies a parameter on the command line, use it as
- * the conninfo string; otherwise default to setting dbname=template1
- * and using environment variables or defaults for all other connection
- * parameters.
- */
- if (argc > 1)
- conninfo = argv[1];
- else
- conninfo = "dbname = template1";
-
- /* Make a connection to the database */
- conn = PQconnectdb(conninfo);
-
- /* Check to see that the backend connection was successfully made */
- if (PQstatus(conn) != CONNECTION_OK)
- {
- fprintf(stderr, "Connection to database '%s' failed.\n", PQdb(conn));
- fprintf(stderr, "%s", PQerrorMessage(conn));
- exit_nicely(conn);
- }
-
- /*
- * Our test case here involves using a cursor, for which we must be
- * inside a transaction block. We could do the whole thing with a
- * single PQexec() of "select * from pg_database", but that's too
- * trivial to make a good example.
- */
-
- /* Start a transaction block */
- res = PQexec(conn, "BEGIN");
- if (PQresultStatus(res) != PGRES_COMMAND_OK)
- {
- fprintf(stderr, "BEGIN command failed: %s", PQerrorMessage(conn));
- PQclear(res);
- exit_nicely(conn);
- }
-
- /*
- * Should PQclear PGresult whenever it is no longer needed to avoid
- * memory leaks
- */
- PQclear(res);
-
- /*
- * Fetch rows from pg_database, the system catalog of databases
- */
- res = PQexec(conn, "DECLARE myportal CURSOR FOR select * from pg_database");
- if (PQresultStatus(res) != PGRES_COMMAND_OK)
- {
- fprintf(stderr, "DECLARE CURSOR failed: %s", PQerrorMessage(conn));
- PQclear(res);
- exit_nicely(conn);
- }
- PQclear(res);
-
- res = PQexec(conn, "FETCH ALL in myportal");
- if (PQresultStatus(res) != PGRES_TUPLES_OK)
- {
- fprintf(stderr, "FETCH ALL failed: %s", PQerrorMessage(conn));
- PQclear(res);
- exit_nicely(conn);
- }
-
- /* first, print out the attribute names */
- nFields = PQnfields(res);
- for (i = 0; i < nFields; i++)
- printf("%-15s", PQfname(res, i));
- printf("\n\n");
-
- /* next, print out the rows */
- for (i = 0; i < PQntuples(res); i++)
- {
- for (j = 0; j < nFields; j++)
- printf("%-15s", PQgetvalue(res, i, j));
- printf("\n");
- }
-
- PQclear(res);
-
- /* close the portal ... we don't bother to check for errors ... */
- res = PQexec(conn, "CLOSE myportal");
- PQclear(res);
-
- /* end the transaction */
- res = PQexec(conn, "END");
- PQclear(res);
-
- /* close the connection to the database and cleanup */
- PQfinish(conn);
-
- return 0;
+ const char *conninfo;
+ PGconn *conn;
+ PGresult *res;
+ int nFields;
+ int i,
+ j;
+
+ /*
+ * If the user supplies a parameter on the command line, use it as
+ * the conninfo string; otherwise default to setting dbname=template1
+ * and using environment variables or defaults for all other connection
+ * parameters.
+ */
+ if (argc > 1)
+ conninfo = argv[1];
+ else
+ conninfo = "dbname = template1";
+
+ /* Make a connection to the database */
+ conn = PQconnectdb(conninfo);
+
+ /* Check to see that the backend connection was successfully made */
+ if (PQstatus(conn) != CONNECTION_OK)
+ {
+ fprintf(stderr, "Connection to database '%s' failed.\n", PQdb(conn));
+ fprintf(stderr, "%s", PQerrorMessage(conn));
+ exit_nicely(conn);
+ }
+
+ /*
+ * Our test case here involves using a cursor, for which we must be
+ * inside a transaction block. We could do the whole thing with a
+ * single PQexec() of "select * from pg_database", but that's too
+ * trivial to make a good example.
+ */
+
+ /* Start a transaction block */
+ res = PQexec(conn, "BEGIN");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "BEGIN command failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+
+ /*
+ * Should PQclear PGresult whenever it is no longer needed to avoid
+ * memory leaks
+ */
+ PQclear(res);
+
+ /*
+ * Fetch rows from pg_database, the system catalog of databases
+ */
+ res = PQexec(conn, "DECLARE myportal CURSOR FOR select * from pg_database");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "DECLARE CURSOR failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+ PQclear(res);
+
+ res = PQexec(conn, "FETCH ALL in myportal");
+ if (PQresultStatus(res) != PGRES_TUPLES_OK)
+ {
+ fprintf(stderr, "FETCH ALL failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+
+ /* first, print out the attribute names */
+ nFields = PQnfields(res);
+ for (i = 0; i < nFields; i++)
+ printf("%-15s", PQfname(res, i));
+ printf("\n\n");
+
+ /* next, print out the rows */
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ for (j = 0; j < nFields; j++)
+ printf("%-15s", PQgetvalue(res, i, j));
+ printf("\n");
+ }
+
+ PQclear(res);
+
+ /* close the portal ... we don't bother to check for errors ... */
+ res = PQexec(conn, "CLOSE myportal");
+ PQclear(res);
+
+ /* end the transaction */
+ res = PQexec(conn, "END");
+ PQclear(res);
+
+ /* close the connection to the database and cleanup */
+ PQfinish(conn);
+
+ return 0;
}
</programlisting>
</example>
<programlisting>
/*
* testlibpq2.c
- * Test of the asynchronous notification interface
+ * Test of the asynchronous notification interface
*
* Start this program, then from psql in another window do
* NOTIFY TBL2;
static void
exit_nicely(PGconn *conn)
{
- PQfinish(conn);
- exit(1);
+ PQfinish(conn);
+ exit(1);
}
int
main(int argc, char **argv)
{
- const char *conninfo;
- PGconn *conn;
- PGresult *res;
- PGnotify *notify;
- int nnotifies;
-
- /*
- * If the user supplies a parameter on the command line, use it as
- * the conninfo string; otherwise default to setting dbname=template1
- * and using environment variables or defaults for all other connection
- * parameters.
- */
- if (argc > 1)
- conninfo = argv[1];
- else
- conninfo = "dbname = template1";
-
- /* Make a connection to the database */
- conn = PQconnectdb(conninfo);
-
- /* Check to see that the backend connection was successfully made */
- if (PQstatus(conn) != CONNECTION_OK)
- {
- fprintf(stderr, "Connection to database '%s' failed.\n", PQdb(conn));
- fprintf(stderr, "%s", PQerrorMessage(conn));
- exit_nicely(conn);
- }
-
- /*
- * Issue LISTEN command to enable notifications from the rule's NOTIFY.
- */
- res = PQexec(conn, "LISTEN TBL2");
- if (PQresultStatus(res) != PGRES_COMMAND_OK)
- {
- fprintf(stderr, "LISTEN command failed: %s", PQerrorMessage(conn));
- PQclear(res);
- exit_nicely(conn);
- }
-
- /*
- * should PQclear PGresult whenever it is no longer needed to avoid
- * memory leaks
- */
- PQclear(res);
-
- /* Quit after four notifies are received. */
- nnotifies = 0;
- while (nnotifies < 4)
- {
- /*
- * Sleep until something happens on the connection. We use select(2)
- * to wait for input, but you could also use poll() or similar
- * facilities.
- */
- int sock;
- fd_set input_mask;
-
- sock = PQsocket(conn);
-
- if (sock < 0)
- break; /* shouldn't happen */
-
- FD_ZERO(&input_mask);
- FD_SET(sock, &input_mask);
-
- if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0)
- {
- fprintf(stderr, "select() failed: %s\n", strerror(errno));
- exit_nicely(conn);
- }
-
- /* Now check for input */
- PQconsumeInput(conn);
- while ((notify = PQnotifies(conn)) != NULL)
- {
- fprintf(stderr,
- "ASYNC NOTIFY of '%s' received from backend pid %d\n",
- notify->relname, notify->be_pid);
- PQfreemem(notify);
- nnotifies++;
- }
- }
-
- fprintf(stderr, "Done.\n");
-
- /* close the connection to the database and cleanup */
- PQfinish(conn);
-
- return 0;
+ const char *conninfo;
+ PGconn *conn;
+ PGresult *res;
+ PGnotify *notify;
+ int nnotifies;
+
+ /*
+ * If the user supplies a parameter on the command line, use it as
+ * the conninfo string; otherwise default to setting dbname=template1
+ * and using environment variables or defaults for all other connection
+ * parameters.
+ */
+ if (argc > 1)
+ conninfo = argv[1];
+ else
+ conninfo = "dbname = template1";
+
+ /* Make a connection to the database */
+ conn = PQconnectdb(conninfo);
+
+ /* Check to see that the backend connection was successfully made */
+ if (PQstatus(conn) != CONNECTION_OK)
+ {
+ fprintf(stderr, "Connection to database '%s' failed.\n", PQdb(conn));
+ fprintf(stderr, "%s", PQerrorMessage(conn));
+ exit_nicely(conn);
+ }
+
+ /*
+ * Issue LISTEN command to enable notifications from the rule's NOTIFY.
+ */
+ res = PQexec(conn, "LISTEN TBL2");
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ {
+ fprintf(stderr, "LISTEN command failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+
+ /*
+ * should PQclear PGresult whenever it is no longer needed to avoid
+ * memory leaks
+ */
+ PQclear(res);
+
+ /* Quit after four notifies are received. */
+ nnotifies = 0;
+ while (nnotifies < 4)
+ {
+ /*
+ * Sleep until something happens on the connection. We use select(2)
+ * to wait for input, but you could also use poll() or similar
+ * facilities.
+ */
+ int sock;
+ fd_set input_mask;
+
+ sock = PQsocket(conn);
+
+ if (sock < 0)
+ break; /* shouldn't happen */
+
+ FD_ZERO(&input_mask);
+ FD_SET(sock, &input_mask);
+
+ if (select(sock + 1, &input_mask, NULL, NULL, NULL) < 0)
+ {
+ fprintf(stderr, "select() failed: %s\n", strerror(errno));
+ exit_nicely(conn);
+ }
+
+ /* Now check for input */
+ PQconsumeInput(conn);
+ while ((notify = PQnotifies(conn)) != NULL)
+ {
+ fprintf(stderr,
+ "ASYNC NOTIFY of '%s' received from backend pid %d\n",
+ notify->relname, notify->be_pid);
+ PQfreemem(notify);
+ nnotifies++;
+ }
+ }
+
+ fprintf(stderr, "Done.\n");
+
+ /* close the connection to the database and cleanup */
+ PQfinish(conn);
+
+ return 0;
}
</programlisting>
</example>
<programlisting>
/*
* testlibpq3.c
- * Test out-of-line parameters and binary I/O.
+ * Test out-of-line parameters and binary I/O.
*
* Before running this, populate a database with the following commands
* (provided in src/test/examples/testlibpq3.sql):
static void
exit_nicely(PGconn *conn)
{
- PQfinish(conn);
- exit(1);
+ PQfinish(conn);
+ exit(1);
}
int
main(int argc, char **argv)
{
- const char *conninfo;
- PGconn *conn;
- PGresult *res;
- const char *paramValues[1];
- int i,
- j;
- int i_fnum,
- t_fnum,
- b_fnum;
-
- /*
- * If the user supplies a parameter on the command line, use it as
- * the conninfo string; otherwise default to setting dbname=template1
- * and using environment variables or defaults for all other connection
- * parameters.
- */
- if (argc > 1)
- conninfo = argv[1];
- else
- conninfo = "dbname = template1";
-
- /* Make a connection to the database */
- conn = PQconnectdb(conninfo);
-
- /* Check to see that the backend connection was successfully made */
- if (PQstatus(conn) != CONNECTION_OK)
- {
- fprintf(stderr, "Connection to database '%s' failed.\n", PQdb(conn));
- fprintf(stderr, "%s", PQerrorMessage(conn));
- exit_nicely(conn);
- }
-
- /*
- * The point of this program is to illustrate use of PQexecParams()
- * with out-of-line parameters, as well as binary transmission of
- * results. By using out-of-line parameters we can avoid a lot of
- * tedious mucking about with quoting and escaping. Notice how we
- * don't have to do anything special with the quote mark in the
- * parameter value.
- */
-
- /* Here is our out-of-line parameter value */
- paramValues[0] = "joe's place";
-
- res = PQexecParams(conn,
- "SELECT * FROM test1 WHERE t = $1",
- 1, /* one param */
- NULL, /* let the backend deduce param type */
- paramValues,
- NULL, /* don't need param lengths since text */
- NULL, /* default to all text params */
- 1); /* ask for binary results */
-
- if (PQresultStatus(res) != PGRES_TUPLES_OK)
- {
- fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn));
- PQclear(res);
- exit_nicely(conn);
- }
-
- /* Use PQfnumber to avoid assumptions about field order in result */
- i_fnum = PQfnumber(res, "i");
- t_fnum = PQfnumber(res, "t");
- b_fnum = PQfnumber(res, "b");
-
- for (i = 0; i < PQntuples(res); i++)
- {
- char *iptr;
- char *tptr;
- char *bptr;
- int blen;
- int ival;
-
- /* Get the field values (we ignore possibility they are null!) */
- iptr = PQgetvalue(res, i, i_fnum);
- tptr = PQgetvalue(res, i, t_fnum);
- bptr = PQgetvalue(res, i, b_fnum);
-
- /*
- * The binary representation of INT4 is in network byte order,
- * which we'd better coerce to the local byte order.
- */
- ival = ntohl(*((uint32_t *) iptr));
-
- /*
- * The binary representation of TEXT is, well, text, and since
- * libpq was nice enough to append a zero byte to it, it'll work
- * just fine as a C string.
- *
- * The binary representation of BYTEA is a bunch of bytes, which
- * could include embedded nulls so we have to pay attention to
- * field length.
- */
- blen = PQgetlength(res, i, b_fnum);
-
- printf("tuple %d: got\n", i);
- printf(" i = (%d bytes) %d\n",
- PQgetlength(res, i, i_fnum), ival);
- printf(" t = (%d bytes) '%s'\n",
- PQgetlength(res, i, t_fnum), tptr);
- printf(" b = (%d bytes) ", blen);
- for (j = 0; j < blen; j++)
- printf("\\%03o", bptr[j]);
- printf("\n\n");
- }
-
- PQclear(res);
-
- /* close the connection to the database and cleanup */
- PQfinish(conn);
-
- return 0;
+ const char *conninfo;
+ PGconn *conn;
+ PGresult *res;
+ const char *paramValues[1];
+ int i,
+ j;
+ int i_fnum,
+ t_fnum,
+ b_fnum;
+
+ /*
+ * If the user supplies a parameter on the command line, use it as
+ * the conninfo string; otherwise default to setting dbname=template1
+ * and using environment variables or defaults for all other connection
+ * parameters.
+ */
+ if (argc > 1)
+ conninfo = argv[1];
+ else
+ conninfo = "dbname = template1";
+
+ /* Make a connection to the database */
+ conn = PQconnectdb(conninfo);
+
+ /* Check to see that the backend connection was successfully made */
+ if (PQstatus(conn) != CONNECTION_OK)
+ {
+ fprintf(stderr, "Connection to database '%s' failed.\n", PQdb(conn));
+ fprintf(stderr, "%s", PQerrorMessage(conn));
+ exit_nicely(conn);
+ }
+
+ /*
+ * The point of this program is to illustrate use of PQexecParams()
+ * with out-of-line parameters, as well as binary transmission of
+ * results. By using out-of-line parameters we can avoid a lot of
+ * tedious mucking about with quoting and escaping. Notice how we
+ * don't have to do anything special with the quote mark in the
+ * parameter value.
+ */
+
+ /* Here is our out-of-line parameter value */
+ paramValues[0] = "joe's place";
+
+ res = PQexecParams(conn,
+ "SELECT * FROM test1 WHERE t = $1",
+ 1, /* one param */
+ NULL, /* let the backend deduce param type */
+ paramValues,
+ NULL, /* don't need param lengths since text */
+ NULL, /* default to all text params */
+ 1); /* ask for binary results */
+
+ if (PQresultStatus(res) != PGRES_TUPLES_OK)
+ {
+ fprintf(stderr, "SELECT failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ exit_nicely(conn);
+ }
+
+ /* Use PQfnumber to avoid assumptions about field order in result */
+ i_fnum = PQfnumber(res, "i");
+ t_fnum = PQfnumber(res, "t");
+ b_fnum = PQfnumber(res, "b");
+
+ for (i = 0; i < PQntuples(res); i++)
+ {
+ char *iptr;
+ char *tptr;
+ char *bptr;
+ int blen;
+ int ival;
+
+ /* Get the field values (we ignore possibility they are null!) */
+ iptr = PQgetvalue(res, i, i_fnum);
+ tptr = PQgetvalue(res, i, t_fnum);
+ bptr = PQgetvalue(res, i, b_fnum);
+
+ /*
+ * The binary representation of INT4 is in network byte order,
+ * which we'd better coerce to the local byte order.
+ */
+ ival = ntohl(*((uint32_t *) iptr));
+
+ /*
+ * The binary representation of TEXT is, well, text, and since
+ * libpq was nice enough to append a zero byte to it, it'll work
+ * just fine as a C string.
+ *
+ * The binary representation of BYTEA is a bunch of bytes, which
+ * could include embedded nulls so we have to pay attention to
+ * field length.
+ */
+ blen = PQgetlength(res, i, b_fnum);
+
+ printf("tuple %d: got\n", i);
+ printf(" i = (%d bytes) %d\n",
+ PQgetlength(res, i, i_fnum), ival);
+ printf(" t = (%d bytes) '%s'\n",
+ PQgetlength(res, i, t_fnum), tptr);
+ printf(" b = (%d bytes) ", blen);
+ for (j = 0; j < blen; j++)
+ printf("\\%03o", bptr[j]);
+ printf("\n\n");
+ }
+
+ PQclear(res);
+
+ /* close the connection to the database and cleanup */
+ PQfinish(conn);
+
+ return 0;
}
</programlisting>
</example>
<synopsis>
Oid lo_creat(PGconn *conn, int mode);
</synopsis>
+ <indexterm><primary>lo_creat</></>
creates a new large object.
<replaceable class="parameter">mode</replaceable> is a bit mask
describing several different attributes of the new
<synopsis>
Oid lo_import(PGconn *conn, const char *filename);
</synopsis>
- <replaceable class="parameter">filename</replaceable>
+ <indexterm><primary>lo_import</></>
+ <replaceable class="parameter">filename</replaceable>
specifies the operating system name of
the file to be imported as a large object.
The return value is the OID that was assigned to the new large object.
<synopsis>
int lo_export(PGconn *conn, Oid lobjId, const char *filename);
</synopsis>
+ <indexterm><primary>lo_export</></>
The <parameter>lobjId</parameter> argument specifies the OID of the large
object to export and the <parameter>filename</parameter> argument specifies
the operating system name name of the file.
<synopsis>
int lo_open(PGconn *conn, Oid lobjId, int mode);
</synopsis>
+ <indexterm><primary>lo_open</></>
The <parameter>lobjId</parameter> argument specifies the OID of the large
object to open. The <parameter>mode</parameter> bits control whether the
object is opened for reading (<symbol>INV_READ</>), writing (<symbol>INV_WRITE</symbol>), or
<synopsis>
int lo_write(PGconn *conn, int fd, const char *buf, size_t len);
</synopsis>
- writes <parameter>len</parameter> bytes from <parameter>buf</parameter> to large object <parameter>fd</>. The <parameter>fd</parameter>
- argument must have been returned by a previous <function>lo_open</function>.
- The number of bytes actually written is returned. In
- the event of an error, the return value is negative.
+ <indexterm><primary>lo_write</></> writes
+ <parameter>len</parameter> bytes from <parameter>buf</parameter>
+ to large object <parameter>fd</>. The <parameter>fd</parameter>
+ argument must have been returned by a previous
+ <function>lo_open</function>. The number of bytes actually
+ written is returned. In the event of an error, the return value
+ is negative.
</para>
</sect2>
<synopsis>
int lo_read(PGconn *conn, int fd, char *buf, size_t len);
</synopsis>
- reads <parameter>len</parameter> bytes from large object <parameter>fd</parameter> into <parameter>buf</parameter>. The <parameter>fd</parameter>
- argument must have been returned by a previous <function>lo_open</function>.
- The number of bytes actually read is returned. In
- the event of an error, the return value is negative.
+ <indexterm><primary>lo_read</></> reads
+ <parameter>len</parameter> bytes from large object
+ <parameter>fd</parameter> into <parameter>buf</parameter>. The
+ <parameter>fd</parameter> argument must have been returned by a
+ previous <function>lo_open</function>. The number of bytes
+ actually read is returned. In the event of an error, the return
+ value is negative.
</para>
</sect2>
<synopsis>
int lo_lseek(PGconn *conn, int fd, int offset, int whence);
</synopsis>
- This function moves the current location pointer for the
- large object described by <parameter>fd</> to the new location specified
- by <parameter>offset</>. The valid values for <parameter>whence</> are
- <symbol>SEEK_SET</> (seek from object start), <symbol>SEEK_CUR</> (seek from current position), and <symbol>SEEK_END</> (seek from object end). The return value is the new location pointer.
+ <indexterm><primary>lo_lseek</></> This function moves the
+ current location pointer for the large object described by
+ <parameter>fd</> to the new location specified by
+ <parameter>offset</>. The valid values for <parameter>whence</>
+ are <symbol>SEEK_SET</> (seek from object start),
+ <symbol>SEEK_CUR</> (seek from current position), and
+ <symbol>SEEK_END</> (seek from object end). The return value is
+ the new location pointer.
</para>
</sect2>
<synopsis>
int lo_tell(PGconn *conn, int fd);
</synopsis>
- If there is an error, the return value is negative.
+ <indexterm><primary>lo_tell</></> If there is an error, the
+ return value is negative.
</para>
</sect2>
<synopsis>
int lo_close(PGconn *conn, int fd);
</synopsis>
- where <parameter>fd</> is a large object descriptor returned by
- <function>lo_open</function>. On success, <function>lo_close</function>
- returns zero. On error, the return value is negative.
+ <indexterm><primary>lo_close</></> where <parameter>fd</> is a
+ large object descriptor returned by <function>lo_open</function>.
+ On success, <function>lo_close</function> returns zero. On
+ error, the return value is negative.
</para>
<para>
<synopsis>
int lo_unlink(PGconn *conn, Oid lobjId);
</synopsis>
- The <parameter>lobjId</parameter> argument specifies the OID of the large
- object to remove. In the event of an error, the return value is negative.
+ <indexterm><primary>lo_unlink</></> The
+ <parameter>lobjId</parameter> argument specifies the OID of the
+ large object to remove. In the event of an error, the return
+ value is negative.
</para>
</sect2>
<title>Server-side Functions</title>
<para>
- There are two built-in server-side functions, <function>lo_import</function>
- and <function>lo_export</function>, for large object access, which are available for use
- in <acronym>SQL</acronym>
- commands.
- Here is an example of their use:
+ There are two built-in server-side functions,
+ <function>lo_import</function><indexterm><primary>lo_import</></>
+ and
+ <function>lo_export</function>,<indexterm><primary>lo_export</></>
+ for large object access, which are available for use in
+ <acronym>SQL</acronym> commands. Here is an example of their
+ use:
<programlisting>
CREATE TABLE image (
name text,
<chapter id="maintenance">
<title>Routine Database Maintenance Tasks</title>
+ <indexterm zone="maintenance">
+ <primary>maintenance</primary>
+ </indexterm>
+
<para>
There are a few routine maintenance chores that must be performed on
a regular basis to keep a <productname>PostgreSQL</productname>
<sect2 id="vacuum-for-statistics">
<title>Updating planner statistics</title>
+ <indexterm zone="vacuum-for-statistics">
+ <primary>statistics</primary>
+ <secondary>of the planner</secondary>
+ </indexterm>
+
+ <indexterm zone="vacuum-for-statistics">
+ <primary>ANALYZE</primary>
+ </indexterm>
+
<para>
The <productname>PostgreSQL</productname> query planner relies on
statistical information about the contents of tables in order to
<title>Log File Maintenance</title>
<indexterm zone="logfile-maintenance">
- <primary>log files</primary>
+ <primary>server log</primary>
+ <secondary>log file maintenance</secondary>
</indexterm>
<para>
<sect1 id="manage-ag-overview">
<title>Overview</title>
+ <indexterm zone="manage-ag-overview">
+ <primary>schema</primary>
+ </indexterm>
+
<para>
A database is a named collection of <acronym>SQL</acronym> objects
(<quote>database objects</quote>). Generally, every database
</para>
<para>
- Databases are created with the SQL command
- <command>CREATE DATABASE</command>:
+ Databases are created with the SQL command <command>CREATE
+ DATABASE</command>:<indexterm><primary>CREATE DATABASE</></>
<synopsis>
CREATE DATABASE <replaceable>name</>;
</synopsis>
question remains how the <emphasis>first</> database at any given
site can be created. The first database is always created by the
<command>initdb</> command when the data storage area is
- initialized. (See <xref linkend="creating-cluster">.)
- This database is called <literal>template1</>. So to create the
- first <quote>real</> database you can connect to
+ initialized. (See <xref linkend="creating-cluster">.) This
+ database is called
+ <literal>template1</>.<indexterm><primary>template1</></> So to
+ create the first <quote>real</> database you can connect to
<literal>template1</>.
</para>
<para>
As an extra convenience, there is also a program that you can
execute from the shell to create new databases,
- <command>createdb</>.
+ <command>createdb</>.<indexterm><primary>createdb</></>
<synopsis>
createdb <replaceable class="parameter">dbname</replaceable>
<para>
<command>CREATE DATABASE</> actually works by copying an existing
database. By default, it copies the standard system database named
- <literal>template1</>. Thus that database is the <quote>template</>
- from which new databases are made. If you add objects to
- <literal>template1</>, these objects
+ <literal>template1</>.<indexterm><primary>template1</></> Thus that
+ database is the <quote>template</> from which new databases are
+ made. If you add objects to <literal>template1</>, these objects
will be copied into subsequently created user databases. This
behavior allows site-local modifications to the standard set of
objects in databases. For example, if you install the procedural
language <application>PL/pgSQL</> in <literal>template1</>, it will
- automatically be available in user databases without any extra action
- being taken when those databases are made.
+ automatically be available in user databases without any extra
+ action being taken when those databases are made.
</para>
<para>
- There is a second standard system database named <literal>template0</>.
- This database contains the same data as the initial contents of
- <literal>template1</>, that is, only the standard objects predefined by
- your version of <productname>PostgreSQL</productname>.
- <literal>template0</> should never be changed
- after <command>initdb</>. By instructing <command>CREATE DATABASE</> to
- copy <literal>template0</> instead of <literal>template1</>, you can
- create a <quote>virgin</> user database that contains none of the
- site-local additions in <literal>template1</>. This is particularly
- handy when restoring a <literal>pg_dump</> dump: the dump script should
- be restored in a virgin database to ensure that one recreates the
- correct contents of the dumped database, without any conflicts with
- additions that may now be present in <literal>template1</>.
+ There is a second standard system database named
+ <literal>template0</>.<indexterm><primary>template0</></> This
+ database contains the same data as the initial contents of
+ <literal>template1</>, that is, only the standard objects
+ predefined by your version of
+ <productname>PostgreSQL</productname>. <literal>template0</>
+ should never be changed after <command>initdb</>. By instructing
+ <command>CREATE DATABASE</> to copy <literal>template0</> instead
+ of <literal>template1</>, you can create a <quote>virgin</> user
+ database that contains none of the site-local additions in
+ <literal>template1</>. This is particularly handy when restoring a
+ <literal>pg_dump</> dump: the dump script should be restored in a
+ virgin database to ensure that one recreates the correct contents
+ of the dumped database, without any conflicts with additions that
+ may now be present in <literal>template1</>.
</para>
<para>
</para>
<para>
- Two useful flags exist in <literal>pg_database</literal> for each
+ Two useful flags exist in <literal>pg_database</literal><indexterm><primary>pg_database</></> for each
database: the columns <literal>datistemplate</literal> and
<literal>datallowconn</literal>. <literal>datistemplate</literal>
may be set to indicate that a database is intended as a template for
<title>Destroying a Database</title>
<para>
- Databases are destroyed with the command <command>DROP DATABASE</command>:
+ Databases are destroyed with the command <command>DROP
+ DATABASE</command>:<indexterm><primary>DROP DATABASE</></>
<synopsis>
DROP DATABASE <replaceable>name</>;
</synopsis>
</para>
<para>
- For convenience, there is also a shell program to drop databases:
+ For convenience, there is also a shell program to drop
+ databases:<indexterm><primary>dropdb</></>
<synopsis>
dropdb <replaceable class="parameter">dbname</replaceable>
</synopsis>
<chapter id="monitoring">
<title>Monitoring Database Activity</title>
+ <indexterm zone="monitoring">
+ <primary>monitoring</primary>
+ <secondary>database activity</secondary>
+ </indexterm>
+
+ <indexterm zone="monitoring">
+ <primary>database activity</primary>
+ <secondary>monitoring</secondary>
+ </indexterm>
+
<para>
A database administrator frequently wonders, <quote>What is the system
doing right now?</quote>
<sect1 id="monitoring-locks">
<title>Viewing Locks</title>
+ <indexterm zone="monitoring-locks">
+ <primary>lock</primary>
+ <secondary>monitoring</secondary>
+ </indexterm>
+
<para>
Another useful tool for monitoring database activity is the
<literal>pg_locks</literal> system table. It allows the
<sect1 id="mvcc-intro">
<title>Introduction</title>
+ <indexterm>
+ <primary>MVCC</primary>
+ </indexterm>
+
<para>
Unlike traditional database systems which use locks for concurrency control,
<productname>PostgreSQL</productname>
<sect1 id="transaction-iso">
<title>Transaction Isolation</title>
+ <indexterm>
+ <primary>transaction isolation</primary>
+ </indexterm>
+
<para>
The <acronym>SQL</acronym> standard defines four levels of
transaction isolation in terms of three phenomena that must be
<para>
<indexterm>
- <primary>isolation levels</primary>
+ <primary>transaction isolation level</primary>
</indexterm>
The four transaction isolation levels and the corresponding
behaviors are described in <xref linkend="mvcc-isolevel-table">.
<title>Read Committed Isolation Level</title>
<indexterm>
- <primary>isolation levels</primary>
+ <primary>transaction isolation level</primary>
<secondary>read committed</secondary>
</indexterm>
<title>Serializable Isolation Level</title>
<indexterm>
- <primary>isolation levels</primary>
+ <primary>transaction isolation level</primary>
<secondary>serializable</secondary>
</indexterm>
<title>Explicit Locking</title>
<indexterm>
- <primary>locking</primary>
+ <primary>lock</primary>
</indexterm>
<para>
<sect2 id="locking-tables">
<title>Table-Level Locks</title>
+ <indexterm zone="locking-tables">
+ <primary>LOCK</primary>
+ </indexterm>
+
<para>
The list below shows the available lock modes and the contexts in
which they are used automatically by
<sect2 id="locking-deadlocks">
<title>Deadlocks</title>
+ <indexterm zone="locking-deadlocks">
+ <primary>deadlock</primary>
+ </indexterm>
+
<para>
The use of explicit locking can increase the likelyhood of
<firstterm>deadlocks</>, wherein two (or more) transactions each
<sect1 id="locking-indexes">
<title>Locking and Indexes</title>
+ <indexterm zone="locking-indexes">
+ <primary>index</primary>
+ <secondary>locks</secondary>
+ </indexterm>
+
<para>
Though <productname>PostgreSQL</productname>
provides nonblocking read/write access to table
<sect1 id="using-explain">
<title>Using <command>EXPLAIN</command></title>
+ <indexterm zone="using-explain">
+ <primary>EXPLAIN</primary>
+ </indexterm>
+
+ <indexterm zone="using-explain">
+ <primary>query plan</primary>
+ </indexterm>
+
<para>
<productname>PostgreSQL</productname> devises a <firstterm>query
plan</firstterm> for each query it is given. Choosing the right
<sect1 id="planner-stats">
<title>Statistics Used by the Planner</title>
+ <indexterm zone="planner-stats">
+ <primary>statistics</primary>
+ <secondary>of the planner</secondary>
+ </indexterm>
+
<para>
As we saw in the previous section, the query planner needs to estimate
the number of rows retrieved by a query in order to make good choices
since it does not read every row of the table.
</para>
+ <indexterm>
+ <primary>pg_statistic</primary>
+ </indexterm>
+
<para>
Most queries retrieve only a fraction of the rows in a table, due
to having <literal>WHERE</> clauses that restrict the rows to be examined.
and are always approximate even when freshly updated.
</para>
+ <indexterm>
+ <primary>pg_stats</primary>
+ </indexterm>
+
<para>
Rather than look at <structname>pg_statistic</structname> directly,
it's better to look at its view <structname>pg_stats</structname>
<sect1 id="explicit-joins">
<title>Controlling the Planner with Explicit <literal>JOIN</> Clauses</title>
+ <indexterm zone="explicit-joins">
+ <primary>join</primary>
+ <secondary>controlling the order</secondary>
+ </indexterm>
+
<para>
It is possible
to control the query planner to some extent by using the explicit <literal>JOIN</>
<sect2 id="disable-autocommit">
<title>Disable Autocommit</title>
+ <indexterm zone="disable-autocommit">
+ <primary>autocommit</primary>
+ </indexterm>
+
<para>
Turn off autocommit and just do one commit at
the end. (In plain SQL, this means issuing <command>BEGIN</command>
</para>
<para>
- If an SQL null value is passed to a function, the argument value
- will appear as <quote>undefined</> in Perl. The above function
- definition will not behave very nicely with null inputs (in fact,
- it will act as though they are zeroes). We could add
- <literal>STRICT</> to the function definition to make
+ If an SQL null value<indexterm><primary>null value</><secondary
+ sortas="PL/Perl">in PL/Perl</></indexterm> is passed to a function,
+ the argument value will appear as <quote>undefined</> in Perl. The
+ above function definition will not behave very nicely with null
+ inputs (in fact, it will act as though they are zeroes). We could
+ add <literal>STRICT</> to the function definition to make
<productname>PostgreSQL</productname> do something more reasonable:
if a null value is passed, the function will not be called at all,
but will just return a null result automatically. Alternatively,
mirror sites</ulink>). This module makes available a
<acronym>DBI</>-compliant database-handle named
<varname>$pg_dbh</varname> that can be used to perform queries
- with normal <acronym>DBI</> syntax.
+ with normal <acronym>DBI</> syntax.<indexterm><primary>DBI</></indexterm>
</para>
<para>
<varlistentry>
<indexterm>
<primary>elog</primary>
- <secondary>PL/Perl</secondary>
+ <secondary>in PL/Perl</secondary>
</indexterm>
<term><function>elog</> <replaceable>level</replaceable>, <replaceable>msg</replaceable></term>
<sect1 id="plperl-trusted">
<title>Trusted and Untrusted PL/Perl</title>
+ <indexterm zone="plperl-trusted">
+ <primary>trusted</primary>
+ <secondary>PL/Perl</secondary>
+ </indexterm>
+
<para>
Normally, PL/Perl is installed as a <quote>trusted</> programming
language named <literal>plperl</>. In this setup, certain Perl
<para>
Sometimes it is desirable to write Perl functions that are not
- restricted. For example, one might want a Perl function that
- sends mail. To handle these cases, PL/Perl can also be installed
- as an <quote>untrusted</> language (usually called
- <application>PL/PerlU</application>). In this case the full Perl language is
- available. If the <command>createlang</command> program is used to
- install the language, the language name <literal>plperlu</literal>
- will select the untrusted PL/Perl variant.
+ restricted. For example, one might want a Perl function that sends
+ mail. To handle these cases, PL/Perl can also be installed as an
+ <quote>untrusted</> language (usually called
+ <application>PL/PerlU</application><indexterm><primary>PL/PerlU</></indexterm>).
+ In this case the full Perl language is available. If the
+ <command>createlang</command> program is used to install the
+ language, the language name <literal>plperlu</literal> will select
+ the untrusted PL/Perl variant.
</para>
<para>
<listitem>
<para>
- PL/Perl cannot be used to write trigger functions.
+ PL/Perl cannot be used to write trigger
+ functions.<indexterm><primary>trigger</><secondary>in
+ PL/Perl</></indexterm>
</para>
</listitem>
</para>
<para>
- As each expression and <acronym>SQL</acronym> command is first used
- in the function, the <application>PL/pgSQL</> interpreter creates
- a prepared execution plan (using the <acronym>SPI</acronym>
- manager's <function>SPI_prepare</function> and
- <function>SPI_saveplan</function> functions). Subsequent visits
- to that expression or command reuse the prepared plan. Thus, a
- function with conditional code that contains many statements for
- which execution plans might be required will only prepare and save
- those plans that are really used during the lifetime of the
- database connection. This can substantially reduce the total
- amount of time required to parse, and generate execution plans for the
- statements in a <application>PL/pgSQL</> function. A disadvantage is
- that errors in a specific expression or command may not be detected
- until that part of the function is reached in execution.
+ As each expression and <acronym>SQL</acronym> command is first
+ used in the function, the <application>PL/pgSQL</> interpreter
+ creates a prepared execution plan (using the
+ <acronym>SPI</acronym> manager's <function>SPI_prepare</function>
+ and <function>SPI_saveplan</function>
+ functions).<indexterm><primary>preparing a query</><secondary>in
+ PL/pgSQL</></> Subsequent visits to that expression or command
+ reuse the prepared plan. Thus, a function with conditional code
+ that contains many statements for which execution plans might be
+ required will only prepare and save those plans that are really
+ used during the lifetime of the database connection. This can
+ substantially reduce the total amount of time required to parse,
+ and generate execution plans for the statements in a
+ <application>PL/pgSQL</> function. A disadvantage is that errors
+ in a specific expression or command may not be detected until that
+ part of the function is reached in execution.
</para>
<para>
and return the <quote>polymorphic</> types
<type>anyelement</type> and <type>anyarray</type>. The actual
datatypes handled by a polymorphic function can vary from call to
- call, as discussed in <xref linkend="types-polymorphic">.
+ call, as discussed in <xref linkend="extend-types-polymorphic">.
An example is shown in <xref linkend="plpgsql-declaration-aliases">.
</para>
or <type>anyarray</type>), a special parameter <literal>$0</literal>
is created. Its datatype is the actual return type of the function,
as deduced from the actual input types (see <xref
- linkend="types-polymorphic">).
+ linkend="extend-types-polymorphic">).
This allows the function to access its actual return type
as shown in <xref linkend="plpgsql-declaration-type">.
<literal>$0</literal> is initialized to NULL and can be modified by
<sect2 id="plpgsql-select-into">
<title><command>SELECT INTO</command></title>
+ <indexterm zone="plpgsql-select-into">
+ <primary>SELECT INTO</primary>
+ <secondary>in PL/pgSQL</secondary>
+ </indexterm>
+
<para>
The result of a <command>SELECT</command> command yielding multiple columns (but
only one row) can be assigned to a record variable, row-type
<para>
This example shows use of the functions
<function>quote_ident(<type>text</type>)</function> and
- <function>quote_literal(<type>text</type>)</function>.
- Variables containing column and table identifiers should be
- passed to function <function>quote_ident</function>.
- Variables containing values that should be literal strings in the
- constructed command should be passed to
- <function>quote_literal</function>. Both take the
- appropriate steps to return the input text enclosed in double
- or single quotes respectively, with any embedded special characters
+ <function>quote_literal(<type>text</type>)</function>.<indexterm><primary>quote_ident</><secondary>use
+ in
+ PL/pgSQL</></indexterm><indexterm><primary>quote_literal</><secondary>use
+ in PL/pgSQL</></indexterm> Variables containing column and table
+ identifiers should be passed to function
+ <function>quote_ident</function>. Variables containing values
+ that should be literal strings in the constructed command should
+ be passed to <function>quote_literal</function>. Both take the
+ appropriate steps to return the input text enclosed in double or
+ single quotes respectively, with any embedded special characters
properly escaped.
</para>
<sect2 id="plpgsql-control-structures-loops">
<title>Simple Loops</title>
+ <indexterm zone="plpgsql-control-structures-loops">
+ <primary>loop</primary>
+ <secondary>in PL/pgSQL</secondary>
+ </indexterm>
+
<para>
With the <literal>LOOP</>, <literal>EXIT</>, <literal>WHILE</>,
and <literal>FOR</> statements, you can arrange for your
END LOOP;
</programlisting>
</para>
+
+ <para>
+ If the lower bound is greater than the upper bound, the loop body is not
+ executed at all, but no error is raised.
+ </para>
</sect3>
</sect2>
<sect1 id="plpgsql-cursors">
<title>Cursors</title>
+ <indexterm zone="plpgsql-cursors">
+ <primary>cursor</primary>
+ <secondary>in PL/pgSQL</secondary>
+ </indexterm>
+
<para>
Rather than executing a whole query at once, it is possible to set
up a <firstterm>cursor</> that encapsulates the query, and then read
<sect1 id="plpgsql-trigger">
<title>Trigger Procedures</title>
+ <indexterm zone="plpgsql-trigger">
+ <primary>trigger</primary>
+ <secondary>in PL/pgSQL</secondary>
+ </indexterm>
+
<para>
<application>PL/pgSQL</application> can be used to define trigger
procedures. A trigger procedure is created with the
<indexterm zone="plpgsql-porting">
<primary>Oracle</primary>
+ <secondary>porting from PL/SQL to PL/pgSQL</secondary>
</indexterm>
<indexterm zone="plpgsql-porting">
- <primary>PL/SQL</primary>
+ <primary>PL/SQL (Oracle)</primary>
+ <secondary>porting to PL/pgSQL</secondary>
</indexterm>
<para>
with <literal>OUT</> parameters and string manipulation.
<productname>PostgreSQL</> does not have an
<function>instr</function> function, but you can work around it
- using a combination of other functions. In <xref
+ using a combination of other
+ functions.<indexterm><primary>instr</></indexterm> In <xref
linkend="plpgsql-porting-appendix"> there is a
<application>PL/pgSQL</application> implementation of
<function>instr</function> that you can use to make your porting
<para>
If you do not provide a return value, Python returns the default
- <symbol>None</symbol>. The
- language module translates Python's <symbol>None</symbol> into the
- SQL null value.
+ <symbol>None</symbol>. The language module translates Python's
+ <symbol>None</symbol> into the SQL null
+ value.<indexterm><primary>null value</><secondary
+ sortas="PL/Python">in PL/Python</></indexterm>
</para>
<para>
The global dictionary <varname>SD</varname> is available to store
data between function calls. This variable is private static data.
The global dictionary <varname>GD</varname> is public data,
- available to all Python functions within a session. Use with care.
+ available to all Python functions within a session. Use with
+ care.<indexterm><primary>global data</><secondary>in
+ PL/Python</></indexterm>
</para>
<para>
<sect1 id="plpython-trigger">
<title>Trigger Functions</title>
+ <indexterm zone="plpython-trigger">
+ <primary>trigger</primary>
+ <secondary>in PL/Python</secondary>
+ </indexterm>
+
<para>
When a function is used in a trigger, the dictionary
<literal>TD</literal> contains trigger-related values. The trigger
<literal>plpy.error("msg")</literal>, and
<literal>plpy.fatal("msg")</literal>. They are mostly equivalent
to calling <literal>elog(<replaceable>LEVEL</>, "msg")</literal>
- from C code. <function>plpy.error</function> and
+ from C code.<indexterm><primary>elog</><secondary>in
+ PL/Python</></indexterm> <function>plpy.error</function> and
<function>plpy.fatal</function> actually raise a Python exception
which, if uncaught, causes the PL/Python module to call
<literal>elog(ERROR, msg)</literal> when the function handler
</para>
<para>
- The second function, <function>plpy.prepare</function>, prepares the
- execution plan for a query. It is called with a query string and a
- list of parameter types, if you have parameter references in the
- query. For example:
+ <indexterm><primary>preparing a query</><secondary>in PL/Python</></indexterm>
+ The second function, <function>plpy.prepare</function>, prepares
+ the execution plan for a query. It is called with a query string
+ and a list of parameter types, if you have parameter references in
+ the query. For example:
<programlisting>
plan = plpy.prepare("SELECT last_name FROM my_users WHERE first_name = $1", [ "text" ])
</programlisting>
</para>
</sect1>
-<!-- NOT CURRENTLY SUPPORTED
+<![IGNORE[
+ <!-- NOT CURRENTLY SUPPORTED -->
<sect1 id="plpython-trusted">
<title>Restricted Environment</title>
</para>
</sect1>
--->
+]]>
</chapter>
<sect1 id="pltcl-global">
<title>Global Data in PL/Tcl</title>
+ <indexterm zone="pltcl-global">
+ <primary>global data</primary>
+ <secondary>in PL/Tcl</secondary>
+ </indexterm>
+
<para>
Sometimes it
is useful to have some global data that is held between two
<term><function>spi_prepare</function> <replaceable>query</replaceable> <replaceable>typelist</replaceable></term>
<listitem>
<para>
- Prepares and saves a query plan for later execution. The saved plan
- will be retained for the life of the current session.
+ Prepares and saves a query plan for later execution. The
+ saved plan will be retained for the life of the current
+ session.<indexterm><primary>preparing a query</><secondary>in
+ PL/Tcl</></>
</para>
<para>
The query may use parameters, that is, placeholders for
<varlistentry>
<indexterm>
<primary>elog</primary>
- <secondary>PL/Tcl</secondary>
+ <secondary>in PL/Tcl</secondary>
</indexterm>
<term><function>elog</> <replaceable>level</replaceable> <replaceable>msg</replaceable></term>
<listitem>
<title>Trigger Procedures in PL/Tcl</title>
<indexterm>
- <primary>triggers</primary>
+ <primary>trigger</primary>
<secondary>in PL/Tcl</secondary>
</indexterm>
&libpgtcl;
&ecpg;
&jdbc;
- &pygresql;
&infoschema;
</part>
ParameterStatus will be generated: they are
<literal>server_version</> (a pseudo-parameter that cannot change after
startup);
- <literal>server_encoding</> (also not presently changeable after start);
<literal>client_encoding</>,
- <literal>is_superuser</>, and
+ <literal>is_superuser</>,
+ <literal>session_authorization</literal>, and
<literal>DateStyle</>.
This set might change in the future, or even become configurable.
Accordingly, a frontend should simply ignore ParameterStatus for
<chapter id="queries">
<title>Queries</title>
+ <indexterm zone="queries">
+ <primary>query</primary>
+ </indexterm>
+
+ <indexterm zone="queries">
+ <primary>SELECT</primary>
+ </indexterm>
+
<para>
The previous chapters explained how to create tables, how to fill
them with data, and how to manipulate that data. Now we finally
<sect1 id="queries-table-expressions">
<title>Table Expressions</title>
+ <indexterm zone="queries-table-expressions">
+ <primary>table expression</primary>
+ </indexterm>
+
<para>
A <firstterm>table expression</firstterm> computes a table. The
table expression contains a <literal>FROM</> clause that is
overall table expression.
</para>
+ <indexterm>
+ <primary>ONLY</primary>
+ </indexterm>
+
<para>
When a table reference names a table that is the supertable of a
table inheritance hierarchy, the table reference produces rows of
<title>Joined Tables</title>
<indexterm zone="queries-join">
- <primary>joins</primary>
+ <primary>join</primary>
</indexterm>
<para>
<term>Cross join</term>
<indexterm>
- <primary>joins</primary>
+ <primary>join</primary>
<secondary>cross</secondary>
</indexterm>
+ <indexterm>
+ <primary>cross join</primary>
+ </indexterm>
+
<listitem>
<synopsis>
<replaceable>T1</replaceable> CROSS JOIN <replaceable>T2</replaceable>
<term>Qualified joins</term>
<indexterm>
- <primary>joins</primary>
+ <primary>join</primary>
<secondary>outer</secondary>
</indexterm>
+ <indexterm>
+ <primary>outer join</primary>
+ </indexterm>
+
<listitem>
<synopsis>
<replaceable>T1</replaceable> { <optional>INNER</optional> | { LEFT | RIGHT | FULL } <optional>OUTER</optional> } JOIN <replaceable>T2</replaceable> ON <replaceable>boolean_expression</replaceable>
<para>
<indexterm>
- <primary>joins</primary>
+ <primary>join</primary>
<secondary>natural</secondary>
</indexterm>
+ <indexterm>
+ <primary>natural join</primary>
+ </indexterm>
Finally, <literal>NATURAL</> is a shorthand form of
<literal>USING</>: it forms a <literal>USING</> list
consisting of exactly those column names that appear in both
<term><literal>LEFT OUTER JOIN</></term>
<indexterm>
- <primary>joins</primary>
+ <primary>join</primary>
<secondary>left</secondary>
</indexterm>
+ <indexterm>
+ <primary>left join</primary>
+ </indexterm>
+
<listitem>
<para>
First, an inner join is performed. Then, for each row in
<varlistentry>
<term><literal>RIGHT OUTER JOIN</></term>
+ <indexterm>
+ <primary>join</primary>
+ <secondary>right</secondary>
+ </indexterm>
+
+ <indexterm>
+ <primary>right join</primary>
+ </indexterm>
+
<listitem>
<para>
First, an inner join is performed. Then, for each row in
<title>Table and Column Aliases</title>
<indexterm zone="queries-table-aliases">
- <primary>label</primary>
- <secondary>table</secondary>
+ <primary>alias</primary>
+ <secondary>in the FROM clause</secondary>
</indexterm>
<indexterm>
- <primary>alias</primary>
- <see>label</see>
+ <primary>label</primary>
+ <see>alias</see>
</indexterm>
<para>
<title>Subqueries</title>
<indexterm zone="queries-subqueries">
- <primary>subqueries</primary>
+ <primary>subquery</primary>
</indexterm>
<para>
<indexterm zone="queries-tablefunctions"><primary>table function</></>
+ <indexterm zone="queries-tablefunctions">
+ <primary>function</>
+ <secondary>in the FROM clause</>
+ </indexterm>
+
<para>
Table functions are functions that produce a set of rows, made up
of either base data types (scalar types) or composite data types
<title>The WHERE Clause</title>
<indexterm zone="queries-where">
- <primary>where</primary>
+ <primary>WHERE</primary>
</indexterm>
<para>
<title>The GROUP BY and HAVING Clauses</title>
<indexterm zone="queries-group">
- <primary>group</primary>
+ <primary>GROUP BY</primary>
+ </indexterm>
+
+ <indexterm zone="queries-group">
+ <primary>grouping</primary>
</indexterm>
<para>
column names is also allowed.
</para>
+ <indexterm>
+ <primary>HAVING</primary>
+ </indexterm>
+
<para>
If a table has been grouped using a <literal>GROUP BY</literal>
clause, but then only certain groups are of interest, the
<title>Select Lists</title>
<indexterm>
- <primary>select</primary>
+ <primary>SELECT</primary>
<secondary>select list</secondary>
</indexterm>
<sect2 id="queries-select-list-items">
<title>Select-List Items</title>
+ <indexterm>
+ <primary>*</primary>
+ </indexterm>
+
<para>
The simplest kind of select list is <literal>*</literal> which
emits all columns that the table expression produces. Otherwise,
<title>Column Labels</title>
<indexterm zone="queries-column-labels">
- <primary>label</primary>
- <secondary>column</secondary>
+ <primary>alias</primary>
+ <secondary>in the select list</secondary>
</indexterm>
<para>
<title>DISTINCT</title>
<indexterm zone="queries-distinct">
- <primary>distinct</primary>
+ <primary>DISTINCT</primary>
+ </indexterm>
+
+ <indexterm zone="queries-distinct">
+ <primary>duplicates</primary>
</indexterm>
<para>
</para>
<para>
+ <indexterm><primary>null value</><secondary sortas="DISTINCT">in
+ DISTINCT</></indexterm>
Obviously, two rows are considered distinct if they differ in at
least one column value. Null values are considered equal in this
comparison.
<title>Combining Queries</title>
<indexterm zone="queries-union">
- <primary>union</primary>
+ <primary>UNION</primary>
+ </indexterm>
+ <indexterm zone="queries-union">
+ <primary>INTERSECT</primary>
+ </indexterm>
+ <indexterm zone="queries-union">
+ <primary>EXCEPT</primary>
+ </indexterm>
+ <indexterm zone="queries-union">
+ <primary>set union</primary>
+ </indexterm>
+ <indexterm zone="queries-union">
+ <primary>set intersection</primary>
</indexterm>
<indexterm zone="queries-union">
- <primary>intersection</primary>
+ <primary>set difference</primary>
</indexterm>
<indexterm zone="queries-union">
- <primary>except</primary>
+ <primary>set operation</primary>
</indexterm>
<para>
<indexterm zone="queries-order">
<primary>sorting</primary>
- <secondary>query results</secondary>
+ </indexterm>
+
+ <indexterm zone="queries-order">
+ <primary>ORDER BY</primary>
</indexterm>
<para>
<title>LIMIT and OFFSET</title>
<indexterm zone="queries-limit">
- <primary>limit</primary>
+ <primary>LIMIT</primary>
</indexterm>
<indexterm zone="queries-limit">
- <primary>offset</primary>
- <secondary>with query results</secondary>
+ <primary>OFFSET</primary>
</indexterm>
<para>
</para>
<para>
- <indexterm><primary>cluster</primary></indexterm>
+ <indexterm><primary>database cluster</primary></indexterm>
+ <indexterm><primary>cluster</primary><secondary>of databases</secondary><see>database cluster</see></indexterm>
Tables are grouped into databases, and a collection of databases
managed by a single <productname>PostgreSQL</productname> server
<title>Aggregate Functions</title>
<indexterm zone="tutorial-agg">
- <primary>aggregate</primary>
+ <primary>aggregate function</primary>
</indexterm>
<para>
<refpurpose>abort the current transaction</refpurpose>
</refnamediv>
+ <indexterm zone="sql-abort">
+ <primary>ABORT</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ABORT [ WORK | TRANSACTION ]
<refpurpose>change the definition of an aggregate function</refpurpose>
</refnamediv>
+ <indexterm zone="sql-alteraggregate">
+ <primary>ALTER AGGREGATE</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ALTER AGGREGATE <replaceable>name</replaceable> ( <replaceable>type</replaceable> ) RENAME TO <replaceable>newname</replaceable>
<refpurpose>change the definition of a conversion</refpurpose>
</refnamediv>
+ <indexterm zone="sql-alterconversion">
+ <primary>ALTER CONVERSION</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ALTER CONVERSION <replaceable>name</replaceable> RENAME TO <replaceable>newname</replaceable>
<refpurpose>change a database</refpurpose>
</refnamediv>
+ <indexterm zone="sql-alterdatabase">
+ <primary>ALTER DATABASE</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ALTER DATABASE <replaceable class="PARAMETER">name</replaceable> SET <replaceable>variable</replaceable> { TO | = } { <replaceable>value</replaceable> | DEFAULT }
<refentrytitle id="sql-alterdomain-title">ALTER DOMAIN</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
+
<refnamediv>
<refname>
ALTER DOMAIN
change the definition of a domain
</refpurpose>
</refnamediv>
+
+ <indexterm zone="sql-alterdomain">
+ <primary>ALTER DOMAIN</primary>
+ </indexterm>
+
<refsynopsisdiv>
<refsynopsisdivinfo>
<date>2002-11-27</date>
<refpurpose>change the definition of a function</refpurpose>
</refnamediv>
+ <indexterm zone="sql-alterfunction">
+ <primary>ALTER FUNCTION</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ALTER FUNCTION <replaceable>name</replaceable> ( [ <replaceable class="parameter">type</replaceable> [, ...] ] ) RENAME TO <replaceable>newname</replaceable>
<refpurpose>change a user group</refpurpose>
</refnamediv>
+ <indexterm zone="sql-altergroup">
+ <primary>ALTER GROUP</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ALTER GROUP <replaceable class="PARAMETER">groupname</replaceable> ADD USER <replaceable class="PARAMETER">username</replaceable> [, ... ]
<refpurpose>change the definition of a procedural language</refpurpose>
</refnamediv>
+ <indexterm zone="sql-alterlanguage">
+ <primary>ALTER LANGUAGE</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ALTER LANGUAGE <replaceable>name</replaceable> RENAME TO <replaceable>newname</replaceable>
<refpurpose>change the definition of an operator class</refpurpose>
</refnamediv>
+ <indexterm zone="sql-alteropclass">
+ <primary>ALTER OPERATOR CLASS</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ALTER OPERATOR CLASS <replaceable>name</replaceable> USING <replaceable class="parameter">index_method</replaceable> RENAME TO <replaceable>newname</replaceable>
<refpurpose>change the definition of a schema</refpurpose>
</refnamediv>
+ <indexterm zone="sql-alterschema">
+ <primary>ALTER SCHEMA</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ALTER SCHEMA <replaceable>name</replaceable> RENAME TO <replaceable>newname</replaceable>
<refentrytitle id="SQL-ALTERSEQUENCE-TITLE">ALTER SEQUENCE</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
+
<refnamediv>
<refname>
ALTER SEQUENCE
alter the definition of a sequence generator
</refpurpose>
</refnamediv>
+
+ <indexterm zone="sql-altersequence">
+ <primary>ALTER SEQUENCE</primary>
+ </indexterm>
+
<refsynopsisdiv>
<refsynopsisdivinfo>
<date>1999-07-20</date>
<refpurpose>change the definition of a table</refpurpose>
</refnamediv>
+ <indexterm zone="sql-altertable">
+ <primary>ALTER TABLE</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ALTER TABLE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ * ]
<refpurpose>change the definition of a trigger</refpurpose>
</refnamediv>
+ <indexterm zone="sql-altertrigger">
+ <primary>ALTER TRIGGER</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ALTER TRIGGER <replaceable class="PARAMETER">trigger</replaceable> ON <replaceable class="PARAMETER">table</replaceable>
<refpurpose>change a database user account</refpurpose>
</refnamediv>
+ <indexterm zone="sql-alteruser">
+ <primary>ALTER USER</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ALTER USER <replaceable class="PARAMETER">username</replaceable> [ [ WITH ] <replaceable class="PARAMETER">option</replaceable> [ ... ] ]
<refpurpose>collect statistics about a database</refpurpose>
</refnamediv>
+ <indexterm zone="sql-analyze">
+ <primary>ANALYZE</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
ANALYZE [ VERBOSE ] [ <replaceable class="PARAMETER">table</replaceable> [ (<replaceable class="PARAMETER">column</replaceable> [, ...] ) ] ]
<refpurpose>start a transaction block</refpurpose>
</refnamediv>
+ <indexterm zone="sql-begin">
+ <primary>BEGIN</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
BEGIN [ WORK | TRANSACTION ]
<refpurpose>force a transaction log checkpoint</refpurpose>
</refnamediv>
+ <indexterm zone="sql-checkpoint">
+ <primary>CHECKPOINT</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
CHECKPOINT
<refpurpose>close a cursor</refpurpose>
</refnamediv>
+ <indexterm zone="sql-close">
+ <primary>CLOSE</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
CLOSE <replaceable class="PARAMETER">cursor</replaceable>
</para>
<para>
- Every open cursor is implicitly closed when a transaction is
- terminated by <command>COMMIT</command> or
- <command>ROLLBACK</command>.
+ Every non-holdable open cursor is implicitly closed when a
+ transaction is terminated by <command>COMMIT</command> or
+ <command>ROLLBACK</command>. Holdable cursors are implicitely
+ closed if the transaction that created them aborts via
+ <command>ROLLBACK</command>; if this does not happen, the holdable
+ cursor remains open until an explicit <command>CLOSE</command> is
+ executed, or the client disconnects.
</para>
</refsect1>
</varlistentry>
<varlistentry>
- <term><computeroutput>WARNING: PerformPortalClose: portal "<replaceable class="PARAMETER">cursor</replaceable>" not found</computeroutput></term>
+ <term><computeroutput>ERROR: cursor "<replaceable class="PARAMETER">cursor</replaceable>" does not exist</computeroutput></term>
<listitem>
<para>
- This warning is given if <replaceable
+ Message returned if <replaceable
class="PARAMETER">cursor</replaceable> is not declared or has
already been closed.
</para>
<refpurpose>cluster a table according to an index</refpurpose>
</refnamediv>
+ <indexterm zone="sql-cluster">
+ <primary>CLUSTER</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
CLUSTER <replaceable class="PARAMETER">indexname</replaceable> ON <replaceable class="PARAMETER">tablename</replaceable>
<refpurpose>cluster a <productname>PostgreSQL</productname> database</refpurpose>
</refnamediv>
+ <indexterm zone="app-clusterdb">
+ <primary>clusterdb</primary>
+ </indexterm>
+
<refsynopsisdiv>
<cmdsynopsis>
<command>clusterdb</command>
<term><option>--host <replaceable class="parameter">host</replaceable></></term>
<listitem>
<para>
- Specifies the host name of the machine on which the
- server
- is running. If the value begins with a slash, it is used
- as the directory for the Unix domain socket.
+ Specifies the host name of the machine on which the server is
+ running. If the value begins with a slash, it is used as the
+ directory for the Unix domain socket.
</para>
</listitem>
</varlistentry>
<term><computeroutput>CLUSTER</computeroutput></term>
<listitem>
<para>
- Everything went well.
+ The database was successfully clustered.
</para>
</listitem>
</varlistentry>
<refpurpose>define or change the comment of an object</refpurpose>
</refnamediv>
+ <indexterm zone="sql-comment">
+ <primary>COMMENT</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
COMMENT ON
<refpurpose>commit the current transaction</refpurpose>
</refnamediv>
+ <indexterm zone="sql-commit">
+ <primary>COMMIT</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
COMMIT [ WORK | TRANSACTION ]
<refpurpose>copy data between files and tables</refpurpose>
</refnamediv>
+ <indexterm zone="sql-copy">
+ <primary>COPY</primary>
+ </indexterm>
+
<refsynopsisdiv>
<synopsis>
COPY <replaceable class="parameter">table</replaceable> [ ( <replaceable class="parameter">column</replaceable> [, ...] ) ]
The file format used for <command>COPY BINARY</command> changed in
<application>PostgreSQL</application> 7.4. The new format consists
of a file header, zero or more tuples containing the row data, and