]> granicus.if.org Git - postgresql/commitdiff
Implement XMLSERIALIZE for real. Analogously, make the xml to text cast
authorPeter Eisentraut <peter_e@gmx.net>
Sat, 3 Feb 2007 14:06:56 +0000 (14:06 +0000)
committerPeter Eisentraut <peter_e@gmx.net>
Sat, 3 Feb 2007 14:06:56 +0000 (14:06 +0000)
observe the xmloption.

Reorganize the representation of the XML option in the parse tree and the
API to make it easier to manage and understand.

Add regression tests for parsing back XML expressions.

23 files changed:
src/backend/executor/execQual.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/parser/gram.y
src/backend/parser/parse_expr.c
src/backend/parser/parse_target.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/adt/xml.c
src/include/catalog/catversion.h
src/include/catalog/pg_cast.h
src/include/catalog/pg_proc.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/nodes/primnodes.h
src/include/utils/errcodes.h
src/include/utils/xml.h
src/test/regress/expected/opr_sanity.out
src/test/regress/expected/xml.out
src/test/regress/expected/xml_1.out
src/test/regress/sql/opr_sanity.sql
src/test/regress/sql/xml.sql

index 6b72c02781f5dbe1c29f34c04712faf125eba2e9..fd95672deecab8d6c2860a0e1df9bca239307a15 100644 (file)
@@ -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);
@@ -2848,12 +2847,6 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
 
                                e = (ExprState *) lsecond(xmlExpr->args);
                                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);
@@ -2861,7 +2854,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
                                *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;
index f213f216de461cbe0f7a3ec8cccc10b4bbb63e29..2d38d7fd60c0160a97a399c6fd7c5ae12f78d777 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.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));
index 31754a7bc023f47e6e5bbefd67da0849ef041cf9..c17a40bbbb246013f89a3c66be2771a1404667d4 100644 (file)
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.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",
index b79b7d1a2d8f8a12017cfc17c428f50fe6d6c212..939c21f45a45d9da8fdd14c7ad5e207036f560d3 100644 (file)
@@ -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
@@ -1521,6 +1524,16 @@ _outLockingClause(StringInfo str, LockingClause *node)
        WRITE_BOOL_FIELD(noWait);
 }
 
+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)
 {
@@ -2290,6 +2303,9 @@ _outNode(StringInfo str, void *obj)
                        case T_LockingClause:
                                _outLockingClause(str, obj);
                                break;
+                       case T_XmlSerialize:
+                               _outXmlSerialize(str, obj);
+                               break;
 
                        default:
 
index b90c8dd7130d0e9d6e1763e733c88da4c0244ce3..17d36b4efe6db40a92b054b9bf9a6ad988755fe2 100644 (file)
@@ -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();
 }
index 1f1dfdb761d5e239484a10d71b9c069e7f0083e1..cf25c5607a64e439e3d9c427f0318fb324856676 100644 (file)
@@ -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; }
                ;
 
 /*
index a807ef12de4d36fb29c64c2c01d0de133470a207..e7a37a2cfa62d906fd9bc2d7ee927c4fc755a416 100644 (file)
@@ -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");
@@ -1496,6 +1506,38 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
        return (Node *) newx;
 }
 
+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)
 {
@@ -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;
index dea29d1d8aa4995c859037ddfbee8491851ccfb1..cc4bc091d249e7272e9f67da6c4ef4e67178829f 100644 (file)
@@ -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;
        }
index 668266d1c4de29b91b5e1aea52cdd2d235e2843e..3cd317361f44801d5e0ff89ef28717a7a655201e 100644 (file)
@@ -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
index 7d963148d0e11dfa6afe267d29c26dae2ce79c7b..70e566327da1278c328078d9fe5933da4ddb6ca8 100644 (file)
@@ -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
index 8157a3f6a597246c7071e2acea802fbe94f8edaf..2f1bb8ae1a46e36f7e94b944dca9ba38894cdda5 100644 (file)
@@ -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
index 4fbf237dad220dffa22e83533ae8bcf20aa372c9..0047f865af2328e07f19c27f21a3dbab2a2f75c1 100644 (file)
@@ -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
index eaee34109626fed34d5486437c45f9c545e90e97..500d23954220cd0e4f3778a4bb97afb4570c0a19 100644 (file)
@@ -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_ ));
index f3762facdd629ad7d4dda2b1f0a7dad98a360b0a..2452f792940788985bb36782abc2ab9d9bfbb7e4 100644 (file)
@@ -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
index a252308bdb26b4966924c78d6d340b3556e2c2f2..0db72763021e2e23f5806bfcdc1d6b9ee2f0f7df 100644 (file)
@@ -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
index cea0cd2f6a5c24ac83e036133821019c2141e87f..298ac0d95d6f7920b3312bdd7e3e8151227f3bd1 100644 (file)
@@ -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;
 
 /*
index 0e4d83a80237509d5d37edcdd76cc8a375641c36..010918ab41f2491922debe5b2845881692b7e8e5 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 #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')
index f5b33512cfdfc0f1b720099a71050e5d4880509b..f207917ea85a1bf1dd088314af4b12e70607464e 100644 (file)
@@ -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 $
  *
  *-------------------------------------------------------------------------
  */
 
 #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 */
index 33bebcfa66aa008ee80ed1a55ed17e0e863cdfd2..fcbfe3cad510ac9a612c53be1531e90c42ca9ecd 100644 (file)
@@ -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.
index 0c08667706884fc334e90276c307b40fc9ca2ad6..6d79a4166e7cd95c5c92be30bf13c2896614ede4 100644 (file)
@@ -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)
+
index 89124ebb98e2874c738b2d2108e9f74896e33799..899ed4cd266c3fe5f9d15bc548751d2d435b88e2 100644 (file)
@@ -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)
+
index 7eff2195dfb5f36343d8cc5a4e17369667e3bccb..cbf9baf6728c17d17b8c5f0374a29c764eb5fae2 100644 (file)
@@ -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
index b3117c2424f2f073451a6b0b9b3a72637b04c06f..2f919fb42a015c69b5d6bf61d136ec958297cd69 100644 (file)
@@ -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%';