Initial SQL/XML support: xml data type and initial set of functions.

This commit is contained in:
Peter Eisentraut 2006-12-21 16:05:16 +00:00
parent ed1e9cd501
commit 8c1de5fb00
39 changed files with 2446 additions and 128 deletions

267
configure vendored
View File

@ -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
@ -10359,6 +10477,155 @@ fi
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

View 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, [],

View 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>
@ -233,6 +233,12 @@
<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>
@ -248,7 +254,8 @@
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>

View 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>

View 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>

View 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;

View 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;

View 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;

View 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;

View 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))

View 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;

View 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 WITH WITHOUT WORK WRITE
WHEN WHERE WHITESPACE WITH WITHOUT WORK WRITE
YEAR_P
XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
XMLPI XMLROOT XMLSERIALIZE
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.

View 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},
};

View 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.

View 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;

View 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;
}

View 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

View 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;

942
src/backend/utils/adt/xml.c Normal file
View File

@ -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 */
}

View 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);

View 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

View 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,

View 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 */

View 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
* ----------------

View 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)

View 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
*

View 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,

View File

@ -251,6 +251,9 @@
/* 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
@ -627,6 +630,9 @@
/* 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

View 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 $
*
*-------------------------------------------------------------------------
*/
@ -148,6 +148,10 @@
#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')

37
src/include/utils/xml.h Normal file
View File

@ -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 */

View 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.

View 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;

View 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)

View File

@ -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)

View File

@ -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

View 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

View 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

View 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

View File

@ -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");