aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/execQual.c35
-rw-r--r--src/backend/nodes/copyfuncs.c20
-rw-r--r--src/backend/nodes/equalfuncs.c17
-rw-r--r--src/backend/nodes/outfuncs.c18
-rw-r--r--src/backend/nodes/readfuncs.c5
-rw-r--r--src/backend/parser/gram.y39
-rw-r--r--src/backend/parser/parse_expr.c46
-rw-r--r--src/backend/parser/parse_target.c8
-rw-r--r--src/backend/utils/adt/ruleutils.c52
-rw-r--r--src/backend/utils/adt/xml.c42
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/catalog/pg_cast.h8
-rw-r--r--src/include/catalog/pg_proc.h4
-rw-r--r--src/include/nodes/nodes.h3
-rw-r--r--src/include/nodes/parsenodes.h13
-rw-r--r--src/include/nodes/primnodes.h12
-rw-r--r--src/include/utils/errcodes.h3
-rw-r--r--src/include/utils/xml.h14
-rw-r--r--src/test/regress/expected/opr_sanity.out7
-rw-r--r--src/test/regress/expected/xml.out36
-rw-r--r--src/test/regress/expected/xml_1.out34
-rw-r--r--src/test/regress/sql/opr_sanity.sql3
-rw-r--r--src/test/regress/sql/xml.sql20
23 files changed, 344 insertions, 99 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 6b72c02781f..fd95672deec 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.211 2007/02/02 00:07:03 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.212 2007/02/03 14:06:53 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2834,11 +2834,10 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
{
ExprState *e;
text *data;
- bool is_document;
bool preserve_whitespace;
- /* arguments are known to be text, bool, bool */
- Assert(list_length(xmlExpr->args) == 3);
+ /* arguments are known to be text, bool */
+ Assert(list_length(xmlExpr->args) == 2);
e = (ExprState *) linitial(xmlExpr->args);
value = ExecEvalExpr(e, econtext, &isnull, NULL);
@@ -2850,18 +2849,12 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
value = ExecEvalExpr(e, econtext, &isnull, NULL);
if (isnull) /* probably can't happen */
return (Datum) 0;
- is_document = DatumGetBool(value);
-
- e = (ExprState *) lthird(xmlExpr->args);
- value = ExecEvalExpr(e, econtext, &isnull, NULL);
- if (isnull) /* probably can't happen */
- return (Datum) 0;
preserve_whitespace = DatumGetBool(value);
*isNull = false;
return PointerGetDatum(xmlparse(data,
- is_document,
+ xexpr->xmloption,
preserve_whitespace));
}
break;
@@ -2900,7 +2893,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
text *version;
int standalone;
- /* arguments are known to be xml, text, bool */
+ /* arguments are known to be xml, text, int */
Assert(list_length(xmlExpr->args) == 3);
e = (ExprState *) linitial(xmlExpr->args);
@@ -2928,6 +2921,24 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
}
break;
+ case IS_XMLSERIALIZE:
+ {
+ ExprState *e;
+
+ /* argument type is known to be xml */
+ Assert(list_length(xmlExpr->args) == 1);
+
+ e = (ExprState *) linitial(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull)
+ return (Datum) 0;
+
+ *isNull = false;
+
+ return PointerGetDatum(xmltotext_with_xmloption(DatumGetXmlP(value), xexpr->xmloption));
+ }
+ break;
+
case IS_DOCUMENT:
{
ExprState *e;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index f213f216de4..2d38d7fd60c 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.364 2007/01/23 05:07:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.365 2007/02/03 14:06:54 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1116,6 +1116,9 @@ _copyXmlExpr(XmlExpr *from)
COPY_NODE_FIELD(named_args);
COPY_NODE_FIELD(arg_names);
COPY_NODE_FIELD(args);
+ COPY_SCALAR_FIELD(xmloption);
+ COPY_SCALAR_FIELD(type);
+ COPY_SCALAR_FIELD(typmod);
return newnode;
}
@@ -1723,6 +1726,18 @@ _copyLockingClause(LockingClause *from)
return newnode;
}
+static XmlSerialize *
+_copyXmlSerialize(XmlSerialize *from)
+{
+ XmlSerialize *newnode = makeNode(XmlSerialize);
+
+ COPY_SCALAR_FIELD(xmloption);
+ COPY_NODE_FIELD(expr);
+ COPY_NODE_FIELD(typename);
+
+ return newnode;
+}
+
static Query *
_copyQuery(Query *from)
{
@@ -3430,6 +3445,9 @@ copyObject(void *from)
case T_FuncWithArgs:
retval = _copyFuncWithArgs(from);
break;
+ case T_XmlSerialize:
+ retval = _copyXmlSerialize(from);
+ break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 31754a7bc02..c17a40bbbb2 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.297 2007/01/23 05:07:17 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.298 2007/02/03 14:06:54 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -462,6 +462,9 @@ _equalXmlExpr(XmlExpr *a, XmlExpr *b)
COMPARE_NODE_FIELD(named_args);
COMPARE_NODE_FIELD(arg_names);
COMPARE_NODE_FIELD(args);
+ COMPARE_SCALAR_FIELD(xmloption);
+ COMPARE_SCALAR_FIELD(type);
+ COMPARE_SCALAR_FIELD(typmod);
return true;
}
@@ -1830,6 +1833,15 @@ _equalFkConstraint(FkConstraint *a, FkConstraint *b)
return true;
}
+static bool
+_equalXmlSerialize(XmlSerialize *a, XmlSerialize *b)
+{
+ COMPARE_SCALAR_FIELD(xmloption);
+ COMPARE_NODE_FIELD(expr);
+ COMPARE_NODE_FIELD(typename);
+
+ return true;
+}
/*
* Stuff from pg_list.h
@@ -2411,6 +2423,9 @@ equal(void *a, void *b)
case T_FuncWithArgs:
retval = _equalFuncWithArgs(a, b);
break;
+ case T_XmlSerialize:
+ retval = _equalXmlSerialize(a, b);
+ break;
default:
elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index b79b7d1a2d8..939c21f45a4 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.295 2007/01/22 20:00:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.296 2007/02/03 14:06:54 petere Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@@ -933,6 +933,9 @@ _outXmlExpr(StringInfo str, XmlExpr *node)
WRITE_NODE_FIELD(named_args);
WRITE_NODE_FIELD(arg_names);
WRITE_NODE_FIELD(args);
+ WRITE_ENUM_FIELD(xmloption, XmlOptionType);
+ WRITE_OID_FIELD(type);
+ WRITE_INT_FIELD(typmod);
}
static void
@@ -1522,6 +1525,16 @@ _outLockingClause(StringInfo str, LockingClause *node)
}
static void
+_outXmlSerialize(StringInfo str, XmlSerialize *node)
+{
+ WRITE_NODE_TYPE("XMLSERIALIZE");
+
+ WRITE_ENUM_FIELD(xmloption, XmlOptionType);
+ WRITE_NODE_FIELD(expr);
+ WRITE_NODE_FIELD(typename);
+}
+
+static void
_outColumnDef(StringInfo str, ColumnDef *node)
{
WRITE_NODE_TYPE("COLUMNDEF");
@@ -2290,6 +2303,9 @@ _outNode(StringInfo str, void *obj)
case T_LockingClause:
_outLockingClause(str, obj);
break;
+ case T_XmlSerialize:
+ _outXmlSerialize(str, obj);
+ break;
default:
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index b90c8dd7130..17d36b4efe6 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.201 2007/01/09 02:14:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.202 2007/02/03 14:06:54 petere Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
@@ -723,6 +723,9 @@ _readXmlExpr(void)
READ_NODE_FIELD(named_args);
READ_NODE_FIELD(arg_names);
READ_NODE_FIELD(args);
+ READ_ENUM_FIELD(xmloption, XmlOptionType);
+ READ_OID_FIELD(type);
+ READ_INT_FIELD(typmod);
READ_DONE();
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 1f1dfdb761d..cf25c5607a6 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.578 2007/02/01 19:10:27 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.579 2007/02/03 14:06:54 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -350,7 +350,8 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
%type <target> xml_attribute_el
%type <list> xml_attribute_list xml_attributes
%type <node> xml_root_version opt_xml_root_standalone
-%type <boolean> document_or_content xml_whitespace_option
+%type <ival> document_or_content
+%type <boolean> xml_whitespace_option
/*
@@ -1117,7 +1118,7 @@ set_rest: var_name TO var_list_or_default
{
VariableSetStmt *n = makeNode(VariableSetStmt);
n->name = "xmloption";
- n->args = list_make1(makeStringConst($3 ? "DOCUMENT" : "CONTENT", NULL));
+ n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", NULL));
$$ = n;
}
;
@@ -7903,10 +7904,11 @@ func_expr: func_name '(' ')'
}
| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
{
- $$ = makeXmlExpr(IS_XMLPARSE, NULL, NIL,
- list_make3($4,
- makeBoolAConst($3),
- makeBoolAConst($5)));
+ XmlExpr *x = (XmlExpr *) makeXmlExpr(IS_XMLPARSE, NULL, NIL,
+ list_make2($4,
+ makeBoolAConst($5)));
+ x->xmloption = $3;
+ $$ = (Node *)x;
}
| XMLPI '(' NAME_P ColLabel ')'
{
@@ -7921,14 +7923,13 @@ func_expr: func_name '(' ')'
$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
list_make3($3, $5, $6));
}
- | XMLSERIALIZE '(' document_or_content a_expr AS Typename ')'
+ | XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
{
- /*
- * FIXME: This should be made distinguishable from
- * CAST (for reverse compilation at least). Also,
- * what about the document/content option??
- */
- $$ = makeTypeCast($4, $6);
+ XmlSerialize *n = makeNode(XmlSerialize);
+ n->xmloption = $3;
+ n->expr = $4;
+ n->typename = $6;
+ $$ = (Node *)n;
}
;
@@ -7980,17 +7981,13 @@ xml_attribute_el: a_expr AS ColLabel
}
;
-document_or_content: DOCUMENT_P { $$ = TRUE; }
- | CONTENT_P { $$ = FALSE; }
+document_or_content: DOCUMENT_P { $$ = XMLOPTION_DOCUMENT; }
+ | CONTENT_P { $$ = XMLOPTION_CONTENT; }
;
-/*
- * XXX per SQL spec, the default should be STRIP WHITESPACE, but since we
- * haven't implemented that yet, temporarily default to PRESERVE.
- */
xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = TRUE; }
| STRIP_P WHITESPACE_P { $$ = FALSE; }
- | /*EMPTY*/ { $$ = TRUE; }
+ | /*EMPTY*/ { $$ = FALSE; }
;
/*
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index a807ef12de4..e7a37a2cfa6 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.209 2007/01/25 11:53:51 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.210 2007/02/03 14:06:54 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -57,6 +57,7 @@ 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 *transformXmlSerialize(ParseState *pstate, XmlSerialize *xs);
static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
@@ -224,6 +225,10 @@ transformExpr(ParseState *pstate, Node *expr)
result = transformXmlExpr(pstate, (XmlExpr *) expr);
break;
+ case T_XmlSerialize:
+ result = transformXmlSerialize(pstate, (XmlSerialize *) expr);
+ break;
+
case T_NullTest:
{
NullTest *n = (NullTest *) expr;
@@ -1424,6 +1429,8 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
newx->arg_names = lappend(newx->arg_names, makeString(argname));
}
+ newx->xmloption = x->xmloption;
+
if (x->op == IS_XMLELEMENT)
{
foreach(lc, newx->arg_names)
@@ -1484,6 +1491,9 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
newe = coerce_to_specific_type(pstate, newe, INT4OID,
"XMLROOT");
break;
+ case IS_XMLSERIALIZE:
+ /* not handled here */
+ break;
case IS_DOCUMENT:
newe = coerce_to_specific_type(pstate, newe, XMLOID,
"IS DOCUMENT");
@@ -1497,6 +1507,38 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
}
static Node *
+transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
+{
+ Oid targetType;
+ int32 targetTypmod;
+ XmlExpr *xexpr;
+
+ xexpr = makeNode(XmlExpr);
+ xexpr->op = IS_XMLSERIALIZE;
+ xexpr->args = list_make1(coerce_to_specific_type(pstate,
+ transformExpr(pstate, xs->expr),
+ XMLOID,
+ "XMLSERIALIZE"));
+
+ targetType = typenameTypeId(pstate, xs->typename);
+ targetTypmod = typenameTypeMod(pstate, xs->typename, targetType);
+
+ xexpr->xmloption = xs->xmloption;
+ /* We actually only need these to be able to parse back the expression. */
+ xexpr->type = targetType;
+ xexpr->typmod = targetTypmod;
+
+ /*
+ * The actual target type is determined this way. SQL allows char
+ * and varchar as target types. We allow anything that can be
+ * cast implicitly from text. This way, user-defined text-like
+ * data types automatically fit in.
+ */
+ return (Node *) coerce_to_target_type(pstate, (Node *) xexpr, TEXTOID, targetType, targetTypmod,
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
+}
+
+static Node *
transformBooleanTest(ParseState *pstate, BooleanTest *b)
{
const char *clausename;
@@ -1789,6 +1831,8 @@ exprType(Node *expr)
case T_XmlExpr:
if (((XmlExpr *) expr)->op == IS_DOCUMENT)
type = BOOLOID;
+ else if (((XmlExpr *) expr)->op == IS_XMLSERIALIZE)
+ type = TEXTOID;
else
type = XMLOID;
break;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index dea29d1d8aa..cc4bc091d24 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.153 2007/01/14 13:11:54 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.154 2007/02/03 14:06:54 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1337,11 +1337,17 @@ FigureColnameInternal(Node *node, char **name)
case IS_XMLROOT:
*name = "xmlroot";
return 2;
+ case IS_XMLSERIALIZE:
+ *name = "xmlserialize";
+ return 2;
case IS_DOCUMENT:
/* nothing */
break;
}
break;
+ case T_XmlSerialize:
+ *name = "xmlserialize";
+ return 2;
default:
break;
}
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 668266d1c4d..3cd317361f4 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.247 2007/01/30 02:39:27 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.248 2007/02/03 14:06:54 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3856,9 +3856,19 @@ get_rule_expr(Node *node, deparse_context *context,
case IS_XMLROOT:
appendStringInfoString(buf, "XMLROOT(");
break;
+ case IS_XMLSERIALIZE:
+ appendStringInfoString(buf, "XMLSERIALIZE(");
+ break;
case IS_DOCUMENT:
break;
}
+ if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
+ {
+ if (xexpr->xmloption == XMLOPTION_DOCUMENT)
+ appendStringInfoString(buf, "DOCUMENT ");
+ else
+ appendStringInfoString(buf, "CONTENT ");
+ }
if (xexpr->name)
{
appendStringInfo(buf, "NAME %s",
@@ -3899,24 +3909,17 @@ get_rule_expr(Node *node, deparse_context *context,
case IS_XMLELEMENT:
case IS_XMLFOREST:
case IS_XMLPI:
+ case IS_XMLSERIALIZE:
/* no extra decoration needed */
get_rule_expr((Node *) xexpr->args, context, true);
break;
case IS_XMLPARSE:
- Assert(list_length(xexpr->args) == 3);
-
- con = (Const *) lsecond(xexpr->args);
- Assert(IsA(con, Const));
- Assert(!con->constisnull);
- if (DatumGetBool(con->constvalue))
- appendStringInfoString(buf, "DOCUMENT ");
- else
- appendStringInfoString(buf, "CONTENT ");
+ Assert(list_length(xexpr->args) == 2);
get_rule_expr((Node *) linitial(xexpr->args),
context, true);
- con = (Const *) lthird(xexpr->args);
+ con = (Const *) lsecond(xexpr->args);
Assert(IsA(con, Const));
Assert(!con->constisnull);
if (DatumGetBool(con->constvalue))
@@ -3944,12 +3947,26 @@ get_rule_expr(Node *node, deparse_context *context,
Assert(IsA(con, Const));
if (con->constisnull)
/* suppress STANDALONE NO VALUE */ ;
- else if (DatumGetBool(con->constvalue))
- appendStringInfoString(buf,
- ", STANDALONE YES");
else
- appendStringInfoString(buf,
- ", STANDALONE NO");
+ {
+ switch (DatumGetInt32(con->constvalue))
+ {
+ case XML_STANDALONE_YES:
+ appendStringInfoString(buf,
+ ", STANDALONE YES");
+ break;
+ case XML_STANDALONE_NO:
+ appendStringInfoString(buf,
+ ", STANDALONE NO");
+ break;
+ case XML_STANDALONE_NO_VALUE:
+ appendStringInfoString(buf,
+ ", STANDALONE NO VALUE");
+ break;
+ default:
+ break;
+ }
+ }
break;
case IS_DOCUMENT:
get_rule_expr_paren((Node *) xexpr->args, context, false, node);
@@ -3957,6 +3974,9 @@ get_rule_expr(Node *node, deparse_context *context,
}
}
+ if (xexpr->op == IS_XMLSERIALIZE)
+ appendStringInfo(buf, " AS %s", format_type_with_typemod(xexpr->type,
+ xexpr->typmod));
if (xexpr->op == IS_DOCUMENT)
appendStringInfoString(buf, " IS DOCUMENT");
else
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 7d963148d0e..70e566327da 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.24 2007/01/27 14:50:51 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.25 2007/02/03 14:06:55 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -80,7 +80,7 @@ static void xml_ereport_by_code(int level, int sqlcode,
static xmlChar *xml_text2xmlChar(text *in);
static int parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **encoding, int *standalone);
static bool print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int standalone);
-static xmlDocPtr xml_parse(text *data, bool is_document, bool preserve_whitespace, xmlChar *encoding);
+static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xmlChar *encoding);
#endif /* USE_LIBXML */
@@ -112,7 +112,7 @@ xml_in(PG_FUNCTION_ARGS)
* Parse the data to check if it is well-formed XML data. Assume
* that ERROR occurred if parsing failed.
*/
- doc = xml_parse(vardata, (xmloption == XMLOPTION_DOCUMENT), true, NULL);
+ doc = xml_parse(vardata, xmloption, true, NULL);
xmlFreeDoc(doc);
PG_RETURN_XML_P(vardata);
@@ -211,7 +211,7 @@ xml_recv(PG_FUNCTION_ARGS)
* Parse the data to check if it is well-formed XML data. Assume
* that ERROR occurred if parsing failed.
*/
- doc = xml_parse(result, (xmloption == XMLOPTION_DOCUMENT), true, encoding);
+ doc = xml_parse(result, xmloption, true, encoding);
xmlFreeDoc(doc);
newstr = (char *) pg_do_encoding_conversion((unsigned char *) str,
@@ -435,7 +435,29 @@ texttoxml(PG_FUNCTION_ARGS)
{
text *data = PG_GETARG_TEXT_P(0);
- PG_RETURN_XML_P(xmlparse(data, (xmloption == XMLOPTION_DOCUMENT), true));
+ PG_RETURN_XML_P(xmlparse(data, xmloption, true));
+}
+
+
+Datum
+xmltotext(PG_FUNCTION_ARGS)
+{
+ xmltype *data = PG_GETARG_XML_P(0);
+
+ PG_RETURN_TEXT_P(xmltotext_with_xmloption(data, xmloption));
+}
+
+
+text *
+xmltotext_with_xmloption(xmltype *data, XmlOptionType xmloption_arg)
+{
+ if (xmloption_arg == XMLOPTION_DOCUMENT && !xml_is_document(data))
+ ereport(ERROR,
+ (errcode(ERRCODE_NOT_AN_XML_DOCUMENT),
+ errmsg("not an XML document")));
+
+ /* It's actually binary compatible, save for the above check. */
+ return (text *) data;
}
@@ -499,12 +521,12 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext)
xmltype *
-xmlparse(text *data, bool is_document, bool preserve_whitespace)
+xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace)
{
#ifdef USE_LIBXML
xmlDocPtr doc;
- doc = xml_parse(data, is_document, preserve_whitespace, NULL);
+ doc = xml_parse(data, xmloption_arg, preserve_whitespace, NULL);
xmlFreeDoc(doc);
return (xmltype *) data;
@@ -723,7 +745,7 @@ xml_is_document(xmltype *arg)
PG_TRY();
{
- doc = xml_parse((text *) arg, true, true, NULL);
+ doc = xml_parse((text *) arg, XMLOPTION_DOCUMENT, true, NULL);
result = true;
}
PG_CATCH();
@@ -996,7 +1018,7 @@ print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int stan
* TODO maybe, libxml2's xmlreader is better? (do not construct DOM, yet do not use SAX - see xml_reader.c)
*/
static xmlDocPtr
-xml_parse(text *data, bool is_document, bool preserve_whitespace, xmlChar *encoding)
+xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xmlChar *encoding)
{
int32 len;
xmlChar *string;
@@ -1024,7 +1046,7 @@ xml_parse(text *data, bool is_document, bool preserve_whitespace, xmlChar *encod
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
"could not allocate parser context");
- if (is_document)
+ if (xmloption_arg == XMLOPTION_DOCUMENT)
{
/*
* Note, that here we try to apply DTD defaults
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 8157a3f6a59..2f1bb8ae1a4 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.378 2007/01/31 19:33:54 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.379 2007/02/03 14:06:55 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200701311
+#define CATALOG_VERSION_NO 200702031
#endif
diff --git a/src/include/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 4fbf237dad2..0047f865af2 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -10,7 +10,7 @@
*
* Copyright (c) 2002-2007, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.30 2007/01/31 19:33:54 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.31 2007/02/03 14:06:55 petere Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@@ -300,7 +300,7 @@ 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 ( 142 25 2922 e ));
DATA(insert ( 25 142 2896 e ));
/*
@@ -340,7 +340,7 @@ 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 ( 142 1043 2922 e ));
DATA(insert ( 1043 142 2896 e ));
/*
@@ -381,7 +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 ));
+DATA(insert ( 142 1042 2922 e ));
/*
* Length-coercion functions
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index eaee3410962..500d2395422 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.441 2007/01/28 16:16:52 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.442 2007/02/03 14:06:55 petere Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@@ -4045,6 +4045,8 @@ DATA(insert OID = 2900 ( xmlconcat2 PGNSP PGUID 12 1 0 f f f f i 2 142 "1
DESCR("aggregate transition function");
DATA(insert OID = 2901 ( xmlagg PGNSP PGUID 12 1 0 t f f f i 1 142 "142" _null_ _null_ _null_ aggregate_dummy - _null_ ));
DESCR("concatenate XML values");
+DATA(insert OID = 2922 ( text PGNSP PGUID 12 1 0 f f t f s 1 25 "142" _null_ _null_ _null_ xmltotext - _null_ ));
+DESCR("serialize an XML value to a character string");
/* uuid */
DATA(insert OID = 2952 ( uuid_in PGNSP PGUID 12 1 0 f f t f i 1 2950 "2275" _null_ _null_ _null_ uuid_in - _null_ ));
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index f3762facdd6..2452f792940 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.193 2007/01/23 05:07:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.194 2007/02/03 14:06:55 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -331,6 +331,7 @@ typedef enum NodeTag
T_FunctionParameter,
T_LockingClause,
T_RowMarkClause,
+ T_XmlSerialize,
/*
* TAGS FOR RANDOM OTHER STUFF
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index a252308bdb2..0db72763021 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.339 2007/01/23 05:07:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.340 2007/02/03 14:06:55 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -485,6 +485,17 @@ typedef struct LockingClause
bool noWait; /* NOWAIT option */
} LockingClause;
+/*
+ * XMLSERIALIZE
+ */
+typedef struct XmlSerialize
+{
+ NodeTag type;
+ XmlOptionType xmloption;
+ Node *expr;
+ TypeName *typename;
+} XmlSerialize;
+
/****************************************************************************
* Nodes for a Query tree
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index cea0cd2f6a5..298ac0d95d6 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.123 2007/01/14 13:11:54 petere Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.124 2007/02/03 14:06:56 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -726,9 +726,16 @@ typedef enum XmlExprOp
IS_XMLPARSE, /* XMLPARSE(text, is_doc, preserve_ws) */
IS_XMLPI, /* XMLPI(name [, args]) */
IS_XMLROOT, /* XMLROOT(xml, version, standalone) */
+ IS_XMLSERIALIZE, /* XMLSERIALIZE(is_document, xmlval) */
IS_DOCUMENT /* xmlval IS DOCUMENT */
} XmlExprOp;
+typedef enum
+{
+ XMLOPTION_DOCUMENT,
+ XMLOPTION_CONTENT
+} XmlOptionType;
+
typedef struct XmlExpr
{
Expr xpr;
@@ -737,6 +744,9 @@ typedef struct XmlExpr
List *named_args; /* non-XML expressions for xml_attributes */
List *arg_names; /* parallel list of Value strings */
List *args; /* list of expressions */
+ XmlOptionType xmloption; /* DOCUMENT or CONTENT */
+ Oid type; /* target type for XMLSERIALIZE */
+ int32 typmod;
} XmlExpr;
/*
diff --git a/src/include/utils/errcodes.h b/src/include/utils/errcodes.h
index 0e4d83a8023..010918ab41f 100644
--- a/src/include/utils/errcodes.h
+++ b/src/include/utils/errcodes.h
@@ -11,7 +11,7 @@
*
* Copyright (c) 2003-2007, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.22 2007/01/05 22:19:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.23 2007/02/03 14:06:56 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -148,6 +148,7 @@
#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_NOT_AN_XML_DOCUMENT MAKE_SQLSTATE('2', '2', '0', '0', 'L')
#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')
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
index f5b33512cfd..f207917ea85 100644
--- a/src/include/utils/xml.h
+++ b/src/include/utils/xml.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.13 2007/01/25 11:53:51 petere Exp $
+ * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.14 2007/02/03 14:06:56 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,10 +17,12 @@
#include "fmgr.h"
#include "nodes/execnodes.h"
+#include "nodes/primnodes.h"
typedef struct varlena xmltype;
#define DatumGetXmlP(X) ((xmltype *) PG_DETOAST_DATUM(X))
+#define XmlPGetDatum(X) PointerGetDatum(X)
#define PG_GETARG_XML_P(n) DatumGetXmlP(PG_GETARG_DATUM(n))
#define PG_RETURN_XML_P(x) PG_RETURN_POINTER(x)
@@ -32,6 +34,7 @@ extern Datum xml_send(PG_FUNCTION_ARGS);
extern Datum xmlcomment(PG_FUNCTION_ARGS);
extern Datum xmlconcat2(PG_FUNCTION_ARGS);
extern Datum texttoxml(PG_FUNCTION_ARGS);
+extern Datum xmltotext(PG_FUNCTION_ARGS);
extern Datum xmlvalidate(PG_FUNCTION_ARGS);
typedef enum
@@ -44,10 +47,11 @@ typedef enum
extern xmltype *xmlconcat(List *args);
extern xmltype *xmlelement(XmlExprState *xmlExpr, ExprContext *econtext);
-extern xmltype *xmlparse(text *data, bool is_doc, bool preserve_whitespace);
+extern xmltype *xmlparse(text *data, XmlOptionType xmloption, bool preserve_whitespace);
extern xmltype *xmlpi(char *target, text *arg, bool arg_is_null, bool *result_is_null);
extern xmltype *xmlroot(xmltype *data, text *version, int standalone);
extern bool xml_is_document(xmltype *arg);
+extern text *xmltotext_with_xmloption(xmltype *data, XmlOptionType xmloption_arg);
extern char *map_sql_identifier_to_xml_name(char *ident, bool fully_escaped);
extern char *map_xml_name_to_sql_identifier(char *name);
@@ -61,12 +65,6 @@ typedef enum
extern XmlBinaryType xmlbinary;
-typedef enum
-{
- XMLOPTION_DOCUMENT,
- XMLOPTION_CONTENT
-} XmlOptionType;
-
extern XmlOptionType xmloption;
#endif /* XML_H */
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 33bebcfa66a..fcbfe3cad51 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -288,8 +288,6 @@ 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
@@ -302,10 +300,7 @@ WHERE c.castfunc = 0 AND
25 | 1042 | 0 | i
1043 | 1042 | 0 | i
650 | 869 | 0 | i
- 142 | 25 | 0 | e
- 142 | 1043 | 0 | e
- 142 | 1042 | 0 | e
-(6 rows)
+(3 rows)
-- **************** pg_operator ****************
-- Look for illegal values in pg_operator fields.
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index 0c086677068..6d79a4166e7 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -275,13 +275,21 @@ SELECT 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
+SELECT xmlserialize(content data as character varying(20)) FROM xmltest;
+ xmlserialize
--------------------
<value>one</value>
<value>two</value>
(2 rows)
+SELECT xmlserialize(content 'good' as char(10));
+ xmlserialize
+--------------
+ good
+(1 row)
+
+SELECT xmlserialize(document 'bad' as text);
+ERROR: not an XML document
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
?column?
----------
@@ -368,3 +376,27 @@ EXECUTE foo ('good');
<foo/>good
(1 row)
+-- Test backwards parsing
+CREATE VIEW xmlview1 AS SELECT xmlcomment('test');
+CREATE VIEW xmlview2 AS SELECT xmlconcat('hello', 'you');
+CREATE VIEW xmlview3 AS SELECT xmlelement(name element, xmlattributes (1 as ":one:", 'deuce' as two), 'content&');
+CREATE VIEW xmlview4 AS SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
+CREATE VIEW xmlview5 AS SELECT xmlparse(content '<abc>x</abc>');
+CREATE VIEW xmlview6 AS SELECT xmlpi(name foo, 'bar');
+CREATE VIEW xmlview7 AS SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
+CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10));
+CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text);
+SELECT table_name, view_definition FROM information_schema.views WHERE table_name LIKE 'xmlview%';
+ table_name | view_definition
+------------+--------------------------------------------------------------------------------------------------------------------------------
+ xmlview1 | SELECT xmlcomment('test'::text) AS xmlcomment;
+ xmlview2 | SELECT XMLCONCAT('hello'::"xml", 'you'::"xml") AS "xmlconcat";
+ xmlview3 | SELECT XMLELEMENT(NAME element, XMLATTRIBUTES(1 AS ":one:", 'deuce' AS two), 'content&') AS "xmlelement";
+ xmlview4 | SELECT XMLELEMENT(NAME employee, XMLFOREST(emp."name" AS "name", emp.age AS age, emp.salary AS pay)) AS "xmlelement" FROM emp;
+ xmlview5 | SELECT XMLPARSE(CONTENT '<abc>x</abc>'::text STRIP WHITESPACE) AS "xmlparse";
+ xmlview6 | SELECT XMLPI(NAME foo, 'bar'::text) AS "xmlpi";
+ xmlview7 | SELECT XMLROOT('<foo/>'::"xml", VERSION NO VALUE, STANDALONE YES) AS "xmlroot";
+ xmlview8 | SELECT (XMLSERIALIZE(CONTENT 'good'::"xml" AS character(10)))::character(10) AS "xmlserialize";
+ xmlview9 | SELECT XMLSERIALIZE(CONTENT 'good'::"xml" AS text) AS "xmlserialize";
+(9 rows)
+
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 89124ebb98e..899ed4cd266 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -122,11 +122,15 @@ SELECT xmlroot (
standalone yes
);
ERROR: no XML support in this installation
-SELECT xmlserialize(content data as character varying) FROM xmltest;
- data
-------
+SELECT xmlserialize(content data as character varying(20)) FROM xmltest;
+ xmlserialize
+--------------
(0 rows)
+SELECT xmlserialize(content 'good' as char(10));
+ERROR: no XML support in this installation
+SELECT xmlserialize(document 'bad' as text);
+ERROR: no XML support in this installation
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
ERROR: no XML support in this installation
SELECT xml '<foo>bar</foo><bar>foo</bar>' IS DOCUMENT;
@@ -168,3 +172,27 @@ EXECUTE foo ('<bar/>');
ERROR: prepared statement "foo" does not exist
EXECUTE foo ('good');
ERROR: prepared statement "foo" does not exist
+-- Test backwards parsing
+CREATE VIEW xmlview1 AS SELECT xmlcomment('test');
+CREATE VIEW xmlview2 AS SELECT xmlconcat('hello', 'you');
+ERROR: no XML support in this installation
+CREATE VIEW xmlview3 AS SELECT xmlelement(name element, xmlattributes (1 as ":one:", 'deuce' as two), 'content&');
+ERROR: no XML support in this installation
+CREATE VIEW xmlview4 AS SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
+ERROR: no XML support in this installation
+CREATE VIEW xmlview5 AS SELECT xmlparse(content '<abc>x</abc>');
+CREATE VIEW xmlview6 AS SELECT xmlpi(name foo, 'bar');
+ERROR: no XML support in this installation
+CREATE VIEW xmlview7 AS SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
+ERROR: no XML support in this installation
+CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10));
+ERROR: no XML support in this installation
+CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text);
+ERROR: no XML support in this installation
+SELECT table_name, view_definition FROM information_schema.views WHERE table_name LIKE 'xmlview%';
+ table_name | view_definition
+------------+-------------------------------------------------------------------------------
+ xmlview1 | SELECT xmlcomment('test'::text) AS xmlcomment;
+ xmlview5 | SELECT XMLPARSE(CONTENT '<abc>x</abc>'::text STRIP WHITESPACE) AS "xmlparse";
+(2 rows)
+
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 7eff2195dfb..cbf9baf6728 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -238,9 +238,6 @@ WHERE c.castfunc = p.oid AND
-- As of 8.2, this finds the cast from cidr to inet, because that is a
-- trivial binary coercion while the other way goes through inet_to_cidr().
--- As of 8.3, this finds casts from xml to text, varchar, and bpchar,
--- because the other direction has to go through xmlparse().
-
SELECT *
FROM pg_cast c
WHERE c.castfunc = 0 AND
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index b3117c2424f..2f919fb42a0 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -68,6 +68,7 @@ SELECT xmlpi(name foo, null);
SELECT xmlpi(name xmlstuff, null);
SELECT xmlpi(name foo, ' bar');
+
SELECT xmlroot(xml '<foo/>', version no value, standalone no value);
SELECT xmlroot(xml '<foo/>', version '2.0');
SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
@@ -95,7 +96,9 @@ SELECT xmlroot (
);
-SELECT xmlserialize(content data as character varying) FROM xmltest;
+SELECT xmlserialize(content data as character varying(20)) FROM xmltest;
+SELECT xmlserialize(content 'good' as char(10));
+SELECT xmlserialize(document 'bad' as text);
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
@@ -125,3 +128,18 @@ EXECUTE foo ('bad');
SET XML OPTION CONTENT;
EXECUTE foo ('<bar/>');
EXECUTE foo ('good');
+
+
+-- Test backwards parsing
+
+CREATE VIEW xmlview1 AS SELECT xmlcomment('test');
+CREATE VIEW xmlview2 AS SELECT xmlconcat('hello', 'you');
+CREATE VIEW xmlview3 AS SELECT xmlelement(name element, xmlattributes (1 as ":one:", 'deuce' as two), 'content&');
+CREATE VIEW xmlview4 AS SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
+CREATE VIEW xmlview5 AS SELECT xmlparse(content '<abc>x</abc>');
+CREATE VIEW xmlview6 AS SELECT xmlpi(name foo, 'bar');
+CREATE VIEW xmlview7 AS SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
+CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10));
+CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text);
+
+SELECT table_name, view_definition FROM information_schema.views WHERE table_name LIKE 'xmlview%';