]> granicus.if.org Git - postgresql/commitdiff
Initial SQL/XML support: xml data type and initial set of functions.
authorPeter Eisentraut <peter_e@gmx.net>
Thu, 21 Dec 2006 16:05:16 +0000 (16:05 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Thu, 21 Dec 2006 16:05:16 +0000 (16:05 +0000)
39 files changed:
configure
configure.in
doc/src/sgml/datatype.sgml
doc/src/sgml/func.sgml
doc/src/sgml/installation.sgml
src/backend/executor/execQual.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/util/clauses.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_target.c
src/backend/utils/adt/Makefile
src/backend/utils/adt/ruleutils.c
src/backend/utils/adt/xml.c [new file with mode: 0644]
src/backend/utils/mb/mbutils.c
src/include/catalog/pg_cast.h
src/include/catalog/pg_proc.h
src/include/catalog/pg_type.h
src/include/nodes/execnodes.h
src/include/nodes/nodes.h
src/include/nodes/primnodes.h
src/include/parser/parse_coerce.h
src/include/pg_config.h.in
src/include/utils/errcodes.h
src/include/utils/xml.h [new file with mode: 0644]
src/test/regress/expected/opr_sanity.out
src/test/regress/expected/prepare.out
src/test/regress/expected/rules.out
src/test/regress/expected/xml.out [new file with mode: 0644]
src/test/regress/expected/xml_1.out [new file with mode: 0644]
src/test/regress/parallel_schedule
src/test/regress/serial_schedule
src/test/regress/sql/opr_sanity.sql
src/test/regress/sql/xml.sql [new file with mode: 0644]

index dc96e1ca41a1e5405d5ba9328970a3af1ffdfac3..f85511bdefc20571c78b7d02378e5d117f25bf03 100755 (executable)
--- a/configure
+++ b/configure
@@ -894,6 +894,7 @@ Optional Packages:
   --with-openssl          build with OpenSSL support
   --without-readline      do not use GNU Readline nor BSD Libedit for editing
   --with-libedit-preferred  prefer BSD Libedit over GNU Readline
+  --with-libxml           build with XML support
   --without-zlib          do not use Zlib
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
 
@@ -4160,6 +4161,42 @@ fi;
 
 
 
+#
+# XML
+#
+
+pgac_args="$pgac_args with_libxml"
+
+
+# Check whether --with-libxml or --without-libxml was given.
+if test "${with_libxml+set}" = set; then
+  withval="$with_libxml"
+
+  case $withval in
+    yes)
+
+cat >>confdefs.h <<\_ACEOF
+#define USE_LIBXML 1
+_ACEOF
+
+      ;;
+    no)
+      :
+      ;;
+    *)
+      { { echo "$as_me:$LINENO: error: no argument expected for --with-libxml option" >&5
+echo "$as_me: error: no argument expected for --with-libxml option" >&2;}
+   { (exit 1); exit 1; }; }
+      ;;
+  esac
+
+else
+  with_libxml=no
+
+fi;
+
+
+
 #
 # Zlib
 #
@@ -7268,6 +7305,87 @@ fi
 
 fi
 
+if test "$with_libxml" = yes ; then
+
+echo "$as_me:$LINENO: checking for xmlInitParser in -lxml2" >&5
+echo $ECHO_N "checking for xmlInitParser in -lxml2... $ECHO_C" >&6
+if test "${ac_cv_lib_xml2_xmlInitParser+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lxml2  $LIBS"
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.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 xmlInitParser ();
+int
+main ()
+{
+xmlInitParser ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+  (eval $ac_link) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (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); }; } &&
+        { 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_lib_xml2_xmlInitParser=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_cv_lib_xml2_xmlInitParser=no
+fi
+rm -f conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+echo "$as_me:$LINENO: result: $ac_cv_lib_xml2_xmlInitParser" >&5
+echo "${ECHO_T}$ac_cv_lib_xml2_xmlInitParser" >&6
+if test $ac_cv_lib_xml2_xmlInitParser = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBXML2 1
+_ACEOF
+
+  LIBS="-lxml2 $LIBS"
+
+else
+  { { echo "$as_me:$LINENO: error: library 'xml2' is required for XML support" >&5
+echo "$as_me: error: library 'xml2' is required for XML support" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+fi
+
 
 ##
 ## Header files
 
 done
 
+fi
+
+if test "$with_libxml" = yes ; then
+  if test "${ac_cv_header_libxml_parser_h+set}" = set; then
+  echo "$as_me:$LINENO: checking for libxml/parser.h" >&5
+echo $ECHO_N "checking for libxml/parser.h... $ECHO_C" >&6
+if test "${ac_cv_header_libxml_parser_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_libxml_parser_h" >&5
+echo "${ECHO_T}$ac_cv_header_libxml_parser_h" >&6
+else
+  # Is the header compilable?
+echo "$as_me:$LINENO: checking libxml/parser.h usability" >&5
+echo $ECHO_N "checking libxml/parser.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+$ac_includes_default
+#include <libxml/parser.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+  (eval $ac_compile) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+        { ac_try='test -z "$ac_c_werror_flag"
+                        || test ! -s conftest.err'
+  { (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); }; } &&
+        { ac_try='test -s conftest.$ac_objext'
+  { (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_header_compiler=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking libxml/parser.h presence" >&5
+echo $ECHO_N "checking libxml/parser.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+#include <libxml/parser.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+  (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } >/dev/null; then
+  if test -s conftest.err; then
+    ac_cpp_err=$ac_c_preproc_warn_flag
+    ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+  else
+    ac_cpp_err=
+  fi
+else
+  ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+  ac_header_preproc=yes
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+  yes:no: )
+    { echo "$as_me:$LINENO: WARNING: libxml/parser.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: libxml/parser.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { echo "$as_me:$LINENO: WARNING: libxml/parser.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: libxml/parser.h: proceeding with the compiler's result" >&2;}
+    ac_header_preproc=yes
+    ;;
+  no:yes:* )
+    { echo "$as_me:$LINENO: WARNING: libxml/parser.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: libxml/parser.h: present but cannot be compiled" >&2;}
+    { echo "$as_me:$LINENO: WARNING: libxml/parser.h:     check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: libxml/parser.h:     check for missing prerequisite headers?" >&2;}
+    { echo "$as_me:$LINENO: WARNING: libxml/parser.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: libxml/parser.h: see the Autoconf documentation" >&2;}
+    { echo "$as_me:$LINENO: WARNING: libxml/parser.h:     section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: libxml/parser.h:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { echo "$as_me:$LINENO: WARNING: libxml/parser.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: libxml/parser.h: proceeding with the preprocessor's result" >&2;}
+    { echo "$as_me:$LINENO: WARNING: libxml/parser.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: libxml/parser.h: in the future, the compiler will take precedence" >&2;}
+    (
+      cat <<\_ASBOX
+## ---------------------------------------- ##
+## Report this to pgsql-bugs@postgresql.org ##
+## ---------------------------------------- ##
+_ASBOX
+    ) |
+      sed "s/^/$as_me: WARNING:     /" >&2
+    ;;
+esac
+echo "$as_me:$LINENO: checking for libxml/parser.h" >&5
+echo $ECHO_N "checking for libxml/parser.h... $ECHO_C" >&6
+if test "${ac_cv_header_libxml_parser_h+set}" = set; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  ac_cv_header_libxml_parser_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_libxml_parser_h" >&5
+echo "${ECHO_T}$ac_cv_header_libxml_parser_h" >&6
+
+fi
+if test $ac_cv_header_libxml_parser_h = yes; then
+  :
+else
+  { { echo "$as_me:$LINENO: error: header file <libxml/parser.h> is required for XML support" >&5
+echo "$as_me: error: header file <libxml/parser.h> is required for XML support" >&2;}
+   { (exit 1); exit 1; }; }
+fi
+
+
 fi
 
 if test "$with_ldap" = yes ; then
index 096f806060beec392544a52b57d64535ab65e1f5..1391525acfcd5bd0da132cc823a01dcbe95287c5 100644 (file)
@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-dnl $PostgreSQL: pgsql/configure.in,v 1.492 2006/12/14 21:49:54 tgl Exp $
+dnl $PostgreSQL: pgsql/configure.in,v 1.493 2006/12/21 16:05:12 petere Exp $
 dnl
 dnl Developers, please strive to achieve this order:
 dnl
@@ -531,6 +531,13 @@ PGAC_ARG_BOOL(with, libedit-preferred, no,
               [  --with-libedit-preferred  prefer BSD Libedit over GNU Readline])
 
 
+#
+# XML
+#
+PGAC_ARG_BOOL(with, libxml, no, [  --with-libxml           build with XML support],
+              [AC_DEFINE([USE_LIBXML], 1, [Define to 1 to build with XML support. (--with-libxml)])])
+
+
 #
 # Zlib
 #
@@ -716,6 +723,10 @@ if test "$with_pam" = yes ; then
   AC_CHECK_LIB(pam,    pam_start, [], [AC_MSG_ERROR([library 'pam' is required for PAM])])
 fi
 
+if test "$with_libxml" = yes ; then
+  AC_CHECK_LIB(xml2, xmlInitParser, [], [AC_MSG_ERROR([library 'xml2' is required for XML support])])
+fi
+
 
 ##
 ## Header files
@@ -791,6 +802,10 @@ if test "$with_pam" = yes ; then
                                      [AC_MSG_ERROR([header file <security/pam_appl.h> or <pam/pam_appl.h> is required for PAM.])])])
 fi
 
+if test "$with_libxml" = yes ; then
+  AC_CHECK_HEADER(libxml/parser.h, [], [AC_MSG_ERROR([header file <libxml/parser.h> is required for XML support])])
+fi
+
 if test "$with_ldap" = yes ; then
   if test "$PORTNAME" != "win32"; then
      AC_CHECK_HEADERS(ldap.h, [],
index 4bc950acf0bdf70ea2fb0ba0ebc7d3f6d18c4b2a..f68714bd20f0325dc66b1b90dc263079134776f9 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.181 2006/11/23 04:27:33 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.182 2006/12/21 16:05:12 petere Exp $ -->
 
  <chapter id="datatype">
   <title id="datatype-title">Data Types</title>
        <entry><type>timestamptz</type></entry>
        <entry>date and time, including time zone</entry>
       </row>
+
+      <row>
+       <entry><type>xml</type></entry>
+       <entry></entry>
+       <entry>XML data</entry>
+      </row>
      </tbody>
     </tgroup>
    </table>
     precision</type>, <type>integer</type>, <type>interval</type>,
     <type>numeric</type>, <type>decimal</type>, <type>real</type>,
     <type>smallint</type>, <type>time</type> (with or without time zone),
-    <type>timestamp</type> (with or without time zone).
+    <type>timestamp</type> (with or without time zone),
+    <type>xml</type>.
    </para>
   </note>
 
@@ -3358,12 +3365,21 @@ SELECT * FROM pg_attribute
   </sect1>
 
   <sect1 id="datatype-xml">
-   <title><acronym>XML</> Document Support</title>
+   <title><acronym>XML</> Type</title>
 
-   <indexterm zone="datatype">
-    <primary>xml</primary>
+   <indexterm zone="datatype-xml">
+    <primary>XML</primary>
    </indexterm>
 
+   <para>
+    The data type <type>xml</type> can be used to store XML data.  Its
+    advantage over storing XML data in, say, a text field is that it
+    checks the input values for well-formedness, and there are support
+    functions to perform type-safe operations on it; see <xref
+    linkend="functions-xml">.  Currently, there is no support for
+    validation against a specific <acronym>XML</> schema.
+   </para>
+
    <para>
     <acronym>XML</> (Extensible Markup Language) support is not one
     capability, but a variety of features supported by a database
@@ -3378,22 +3394,6 @@ SELECT * FROM pg_attribute
    </para>
 
    <variablelist>
-
-   <varlistentry>
-    <term>Storage</term>
-    <listitem>
-
-     <para>
-      PostgreSQL does not have a specialized <acronym>XML</> data type.
-      Users should store <acronym>XML</> documents in ordinary
-      <type>TEXT</> fields. If you need the document split apart into
-      its component parts so each element is stored separately, you must
-      use a middle-ware solution to do that, but once done, the data
-      becomes relational and has to be processed accordingly.
-     </para>
-    </listitem>
-   </varlistentry>
-
    <varlistentry>
     <term>Import/Export</term>
     <listitem>
@@ -3408,21 +3408,6 @@ SELECT * FROM pg_attribute
     </listitem>
    </varlistentry>
 
-   <varlistentry>
-    <term>Validation</term>
-    <listitem>
-
-     <para>
-      <filename>/contrib/xml2</> has a function called
-      <function>xml_is_well_formed()</> that can be used in a <literal>CHECK</>
-      constraint to enforce that a field contains well-formed <acronym>XML</>.
-      It does not support validation against a specific <acronym>XML</>
-      schema. A server-side language with <acronym>XML</> capabilities
-      could be used to do schema-specific <acronym>XML</> checks.
-     </para>
-    </listitem>
-   </varlistentry>
-
    <varlistentry>
     <term>Indexing</term>
     <listitem>
@@ -3438,20 +3423,6 @@ SELECT * FROM pg_attribute
     </listitem>
    </varlistentry>
 
-   <varlistentry>
-    <term>Modification</term>
-    <listitem>
-
-     <para>
-      If an <command>UPDATE</> does not modify an <acronym>XML</> field,
-      the <acronym>XML</> data is shared between the old and new rows.
-      However, if the <command>UPDATE</> modifies an <acronym>XML</>
-      field, a full modified copy of the <acronym>XML</> field must be
-      created internally.
-     </para>
-    </listitem>
-   </varlistentry>
-
    <varlistentry>
     <term>Searching</term>
     <listitem>
@@ -3487,19 +3458,6 @@ SELECT * FROM pg_attribute
      </para>
     </listitem>
    </varlistentry>
-
-   <varlistentry>
-    <term>Missing Features</term>
-    <listitem>
-
-     <para>
-      Missing features include XQuery, SQL/XML syntax (ISO/IEC
-      9075-14), and an <acronym>XML</> data type optimized for
-      <acronym>XML</> storage.
-     </para>
-    </listitem>
-   </varlistentry>
-
    </variablelist>
 
   </sect1>
index 1e092c4ce7ca3d345968ee73367f085297a39277..c2a3409645e9067e7e9b52478648573db9d4fcc4 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.347 2006/11/25 00:38:53 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.348 2006/12/21 16:05:12 petere Exp $ -->
 
  <chapter id="functions">
   <title>Functions and Operators</title>
@@ -10741,4 +10741,113 @@ SELECT (pg_stat_file('filename')).modification;
    </para>
 
   </sect1>
+
+  <sect1 id="functions-xml">
+   <title>XML Functions</title>
+
+   <para>
+    The functions and function-like expressions described in this
+    section operate on values of type <type>xml</type>.
+   </para>
+
+   <sect2>
+    <title><literal>xmlcomment</literal></title>
+   <indexterm>
+    <primary>xmlcomment</primary>
+   </indexterm>
+ <synopsis>
+ <function>xmlcomment</function>(<replaceable>text</replaceable>)
+ </synopsis>
+    <para>
+     Creates an XML comment.
+    </para>
+    </sect2>
+   <sect2>
+    <title><literal>xmlconcat</literal></title>
+   <indexterm>
+    <primary>xmlconcat</primary>
+   </indexterm>
+ <synopsis>
+ <function>xmlconcat</function>(<replaceable>xml</replaceable><optional>, xml, ...</optional>)
+ </synopsis>
+    <para>
+     Combines a list of individual XML values to create a
+     single value containing an XML forest.
+    </para>
+    </sect2>
+   <sect2>
+    <title><literal>xmlelement</literal></title>
+   <indexterm>
+    <primary>xmlelement</primary>
+   </indexterm>
+ <synopsis>
+ <function>xmlelement</function>(name <replaceable>name</replaceable><optional>, xmlattribytes(<replaceable>value</replaceable> <optional>AS <replaceable>label</replaceable></optional><optional>, ... </optional>)</optional>
+ <optional><replaceable>, content, ...</replaceable></optional>)
+ </synopsis>
+    <para>
+     Creates an XML element, allowing the name to be specified.
+    </para>
+    </sect2>
+   <sect2>
+    <title><literal>xmlforest</literal></title>
+   <indexterm>
+    <primary>xmlforest</primary>
+   </indexterm>
+ <synopsis>
+ <function>xmlforest</function>(<replaceable>value</replaceable> <optional>AS <replaceable>label</replaceable></optional><optional>, ...</optional>)
+ </synopsis>
+    <para>
+     Creates XML elements from columns, using the name of each
+     column as the name of the corresponding element.
+    </para>
+    </sect2>
+   <sect2>
+    <title><literal>xmlpi</literal></title>
+   <indexterm>
+    <primary>xmlpi</primary>
+   </indexterm>
+ <synopsis>
+ <function>xmlpi</function>(name <replaceable>target</replaceable> <optional>, <replaceable>content</replaceable></optional>)
+ </synopsis>
+    <para>
+     Creates an XML processing instruction.
+    </para>
+    </sect2>
+   <sect2>
+    <title><literal>xmlroot</literal></title>
+   <indexterm>
+    <primary>xmlroot</primary>
+   </indexterm>
+ <synopsis>
+ <function>xmlroot</function>(<replaceable>xml</replaceable>, version <replaceable>text</replaceable> <optional>, standalone yes|no|no value</optional>)
+ </synopsis>
+    <para>
+     Creates the root node of an XML document.
+    </para>
+  </sect2>
+ </sect1>
 </chapter>
index 5d071586fc8c37faf74ee7c0ae017b518e1be218..a56ba9ad9b8461c2fe02f34e61b2d8e86fc536dc 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/installation.sgml,v 1.268 2006/12/02 09:29:51 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/installation.sgml,v 1.269 2006/12/21 16:05:13 petere Exp $ -->
 
 <chapter id="installation">
  <title><![%standalone-include[<productname>PostgreSQL</>]]>
@@ -905,6 +905,15 @@ su - postgres
        </listitem>
       </varlistentry>
 
+      <varlistentry>
+       <term><option>--with-libxml</option></term>
+       <listitem>
+        <para>
+         Build with libxml, required for SQL/XML support.
+        </para>
+       </listitem>
+      </varlistentry>
+
       <varlistentry>
        <term><option>--enable-integer-datetimes</option></term>
        <listitem>
index 1dbef5f15c99628ea625028c801a1d2cb52b1d48..10b02b4a3ec92ded44c37d54e9294f8138a66941 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.199 2006/11/17 16:46:27 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.200 2006/12/21 16:05:13 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -52,6 +52,7 @@
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/typcache.h"
+#include "utils/xml.h"
 
 
 /* static function decls */
@@ -119,6 +120,8 @@ static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr,
 static Datum ExecEvalNullIf(FuncExprState *nullIfExpr,
                           ExprContext *econtext,
                           bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
+                                                bool *isNull, ExprDoneCond *isDone);
 static Datum ExecEvalNullTest(NullTestState *nstate,
                                 ExprContext *econtext,
                                 bool *isNull, ExprDoneCond *isDone);
@@ -2878,6 +2881,120 @@ ExecEvalBooleanTest(GenericExprState *bstate,
        }
 }
 
+/* ----------------------------------------------------------------
+ *             ExecEvalXml
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
+                       bool *isNull, ExprDoneCond *isDone)
+{
+       StringInfoData  buf;
+       bool                    isnull;
+       ListCell           *arg;
+       text               *result = NULL;
+       int                     len;
+
+       initStringInfo(&buf);
+
+       *isNull = false;
+
+       if (isDone)
+               *isDone = ExprSingleResult;
+
+       switch (xmlExpr->op)
+       {
+               case IS_XMLCONCAT:
+                       *isNull = true;
+
+                       foreach(arg, xmlExpr->args)
+                       {
+                               ExprState       *e = (ExprState *) lfirst(arg);
+                               Datum           value = ExecEvalExpr(e, econtext, &isnull, NULL);
+
+                               if (!isnull)
+                               {
+                                       appendStringInfoString(&buf, DatumGetCString(OidFunctionCall1(xmlExpr->arg_typeout, value)));
+                                       *isNull = false;
+                               }
+                       }
+                       break;
+
+               case IS_XMLELEMENT:
+                       {
+                               int state = 0, i = 0;
+                               appendStringInfo(&buf, "<%s", xmlExpr->name);
+                               foreach(arg, xmlExpr->named_args)
+                               {
+                                       GenericExprState *gstate = (GenericExprState *) lfirst(arg);
+                                       Datum value = ExecEvalExpr(gstate->arg, econtext, &isnull, NULL);
+                                       if (!isnull)
+                                       {
+                                               char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->named_args_tcache[i], value));
+                                               appendStringInfo(&buf, " %s=\"%s\"", xmlExpr->named_args_ncache[i], outstr);
+                                               pfree(outstr);
+                                       }
+                                       i++;
+                               }
+                               if (xmlExpr->args)
+                               {
+                                       ExprState       *expr = linitial(xmlExpr->args);
+                                       Datum           value = ExecEvalExpr(expr, econtext, &isnull, NULL);
+
+                                       if (!isnull)
+                                       {
+                                               char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->arg_typeout, value));
+                                               if (state == 0)
+                                               {
+                                                       appendStringInfoChar(&buf, '>');
+                                                       state = 1;
+                                               }
+                                               appendStringInfo(&buf, "%s", outstr);
+                                               pfree(outstr);
+                                       }
+                               }
+
+                               if (state == 0)
+                                       appendStringInfo(&buf, "/>");
+                               else if (state == 1)
+                                       appendStringInfo(&buf, "</%s>", xmlExpr->name);         
+
+                       }
+                       break;
+
+               case IS_XMLFOREST:
+                       {
+                               /* only if all argumets are null returns null */
+                               int i = 0; 
+                               *isNull = true;
+                               foreach(arg, xmlExpr->named_args)
+                               {
+                                       GenericExprState *gstate = (GenericExprState *) lfirst(arg);
+                                       Datum value = ExecEvalExpr(gstate->arg, econtext, &isnull, NULL);
+                                       if (!isnull)
+                                       {
+                                               char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->named_args_tcache[i], value));
+                                               appendStringInfo(&buf, "<%s>%s</%s>", xmlExpr->named_args_ncache[i], outstr, xmlExpr->named_args_ncache[i]);
+                                               pfree(outstr);
+                                               *isNull = false;
+                                       }
+                                       i += 1;
+                               }               
+                       }
+                       break;
+               default:
+                       break;
+       }
+
+       len = buf.len + VARHDRSZ;
+       result = palloc(len);
+       VARATT_SIZEP(result) = len;
+       memcpy(VARDATA(result), buf.data, buf.len);
+       pfree(buf.data);
+       PG_RETURN_TEXT_P(result);
+}
+
 /*
  * ExecEvalCoerceToDomain
  *
@@ -3668,6 +3785,64 @@ ExecInitExpr(Expr *node, PlanState *parent)
                                state = (ExprState *) mstate;
                        }
                        break;
+               case T_XmlExpr:
+                       {
+                               List                    *outlist; 
+                               ListCell                *arg;
+                               XmlExpr                 *xexpr = (XmlExpr *) node;
+                               XmlExprState    *xstate = makeNode(XmlExprState);
+                               int                             i = 0; 
+                               Oid                             typeout;
+               
+                               xstate->name = xexpr->name;
+                                                               
+                               xstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalXml;
+                               xstate->op = xexpr->op;
+                               
+                               outlist = NIL;
+                               if (xexpr->named_args)
+                               {
+                                       xstate->named_args_tcache = (Oid *) palloc(list_length(xexpr->named_args) * sizeof(int));
+                                       xstate->named_args_ncache = (char **) palloc(list_length(xexpr->named_args) * sizeof(char *));
+                                       
+                                       i = 0;
+                                       foreach(arg, xexpr->named_args)
+                                       {
+                                               bool            tpisvarlena;
+                                               Expr            *e = (Expr *) lfirst(arg);
+                                               ExprState       *estate = ExecInitExpr(e, parent);
+                                               TargetEntry     *tle;
+                                               outlist = lappend(outlist, estate);                                     
+                                               tle = (TargetEntry *) ((GenericExprState *) estate)->xprstate.expr;
+                                               getTypeOutputInfo(exprType((Node *)tle->expr), &typeout, &tpisvarlena);
+                                               xstate->named_args_ncache[i] = tle->resname;
+                                               xstate->named_args_tcache[i] = typeout;
+                                               i++;
+                                       }       
+                               }
+                               else
+                               {
+                                       xstate->named_args_tcache = NULL;
+                                       xstate->named_args_ncache = NULL;
+                               }
+                               xstate->named_args = outlist;
+
+                               outlist = NIL;                          
+                               foreach(arg, xexpr->args)
+                               {
+                                       bool            tpisvarlena;
+                                       ExprState       *estate;
+                                       Expr            *e = (Expr *) lfirst(arg);
+                                       getTypeOutputInfo(exprType((Node *)e), &typeout, &tpisvarlena);
+                                       estate = ExecInitExpr(e, parent);
+                                       outlist = lappend(outlist, estate);
+                               }
+                               xstate->arg_typeout = typeout;
+                               xstate->args = outlist;
+                               
+                               state = (ExprState *) xstate;
+                       }
+                       break;
                case T_NullIfExpr:
                        {
                                NullIfExpr *nullifexpr = (NullIfExpr *) node;
index 5047dc8ad7bc2979bc2f1b3fd97c7a99b80be9c5..3bb95b658d18c7afbb8e9a9e768790b71018f83d 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.354 2006/12/10 22:13:26 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.355 2006/12/21 16:05:13 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1136,6 +1136,22 @@ _copyBooleanTest(BooleanTest *from)
        return newnode;
 }
 
+/*
+ * _copyXmlExpr
+ */
+static XmlExpr *
+_copyXmlExpr(XmlExpr *from)
+{
+       XmlExpr *newnode = makeNode(XmlExpr);
+
+       COPY_SCALAR_FIELD(op);
+       COPY_STRING_FIELD(name);
+       COPY_NODE_FIELD(named_args);
+       COPY_NODE_FIELD(args);
+
+       return newnode;
+}
+
 /*
  * _copyCoerceToDomain
  */
@@ -2966,6 +2982,9 @@ copyObject(void *from)
                case T_BooleanTest:
                        retval = _copyBooleanTest(from);
                        break;
+               case T_XmlExpr:
+                       retval = _copyXmlExpr(from);
+                       break;
                case T_CoerceToDomain:
                        retval = _copyCoerceToDomain(from);
                        break;
index e341b74f3e6369505f59224e6cc750dbe25188aa..ef21e67fafb7966271d02c32c35795b797608daa 100644 (file)
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.288 2006/12/10 22:13:26 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.289 2006/12/21 16:05:13 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -495,6 +495,17 @@ _equalBooleanTest(BooleanTest *a, BooleanTest *b)
        return true;
 }
 
+static bool
+_equalXmlExpr(XmlExpr *a, XmlExpr *b)
+{
+       COMPARE_SCALAR_FIELD(op);
+       COMPARE_STRING_FIELD(name);
+       COMPARE_NODE_FIELD(named_args);
+       COMPARE_NODE_FIELD(args);
+
+       return true;
+}
+
 static bool
 _equalCoerceToDomain(CoerceToDomain *a, CoerceToDomain *b)
 {
@@ -1968,6 +1979,9 @@ equal(void *a, void *b)
                case T_BooleanTest:
                        retval = _equalBooleanTest(a, b);
                        break;
+               case T_XmlExpr:
+                       retval = _equalXmlExpr(a, b);
+                       break;
                case T_CoerceToDomain:
                        retval = _equalCoerceToDomain(a, b);
                        break;
index daeb3fe872d08fb756a0c6e6a02d758ff14e8bd7..5ddf60dbbb1ea1e8d6bcd8ad38626865086df6bd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.286 2006/12/10 22:13:26 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.287 2006/12/21 16:05:13 petere Exp $
  *
  * NOTES
  *       Every node type that can appear in stored rules' parsetrees *must*
@@ -920,6 +920,17 @@ _outBooleanTest(StringInfo str, BooleanTest *node)
        WRITE_ENUM_FIELD(booltesttype, BoolTestType);
 }
 
+static void
+_outXmlExpr(StringInfo str, XmlExpr *node)
+{
+       WRITE_NODE_TYPE("XMLEXPR");
+       
+       WRITE_ENUM_FIELD(op, XmlExprOp);
+       WRITE_STRING_FIELD(name);
+       WRITE_NODE_FIELD(named_args);
+       WRITE_NODE_FIELD(args);
+}
+
 static void
 _outCoerceToDomain(StringInfo str, CoerceToDomain *node)
 {
@@ -2019,6 +2030,9 @@ _outNode(StringInfo str, void *obj)
                        case T_BooleanTest:
                                _outBooleanTest(str, obj);
                                break;
+                       case T_XmlExpr:
+                               _outXmlExpr(str, obj);
+                               break;
                        case T_CoerceToDomain:
                                _outCoerceToDomain(str, obj);
                                break;
index df0a2170272ed696378334739dca0c02c534d756..689cef3edf25f175c6ed88657663b1610362168e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.196 2006/12/10 22:13:26 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.197 2006/12/21 16:05:13 petere Exp $
  *
  * NOTES
  *       Path and Plan nodes do not have any readfuncs support, because we
@@ -764,6 +764,22 @@ _readBooleanTest(void)
        READ_DONE();
 }
 
+/*
+ * _readXmlExpr
+ */
+static XmlExpr *
+_readXmlExpr(void)
+{
+       READ_LOCALS(XmlExpr);
+
+       READ_ENUM_FIELD(op, XmlExprOp);
+       READ_STRING_FIELD(name);
+       READ_NODE_FIELD(named_args);
+       READ_NODE_FIELD(args);
+
+       READ_DONE();
+}
+
 /*
  * _readCoerceToDomain
  */
@@ -1014,6 +1030,8 @@ parseNodeString(void)
                return_value = _readNullTest();
        else if (MATCH("BOOLEANTEST", 11))
                return_value = _readBooleanTest();
+       else if (MATCH("XMLEXPR", 7))
+               return_value = _readXmlExpr();
        else if (MATCH("COERCETODOMAIN", 14))
                return_value = _readCoerceToDomain();
        else if (MATCH("COERCETODOMAINVALUE", 19))
index 3800228398eaf826c40f81be134f6d2d46dc0871..73ad926418fb0c49ffc3f810fcc6ee1806437a5b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.223 2006/10/25 22:11:32 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.224 2006/12/21 16:05:13 petere Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -559,6 +559,8 @@ expression_returns_set_walker(Node *node, void *context)
                return false;
        if (IsA(node, NullIfExpr))
                return false;
+       if (IsA(node, XmlExpr))
+               return false;
 
        return expression_tree_walker(node, expression_returns_set_walker,
                                                                  context);
@@ -876,6 +878,8 @@ contain_nonstrict_functions_walker(Node *node, void *context)
                return true;
        if (IsA(node, BooleanTest))
                return true;
+       if (IsA(node, XmlExpr))
+               return true;
        return expression_tree_walker(node, contain_nonstrict_functions_walker,
                                                                  context);
 }
@@ -3334,6 +3338,16 @@ expression_tree_walker(Node *node,
                        return walker(((NullTest *) node)->arg, context);
                case T_BooleanTest:
                        return walker(((BooleanTest *) node)->arg, context);
+               case T_XmlExpr:
+                       {
+                               XmlExpr *xexpr = (XmlExpr *) node;
+                               
+                               if (walker(xexpr->named_args, context))
+                                       return true;
+                               if (walker(xexpr->args, context))
+                                       return true;
+                       }
+                       break;
                case T_CoerceToDomain:
                        return walker(((CoerceToDomain *) node)->arg, context);
                case T_TargetEntry:
@@ -3857,6 +3871,17 @@ expression_tree_mutator(Node *node,
                                return (Node *) newnode;
                        }
                        break;
+               case T_XmlExpr:
+                       {
+                               XmlExpr *xexpr = (XmlExpr *) node;
+                               XmlExpr *newnode;
+
+                               FLATCOPY(newnode, xexpr, XmlExpr);
+                               MUTATE(newnode->named_args, xexpr->named_args, List *);
+                               MUTATE(newnode->args, xexpr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
                case T_NullIfExpr:
                        {
                                NullIfExpr *expr = (NullIfExpr *) node;
index c90743a1017b7d33b31c02c782dac3f3791fb2da..cc400407363e660df5060a223cf8c1b27a8cf152 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.568 2006/11/05 22:42:09 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.569 2006/12/21 16:05:14 petere Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -106,6 +106,7 @@ static void insertSelectOptions(SelectStmt *stmt,
 static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
 static Node *doNegate(Node *n, int location);
 static void doNegateFloat(Value *v);
+static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args);
 
 %}
 
@@ -345,6 +346,11 @@ static void doNegateFloat(Value *v);
 %type <str>            OptTableSpace OptConsTableSpace OptTableSpaceOwner
 %type <list>   opt_check_option
 
+%type <target> xml_attribute_el
+%type <list>   xml_attribute_list xml_attributes
+%type <node>   xml_root_version
+%type <ival>   opt_xml_root_standalone document_or_content xml_whitespace_option
+
 
 /*
  * If you make any token changes, update the keyword table in
@@ -365,13 +371,13 @@ static void doNegateFloat(Value *v);
        CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
        CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
        COMMITTED CONCURRENTLY CONNECTION CONSTRAINT CONSTRAINTS
-       CONVERSION_P CONVERT COPY CREATE CREATEDB
+       CONTENT CONVERSION_P CONVERT COPY CREATE CREATEDB
        CREATEROLE CREATEUSER CROSS CSV CURRENT_DATE CURRENT_ROLE CURRENT_TIME
        CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
 
        DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
        DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS
-       DESC DISABLE_P DISTINCT DO DOMAIN_P DOUBLE_P DROP
+       DESC DISABLE_P DISTINCT DO DOCUMENT DOMAIN_P DOUBLE_P DROP
 
        EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
        EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
@@ -398,7 +404,7 @@ static void doNegateFloat(Value *v);
 
        MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
 
-       NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
+       NAME NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
        NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
        NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NUMERIC
 
@@ -417,8 +423,8 @@ static void doNegateFloat(Value *v);
 
        SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
        SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
-       SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT
-       STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SUPERUSER_P SYMMETRIC
+       SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE START STATEMENT
+       STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP SUBSTRING SUPERUSER_P SYMMETRIC
        SYSID SYSTEM_P
 
        TABLE TABLESPACE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP
@@ -428,12 +434,15 @@ static void doNegateFloat(Value *v);
        UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
        UPDATE USER USING
 
-       VACUUM VALID VALIDATOR VALUES VARCHAR VARYING
-       VERBOSE VIEW VOLATILE
+       VACUUM VALID VALIDATOR VALUE VALUES VARCHAR VARYING
+       VERBOSE VERSION VIEW VOLATILE
+
+       WHEN WHERE WHITESPACE WITH WITHOUT WORK WRITE
 
-       WHEN WHERE WITH WITHOUT WORK WRITE
+       XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
+       XMLPI XMLROOT XMLSERIALIZE
 
-       YEAR_P
+       YEAR_P YES
 
        ZONE
 
@@ -484,6 +493,7 @@ static void doNegateFloat(Value *v);
  * left-associativity among the JOIN rules themselves.
  */
 %left          JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
+%right         PRESERVE STRIP
 %%
 
 /*
@@ -7868,6 +7878,146 @@ func_expr:      func_name '(' ')'
                                        v->op = IS_LEAST;
                                        $$ = (Node *)v;
                                }
+                       | XMLCONCAT '(' expr_list ')'
+                               {               
+                                       $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NULL, $3);
+                               }
+                       | XMLELEMENT '(' NAME ColLabel ')'
+                               {
+                                       $$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, NULL);
+                               }
+                       | XMLELEMENT '(' NAME ColLabel ',' xml_attributes ')'
+                               {
+                                       $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NULL);
+                               }
+                       | XMLELEMENT '(' NAME ColLabel ',' expr_list ')'
+                               {
+                                       $$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, $6);
+                               }
+                       | XMLELEMENT '(' NAME ColLabel ',' xml_attributes ',' expr_list ')'
+                               {
+                                       $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8);
+                               }
+                       | XMLFOREST '(' xml_attribute_list ')'
+                               {
+                                       $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NULL);
+                               }
+                       | XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
+                               {
+                                       FuncCall *n = makeNode(FuncCall);
+                                       n->funcname = SystemFuncName("xmlparse");
+                                       n->args = list_make3(makeBoolAConst($3 == DOCUMENT), $4, makeBoolAConst($5 == PRESERVE));
+                                       n->agg_star = FALSE;
+                                       n->agg_distinct = FALSE;
+                                       n->location = @1;
+                                       $$ = (Node *)n;
+                               }
+                       | XMLPI '(' NAME ColLabel ')'
+                               {
+                                       FuncCall *n = makeNode(FuncCall);
+                                       n->funcname = SystemFuncName("xmlpi");
+                                       n->args = list_make1(makeStringConst($4, NULL));
+                                       n->agg_star = FALSE;
+                                       n->agg_distinct = FALSE;
+                                       n->location = @1;
+                                       $$ = (Node *)n;
+                               }
+                       | XMLPI '(' NAME ColLabel ',' a_expr ')'
+                               {
+                                       FuncCall *n = makeNode(FuncCall);
+                                       n->funcname = SystemFuncName("xmlpi");
+                                       n->args = list_make2(makeStringConst($4, NULL), $6);
+                                       n->agg_star = FALSE;
+                                       n->agg_distinct = FALSE;
+                                       n->location = @1;
+                                       $$ = (Node *)n;
+                               }
+                       | XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
+                               {
+                                       FuncCall *n = makeNode(FuncCall);
+                                       Node *ver;
+                                       A_Const *sa;
+
+                                       if ($5)
+                                               ver = $5;
+                                       else
+                                       {
+                                               A_Const *val;
+
+                                               val = makeNode(A_Const);
+                                               val->val.type = T_Null;
+                                               ver = (Node *) val;
+                                       }
+
+                                       if ($6)
+                                               sa = makeBoolAConst($6 == 1);
+                                       else
+                                       {
+                                               sa = makeNode(A_Const);
+                                               sa->val.type = T_Null;
+                                       }
+
+                                       n->funcname = SystemFuncName("xmlroot");
+                                       n->args = list_make3($3, ver, sa);
+                                       n->agg_star = FALSE;
+                                       n->agg_distinct = FALSE;
+                                       n->location = @1;
+                                       $$ = (Node *)n;
+                               }
+                       | XMLSERIALIZE '(' document_or_content a_expr AS Typename ')'
+                               {
+                                       /*
+                                        * FIXME: This should be made distinguishable from
+                                        * CAST (for reverse compilation at least).
+                                        */
+                                       $$ = makeTypeCast($4, $6);
+                               }
+               ;
+
+/*
+ * SQL/XML support
+ */
+xml_root_version: VERSION a_expr       { $$ = $2; }
+                       | VERSION NO VALUE              { $$ = NULL; }
+               ;
+
+opt_xml_root_standalone: ',' STANDALONE YES    { $$ = 1; }
+                       | ',' STANDALONE NO                             { $$ = -1; }
+                       | ',' STANDALONE NO VALUE               { $$ = 0; }
+                       | /*EMPTY*/                                             { $$ = 0; }
+               ;
+
+xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; }
+               ;
+
+xml_attribute_list:    xml_attribute_el                                        { $$ = list_make1($1); }
+                       | xml_attribute_list ',' xml_attribute_el       { $$ = lappend($1, $3); }
+               ;
+
+xml_attribute_el: a_expr AS ColLabel
+                               {
+                                       $$ = makeNode(ResTarget);
+                                       $$->name = $3;
+                                       $$->indirection = NULL;
+                                       $$->val = (Node *) $1;
+
+                               }
+                       | a_expr
+                               {
+                                       $$ = makeNode(ResTarget);
+                                       $$->name = NULL;
+                                       $$->indirection = NULL;
+                                       $$->val = (Node *) $1;                          
+                               }
+               ;
+
+document_or_content: DOCUMENT { $$ = DOCUMENT; }
+                       | CONTENT { $$ = CONTENT; }
+               ;
+
+xml_whitespace_option: PRESERVE WHITESPACE { $$ = PRESERVE; }
+                       | STRIP WHITESPACE { $$ = STRIP; }
+                       | /*EMPTY*/ { $$ = STRIP; }
                ;
 
 /*
@@ -8562,6 +8712,7 @@ unreserved_keyword:
                        | CONCURRENTLY
                        | CONNECTION
                        | CONSTRAINTS
+                       | CONTENT
                        | CONVERSION_P
                        | COPY
                        | CREATEDB
@@ -8581,6 +8732,7 @@ unreserved_keyword:
                        | DELIMITER
                        | DELIMITERS
                        | DISABLE_P
+                       | DOCUMENT
                        | DOMAIN_P
                        | DOUBLE_P
                        | DROP
@@ -8640,6 +8792,7 @@ unreserved_keyword:
                        | MODE
                        | MONTH_P
                        | MOVE
+                       | NAME
                        | NAMES
                        | NEXT
                        | NO
@@ -8700,12 +8853,14 @@ unreserved_keyword:
                        | SHOW
                        | SIMPLE
                        | STABLE
+                       | STANDALONE
                        | START
                        | STATEMENT
                        | STATISTICS
                        | STDIN
                        | STDOUT
                        | STORAGE
+                       | STRIP
                        | SUPERUSER_P
                        | SYSID
                        | SYSTEM_P
@@ -8729,13 +8884,17 @@ unreserved_keyword:
                        | VALID
                        | VALIDATOR
                        | VARYING
+                       | VERSION
                        | VIEW
+                       | VALUE
                        | VOLATILE
+                       | WHITESPACE
                        | WITH
                        | WITHOUT
                        | WORK
                        | WRITE
                        | YEAR_P
+                       | YES
                        | ZONE
                ;
 
@@ -8788,6 +8947,14 @@ col_name_keyword:
                        | TRIM
                        | VALUES
                        | VARCHAR
+                       | XMLATTRIBUTES
+                       | XMLELEMENT
+                       | XMLCONCAT
+                       | XMLFOREST
+                       | XMLPARSE
+                       | XMLPI
+                       | XMLROOT
+                       | XMLSERIALIZE
                ;
 
 /* Function identifier --- keywords that can be function names.
@@ -9322,6 +9489,17 @@ doNegateFloat(Value *v)
        }
 }
 
+static Node *
+makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
+{
+       XmlExpr *x = makeNode(XmlExpr);
+       x->op = op;
+       x->name = name;
+       x->named_args = named_args;
+       x->args = args;
+       return (Node *) x;
+}
+
 /*
  * Must undefine base_yylex before including scan.c, since we want it
  * to create the function base_yylex not filtered_base_yylex.
index 50fd3aac4054f4277ac04f9462377a93fc8930cf..b5e49e955fc1e30173731bff1f457b0a30e8e6e7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.177 2006/10/07 21:51:02 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.178 2006/12/21 16:05:14 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -89,6 +89,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"connection", CONNECTION},
        {"constraint", CONSTRAINT},
        {"constraints", CONSTRAINTS},
+       {"content", CONTENT},
        {"conversion", CONVERSION_P},
        {"convert", CONVERT},
        {"copy", COPY},
@@ -123,6 +124,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"disable", DISABLE_P},
        {"distinct", DISTINCT},
        {"do", DO},
+       {"document", DOCUMENT},
        {"domain", DOMAIN_P},
        {"double", DOUBLE_P},
        {"drop", DROP},
@@ -218,6 +220,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"mode", MODE},
        {"month", MONTH_P},
        {"move", MOVE},
+       {"name", NAME},
        {"names", NAMES},
        {"national", NATIONAL},
        {"natural", NATURAL},
@@ -314,6 +317,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"smallint", SMALLINT},
        {"some", SOME},
        {"stable", STABLE},
+       {"standalone", STANDALONE},
        {"start", START},
        {"statement", STATEMENT},
        {"statistics", STATISTICS},
@@ -321,6 +325,7 @@ static const ScanKeyword ScanKeywords[] = {
        {"stdout", STDOUT},
        {"storage", STORAGE},
        {"strict", STRICT_P},
+       {"strip", STRIP},
        {"substring", SUBSTRING},
        {"superuser", SUPERUSER_P},
        {"symmetric", SYMMETRIC},
@@ -357,19 +362,31 @@ static const ScanKeyword ScanKeywords[] = {
        {"vacuum", VACUUM},
        {"valid", VALID},
        {"validator", VALIDATOR},
+       {"value", VALUE},
        {"values", VALUES},
        {"varchar", VARCHAR},
        {"varying", VARYING},
        {"verbose", VERBOSE},
+       {"version", VERSION},
        {"view", VIEW},
        {"volatile", VOLATILE},
        {"when", WHEN},
        {"where", WHERE},
+       {"whitespace", WHITESPACE},
        {"with", WITH},
        {"without", WITHOUT},
        {"work", WORK},
        {"write", WRITE},
+       {"xmlattributes", XMLATTRIBUTES},
+       {"xmlconcat", XMLCONCAT},
+       {"xmlelement", XMLELEMENT},
+       {"xmlforest", XMLFOREST},
+       {"xmlparse", XMLPARSE},
+       {"xmlpi", XMLPI},
+       {"xmlroot", XMLROOT},
+       {"xmlserialize", XMLSERIALIZE},
        {"year", YEAR_P},
+       {"yes", YES},
        {"zone", ZONE},
 };
 
index 2a468c682712c3d354f85b070755802af601723d..5670ed4fe742188c1b00a03f57340b95a4881edd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.147 2006/12/10 22:13:26 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.148 2006/12/21 16:05:14 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -919,6 +919,46 @@ coerce_to_bigint(ParseState *pstate, Node *node,
        return node;
 }
 
+/*
+ * coerce_to_xml()
+ *             Coerce an argument of a construct that requires xml input.
+ *             Also check that input is not a set.
+ *
+ * Returns the possibly-transformed node tree.
+ *
+ * As with coerce_type, pstate may be NULL if no special unknown-Param
+ * processing is wanted.
+ */
+Node *
+coerce_to_xml(ParseState *pstate, Node *node,
+                                const char *constructName)
+{
+       Oid                     inputTypeId = exprType(node);
+
+       if (inputTypeId != XMLOID)
+       {
+               node = coerce_to_target_type(pstate, node, inputTypeId,
+                                                                        XMLOID, -1,
+                                                                        COERCION_ASSIGNMENT,
+                                                                        COERCE_IMPLICIT_CAST);
+               if (node == NULL)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_DATATYPE_MISMATCH),
+                       /* translator: first %s is name of a SQL construct, eg LIMIT */
+                                        errmsg("argument of %s must be type xml, not type %s",
+                                                       constructName, format_type_be(inputTypeId))));
+       }
+
+       if (expression_returns_set(node))
+               ereport(ERROR,
+                               (errcode(ERRCODE_DATATYPE_MISMATCH),
+               /* translator: %s is name of a SQL construct, eg LIMIT */
+                                errmsg("argument of %s must not return a set",
+                                               constructName)));
+
+       return node;
+}
+
 
 /* select_common_type()
  *             Determine the common supertype of a list of input expression types.
index b1b6ea81456a9babde1f6ecd2808147aeaaf57be..234a15b6afbdc6073957b1a7635beba30f9fc899 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.199 2006/12/10 22:13:26 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.200 2006/12/21 16:05:14 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,6 +33,7 @@
 #include "parser/parse_type.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
+#include "utils/xml.h"
 
 
 bool           Transform_null_equals = false;
@@ -55,6 +56,7 @@ static Node *transformArrayExpr(ParseState *pstate, ArrayExpr *a);
 static Node *transformRowExpr(ParseState *pstate, RowExpr *r);
 static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
 static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
+static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x);
 static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
 static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
 static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
@@ -232,6 +234,10 @@ transformExpr(ParseState *pstate, Node *expr)
                        result = transformBooleanTest(pstate, (BooleanTest *) expr);
                        break;
 
+               case T_XmlExpr:
+                       result = transformXmlExpr(pstate, (XmlExpr *) expr);
+                       break;
+
                        /*********************************************
                         * Quietly accept node types that may be presented when we are
                         * called on an already-transformed tree.
@@ -1409,6 +1415,56 @@ transformBooleanTest(ParseState *pstate, BooleanTest *b)
        return (Node *) b;
 }
 
+static Node *
+transformXmlExpr(ParseState *pstate, XmlExpr *x)
+{
+       ListCell        *lc;
+       XmlExpr *newx = makeNode(XmlExpr);
+
+       newx->op = x->op;
+       if (x->name)
+               newx->name = map_sql_identifier_to_xml_name(x->name, false);
+       else
+               newx->name = NULL;
+
+       foreach(lc, x->named_args)
+       {
+               ResTarget       *r = (ResTarget *) lfirst(lc);
+               Node            *expr = transformExpr(pstate, r->val);
+               char            *argname = NULL;
+
+               if (r->name)
+                       argname = map_sql_identifier_to_xml_name(r->name, false);
+               else if (IsA(r->val, ColumnRef))
+                       argname = map_sql_identifier_to_xml_name(FigureColname(r->val), true);
+               else
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_SYNTAX_ERROR),
+                                        x->op == IS_XMLELEMENT
+                                        ? errmsg("unnamed attribute value must be a column reference")
+                                        : errmsg("unnamed element value must be a column reference")));
+
+               newx->named_args = lappend(newx->named_args, 
+                                                                  makeTargetEntry((Expr *) expr, 0, argname, false)); 
+       }
+
+       foreach(lc, x->args)
+       {
+               Node       *e = (Node *) lfirst(lc);
+               Node       *newe;
+
+               newe = coerce_to_xml(pstate, transformExpr(pstate, e),
+                                                        (x->op == IS_XMLCONCAT 
+                                                         ? "XMLCONCAT"
+                                                         : (x->op == IS_XMLELEMENT
+                                                                ? "XMLELEMENT"
+                                                                : "XMLFOREST")));
+               newx->args = lappend(newx->args, newe);
+       }
+               
+       return (Node *) newx;
+}
+
 /*
  * Construct a whole-row reference to represent the notation "relation.*".
  *
@@ -1668,6 +1724,9 @@ exprType(Node *expr)
                case T_BooleanTest:
                        type = BOOLOID;
                        break;
+               case T_XmlExpr:
+                       type = XMLOID;
+                       break;
                case T_CoerceToDomain:
                        type = ((CoerceToDomain *) expr)->resulttype;
                        break;
index bb4b065eebb43d9685b26cd72200f34fa6e6156d..906d96e45c6c6f069476dae44952c5236819a0b5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.149 2006/10/04 00:29:56 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.150 2006/12/21 16:05:14 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1315,6 +1315,21 @@ FigureColnameInternal(Node *node, char **name)
                                        return 2;
                        }
                        break;
+               case T_XmlExpr:
+                       /* make SQL/XML functions act like a regular function */
+                       switch (((XmlExpr*) node)->op)
+                       {               
+                               case IS_XMLCONCAT:
+                                       *name = "xmlconcat";
+                                       return 2;
+                               case IS_XMLELEMENT:
+                                       *name = "xmlelement";
+                                       return 2;
+                               case IS_XMLFOREST:
+                                       *name = "xmlforest";
+                                       return 2;
+                       } 
+                       break;
                default:
                        break;
        }
index 5a1996c3439461cece6b6f06df8c21c85a5c9c38..11a03f318570699bef20b0d063a0a2bf51f9c10c 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Makefile for utils/adt
 #
-# $PostgreSQL: pgsql/src/backend/utils/adt/Makefile,v 1.60 2006/04/05 22:11:55 tgl Exp $
+# $PostgreSQL: pgsql/src/backend/utils/adt/Makefile,v 1.61 2006/12/21 16:05:15 petere Exp $
 #
 
 subdir = src/backend/utils/adt
@@ -25,7 +25,7 @@ OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \
        tid.o timestamp.o varbit.o varchar.o varlena.o version.o xid.o \
        network.o mac.o inet_net_ntop.o inet_net_pton.o \
        ri_triggers.o pg_lzcompress.o pg_locale.o formatting.o \
-       ascii.o quote.o pgstatfuncs.o encode.o dbsize.o genfile.o
+       ascii.o quote.o pgstatfuncs.o encode.o dbsize.o genfile.o xml.o
 
 like.o: like.c like_match.c
 
index 9d9404bde4c481cd68fe4858ab30cc6ddb5f7e09..a99942010b66a8c46ca404856c23283c12e253b6 100644 (file)
@@ -2,7 +2,7 @@
  * ruleutils.c - Functions to convert stored expressions/querytrees
  *                             back to source text
  *
- *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.235 2006/11/10 22:59:29 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.236 2006/12/21 16:05:15 petere Exp $
  **********************************************************************/
 
 #include "postgres.h"
@@ -2988,6 +2988,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
                case T_CoalesceExpr:
                case T_MinMaxExpr:
                case T_NullIfExpr:
+               case T_XmlExpr:
                case T_Aggref:
                case T_FuncExpr:
                        /* function-like: name(..) or name[..] */
@@ -3096,6 +3097,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
                                case T_CoalesceExpr:    /* own parentheses */
                                case T_MinMaxExpr:              /* own parentheses */
                                case T_NullIfExpr:              /* other separators */
+                               case T_XmlExpr:                 /* own parentheses */
                                case T_Aggref:  /* own parentheses */
                                case T_CaseExpr:                /* other separators */
                                        return true;
@@ -3144,6 +3146,7 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
                                case T_CoalesceExpr:    /* own parentheses */
                                case T_MinMaxExpr:              /* own parentheses */
                                case T_NullIfExpr:              /* other separators */
+                               case T_XmlExpr:                 /* own parentheses */
                                case T_Aggref:  /* own parentheses */
                                case T_CaseExpr:                /* other separators */
                                        return true;
@@ -3845,6 +3848,28 @@ get_rule_expr(Node *node, deparse_context *context,
                        }
                        break;
 
+               case T_XmlExpr:
+                       {
+                               XmlExpr *xexpr = (XmlExpr *) node;
+
+                               switch (xexpr->op)
+                               {
+                                       case IS_XMLCONCAT:
+                                               appendStringInfo(buf, "XMLCONCAT(");
+                                               break;
+                                       case IS_XMLELEMENT:
+                                               appendStringInfo(buf, "XMLELEMENT(");
+                                               break;
+                                       case IS_XMLFOREST:
+                                               appendStringInfo(buf, "XMLFOREST(");
+                                               break;
+                               }
+                               get_rule_expr((Node *) xexpr->named_args, context, true);
+                               get_rule_expr((Node *) xexpr->args, context, true);
+                               appendStringInfoChar(buf, ')');
+                       }
+                       break;
+
                case T_CoerceToDomain:
                        {
                                CoerceToDomain *ctest = (CoerceToDomain *) node;
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
new file mode 100644 (file)
index 0000000..8997730
--- /dev/null
@@ -0,0 +1,942 @@
+/*-------------------------------------------------------------------------
+ *
+ * xml.c
+ *       XML data type support.
+ *
+ *
+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.1 2006/12/21 16:05:15 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+/*
+ * Generally, XML type support is only available when libxml use was
+ * configured during the build.  But even if that is not done, the
+ * type and all the functions are available, but most of them will
+ * fail.  For one thing, this avoids having to manage variant catalog
+ * installations.  But it also has nice effects such as that you can
+ * dump a database containing XML type data even if the server is not
+ * linked with libxml.
+ */
+
+#include "postgres.h"
+
+#ifdef USE_LIBXML
+#include <libxml/chvalid.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/uri.h>
+#include <libxml/xmlerror.h>
+#endif /* USE_LIBXML */
+
+#include "fmgr.h"
+#include "mb/pg_wchar.h"
+#include "nodes/execnodes.h"
+#include "utils/builtins.h"
+#include "utils/xml.h"
+
+
+#ifdef USE_LIBXML
+
+/*
+ * A couple of useful macros (similar to ones from libxml/parse.c)
+ */
+#define CMP4( s, c1, c2, c3, c4 ) \
+  ( ((unsigned char *) s)[ 0 ] == c1 && ((unsigned char *) s)[ 1 ] == c2 && \
+    ((unsigned char *) s)[ 2 ] == c3 && ((unsigned char *) s)[ 3 ] == c4 )
+#define CMP5( s, c1, c2, c3, c4, c5 ) \
+  ( CMP4( s, c1, c2, c3, c4 ) && ((unsigned char *) s)[ 4 ] == c5 )
+
+#define PG_XML_DEFAULT_URI "dummy.xml"
+#define XML_ERRBUF_SIZE 200
+
+
+static void    xml_init(void);
+static void    *xml_palloc(size_t size);
+static void    *xml_repalloc(void *ptr, size_t size);
+static void    xml_pfree(void *ptr);
+static char    *xml_pstrdup(const char *string);
+static void    xml_ereport(int level, char *msg, void *ctxt);
+static void    xml_errorHandler(void *ctxt, const char *msg, ...);
+static void    xml_ereport_by_code(int level, char *msg, int errcode);
+static xmlChar *xml_text2xmlChar(text *in);
+static xmlDocPtr xml_parse(text *data, int opts, bool is_document);
+
+
+/* Global variables */
+/* taken from contrib/xml2 */
+/* FIXME: DO NOT USE global vars !!! */
+char      *xml_errbuf;                         /* per line error buffer */
+char      *xml_errmsg = NULL;          /* overall error message */
+
+#endif /* USE_LIBXML */
+
+
+#define NO_XML_SUPPORT() ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("no XML support in this installation")))
+
+
+Datum
+xml_in(PG_FUNCTION_ARGS)
+{
+#ifdef USE_LIBXML
+       char            *s = PG_GETARG_CSTRING(0);
+       size_t          len;
+       xmltype         *vardata;
+
+       len = strlen(s);
+       vardata = palloc(len + VARHDRSZ);
+       VARATT_SIZEP(vardata) = len + VARHDRSZ;
+       memcpy(VARDATA(vardata), s, len);
+
+       /*
+        * Parse the data to check if it is well-formed XML data.  Assume
+        * that ERROR occurred if parsing failed.  Do we need DTD
+        * validation (if DTD exists)?
+        */
+       xml_parse(vardata, XML_PARSE_DTDATTR | XML_PARSE_DTDVALID, false);
+
+       PG_RETURN_XML_P(vardata);
+#else
+       NO_XML_SUPPORT();
+       return 0;
+#endif
+}
+
+
+Datum
+xml_out(PG_FUNCTION_ARGS)
+{
+       xmltype         *s = PG_GETARG_XML_P(0);
+       char            *result;
+       int32           len;
+       
+       len = VARSIZE(s) - VARHDRSZ;
+       result = palloc(len + 1);
+       memcpy(result, VARDATA(s), len);
+       result[len] = '\0';
+       
+       PG_RETURN_CSTRING(result);
+}
+
+
+#ifdef USE_LIBXML
+static void
+appendStringInfoText(StringInfo str, const text *t)
+{
+       appendBinaryStringInfo(str, VARDATA(t), VARSIZE(t) - VARHDRSZ);
+}
+
+
+static xmltype *
+stringinfo_to_xmltype(StringInfo buf)
+{
+       int32 len;
+       xmltype *result;
+
+       len = buf->len + VARHDRSZ;
+       result = palloc(len);
+       VARATT_SIZEP(result) = len;
+       memcpy(VARDATA(result), buf->data, buf->len);
+
+       return result;
+}
+#endif
+
+
+Datum
+xmlcomment(PG_FUNCTION_ARGS)
+{
+#ifdef USE_LIBXML
+       text *arg = PG_GETARG_TEXT_P(0);
+       int len =  VARATT_SIZEP(arg) - VARHDRSZ;
+       StringInfoData buf;
+       int i;
+
+       /* check for "--" in string or "-" at the end */
+       for (i = 1; i < len; i++)
+               if ((VARDATA(arg)[i] == '-' && VARDATA(arg)[i - 1] == '-')
+                       || (VARDATA(arg)[i] == '-' && i == len - 1))
+                                       ereport(ERROR,
+                                                       (errcode(ERRCODE_INVALID_XML_COMMENT),
+                                                        errmsg("invalid XML comment")));
+
+       initStringInfo(&buf);
+       appendStringInfo(&buf, "<!--");
+       appendStringInfoText(&buf, arg);
+       appendStringInfo(&buf, "-->");
+
+       PG_RETURN_XML_P(stringinfo_to_xmltype(&buf));
+#else
+       NO_XML_SUPPORT();
+       return 0;
+#endif
+}
+
+
+Datum
+xmlparse(PG_FUNCTION_ARGS)
+{
+#ifdef USE_LIBXML
+       text       *data;
+       bool            is_document;
+       bool            preserve_whitespace;
+
+       data = PG_GETARG_TEXT_P(0);
+
+       if (PG_NARGS() >= 2)
+               is_document = PG_GETARG_BOOL(1);
+       else
+               is_document = false;
+
+       if (PG_NARGS() >= 3)
+               preserve_whitespace = PG_GETARG_BOOL(2);
+       else
+               /*
+                * Since the XMLPARSE grammar makes STRIP WHITESPACE the
+                * default, this argument should really default to false.  But
+                * until we have actually implemented whitespace stripping,
+                * this would be annoying.
+                */
+               preserve_whitespace = true;
+
+       if (!preserve_whitespace)
+               ereport(WARNING,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("XMLPARSE with STRIP WHITESPACE is not implemented")));
+
+       /*
+        * Note, that here we try to apply DTD defaults
+        * (XML_PARSE_DTDATTR) according to SQL/XML:10.16.7.d: 'Default
+        * valies defined by internal DTD are applied'.  As for external
+        * DTDs, we try to support them too, (see SQL/XML:10.16.7.e)
+        */
+       xml_parse(data, XML_PARSE_DTDATTR, is_document); /* assume that ERROR occurred if parsing failed */
+
+       PG_RETURN_XML_P(data);
+#else
+       NO_XML_SUPPORT();
+       return 0;
+#endif
+}
+
+
+Datum
+xmlpi(PG_FUNCTION_ARGS)
+{
+#ifdef USE_LIBXML
+       char       *target = NameStr(*PG_GETARG_NAME(0));
+       StringInfoData buf;
+
+       if (strlen(target) >= 3
+               && (target[0] == 'x' || target[0] == 'X')
+               && (target[1] == 'm' || target[1] == 'M')
+               && (target[2] == 'l' || target[2] == 'L'))
+       {
+               ereport(ERROR,
+                               (errcode(ERRCODE_SYNTAX_ERROR),
+                                errmsg("invalid XML processing instruction"),
+                                errdetail("XML processing instruction target name cannot start with \"xml\".")));
+       }
+
+       initStringInfo(&buf);
+
+       appendStringInfo(&buf, "<?");
+       appendStringInfoString(&buf, map_sql_identifier_to_xml_name(target, false));
+       if (PG_NARGS() > 1)
+       {
+               text *arg = PG_GETARG_TEXT_P(1);
+               char *string;
+
+               string = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(arg)));
+               if (strstr(string, "?>"))
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
+                                errmsg("invalid XML processing instruction"),
+                                errdetail("XML processing instruction cannot contain \"?>\".")));
+
+               appendStringInfoString(&buf, " ");
+               appendStringInfoString(&buf, string);
+       }
+       appendStringInfoString(&buf, "?>");
+
+       PG_RETURN_XML_P(stringinfo_to_xmltype(&buf));
+#else
+       NO_XML_SUPPORT();
+       return 0;
+#endif
+}
+
+
+Datum
+xmlroot(PG_FUNCTION_ARGS)
+{
+#ifdef USE_LIBXML
+       xmltype    *data;
+       text       *version;
+       int                     standalone;
+       StringInfoData buf;
+
+       if (PG_ARGISNULL(0))
+               PG_RETURN_NULL();
+       else
+               data = PG_GETARG_XML_P(0);
+
+       if (PG_ARGISNULL(1))
+               version = NULL;
+       else
+               version = PG_GETARG_TEXT_P(1);
+
+       if (PG_ARGISNULL(2))
+               standalone = 0;
+       else
+       {
+               bool tmp = PG_GETARG_BOOL(2);
+               standalone = (tmp ? 1 : -1);
+       }
+
+       /*
+        * FIXME: This is probably supposed to be cleverer if there
+        * already is an XML preamble.
+        */
+       initStringInfo(&buf);
+
+       appendStringInfo(&buf,"<?xml");
+       if (version) {
+               appendStringInfo(&buf, " version=\"");
+               appendStringInfoText(&buf, version);
+               appendStringInfo(&buf, "\"");
+       }
+       if (standalone)
+               appendStringInfo(&buf, " standalone=\"%s\"", (standalone == 1 ? "yes" : "no"));
+       appendStringInfo(&buf, "?>");
+       appendStringInfoText(&buf, (text *) data);
+
+       PG_RETURN_XML_P(stringinfo_to_xmltype(&buf));
+#else
+       NO_XML_SUPPORT();
+       return 0;
+#endif
+}
+
+
+/*
+ * Validate document (given as string) against DTD (given as external link)
+ * TODO !!! use text instead of cstring for second arg
+ * TODO allow passing DTD as a string value (not only as an URI)
+ * TODO redesign (see comment with '!!!' below)
+ */
+Datum
+xmlvalidate(PG_FUNCTION_ARGS)
+{
+#ifdef USE_LIBXML
+       text                            *data = PG_GETARG_TEXT_P(0);
+       text                            *dtdOrUri = PG_GETARG_TEXT_P(1);
+       bool                            result = FALSE;
+       xmlParserCtxtPtr        ctxt; /* the parser context */
+       xmlDocPtr                       doc; /* the resulting document tree */
+       xmlDtdPtr                       dtd;
+
+       xml_init();
+
+       ctxt = xmlNewParserCtxt();
+       if (ctxt == NULL)
+               xml_ereport(ERROR, "could not allocate parser context", ctxt);
+       doc = xmlCtxtReadMemory(ctxt, (char *) VARDATA(data), 
+                                                       VARSIZE(data) - VARHDRSZ, PG_XML_DEFAULT_URI, NULL, 0);
+       if (doc == NULL)
+               xml_ereport(ERROR, "could not parse XML data", ctxt);
+
+#if 0
+       uri = xmlCreateURI();
+       ereport(NOTICE, (errcode(0),errmsg(" dtd - %s", dtdOrUri)));
+       dtd = palloc(sizeof(xmlDtdPtr));
+       uri = xmlParseURI(dtdOrUri);
+       if (uri == NULL)
+               xml_ereport(ERROR, "not implemented yet... (TODO)", ctxt);
+       else
+#endif
+               dtd = xmlParseDTD(NULL, xml_text2xmlChar(dtdOrUri));
+
+       if (dtd == NULL)
+       {
+#if 0
+               xmlFreeDoc(doc);
+               xmlFreeParserCtxt(ctxt);
+#endif
+               xml_ereport(ERROR, "could not load DTD", ctxt);
+       }
+
+       if (xmlValidateDtd(xmlNewValidCtxt(), doc, dtd) == 1)
+               result = TRUE;
+       
+#if 0
+       xmlFreeURI(uri);
+       xmlFreeDtd(dtd);
+       xmlFreeDoc(doc);
+       xmlFreeParserCtxt(ctxt);
+       xmlCleanupParser();
+#endif
+       
+       if (!result)
+               xml_ereport(NOTICE, "validation against DTD failed", ctxt);
+
+       PG_RETURN_BOOL(result);
+#else /* not USE_LIBXML */
+       NO_XML_SUPPORT();
+       return 0;
+#endif /* not USE_LIBXML */
+}
+
+
+#ifdef USE_LIBXML
+
+/*
+ * Container for some init stuff (not good design!)
+ * TODO xmlChar is utf8-char, make proper tuning (initdb with enc!=utf8 and check)
+ */
+static void
+xml_init(void)
+{
+       /*
+        * Currently, we have no pure UTF-8 support for internals -- check
+        * if we can work.
+        */
+       if (sizeof (char) != sizeof (xmlChar))
+               ereport(ERROR, 
+                               (errmsg("cannot initialize XML library"),
+                                errdetail("libxml2 has incompatible char type: sizeof(char)=%u, sizeof(xmlChar)=%u.", 
+                                                  sizeof(char), sizeof(xmlChar))));
+       
+       xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup);
+       xmlInitParser();
+       LIBXML_TEST_VERSION;
+       /* do not flood PG's logfile with libxml error messages - reset error handler*/ 
+       xmlSetGenericErrorFunc(NULL, xml_errorHandler);
+       xml_errmsg = NULL;
+       xml_errbuf = palloc(XML_ERRBUF_SIZE);
+       memset(xml_errbuf, 0, XML_ERRBUF_SIZE);
+}
+
+
+/*
+ * Convert a C string to XML internal representation
+ * (same things as for TEXT, but with checking the data for well-formedness
+ * and, moreover, validation against DTD, if needed).
+ * NOTICE: We use TEXT type as internal storage type. In the future,
+ * we plan to create own storage type (maybe several types/strategies)
+ * TODO predefined DTDs / XSDs and validation
+ * TODO validation against XML Schema
+ * TODO maybe, libxml2's xmlreader is better? (do not construct DOM, yet do not use SAX - see xml_reader.c)
+ * TODO what about internal URI for docs? (see PG_XML_DEFAULT_URI below)
+ */
+static xmlDocPtr
+xml_parse(text *data, int opts, bool is_document)
+{
+       bool                            validationFailed = FALSE;
+       xmlParserCtxtPtr        ctxt; /* the parser context */
+       xmlDocPtr                       doc; /* the resulting document tree */
+       int                                     res_code;
+       int32                           len;
+       xmlChar                         *string;
+#ifdef XML_DEBUG_DTD_CONST
+       xmlDtdPtr                       dtd; /* pointer to DTD */
+#endif
+
+       xml_init();
+       
+       len = VARSIZE(data) - VARHDRSZ; /* will be useful later */
+       string = xml_text2xmlChar(data);
+       
+       ctxt = xmlNewParserCtxt();
+       if (ctxt == NULL)
+               xml_ereport(ERROR, "could not allocate parser context", ctxt);
+       
+       /* first, we try to parse the string as it is XML doc, then, as XML chunk */
+       ereport(DEBUG3, (errmsg("string to parse: %s", string)));
+       if (len > 4 && CMP5(string, '<', '?', 'x', 'm', 'l'))
+       {
+               /* consider it as DOCUMENT */
+               doc = xmlCtxtReadMemory(ctxt, string, len, PG_XML_DEFAULT_URI, NULL, opts);
+               if (doc == NULL)
+               {
+                       xml_ereport(ERROR, "could not parse XML data", ctxt);
+#if 0
+                       xmlFreeParserCtxt(ctxt);
+                       xmlCleanupParser();
+                       ereport(ERROR, (errmsg("could not parse XML data")));
+#endif
+               }
+       }
+       else
+       {
+               /* attempt to parse the string as if it is an XML fragment */
+               ereport(DEBUG3, (errmsg("the string is not an XML doc, trying to parse as a CHUNK")));
+               doc = xmlNewDoc(NULL);
+               /* TODO resolve: xmlParseBalancedChunkMemory assumes that string is UTF8 encoded! */
+               res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, string, NULL);
+               if (res_code != 0)
+               {
+                       xmlFreeParserCtxt(ctxt);
+                       xmlCleanupParser();
+                       xml_ereport_by_code(ERROR, "could not parse XML data", res_code);
+               }
+       }
+
+#ifdef XML_DEBUG_DTD_CONST
+       dtd = xmlParseDTD(NULL, (xmlChar *) XML_DEBUG_DTD_CONST);
+       xml_ereport(DEBUG3, "solid path to DTD was defined for debugging purposes", ctxt);
+       if (dtd == NULL)
+       {
+               xml_ereport(ERROR, "could not parse DTD data", ctxt);
+       }
+       else
+#else
+       /* if dtd for our xml data is detected... */
+       if ((doc->intSubset != NULL) || (doc->extSubset != NULL))
+#endif
+       {
+               /* assume that inline DTD exists - validation should be performed */
+#ifdef XML_DEBUG_DTD_CONST
+               if (xmlValidateDtd(xmlNewValidCtxt(), doc, dtd) != 1)
+#else
+               if (ctxt->valid == 0)
+#endif
+               {
+                       /* DTD exists, but validator reported 'validation failed' */
+                       validationFailed = TRUE;
+               }
+       }
+       
+       if (validationFailed)
+               xml_ereport(WARNING, "validation against DTD failed", ctxt);
+       
+       /* TODO encoding issues 
+        * (thoughts:
+        *              CASE:
+        *              - XML data has explicit encoding attribute in its prolog
+        *              - if not, assume that enc. of XML data is the same as client's one
+        * 
+        *              The common rule is to accept the XML data only if its encoding
+        *              is the same as encoding of the storage (server's). The other possible
+        *              option is to accept all the docs, but DO TRANSFORMATION and, if needed,
+        *              change the prolog.
+        * 
+        *              I think I'd stick the first way (for the 1st version), 
+        *              it's much simplier (less errors...)
+        * ) */
+       /* ... */
+       
+       xmlFreeParserCtxt(ctxt);
+       xmlCleanupParser();
+       
+       ereport(DEBUG3, (errmsg("XML data successfully parsed, encoding: %s", 
+               (char *) doc->encoding)));
+       
+       return doc;
+}
+
+
+/* 
+ * xmlChar<->text convertions 
+ */
+static xmlChar *
+xml_text2xmlChar(text *in)
+{
+       int32           len = VARSIZE(in) - VARHDRSZ;
+       xmlChar         *res;
+
+       res = palloc(len + 1);
+       memcpy(res, VARDATA(in), len);
+       res[len] = '\0';
+       
+       return(res);
+}
+
+
+/* 
+ * Wrappers for memory management functions 
+ */
+static void *
+xml_palloc(size_t size)
+{
+       return palloc(size);
+}
+
+
+static void *
+xml_repalloc(void *ptr, size_t size)
+{
+       return repalloc(ptr, size);
+}
+
+
+static void
+xml_pfree(void *ptr)
+{
+       pfree(ptr);
+}
+
+
+static char *
+xml_pstrdup(const char *string)
+{
+       return pstrdup(string);
+}
+
+
+/*
+ * Wrapper for "ereport" function. 
+ * Adds detail - libxml's native error message, if any.
+ */
+static void
+xml_ereport(int level, char *msg, void *ctxt)
+{
+       char *xmlErrDetail;
+       int xmlErrLen, i;
+       xmlErrorPtr libxmlErr = NULL;
+       
+       if (xml_errmsg != NULL)
+       {
+               ereport(DEBUG1, (errmsg("%s", xml_errmsg)));
+               pfree(xml_errmsg);
+       }
+       
+       if (ctxt != NULL)
+               libxmlErr = xmlCtxtGetLastError(ctxt);
+       
+       if (libxmlErr == NULL)
+       {
+               if (level == ERROR)
+               {
+                       xmlFreeParserCtxt(ctxt);
+                       xmlCleanupParser();
+               }
+               ereport(level, (errmsg(msg)));
+       }
+       else
+       {
+               /* as usual, libxml error message contains '\n'; get rid of it */
+               xmlErrLen = strlen(libxmlErr->message); /* - 1; */
+               xmlErrDetail = (char *) palloc(xmlErrLen);
+               for (i = 0; i < xmlErrLen; i++)
+               {
+                       if (libxmlErr->message[i] == '\n')
+                               xmlErrDetail[i] = '.';
+                       else
+                               xmlErrDetail[i] = libxmlErr->message[i];
+               }
+               if (level == ERROR)
+               {
+                       xmlFreeParserCtxt(ctxt);
+                       xmlCleanupParser();
+               }
+               ereport(level, (errmsg(msg), errdetail("%s", xmlErrDetail)));
+       }
+}
+
+
+/*
+ * Error handler for libxml error messages
+ */
+static void
+xml_errorHandler(void *ctxt, const char *msg,...)
+{
+       va_list         args;
+       
+       va_start(args, msg);
+       vsnprintf(xml_errbuf, XML_ERRBUF_SIZE, msg, args);
+       va_end(args);
+       /* Now copy the argument across */
+       if (xml_errmsg == NULL)
+               xml_errmsg = pstrdup(xml_errbuf);
+       else
+       {
+               int32           xsize = strlen(xml_errmsg);
+
+               xml_errmsg = repalloc(xml_errmsg, (size_t) (xsize + strlen(xml_errbuf) + 1));
+               strncpy(&xml_errmsg[xsize - 1], xml_errbuf, strlen(xml_errbuf));
+               xml_errmsg[xsize + strlen(xml_errbuf) - 1] = '\0';
+       }
+       memset(xml_errbuf, 0, XML_ERRBUF_SIZE);
+}
+
+
+/*
+ * Return error message by libxml error code
+ * TODO make them closer to recommendations from Postgres manual
+ */
+static void
+xml_ereport_by_code(int level, char *msg, int code)
+{
+    const char *det;
+
+       if (code < 0)
+       {
+               ereport(level, (errmsg(msg)));
+               return;
+       }
+
+    switch (code) {
+        case XML_ERR_INTERNAL_ERROR:
+            det = "libxml internal error";
+            break;
+        case XML_ERR_ENTITY_LOOP:
+            det = "Detected an entity reference loop";
+            break;
+        case XML_ERR_ENTITY_NOT_STARTED:
+            det = "EntityValue: \" or ' expected";
+            break;
+        case XML_ERR_ENTITY_NOT_FINISHED:
+            det = "EntityValue: \" or ' expected";
+            break;
+        case XML_ERR_ATTRIBUTE_NOT_STARTED:
+            det = "AttValue: \" or ' expected";
+            break;
+        case XML_ERR_LT_IN_ATTRIBUTE:
+            det = "Unescaped '<' not allowed in attributes values";
+            break;
+        case XML_ERR_LITERAL_NOT_STARTED:
+            det = "SystemLiteral \" or ' expected";
+            break;
+        case XML_ERR_LITERAL_NOT_FINISHED:
+            det = "Unfinished System or Public ID \" or ' expected";
+            break;
+        case XML_ERR_MISPLACED_CDATA_END:
+            det = "Sequence ']]>' not allowed in content";
+            break;
+        case XML_ERR_URI_REQUIRED:
+            det = "SYSTEM or PUBLIC, the URI is missing";
+            break;
+        case XML_ERR_PUBID_REQUIRED:
+            det = "PUBLIC, the Public Identifier is missing";
+            break;
+        case XML_ERR_HYPHEN_IN_COMMENT:
+            det = "Comment must not contain '--' (double-hyphen)";
+            break;
+        case XML_ERR_PI_NOT_STARTED:
+            det = "xmlParsePI : no target name";
+            break;
+        case XML_ERR_RESERVED_XML_NAME:
+            det = "Invalid PI name";
+            break;
+        case XML_ERR_NOTATION_NOT_STARTED:
+            det = "NOTATION: Name expected here";
+            break;
+        case XML_ERR_NOTATION_NOT_FINISHED:
+            det = "'>' required to close NOTATION declaration";
+            break;
+        case XML_ERR_VALUE_REQUIRED:
+            det = "Entity value required";
+            break;
+        case XML_ERR_URI_FRAGMENT:
+            det = "Fragment not allowed";
+            break;
+        case XML_ERR_ATTLIST_NOT_STARTED:
+            det = "'(' required to start ATTLIST enumeration";
+            break;
+        case XML_ERR_NMTOKEN_REQUIRED:
+            det = "NmToken expected in ATTLIST enumeration";
+            break;
+        case XML_ERR_ATTLIST_NOT_FINISHED:
+            det = "')' required to finish ATTLIST enumeration";
+            break;
+        case XML_ERR_MIXED_NOT_STARTED:
+            det = "MixedContentDecl : '|' or ')*' expected";
+            break;
+        case XML_ERR_PCDATA_REQUIRED:
+            det = "MixedContentDecl : '#PCDATA' expected";
+            break;
+        case XML_ERR_ELEMCONTENT_NOT_STARTED:
+            det = "ContentDecl : Name or '(' expected";
+            break;
+        case XML_ERR_ELEMCONTENT_NOT_FINISHED:
+            det = "ContentDecl : ',' '|' or ')' expected";
+            break;
+        case XML_ERR_PEREF_IN_INT_SUBSET:
+            det = "PEReference: forbidden within markup decl in internal subset";
+            break;
+        case XML_ERR_GT_REQUIRED:
+            det = "Expected '>'";
+            break;
+        case XML_ERR_CONDSEC_INVALID:
+            det = "XML conditional section '[' expected";
+            break;
+        case XML_ERR_EXT_SUBSET_NOT_FINISHED:
+            det = "Content error in the external subset";
+            break;
+        case XML_ERR_CONDSEC_INVALID_KEYWORD:
+            det = "conditional section INCLUDE or IGNORE keyword expected";
+            break;
+        case XML_ERR_CONDSEC_NOT_FINISHED:
+            det = "XML conditional section not closed";
+            break;
+        case XML_ERR_XMLDECL_NOT_STARTED:
+            det = "Text declaration '<?xml' required";
+            break;
+        case XML_ERR_XMLDECL_NOT_FINISHED:
+            det = "parsing XML declaration: '?>' expected";
+            break;
+        case XML_ERR_EXT_ENTITY_STANDALONE:
+            det = "external parsed entities cannot be standalone";
+            break;
+        case XML_ERR_ENTITYREF_SEMICOL_MISSING:
+            det = "EntityRef: expecting ';'";
+            break;
+        case XML_ERR_DOCTYPE_NOT_FINISHED:
+            det = "DOCTYPE improperly terminated";
+            break;
+        case XML_ERR_LTSLASH_REQUIRED:
+            det = "EndTag: '</' not found";
+            break;
+        case XML_ERR_EQUAL_REQUIRED:
+            det = "Expected '='";
+            break;
+        case XML_ERR_STRING_NOT_CLOSED:
+            det = "String not closed expecting \" or '";
+            break;
+        case XML_ERR_STRING_NOT_STARTED:
+            det = "String not started expecting ' or \"";
+            break;
+        case XML_ERR_ENCODING_NAME:
+            det = "Invalid XML encoding name";
+            break;
+        case XML_ERR_STANDALONE_VALUE:
+            det = "Standalone accepts only 'yes' or 'no'";
+            break;
+        case XML_ERR_DOCUMENT_EMPTY:
+            det = "Document is empty";
+            break;
+        case XML_ERR_DOCUMENT_END:
+            det = "Extra content at the end of the document";
+            break;
+        case XML_ERR_NOT_WELL_BALANCED:
+            det = "Chunk is not well balanced";
+            break;
+        case XML_ERR_EXTRA_CONTENT:
+            det = "Extra content at the end of well balanced chunk";
+            break;
+        case XML_ERR_VERSION_MISSING:
+            det = "Malformed declaration expecting version";
+            break;
+        /* more err codes... Please, keep the order! */
+        case XML_ERR_ATTRIBUTE_WITHOUT_VALUE: /* 41 */
+               det ="Attribute without value";
+               break;
+        case XML_ERR_ATTRIBUTE_REDEFINED:
+               det ="Attribute defined more than once in the same element";
+               break;
+        case XML_ERR_COMMENT_NOT_FINISHED: /* 45 */
+            det = "Comment is not finished";
+            break;
+        case XML_ERR_NAME_REQUIRED: /* 68 */
+            det = "Element name not found";
+            break;
+        case XML_ERR_TAG_NOT_FINISHED: /* 77 */
+            det = "Closing tag not found";
+            break;
+        default:
+            det = "Unregistered error (libxml error code: %d)";
+            ereport(DEBUG1, (errmsg("Check out \"libxml/xmlerror.h\" and bring errcode \"%d\" processing to \"xml.c\".", code)));
+    }
+    
+       if (xml_errmsg != NULL)
+       {
+               ereport(DEBUG1, (errmsg("%s", xml_errmsg)));
+               pfree(xml_errmsg);
+       }
+    
+       ereport(level, (errmsg(msg), errdetail(det, code)));
+}
+
+
+/*
+ * Convert one char in the current server encoding to a Unicode
+ * codepoint.
+ */
+static pg_wchar
+sqlchar_to_unicode(unsigned char *s)
+{
+       int save_enc;
+       pg_wchar ret;
+       char *utf8string = pg_do_encoding_conversion(s, pg_mblen(s), GetDatabaseEncoding(), PG_UTF8);
+
+       save_enc = GetDatabaseEncoding();
+       SetDatabaseEncoding(PG_UTF8);
+       pg_mb2wchar_with_len(utf8string, &ret, pg_mblen(s));
+       SetDatabaseEncoding(save_enc);
+
+       return ret;
+}
+
+
+static bool
+is_valid_xml_namefirst(pg_wchar c)
+{
+       /* (Letter | '_' | ':') */
+       return (xmlIsBaseCharQ(c) || xmlIsIdeographicQ(c)
+                       || c == '_' || c == ':');
+}
+
+
+static bool
+is_valid_xml_namechar(pg_wchar c)
+{
+       /* Letter | Digit | '.' | '-' | '_' | ':' | CombiningChar | Extender */
+       return (xmlIsBaseCharQ(c) || xmlIsIdeographicQ(c)
+                       || xmlIsDigitQ(c)
+                       || c == '.' || c == '-' || c == '_' || c == ':'
+                       || xmlIsCombiningQ(c)
+                       || xmlIsExtenderQ(c));
+}
+#endif /* USE_LIBXML */
+
+
+/*
+ * Map SQL identifier to XML name; see SQL/XML:2003 section 9.1.
+ */
+char *
+map_sql_identifier_to_xml_name(unsigned char *ident, bool fully_escaped)
+{
+#ifdef USE_LIBXML
+       StringInfoData buf;
+       unsigned char *p;
+
+       initStringInfo(&buf);
+
+       for (p = ident; *p; p += pg_mblen(p))
+       {
+               if (*p == ':' && (p == ident || fully_escaped))
+                       appendStringInfo(&buf, "_x003A_");
+               else if (*p == '_' && *(p+1) == 'x')
+                       appendStringInfo(&buf, "_x005F_");
+               else if (fully_escaped && p == ident
+                                && ( *p == 'x' || *p == 'X')
+                                && ( *(p+1) == 'm' || *(p+1) == 'M')
+                                && ( *(p+2) == 'l' || *(p+2) == 'L'))
+               {
+                       if (*p == 'x')
+                               appendStringInfo(&buf, "_x0078_");
+                       else
+                               appendStringInfo(&buf, "_x0058_");
+               }
+               else
+               {
+                       pg_wchar u = sqlchar_to_unicode(p);
+
+                       if (!is_valid_xml_namechar(u)
+                               || (p == ident && !is_valid_xml_namefirst(u)))
+                       appendStringInfo(&buf, "_x%04X_", (unsigned int) u);
+                       else
+                               appendBinaryStringInfo(&buf, p, pg_mblen(p));
+               }
+       }
+
+       return buf.data;
+#else /* not USE_LIBXML */
+       NO_XML_SUPPORT();
+       return NULL;
+#endif /* not USE_LIBXML */
+}
index e91c8a2a58c2a2f6a874fc0490b200f54ce40255..89845b08c16ae0b33efa6c42db72452804c9b058 100644 (file)
@@ -4,7 +4,7 @@
  * (currently mule internal code (mic) is used)
  * Tatsuo Ishii
  *
- * $PostgreSQL: pgsql/src/backend/utils/mb/mbutils.c,v 1.59 2006/10/04 00:30:02 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/mb/mbutils.c,v 1.60 2006/12/21 16:05:15 petere Exp $
  */
 #include "postgres.h"
 
@@ -599,7 +599,7 @@ void
 SetDatabaseEncoding(int encoding)
 {
        if (!PG_VALID_BE_ENCODING(encoding))
-               elog(ERROR, "invalid database encoding");
+               elog(ERROR, "invalid database encoding: %d", encoding);
 
        DatabaseEncoding = &pg_enc2name_tbl[encoding];
        Assert(DatabaseEncoding->encoding == encoding);
index 40c0fb0ee50ff58cd5bb0eccffe6eb2de95f153a..942c4f906eda686452cc2f74b29fbadbdf666027 100644 (file)
@@ -10,7 +10,7 @@
  *
  * Copyright (c) 2002-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.26 2006/03/05 15:58:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.27 2006/12/21 16:05:15 petere Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -300,6 +300,8 @@ DATA(insert ( 1266   25  939 i ));
 DATA(insert (  25 1266  938 e ));
 DATA(insert ( 1700      25 1688 i ));
 DATA(insert (  25 1700 1686 e ));
+DATA(insert (  142   25    0 e ));
+DATA(insert (   25  142        2896 e ));
 
 /*
  * Cross-category casts to and from VARCHAR
@@ -338,6 +340,8 @@ DATA(insert ( 1266 1043  939 a ));
 DATA(insert ( 1043 1266  938 e ));
 DATA(insert ( 1700 1043 1688 a ));
 DATA(insert ( 1043 1700 1686 e ));
+DATA(insert (  142 1043    0 e ));
+DATA(insert ( 1043  142 2896 e ));
 
 /*
  * Cross-category casts to and from BPCHAR
@@ -377,6 +381,7 @@ DATA(insert ( 1266 1042  939 a ));
 DATA(insert ( 1042 1266  938 e ));
 DATA(insert ( 1700 1042 1688 a ));
 DATA(insert ( 1042 1700 1686 e ));
+DATA(insert (  142 1042    0 e ));
 
 /*
  * Length-coercion functions
index 9dee8f6a3c6acffbc29866efc7e0a8def3685e9f..974a2db360ca4c5eca15e02174296ba348be78f6 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.430 2006/12/06 18:06:47 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.431 2006/12/21 16:05:15 petere Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -3976,6 +3976,26 @@ DESCR("release shared advisory lock");
 DATA(insert OID = 2892 (  pg_advisory_unlock_all               PGNSP PGUID 12 f f t f v 0 2278 "" _null_ _null_ _null_ pg_advisory_unlock_all - _null_ ));
 DESCR("release all advisory locks");
 
+/* XML support */
+DATA(insert OID = 2893 (  xml_in                  PGNSP PGUID 12 f f t f i 1 142 "2275" _null_ _null_ _null_ xml_in - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2894 (  xml_out                 PGNSP PGUID 12 f f t f i 1 2275 "142" _null_ _null_ _null_ xml_out - _null_ ));
+DESCR("I/O");
+DATA(insert OID = 2895 (  xmlcomment      PGNSP PGUID 12 f f t f i 1 142 "25" _null_ _null_ _null_ xmlcomment - _null_ ));
+DESCR("generate an XML comment");
+DATA(insert OID = 2896 (  xmlparse                PGNSP PGUID 12 f f t f i 1 142 "25" _null_ _null_ _null_ xmlparse - _null_ ));
+DESCR("perform a non-validating parse of a character string to produce an XML value");
+DATA(insert OID = 2897 (  xmlparse                PGNSP PGUID 12 f f t f i 3 142 "25 16 16" _null_ _null_ _null_ xmlparse - _null_ ));
+DESCR("perform a non-validating parse of a character string to produce an XML value");
+DATA(insert OID = 2898 (  xmlpi                           PGNSP PGUID 12 f f t f i 1 142 "19" _null_ _null_ _null_ xmlpi - _null_ ));
+DESCR("generate an XML processing instruction");
+DATA(insert OID = 2899 (  xmlpi                           PGNSP PGUID 12 f f t f i 2 142 "19 25" _null_ _null_ _null_ xmlpi - _null_ ));
+DESCR("generate an XML processing instruction");
+DATA(insert OID = 2900 (  xmlroot                 PGNSP PGUID 12 f f f f i 3 142 "142 25 16" _null_ _null_ _null_ xmlroot - _null_ ));
+DESCR("create an XML value by modifying the properties of the XML root information item of another XML value");
+DATA(insert OID = 2901 (  xmlvalidate     PGNSP PGUID 12 f f t f i 2 16 "142 25" _null_ _null_ _null_ xmlvalidate - _null_ ));
+DESCR("validate an XML value");
+
 /*
  * Symbolic values for provolatile column: these indicate whether the result
  * of a function is dependent *only* on the values of its explicit arguments,
index 488ff66beddbb5f05e50bfb5bf2e5736e5d95481..cb0c0e85746dcaa2bc8bb7e21bb3414ba9298c9c 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.172 2006/10/04 00:30:08 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.173 2006/12/21 16:05:15 petere Exp $
  *
  * NOTES
  *       the genbki.sh script reads this file and generates .bki
@@ -316,6 +316,10 @@ DATA(insert OID = 83 (     pg_class                PGNSP PGUID -1 f c t \054 1259 0 record_in reco
 #define PG_CLASS_RELTYPE_OID 83
 
 /* OIDS 100 - 199 */
+DATA(insert OID = 142 ( xml               PGNSP PGUID -1 f b t \054 0 0 xml_in xml_out - - - i x f 0 -1 0 _null_ _null_ ));
+DESCR("XML content");
+#define XMLOID 142
+DATA(insert OID = 143 ( _xml      PGNSP PGUID -1 f b t \054 0 142 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ ));
 
 /* OIDS 200 - 299 */
 
index 273d5c33261fc2fdf1b8c648f3fc5edffac6abde..1db920aa0c1b0c4836c5b3e32b9d9ea564b123b9 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.162 2006/12/04 02:06:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.163 2006/12/21 16:05:16 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -723,6 +723,22 @@ typedef struct NullTestState
        TupleDesc       argdesc;                /* tupdesc for most recent input */
 } NullTestState;
 
+/* ----------------
+ *             XmlExprState node
+ * ----------------
+ */
+typedef struct XmlExprState
+{
+       ExprState       xprstate;
+       XmlExprOp       op;
+       char       *name;
+       List       *named_args;
+       List       *args;
+       Oid                *named_args_tcache;
+       char      **named_args_ncache;
+       Oid                     arg_typeout;
+} XmlExprState;
+
 /* ----------------
  *             CoerceToDomainState node
  * ----------------
index c7abfba91a4726ba5f5eb6415c89cb82e8cc11ea..eb6ba18adab390357a05f9865d3b98b570b92b11 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.188 2006/09/28 20:51:42 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.189 2006/12/21 16:05:16 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -140,6 +140,7 @@ typedef enum NodeTag
        T_RangeTblRef,
        T_JoinExpr,
        T_FromExpr,
+       T_XmlExpr,
 
        /*
         * TAGS FOR EXPRESSION STATE NODES (execnodes.h)
@@ -168,6 +169,7 @@ typedef enum NodeTag
        T_NullTestState,
        T_CoerceToDomainState,
        T_DomainConstraintState,
+       T_XmlExprState,
 
        /*
         * TAGS FOR PLANNER NODES (relation.h)
index 6c5e761275e484a27901aa5a857ead3cfb37fcfc..9654181bc3d745f76c09ad6caa2eabab19fda5db 100644 (file)
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.118 2006/12/10 22:13:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.119 2006/12/21 16:05:16 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -765,6 +765,26 @@ typedef struct BooleanTest
        BoolTestType booltesttype;      /* test type */
 } BooleanTest;
 
+/*
+ * XmlExpr - holder for SQL/XML functions XMLCONCAT,
+ * XMLELEMENT, XMLFOREST
+ */
+typedef enum XmlExprOp
+{
+       IS_XMLCONCAT,
+       IS_XMLELEMENT,
+       IS_XMLFOREST,
+} XmlExprOp;
+
+typedef struct XmlExpr
+{
+       Expr            xpr;
+       XmlExprOp       op;                             /* xml expression type */
+       char       *name;                       /* element name */
+       List       *named_args;
+       List       *args;
+} XmlExpr;
+
 /*
  * CoerceToDomain
  *
index e29a64d48f479a4be154e80bde596b5c0b50b3d8..9c077095e9e563822fff96fd50244bb74fec66f7 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.66 2006/10/04 00:30:09 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.67 2006/12/21 16:05:16 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,6 +59,8 @@ extern Node *coerce_to_integer(ParseState *pstate, Node *node,
                                  const char *constructName);
 extern Node *coerce_to_bigint(ParseState *pstate, Node *node,
                                 const char *constructName);
+extern Node *coerce_to_xml(ParseState *pstate, Node *node,
+                                const char *constructName);
 
 extern Oid     select_common_type(List *typeids, const char *context);
 extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
index 7c1ac6b69bf13995a6a9588be7328421ceaf83f8..a75f1dccfa9ac5d7e37d120d5f508e7623235cd6 100644 (file)
 /* Define to 1 if you have the `wldap32' library (-lwldap32). */
 #undef HAVE_LIBWLDAP32
 
+/* Define to 1 if you have the `xml2' library (-lxml2). */
+#undef HAVE_LIBXML2
+
 /* Define to 1 if you have the `z' library (-lz). */
 #undef HAVE_LIBZ
 
 /* Define to 1 to build with LDAP support. (--with-ldap) */
 #undef USE_LDAP
 
+/* Define to 1 to build with XML support. (--with-libxml) */
+#undef USE_LIBXML
+
 /* Define to select named POSIX semaphores. */
 #undef USE_NAMED_POSIX_SEMAPHORES
 
index 8ba809d2ee8fd7095a2d93252e101dbfb70b0afe..9346644774742c3421f0dc5119779c4361d642aa 100644 (file)
@@ -11,7 +11,7 @@
  *
  * Copyright (c) 2003-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.20 2006/06/16 23:29:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.21 2006/12/21 16:05:16 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
 #define ERRCODE_INVALID_BINARY_REPRESENTATION  MAKE_SQLSTATE('2','2', 'P','0','3')
 #define ERRCODE_BAD_COPY_FILE_FORMAT           MAKE_SQLSTATE('2','2', 'P','0','4')
 #define ERRCODE_UNTRANSLATABLE_CHARACTER       MAKE_SQLSTATE('2','2', 'P','0','5')
+#define ERRCODE_INVALID_XML_DOCUMENT                   MAKE_SQLSTATE('2', '2', '0', '0', 'M')
+#define ERRCODE_INVALID_XML_CONTENT                    MAKE_SQLSTATE('2', '2', '0', '0', 'N')
+#define ERRCODE_INVALID_XML_COMMENT                    MAKE_SQLSTATE('2', '2', '0', '0', 'S')
+#define ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION     MAKE_SQLSTATE('2', '2', '0', '0', 'T')
 
 /* Class 23 - Integrity Constraint Violation */
 #define ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION         MAKE_SQLSTATE('2','3', '0','0','0')
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
new file mode 100644 (file)
index 0000000..8932330
--- /dev/null
@@ -0,0 +1,37 @@
+/*-------------------------------------------------------------------------
+ *
+ * xml.h
+ *       Declarations for XML data type support.
+ *
+ *
+ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.1 2006/12/21 16:05:16 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#ifndef XML_H
+#define XML_H
+
+#include "fmgr.h"
+
+typedef struct varlena xmltype;
+
+#define DatumGetXmlP(X)                ((xmltype *) PG_DETOAST_DATUM(X))
+
+#define PG_GETARG_XML_P(n)     DatumGetXmlP(PG_GETARG_DATUM(n))
+#define PG_RETURN_XML_P(x)     PG_RETURN_POINTER(x)
+
+extern Datum xml_in(PG_FUNCTION_ARGS);
+extern Datum xml_out(PG_FUNCTION_ARGS);
+extern Datum xmlcomment(PG_FUNCTION_ARGS);
+extern Datum xmlparse(PG_FUNCTION_ARGS);
+extern Datum xmlpi(PG_FUNCTION_ARGS);
+extern Datum xmlroot(PG_FUNCTION_ARGS);
+extern Datum xmlvalidate(PG_FUNCTION_ARGS);
+
+extern char *map_sql_identifier_to_xml_name(unsigned char *ident, bool fully_escaped);
+
+#endif /* XML_H */
index 0be263e6d8a7f795be2f07078f3708cc1db1cdc1..e455538d69fded0d06f380dec5571f84f87dc623 100644 (file)
@@ -73,7 +73,7 @@ WHERE p1.oid != p2.oid AND
 SELECT p1.oid, p1.proname, p2.oid, p2.proname
 FROM pg_proc AS p1, pg_proc AS p2
 WHERE p1.oid < p2.oid AND
-    p1.prosrc = p2.prosrc AND
+    p1.prosrc = p2.prosrc AND p1.prosrc NOT IN ('xmlparse', 'xmlpi') AND
     p1.prolang = 12 AND p2.prolang = 12 AND
     (p1.proisagg = false OR p2.proisagg = false) AND
     (p1.prolang != p2.prolang OR
@@ -285,6 +285,8 @@ WHERE c.castfunc = p.oid AND
 -- those are binary-compatible while the reverse way goes through rtrim().
 -- As of 8.2, this finds the cast from cidr to inet, because that is a
 -- trivial binary coercion while the other way goes through inet_to_cidr().
+-- As of 8.3, this finds casts from xml to text, varchar, and bpchar,
+-- because the other direction has to go through xmlparse().
 SELECT *
 FROM pg_cast c
 WHERE c.castfunc = 0 AND
@@ -297,7 +299,10 @@ WHERE c.castfunc = 0 AND
          25 |       1042 |        0 | i
        1043 |       1042 |        0 | i
         650 |        869 |        0 | i
-(3 rows)
+        142 |         25 |        0 | e
+        142 |       1043 |        0 | e
+        142 |       1042 |        0 | e
+(6 rows)
 
 -- **************** pg_operator ****************
 -- Look for illegal values in pg_operator fields.
index 902acba4c2679ff72d01e01121c6e148b5ed0d2f..73d38c1ca17b94260f14f7e27405085c43aa7f0f 100644 (file)
@@ -160,7 +160,7 @@ SELECT name, statement, parameter_types FROM pg_prepared_statements
       : \x09ten = $3::bigint OR true = $4 OR oid = $5 OR odd = $6::int);   
  q5   | PREPARE q5(int, text) AS                                         | {integer,text}
       : \x09SELECT * FROM tenk1 WHERE unique1 = $1 OR stringu1 = $2;       
- q6   | PREPARE q6 AS                                                    | {integer,name}
+ q6   | PREPARE q6 AS                                                    | {integer,"\"name\""}
       :     SELECT * FROM tenk1 WHERE unique1 = $1 AND stringu1 = $2;      
  q7   | PREPARE q7(unknown) AS                                           | {path}
       :     SELECT * FROM road WHERE thepath = $1;                         
index 9c0f055edcc458e9ae3261a61a833abc47ae2161..d5a3dc09f1506aa98bc1e3da684678eef37a2c3a 100644 (file)
@@ -1276,38 +1276,38 @@ drop table cchild;
 SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
          viewname         |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               definition                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
 --------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- iexit                    | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
- pg_cursors               | SELECT c.name, c."statement", c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c(name text, "statement" text, is_holdable boolean, is_binary boolean, is_scrollable boolean, creation_time timestamp with time zone);
+ iexit                    | SELECT ih."name", ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
+ pg_cursors               | SELECT c."name", c."statement", c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c("name" text, "statement" text, is_holdable boolean, is_binary boolean, is_scrollable boolean, creation_time timestamp with time zone);
  pg_group                 | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
  pg_indexes               | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, t.spcname AS "tablespace", pg_get_indexdef(i.oid) AS indexdef FROM ((((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
  pg_locks                 | SELECT l.locktype, l."database", l.relation, l.page, l.tuple, l.transactionid, l.classid, l.objid, l.objsubid, l."transaction", l.pid, l."mode", l."granted" FROM pg_lock_status() l(locktype text, "database" oid, relation oid, page integer, tuple smallint, transactionid xid, classid oid, objid oid, objsubid smallint, "transaction" xid, pid integer, "mode" text, "granted" boolean);
- pg_prepared_statements   | SELECT p.name, p."statement", p.prepare_time, p.parameter_types, p.from_sql FROM pg_prepared_statement() p(name text, "statement" text, prepare_time timestamp with time zone, parameter_types regtype[], from_sql boolean);
+ pg_prepared_statements   | SELECT p."name", p."statement", p.prepare_time, p.parameter_types, p.from_sql FROM pg_prepared_statement() p("name" text, "statement" text, prepare_time timestamp with time zone, parameter_types regtype[], from_sql boolean);
  pg_prepared_xacts        | SELECT p."transaction", p.gid, p."prepared", u.rolname AS "owner", d.datname AS "database" FROM ((pg_prepared_xact() p("transaction" xid, gid text, "prepared" timestamp with time zone, ownerid oid, dbid oid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid)));
  pg_roles                 | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, pg_authid.rolconnlimit, '********'::text AS rolpassword, pg_authid.rolvaliduntil, pg_authid.rolconfig, pg_authid.oid FROM pg_authid;
- pg_rules                 | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
- pg_settings              | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val FROM pg_show_all_settings() a(name text, setting text, unit text, category text, short_desc text, extra_desc text, context text, vartype text, source text, min_val text, max_val text);
+ pg_rules                 | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::"name");
+ pg_settings              | SELECT a."name", a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val FROM pg_show_all_settings() a("name" text, setting text, unit text, category text, short_desc text, extra_desc text, context text, vartype text, source text, min_val text, max_val text);
  pg_shadow                | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, pg_authid.rolconfig AS useconfig FROM pg_authid WHERE pg_authid.rolcanlogin;
  pg_stat_activity         | SELECT d.oid AS datid, d.datname, pg_stat_get_backend_pid(s.backendid) AS procpid, pg_stat_get_backend_userid(s.backendid) AS usesysid, u.rolname AS usename, pg_stat_get_backend_activity(s.backendid) AS current_query, pg_stat_get_backend_waiting(s.backendid) AS waiting, pg_stat_get_backend_txn_start(s.backendid) AS txn_start, pg_stat_get_backend_activity_start(s.backendid) AS query_start, pg_stat_get_backend_start(s.backendid) AS backend_start, pg_stat_get_backend_client_addr(s.backendid) AS client_addr, pg_stat_get_backend_client_port(s.backendid) AS client_port FROM pg_database d, (SELECT pg_stat_get_backend_idset() AS backendid) s, pg_authid u WHERE ((pg_stat_get_backend_dbid(s.backendid) = d.oid) AND (pg_stat_get_backend_userid(s.backendid) = u.oid));
  pg_stat_all_indexes      | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, pg_stat_get_numscans(i.oid) AS idx_scan, pg_stat_get_tuples_returned(i.oid) AS idx_tup_read, pg_stat_get_tuples_fetched(i.oid) AS idx_tup_fetch FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"]));
  pg_stat_all_tables       | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, pg_stat_get_numscans(c.oid) AS seq_scan, pg_stat_get_tuples_returned(c.oid) AS seq_tup_read, (sum(pg_stat_get_numscans(i.indexrelid)))::bigint AS idx_scan, ((sum(pg_stat_get_tuples_fetched(i.indexrelid)))::bigint + pg_stat_get_tuples_fetched(c.oid)) AS idx_tup_fetch, pg_stat_get_tuples_inserted(c.oid) AS n_tup_ins, pg_stat_get_tuples_updated(c.oid) AS n_tup_upd, pg_stat_get_tuples_deleted(c.oid) AS n_tup_del, pg_stat_get_last_vacuum_time(c.oid) AS last_vacuum, pg_stat_get_last_autovacuum_time(c.oid) AS last_autovacuum, pg_stat_get_last_analyze_time(c.oid) AS last_analyze, pg_stat_get_last_autoanalyze_time(c.oid) AS last_autoanalyze FROM ((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname;
  pg_stat_database         | SELECT d.oid AS datid, d.datname, pg_stat_get_db_numbackends(d.oid) AS numbackends, pg_stat_get_db_xact_commit(d.oid) AS xact_commit, pg_stat_get_db_xact_rollback(d.oid) AS xact_rollback, (pg_stat_get_db_blocks_fetched(d.oid) - pg_stat_get_db_blocks_hit(d.oid)) AS blks_read, pg_stat_get_db_blocks_hit(d.oid) AS blks_hit FROM pg_database d;
- pg_stat_sys_indexes      | SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes WHERE (pg_stat_all_indexes.schemaname = ANY (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
- pg_stat_sys_tables       | SELECT pg_stat_all_tables.relid, pg_stat_all_tables.schemaname, pg_stat_all_tables.relname, pg_stat_all_tables.seq_scan, pg_stat_all_tables.seq_tup_read, pg_stat_all_tables.idx_scan, pg_stat_all_tables.idx_tup_fetch, pg_stat_all_tables.n_tup_ins, pg_stat_all_tables.n_tup_upd, pg_stat_all_tables.n_tup_del, pg_stat_all_tables.last_vacuum, pg_stat_all_tables.last_autovacuum, pg_stat_all_tables.last_analyze, pg_stat_all_tables.last_autoanalyze FROM pg_stat_all_tables WHERE (pg_stat_all_tables.schemaname = ANY (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
- pg_stat_user_indexes     | SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes WHERE (pg_stat_all_indexes.schemaname <> ALL (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
- pg_stat_user_tables      | SELECT pg_stat_all_tables.relid, pg_stat_all_tables.schemaname, pg_stat_all_tables.relname, pg_stat_all_tables.seq_scan, pg_stat_all_tables.seq_tup_read, pg_stat_all_tables.idx_scan, pg_stat_all_tables.idx_tup_fetch, pg_stat_all_tables.n_tup_ins, pg_stat_all_tables.n_tup_upd, pg_stat_all_tables.n_tup_del, pg_stat_all_tables.last_vacuum, pg_stat_all_tables.last_autovacuum, pg_stat_all_tables.last_analyze, pg_stat_all_tables.last_autoanalyze FROM pg_stat_all_tables WHERE (pg_stat_all_tables.schemaname <> ALL (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
+ pg_stat_sys_indexes      | SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes WHERE (pg_stat_all_indexes.schemaname = ANY (ARRAY['pg_catalog'::"name", 'pg_toast'::"name", 'information_schema'::"name"]));
+ pg_stat_sys_tables       | SELECT pg_stat_all_tables.relid, pg_stat_all_tables.schemaname, pg_stat_all_tables.relname, pg_stat_all_tables.seq_scan, pg_stat_all_tables.seq_tup_read, pg_stat_all_tables.idx_scan, pg_stat_all_tables.idx_tup_fetch, pg_stat_all_tables.n_tup_ins, pg_stat_all_tables.n_tup_upd, pg_stat_all_tables.n_tup_del, pg_stat_all_tables.last_vacuum, pg_stat_all_tables.last_autovacuum, pg_stat_all_tables.last_analyze, pg_stat_all_tables.last_autoanalyze FROM pg_stat_all_tables WHERE (pg_stat_all_tables.schemaname = ANY (ARRAY['pg_catalog'::"name", 'pg_toast'::"name", 'information_schema'::"name"]));
+ pg_stat_user_indexes     | SELECT pg_stat_all_indexes.relid, pg_stat_all_indexes.indexrelid, pg_stat_all_indexes.schemaname, pg_stat_all_indexes.relname, pg_stat_all_indexes.indexrelname, pg_stat_all_indexes.idx_scan, pg_stat_all_indexes.idx_tup_read, pg_stat_all_indexes.idx_tup_fetch FROM pg_stat_all_indexes WHERE (pg_stat_all_indexes.schemaname <> ALL (ARRAY['pg_catalog'::"name", 'pg_toast'::"name", 'information_schema'::"name"]));
+ pg_stat_user_tables      | SELECT pg_stat_all_tables.relid, pg_stat_all_tables.schemaname, pg_stat_all_tables.relname, pg_stat_all_tables.seq_scan, pg_stat_all_tables.seq_tup_read, pg_stat_all_tables.idx_scan, pg_stat_all_tables.idx_tup_fetch, pg_stat_all_tables.n_tup_ins, pg_stat_all_tables.n_tup_upd, pg_stat_all_tables.n_tup_del, pg_stat_all_tables.last_vacuum, pg_stat_all_tables.last_autovacuum, pg_stat_all_tables.last_analyze, pg_stat_all_tables.last_autoanalyze FROM pg_stat_all_tables WHERE (pg_stat_all_tables.schemaname <> ALL (ARRAY['pg_catalog'::"name", 'pg_toast'::"name", 'information_schema'::"name"]));
  pg_statio_all_indexes    | SELECT c.oid AS relid, i.oid AS indexrelid, n.nspname AS schemaname, c.relname, i.relname AS indexrelname, (pg_stat_get_blocks_fetched(i.oid) - pg_stat_get_blocks_hit(i.oid)) AS idx_blks_read, pg_stat_get_blocks_hit(i.oid) AS idx_blks_hit FROM (((pg_class c JOIN pg_index x ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"]));
  pg_statio_all_sequences  | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, (pg_stat_get_blocks_fetched(c.oid) - pg_stat_get_blocks_hit(c.oid)) AS blks_read, pg_stat_get_blocks_hit(c.oid) AS blks_hit FROM (pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = 'S'::"char");
  pg_statio_all_tables     | SELECT c.oid AS relid, n.nspname AS schemaname, c.relname, (pg_stat_get_blocks_fetched(c.oid) - pg_stat_get_blocks_hit(c.oid)) AS heap_blks_read, pg_stat_get_blocks_hit(c.oid) AS heap_blks_hit, (sum((pg_stat_get_blocks_fetched(i.indexrelid) - pg_stat_get_blocks_hit(i.indexrelid))))::bigint AS idx_blks_read, (sum(pg_stat_get_blocks_hit(i.indexrelid)))::bigint AS idx_blks_hit, (pg_stat_get_blocks_fetched(t.oid) - pg_stat_get_blocks_hit(t.oid)) AS toast_blks_read, pg_stat_get_blocks_hit(t.oid) AS toast_blks_hit, (pg_stat_get_blocks_fetched(x.oid) - pg_stat_get_blocks_hit(x.oid)) AS tidx_blks_read, pg_stat_get_blocks_hit(x.oid) AS tidx_blks_hit FROM ((((pg_class c LEFT JOIN pg_index i ON ((c.oid = i.indrelid))) LEFT JOIN pg_class t ON ((c.reltoastrelid = t.oid))) LEFT JOIN pg_class x ON ((t.reltoastidxid = x.oid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = ANY (ARRAY['r'::"char", 't'::"char"])) GROUP BY c.oid, n.nspname, c.relname, t.oid, x.oid;
- pg_statio_sys_indexes    | SELECT pg_statio_all_indexes.relid, pg_statio_all_indexes.indexrelid, pg_statio_all_indexes.schemaname, pg_statio_all_indexes.relname, pg_statio_all_indexes.indexrelname, pg_statio_all_indexes.idx_blks_read, pg_statio_all_indexes.idx_blks_hit FROM pg_statio_all_indexes WHERE (pg_statio_all_indexes.schemaname = ANY (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
- pg_statio_sys_sequences  | SELECT pg_statio_all_sequences.relid, pg_statio_all_sequences.schemaname, pg_statio_all_sequences.relname, pg_statio_all_sequences.blks_read, pg_statio_all_sequences.blks_hit FROM pg_statio_all_sequences WHERE (pg_statio_all_sequences.schemaname = ANY (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
- pg_statio_sys_tables     | SELECT pg_statio_all_tables.relid, pg_statio_all_tables.schemaname, pg_statio_all_tables.relname, pg_statio_all_tables.heap_blks_read, pg_statio_all_tables.heap_blks_hit, pg_statio_all_tables.idx_blks_read, pg_statio_all_tables.idx_blks_hit, pg_statio_all_tables.toast_blks_read, pg_statio_all_tables.toast_blks_hit, pg_statio_all_tables.tidx_blks_read, pg_statio_all_tables.tidx_blks_hit FROM pg_statio_all_tables WHERE (pg_statio_all_tables.schemaname = ANY (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
- pg_statio_user_indexes   | SELECT pg_statio_all_indexes.relid, pg_statio_all_indexes.indexrelid, pg_statio_all_indexes.schemaname, pg_statio_all_indexes.relname, pg_statio_all_indexes.indexrelname, pg_statio_all_indexes.idx_blks_read, pg_statio_all_indexes.idx_blks_hit FROM pg_statio_all_indexes WHERE (pg_statio_all_indexes.schemaname <> ALL (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
- pg_statio_user_sequences | SELECT pg_statio_all_sequences.relid, pg_statio_all_sequences.schemaname, pg_statio_all_sequences.relname, pg_statio_all_sequences.blks_read, pg_statio_all_sequences.blks_hit FROM pg_statio_all_sequences WHERE (pg_statio_all_sequences.schemaname <> ALL (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
- pg_statio_user_tables    | SELECT pg_statio_all_tables.relid, pg_statio_all_tables.schemaname, pg_statio_all_tables.relname, pg_statio_all_tables.heap_blks_read, pg_statio_all_tables.heap_blks_hit, pg_statio_all_tables.idx_blks_read, pg_statio_all_tables.idx_blks_hit, pg_statio_all_tables.toast_blks_read, pg_statio_all_tables.toast_blks_hit, pg_statio_all_tables.tidx_blks_read, pg_statio_all_tables.tidx_blks_hit FROM pg_statio_all_tables WHERE (pg_statio_all_tables.schemaname <> ALL (ARRAY['pg_catalog'::name, 'pg_toast'::name, 'information_schema'::name]));
+ pg_statio_sys_indexes    | SELECT pg_statio_all_indexes.relid, pg_statio_all_indexes.indexrelid, pg_statio_all_indexes.schemaname, pg_statio_all_indexes.relname, pg_statio_all_indexes.indexrelname, pg_statio_all_indexes.idx_blks_read, pg_statio_all_indexes.idx_blks_hit FROM pg_statio_all_indexes WHERE (pg_statio_all_indexes.schemaname = ANY (ARRAY['pg_catalog'::"name", 'pg_toast'::"name", 'information_schema'::"name"]));
+ pg_statio_sys_sequences  | SELECT pg_statio_all_sequences.relid, pg_statio_all_sequences.schemaname, pg_statio_all_sequences.relname, pg_statio_all_sequences.blks_read, pg_statio_all_sequences.blks_hit FROM pg_statio_all_sequences WHERE (pg_statio_all_sequences.schemaname = ANY (ARRAY['pg_catalog'::"name", 'pg_toast'::"name", 'information_schema'::"name"]));
+ pg_statio_sys_tables     | SELECT pg_statio_all_tables.relid, pg_statio_all_tables.schemaname, pg_statio_all_tables.relname, pg_statio_all_tables.heap_blks_read, pg_statio_all_tables.heap_blks_hit, pg_statio_all_tables.idx_blks_read, pg_statio_all_tables.idx_blks_hit, pg_statio_all_tables.toast_blks_read, pg_statio_all_tables.toast_blks_hit, pg_statio_all_tables.tidx_blks_read, pg_statio_all_tables.tidx_blks_hit FROM pg_statio_all_tables WHERE (pg_statio_all_tables.schemaname = ANY (ARRAY['pg_catalog'::"name", 'pg_toast'::"name", 'information_schema'::"name"]));
+ pg_statio_user_indexes   | SELECT pg_statio_all_indexes.relid, pg_statio_all_indexes.indexrelid, pg_statio_all_indexes.schemaname, pg_statio_all_indexes.relname, pg_statio_all_indexes.indexrelname, pg_statio_all_indexes.idx_blks_read, pg_statio_all_indexes.idx_blks_hit FROM pg_statio_all_indexes WHERE (pg_statio_all_indexes.schemaname <> ALL (ARRAY['pg_catalog'::"name", 'pg_toast'::"name", 'information_schema'::"name"]));
+ pg_statio_user_sequences | SELECT pg_statio_all_sequences.relid, pg_statio_all_sequences.schemaname, pg_statio_all_sequences.relname, pg_statio_all_sequences.blks_read, pg_statio_all_sequences.blks_hit FROM pg_statio_all_sequences WHERE (pg_statio_all_sequences.schemaname <> ALL (ARRAY['pg_catalog'::"name", 'pg_toast'::"name", 'information_schema'::"name"]));
+ pg_statio_user_tables    | SELECT pg_statio_all_tables.relid, pg_statio_all_tables.schemaname, pg_statio_all_tables.relname, pg_statio_all_tables.heap_blks_read, pg_statio_all_tables.heap_blks_hit, pg_statio_all_tables.idx_blks_read, pg_statio_all_tables.idx_blks_hit, pg_statio_all_tables.toast_blks_read, pg_statio_all_tables.toast_blks_hit, pg_statio_all_tables.tidx_blks_read, pg_statio_all_tables.tidx_blks_hit FROM pg_statio_all_tables WHERE (pg_statio_all_tables.schemaname <> ALL (ARRAY['pg_catalog'::"name", 'pg_toast'::"name", 'information_schema'::"name"]));
  pg_stats                 | SELECT n.nspname AS schemaname, c.relname AS tablename, a.attname, s.stanullfrac AS null_frac, s.stawidth AS avg_width, s.stadistinct AS n_distinct, CASE 1 WHEN s.stakind1 THEN s.stavalues1 WHEN s.stakind2 THEN s.stavalues2 WHEN s.stakind3 THEN s.stavalues3 WHEN s.stakind4 THEN s.stavalues4 ELSE NULL::anyarray END AS most_common_vals, CASE 1 WHEN s.stakind1 THEN s.stanumbers1 WHEN s.stakind2 THEN s.stanumbers2 WHEN s.stakind3 THEN s.stanumbers3 WHEN s.stakind4 THEN s.stanumbers4 ELSE NULL::real[] END AS most_common_freqs, CASE 2 WHEN s.stakind1 THEN s.stavalues1 WHEN s.stakind2 THEN s.stavalues2 WHEN s.stakind3 THEN s.stavalues3 WHEN s.stakind4 THEN s.stavalues4 ELSE NULL::anyarray END AS histogram_bounds, CASE 3 WHEN s.stakind1 THEN s.stanumbers1[1] WHEN s.stakind2 THEN s.stanumbers2[1] WHEN s.stakind3 THEN s.stanumbers3[1] WHEN s.stakind4 THEN s.stanumbers4[1] ELSE NULL::real END AS correlation FROM (((pg_statistic s JOIN pg_class c ON ((c.oid = s.starelid))) JOIN pg_attribute a ON (((c.oid = a.attrelid) AND (a.attnum = s.staattnum)))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE has_table_privilege(c.oid, 'select'::text);
  pg_tables                | SELECT n.nspname AS schemaname, c.relname AS tablename, pg_get_userbyid(c.relowner) AS tableowner, t.spcname AS "tablespace", c.relhasindex AS hasindexes, c.relhasrules AS hasrules, (c.reltriggers > 0) AS hastriggers FROM ((pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = c.reltablespace))) WHERE (c.relkind = 'r'::"char");
  pg_timezone_abbrevs      | SELECT pg_timezone_abbrevs.abbrev, pg_timezone_abbrevs.utc_offset, pg_timezone_abbrevs.is_dst FROM pg_timezone_abbrevs() pg_timezone_abbrevs(abbrev, utc_offset, is_dst);
- pg_timezone_names        | SELECT pg_timezone_names.name, pg_timezone_names.abbrev, pg_timezone_names.utc_offset, pg_timezone_names.is_dst FROM pg_timezone_names() pg_timezone_names(name, abbrev, utc_offset, is_dst);
+ pg_timezone_names        | SELECT pg_timezone_names."name", pg_timezone_names.abbrev, pg_timezone_names.utc_offset, pg_timezone_names.is_dst FROM pg_timezone_names() pg_timezone_names("name", abbrev, utc_offset, is_dst);
  pg_user                  | SELECT pg_shadow.usename, pg_shadow.usesysid, pg_shadow.usecreatedb, pg_shadow.usesuper, pg_shadow.usecatupd, '********'::text AS passwd, pg_shadow.valuntil, pg_shadow.useconfig FROM pg_shadow;
  pg_views                 | SELECT n.nspname AS schemaname, c.relname AS viewname, pg_get_userbyid(c.relowner) AS viewowner, pg_get_viewdef(c.oid) AS definition FROM (pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = 'v'::"char");
  rtest_v1                 | SELECT rtest_t1.a, rtest_t1.b FROM rtest_t1;
@@ -1322,16 +1322,16 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
  shoelace                 | SELECT s.sl_name, s.sl_avail, s.sl_color, s.sl_len, s.sl_unit, (s.sl_len * u.un_fact) AS sl_len_cm FROM shoelace_data s, unit u WHERE (s.sl_unit = u.un_name);
  shoelace_candelete       | SELECT shoelace_obsolete.sl_name, shoelace_obsolete.sl_avail, shoelace_obsolete.sl_color, shoelace_obsolete.sl_len, shoelace_obsolete.sl_unit, shoelace_obsolete.sl_len_cm FROM shoelace_obsolete WHERE (shoelace_obsolete.sl_avail = 0);
  shoelace_obsolete        | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
- street                   | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
- toyemp                   | SELECT emp.name, emp.age, emp."location", (12 * emp.salary) AS annualsal FROM emp;
+ street                   | SELECT r."name", r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
+ toyemp                   | SELECT emp."name", emp.age, emp."location", (12 * emp.salary) AS annualsal FROM emp;
 (48 rows)
 
 SELECT tablename, rulename, definition FROM pg_rules 
        ORDER BY tablename, rulename;
-   tablename   |    rulename     |                                                                                                                                  definition                                                                                                                                   
----------------+-----------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+   tablename   |    rulename     |                                                                                                                                   definition                                                                                                                                    
+---------------+-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  pg_settings   | pg_settings_n   | CREATE RULE pg_settings_n AS ON UPDATE TO pg_settings DO INSTEAD NOTHING;
- pg_settings   | pg_settings_u   | CREATE RULE pg_settings_u AS ON UPDATE TO pg_settings WHERE (new.name = old.name) DO SELECT set_config(old.name, new.setting, false) AS set_config;
+ pg_settings   | pg_settings_u   | CREATE RULE pg_settings_u AS ON UPDATE TO pg_settings WHERE (new."name" = old."name") DO SELECT set_config(old."name", new.setting, false) AS set_config;
  rtest_emp     | rtest_emp_del   | CREATE RULE rtest_emp_del AS ON DELETE TO rtest_emp DO INSERT INTO rtest_emplog (ename, who, "action", newsal, oldsal) VALUES (old.ename, "current_user"(), 'fired'::bpchar, '$0.00'::money, old.salary);
  rtest_emp     | rtest_emp_ins   | CREATE RULE rtest_emp_ins AS ON INSERT TO rtest_emp DO INSERT INTO rtest_emplog (ename, who, "action", newsal, oldsal) VALUES (new.ename, "current_user"(), 'hired'::bpchar, new.salary, '$0.00'::money);
  rtest_emp     | rtest_emp_upd   | CREATE RULE rtest_emp_upd AS ON UPDATE TO rtest_emp WHERE (new.salary <> old.salary) DO INSERT INTO rtest_emplog (ename, who, "action", newsal, oldsal) VALUES (new.ename, "current_user"(), 'honored'::bpchar, new.salary, old.salary);
@@ -1357,7 +1357,7 @@ SELECT tablename, rulename, definition FROM pg_rules
  shoelace      | shoelace_del    | CREATE RULE shoelace_del AS ON DELETE TO shoelace DO INSTEAD DELETE FROM shoelace_data WHERE (shoelace_data.sl_name = old.sl_name);
  shoelace      | shoelace_ins    | CREATE RULE shoelace_ins AS ON INSERT TO shoelace DO INSTEAD INSERT INTO shoelace_data (sl_name, sl_avail, sl_color, sl_len, sl_unit) VALUES (new.sl_name, new.sl_avail, new.sl_color, new.sl_len, new.sl_unit);
  shoelace      | shoelace_upd    | CREATE RULE shoelace_upd AS ON UPDATE TO shoelace DO INSTEAD UPDATE shoelace_data SET sl_name = new.sl_name, sl_avail = new.sl_avail, sl_color = new.sl_color, sl_len = new.sl_len, sl_unit = new.sl_unit WHERE (shoelace_data.sl_name = old.sl_name);
- shoelace_data | log_shoelace    | CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data WHERE (new.sl_avail <> old.sl_avail) DO INSERT INTO shoelace_log (sl_name, sl_avail, log_who, log_when) VALUES (new.sl_name, new.sl_avail, 'Al Bundy'::name, 'Thu Jan 01 00:00:00 1970'::timestamp without time zone);
+ shoelace_data | log_shoelace    | CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data WHERE (new.sl_avail <> old.sl_avail) DO INSERT INTO shoelace_log (sl_name, sl_avail, log_who, log_when) VALUES (new.sl_name, new.sl_avail, 'Al Bundy'::"name", 'Thu Jan 01 00:00:00 1970'::timestamp without time zone);
  shoelace_ok   | shoelace_ok_ins | CREATE RULE shoelace_ok_ins AS ON INSERT TO shoelace_ok DO INSTEAD UPDATE shoelace SET sl_avail = (shoelace.sl_avail + new.ok_quant) WHERE (shoelace.sl_name = new.ok_name);
 (29 rows)
 
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
new file mode 100644 (file)
index 0000000..20a2d4f
--- /dev/null
@@ -0,0 +1,145 @@
+CREATE TABLE xmltest (
+    id int,
+    data xml
+);
+INSERT INTO xmltest VALUES (1, '<value>one</value>');
+INSERT INTO xmltest VALUES (2, '<value>two</value>');
+INSERT INTO xmltest VALUES (3, '<wrong');
+ERROR:  could not parse XML data
+DETAIL:  Expected '>'
+SELECT * FROM xmltest;
+ id |        data        
+----+--------------------
+  1 | <value>one</value>
+  2 | <value>two</value>
+(2 rows)
+
+SELECT xmlcomment('test');
+ xmlcomment  
+-------------
+ <!--test-->
+(1 row)
+
+SELECT xmlcomment('-test');
+  xmlcomment  
+--------------
+ <!---test-->
+(1 row)
+
+SELECT xmlcomment('test-');
+ERROR:  invalid XML comment
+SELECT xmlcomment('--test');
+ERROR:  invalid XML comment
+SELECT xmlcomment('te st');
+  xmlcomment  
+--------------
+ <!--te st-->
+(1 row)
+
+SELECT xmlconcat(xmlcomment('hello'),
+                 xmlelement(NAME qux, 'foo'),
+                 xmlcomment('world'));
+               xmlconcat                
+----------------------------------------
+ <!--hello--><qux>foo</qux><!--world-->
+(1 row)
+
+SELECT xmlconcat('hello', 'you');
+ xmlconcat 
+-----------
+ helloyou
+(1 row)
+
+SELECT xmlconcat(1, 2);
+ERROR:  argument of XMLCONCAT must be type xml, not type integer
+SELECT xmlconcat('bad', '<syntax');
+ERROR:  could not parse XML data
+DETAIL:  Expected '>'
+SELECT xmlelement(name element,
+                  xmlattributes (1 as one, 'deuce' as two),
+                  'content');
+                   xmlelement                   
+------------------------------------------------
+ <element one="1" two="deuce">content</element>
+(1 row)
+
+SELECT xmlelement(name element,
+                  xmlattributes ('unnamed and wrong'));
+ERROR:  unnamed attribute value must be a column reference
+SELECT xmlelement(name element, xmlelement(name nested, 'stuff'));
+                xmlelement                 
+-------------------------------------------
+ <element><nested>stuff</nested></element>
+(1 row)
+
+SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
+                              xmlelement                              
+----------------------------------------------------------------------
+ <employee><name>sharon</name><age>25</age><pay>1000</pay></employee>
+ <employee><name>sam</name><age>30</age><pay>2000</pay></employee>
+ <employee><name>bill</name><age>20</age><pay>1000</pay></employee>
+ <employee><name>jeff</name><age>23</age><pay>600</pay></employee>
+ <employee><name>cim</name><age>30</age><pay>400</pay></employee>
+ <employee><name>linda</name><age>19</age><pay>100</pay></employee>
+(6 rows)
+
+SELECT xmlelement(name wrong, 37);
+ERROR:  argument of XMLELEMENT must be type xml, not type integer
+SELECT xmlpi(name foo);
+  xmlpi  
+---------
+ <?foo?>
+(1 row)
+
+SELECT xmlpi(name xmlstuff);
+ERROR:  invalid XML processing instruction
+DETAIL:  XML processing instruction target name cannot start with "xml".
+SELECT xmlpi(name foo, 'bar');
+    xmlpi    
+-------------
+ <?foo bar?>
+(1 row)
+
+SELECT xmlpi(name foo, 'in?>valid');
+ERROR:  invalid XML processing instruction
+DETAIL:  XML processing instruction cannot contain "?>".
+SELECT xmlroot (
+  xmlelement (
+    name gazonk,
+    xmlattributes (
+      'val' AS name,
+      1 + 1 AS num
+    ),
+    xmlelement (
+      NAME qux,
+      'foo'
+    )
+  ),
+  version '1.0',
+  standalone yes
+);
+                                         xmlroot                                          
+------------------------------------------------------------------------------------------
+ <?xml version="1.0" standalone="yes"?><gazonk name="val" num="2"><qux>foo</qux></gazonk>
+(1 row)
+
+SELECT xmlserialize(content data as character varying) FROM xmltest;
+        data        
+--------------------
+ <value>one</value>
+ <value>two</value>
+(2 rows)
+
+-- Check mapping SQL identifier to XML name
+SELECT xmlpi(name ":::_xml_abc135.%-&_");
+                      xmlpi                      
+-------------------------------------------------
+ <?_x003A_::_x005F_xml_abc135._x0025_-_x0026__?>
+(1 row)
+
+SELECT xmlpi(name "123");
+     xmlpi     
+---------------
+ <?_x0031_23?>
+(1 row)
+
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
new file mode 100644 (file)
index 0000000..24d1e18
--- /dev/null
@@ -0,0 +1,77 @@
+CREATE TABLE xmltest (
+    id int,
+    data xml
+);
+INSERT INTO xmltest VALUES (1, '<value>one</value>');
+ERROR:  no XML support in this installation
+INSERT INTO xmltest VALUES (2, '<value>two</value>');
+ERROR:  no XML support in this installation
+INSERT INTO xmltest VALUES (3, '<wrong');
+ERROR:  no XML support in this installation
+SELECT * FROM xmltest;
+ id | data 
+----+------
+(0 rows)
+
+SELECT xmlcomment('test');
+ERROR:  no XML support in this installation
+SELECT xmlcomment('-test');
+ERROR:  no XML support in this installation
+SELECT xmlcomment('test-');
+ERROR:  no XML support in this installation
+SELECT xmlcomment('--test');
+ERROR:  no XML support in this installation
+SELECT xmlcomment('te st');
+ERROR:  no XML support in this installation
+SELECT xmlconcat(xmlcomment('hello'),
+                 xmlelement(NAME qux, 'foo'),
+                 xmlcomment('world'));
+ERROR:  no XML support in this installation
+SELECT xmlconcat('hello', 'you');
+ERROR:  no XML support in this installation
+SELECT xmlconcat(1, 2);
+ERROR:  argument of XMLCONCAT must be type xml, not type integer
+SELECT xmlconcat('bad', '<syntax');
+ERROR:  no XML support in this installation
+SELECT xmlelement(name element,
+                  xmlattributes (1 as one, 'deuce' as two),
+                  'content');
+ERROR:  no XML support in this installation
+SELECT xmlelement(name element,
+                  xmlattributes ('unnamed and wrong'));
+ERROR:  no XML support in this installation
+SELECT xmlelement(name element, xmlelement(name nested, 'stuff'));
+ERROR:  no XML support in this installation
+SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
+ERROR:  no XML support in this installation
+SELECT xmlelement(name wrong, 37);
+ERROR:  no XML support in this installation
+SELECT xmlpi(name foo);
+ERROR:  no XML support in this installation
+SELECT xmlpi(name xmlstuff);
+ERROR:  no XML support in this installation
+SELECT xmlpi(name foo, 'bar');
+ERROR:  no XML support in this installation
+SELECT xmlpi(name foo, 'in?>valid');
+ERROR:  no XML support in this installation
+SELECT xmlroot (
+  xmlelement (
+    name gazonk,
+    xmlattributes (
+      'val' AS name,
+      1 + 1 AS num
+    ),
+    xmlelement (
+      NAME qux,
+      'foo'
+    )
+  ),
+  version '1.0',
+  standalone yes
+);
+ERROR:  no XML support in this installation
+-- Check mapping SQL identifier to XML name
+SELECT xmlpi(name ":::_xml_abc135.%-&_");
+ERROR:  no XML support in this installation
+SELECT xmlpi(name "123");
+ERROR:  no XML support in this installation
index f13ea4792a341b67c139d186d2ab7a4c0eaeab90..a8f9ee09b591db09427c85f179e14c801294673c 100644 (file)
@@ -1,6 +1,6 @@
 # ----------
 # The first group of parallel test
-# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.35 2006/08/30 23:34:22 tgl Exp $
+# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.36 2006/12/21 16:05:16 petere Exp $
 # ----------
 test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric
 
@@ -75,7 +75,7 @@ test: select_views portals_p2 rules foreign_key cluster dependency guc
 # The sixth group of parallel test
 # ----------
 # "plpgsql" cannot run concurrently with "rules"
-test: limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism rowtypes returning
+test: limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate alter_table sequence polymorphism rowtypes returning xml
 
 # run stats by itself because its delay may be insufficient under heavy load
 test: stats
index 2d44e585d38a628802fa5e29fee07fbcfa715b94..1fa94fadc0417d7ba4005300097bcb1cac384ad0 100644 (file)
@@ -1,4 +1,4 @@
-# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.33 2006/08/30 23:34:22 tgl Exp $
+# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.34 2006/12/21 16:05:16 petere Exp $
 # This should probably be in an order similar to parallel_schedule.
 test: boolean
 test: char
@@ -102,5 +102,6 @@ test: sequence
 test: polymorphism
 test: rowtypes
 test: returning
+test: xml
 test: stats
 test: tablespace
index 7fc99152757b65f76382fd9f81b2f7df9e3618d2..5195a290abb994fb1be49efdeae28adb75b926c7 100644 (file)
@@ -76,7 +76,7 @@ WHERE p1.oid != p2.oid AND
 SELECT p1.oid, p1.proname, p2.oid, p2.proname
 FROM pg_proc AS p1, pg_proc AS p2
 WHERE p1.oid < p2.oid AND
-    p1.prosrc = p2.prosrc AND
+    p1.prosrc = p2.prosrc AND p1.prosrc NOT IN ('xmlparse', 'xmlpi') AND
     p1.prolang = 12 AND p2.prolang = 12 AND
     (p1.proisagg = false OR p2.proisagg = false) AND
     (p1.prolang != p2.prolang OR
@@ -235,6 +235,9 @@ WHERE c.castfunc = p.oid AND
 -- As of 8.2, this finds the cast from cidr to inet, because that is a
 -- trivial binary coercion while the other way goes through inet_to_cidr().
 
+-- As of 8.3, this finds casts from xml to text, varchar, and bpchar,
+-- because the other direction has to go through xmlparse().
+
 SELECT *
 FROM pg_cast c
 WHERE c.castfunc = 0 AND
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
new file mode 100644 (file)
index 0000000..061f632
--- /dev/null
@@ -0,0 +1,72 @@
+CREATE TABLE xmltest (
+    id int,
+    data xml
+);
+
+INSERT INTO xmltest VALUES (1, '<value>one</value>');
+INSERT INTO xmltest VALUES (2, '<value>two</value>');
+INSERT INTO xmltest VALUES (3, '<wrong');
+
+SELECT * FROM xmltest;
+
+
+SELECT xmlcomment('test');
+SELECT xmlcomment('-test');
+SELECT xmlcomment('test-');
+SELECT xmlcomment('--test');
+SELECT xmlcomment('te st');
+
+
+SELECT xmlconcat(xmlcomment('hello'),
+                 xmlelement(NAME qux, 'foo'),
+                 xmlcomment('world'));
+
+SELECT xmlconcat('hello', 'you');
+SELECT xmlconcat(1, 2);
+SELECT xmlconcat('bad', '<syntax');
+
+
+SELECT xmlelement(name element,
+                  xmlattributes (1 as one, 'deuce' as two),
+                  'content');
+
+SELECT xmlelement(name element,
+                  xmlattributes ('unnamed and wrong'));
+
+SELECT xmlelement(name element, xmlelement(name nested, 'stuff'));
+
+SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
+
+SELECT xmlelement(name wrong, 37);
+
+
+SELECT xmlpi(name foo);
+SELECT xmlpi(name xmlstuff);
+SELECT xmlpi(name foo, 'bar');
+SELECT xmlpi(name foo, 'in?>valid');
+
+
+SELECT xmlroot (
+  xmlelement (
+    name gazonk,
+    xmlattributes (
+      'val' AS name,
+      1 + 1 AS num
+    ),
+    xmlelement (
+      NAME qux,
+      'foo'
+    )
+  ),
+  version '1.0',
+  standalone yes
+);
+
+
+SELECT xmlserialize(content data as character varying) FROM xmltest;
+
+
+-- Check mapping SQL identifier to XML name
+
+SELECT xmlpi(name ":::_xml_abc135.%-&_");
+SELECT xmlpi(name "123");