XML syntax patch - Mailing list pgsql-patches

From Bruce Momjian
Subject XML syntax patch
Date
Msg-id 200609050121.k851LCj12531@momjian.us
Whole thread Raw
Responses Re: XML syntax patch  ("Nikolay Samokhvalov" <samokhvalov@gmail.com>)
Re: XML syntax patch  (David Fetter <david@fetter.org>)
Re: XML syntax patch  (Peter Eisentraut <peter_e@gmx.net>)
List pgsql-patches
I have received an update XML syntax patch from Nikolay (summer of code)
based on David Fetter's patch from 2005.

Comments?  It would be nice to have for 8.2.

--
  Bruce Momjian   bruce@momjian.us
  EnterpriseDB    http://www.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +
Index: src/include/utils/builtins.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/builtins.h,v
retrieving revision 1.281
diff -u -r1.281 builtins.h
--- src/include/utils/builtins.h    28 Jul 2006 18:33:04 -0000    1.281
+++ src/include/utils/builtins.h    4 Sep 2006 23:33:10 -0000
@@ -905,4 +905,9 @@
 /* utils/mmgr/portalmem.c */
 extern Datum pg_cursor(PG_FUNCTION_ARGS);

+/* SQL/XML auxilliary functions (now as a part of varchar.c) */
+extern Datum text_xmlagg_accum(PG_FUNCTION_ARGS);
+extern Datum text_xmlagg(PG_FUNCTION_ARGS);
+
+
 #endif   /* BUILTINS_H */
Index: src/include/catalog/pg_proc.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v
retrieving revision 1.422
diff -u -r1.422 pg_proc.h
--- src/include/catalog/pg_proc.h    19 Aug 2006 01:36:33 -0000    1.422
+++ src/include/catalog/pg_proc.h    4 Sep 2006 23:33:02 -0000
@@ -2756,6 +2756,12 @@
 DESCR("COVAR_SAMP(double, double) aggregate final function");
 DATA(insert OID = 2817 (  float8_corr                PGNSP PGUID 12 f f t f i 1 701 "1022" _null_ _null_ _null_
float8_corr- _null_ )); 
 DESCR("CORR(double, double) aggregate final function");
+DATA(insert OID = 5011 (  text_xmlagg_accum            PGNSP PGUID 12 f f f f i 2 25 "25 25" _null_ _null_ _null_
text_xmlagg_accum- _null_ )); 
+DESCR("XMLAGG accumulate function");
+DATA(insert OID = 5012 (  text_xmlagg                PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_
text_xmlagg- _null_ )); 
+DESCR("XMLAGG aggregate final function");
+DATA(insert OID = 5010 (  xmlagg                    PGNSP PGUID 12 t f f f i 1 25 "25" _null_ _null_ _null_
aggregate_dummy- _null_ )); 
+DESCR("XMLAGG");

 /* To ASCII conversion */
 DATA(insert OID = 1845 ( to_ascii    PGNSP PGUID 12 f f t f i 1    25 "25" _null_ _null_ _null_    to_ascii_default -
_null_)); 
Index: src/include/catalog/pg_aggregate.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_aggregate.h,v
retrieving revision 1.57
diff -u -r1.57 pg_aggregate.h
--- src/include/catalog/pg_aggregate.h    28 Jul 2006 18:33:04 -0000    1.57
+++ src/include/catalog/pg_aggregate.h    4 Sep 2006 23:32:43 -0000
@@ -221,6 +221,9 @@
 DATA(insert ( 2242 bitand          -                    0    1560    _null_ ));
 DATA(insert ( 2243 bitor          -                    0    1560    _null_ ));

+/* xml */
+DATA(insert ( 5010    text_xmlagg_accum    text_xmlagg    0    25    _null_ ));
+
 /*
  * prototypes for functions in pg_aggregate.c
  */
Index: src/include/nodes/nodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/nodes.h,v
retrieving revision 1.187
diff -u -r1.187 nodes.h
--- src/include/nodes/nodes.h    2 Aug 2006 01:59:47 -0000    1.187
+++ src/include/nodes/nodes.h    4 Sep 2006 23:33:05 -0000
@@ -140,6 +140,8 @@
     T_RangeTblRef,
     T_JoinExpr,
     T_FromExpr,
+    T_XmlExpr,
+    T_XmlParams,

     /*
      * TAGS FOR EXPRESSION STATE NODES (execnodes.h)
@@ -167,6 +169,7 @@
     T_MinMaxExprState,
     T_CoerceToDomainState,
     T_DomainConstraintState,
+    T_XmlExprState,

     /*
      * TAGS FOR PLANNER NODES (relation.h)
Index: src/include/nodes/execnodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/execnodes.h,v
retrieving revision 1.160
diff -u -r1.160 execnodes.h
--- src/include/nodes/execnodes.h    25 Aug 2006 04:06:56 -0000    1.160
+++ src/include/nodes/execnodes.h    4 Sep 2006 23:33:05 -0000
@@ -706,6 +706,24 @@
 } MinMaxExprState;

 /* ----------------
+ *        XmlExprState node
+ * ----------------
+ */
+typedef struct XmlExprState
+{
+    ExprState    xprstate;
+    XmlExprOp    op;
+    List        *nargs;            /* the named arguments */
+    List        *args;            /* the arguments, only last should be non xml */
+    List        *xml_args;        /* xml arguments, result is always cstring */
+    Oid            *nargs_tcache;
+    char        **nargs_ncache;
+    Oid            arg_typeId;
+    XmlParams    *params;
+    int    level;                    /* info about tabs now, shared tag's table in future */
+} XmlExprState;
+
+/* ----------------
  *        CoerceToDomainState node
  * ----------------
  */
Index: src/include/nodes/primnodes.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/nodes/primnodes.h,v
retrieving revision 1.115
diff -u -r1.115 primnodes.h
--- src/include/nodes/primnodes.h    27 Jul 2006 19:52:07 -0000    1.115
+++ src/include/nodes/primnodes.h    4 Sep 2006 23:33:07 -0000
@@ -706,6 +706,57 @@
 } MinMaxExpr;

 /*
+ * XmlExpr - holder SQL/XML functions XMLROOT, XMLFOREST, XMLELEMENT,
+ * XMLPI, XMLCOMMENT, XMLCONCAT
+ */
+typedef enum XmlExprOp
+{
+    IS_XMLUNKNOWN = 0,
+    IS_XMLAGG,
+    IS_XMLROOT,
+    IS_XMLELEMENT,
+    IS_XMLFOREST,
+    IS_XMLPI,
+    IS_XMLCOMMENT,
+    IS_XMLCONCAT,
+    IS_XMLSERIALIZE
+} XmlExprOp;
+
+typedef enum XmlParamOp
+{
+    IS_XMLENCODING,
+    IS_XMLVERSION,
+    IS_XMLNAME,
+    IS_XMLSTANDALONE
+} XmlParamOp;
+
+typedef struct XmlParam
+{
+    XmlParamOp    op;
+    char         *value;
+} XmlParam;
+
+typedef struct XmlParams
+{
+    NodeTag     type;
+    char         *encoding;
+    char         *version;
+    char         *name;
+    char         *standalone;
+} XmlParams;
+
+typedef struct XmlExpr
+{
+    Expr        xpr;
+    XmlExprOp    op;                /* function to execute */
+    List        *xml_args;        /* xml arguments */
+    List        *nargs;            /* named arguments */
+    List        *args;
+    XmlParams    *params;        /* non xml argument */
+    int    level;
+} XmlExpr;
+
+/*
  * NullIfExpr - a NULLIF expression
  *
  * Like DistinctExpr, this is represented the same as an OpExpr referencing
Index: src/backend/optimizer/util/clauses.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v
retrieving revision 1.219
diff -u -r1.219 clauses.c
--- src/backend/optimizer/util/clauses.c    12 Aug 2006 20:05:55 -0000    1.219
+++ src/backend/optimizer/util/clauses.c    4 Sep 2006 23:32:11 -0000
@@ -557,6 +557,8 @@
         return false;
     if (IsA(node, MinMaxExpr))
         return false;
+    if (IsA(node, XmlExpr))
+        return false;
     if (IsA(node, NullIfExpr))
         return false;

@@ -870,6 +872,8 @@
         return true;
     if (IsA(node, MinMaxExpr))
         return true;
+    if (IsA(node, XmlExpr))
+        return true;
     if (IsA(node, NullIfExpr))
         return true;
     if (IsA(node, NullTest))
@@ -3243,6 +3247,18 @@
             return walker(((CoalesceExpr *) node)->args, context);
         case T_MinMaxExpr:
             return walker(((MinMaxExpr *) node)->args, context);
+        case T_XmlExpr:
+            {
+                XmlExpr *xexpr = (XmlExpr *) node;
+
+                if (walker(xexpr->nargs, context))
+                    return true;
+                if (walker(xexpr->xml_args, context))
+                    return true;
+                if (walker(xexpr->args, context))
+                    return true;
+            }
+            break;
         case T_NullIfExpr:
             return walker(((NullIfExpr *) node)->args, context);
         case T_NullTest:
@@ -3740,6 +3756,18 @@
                 return (Node *) newnode;
             }
             break;
+        case T_XmlExpr:
+            {
+                XmlExpr *xexpr = (XmlExpr *) node;
+                XmlExpr *newnode;
+
+                FLATCOPY(newnode, xexpr, XmlExpr);
+                MUTATE(newnode->nargs, xexpr->nargs, List *);
+                MUTATE(newnode->xml_args, xexpr->xml_args, List *);
+                MUTATE(newnode->args, xexpr->args, List *);
+                return (Node *) newnode;
+            }
+            break;
         case T_NullIfExpr:
             {
                 NullIfExpr *expr = (NullIfExpr *) node;
Index: src/backend/utils/adt/varchar.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/varchar.c,v
retrieving revision 1.118
diff -u -r1.118 varchar.c
--- src/backend/utils/adt/varchar.c    14 Jul 2006 14:52:24 -0000    1.118
+++ src/backend/utils/adt/varchar.c    4 Sep 2006 23:32:43 -0000
@@ -19,7 +19,7 @@
 #include "libpq/pqformat.h"
 #include "utils/builtins.h"
 #include "mb/pg_wchar.h"
-
+#include "nodes/execnodes.h"

 /*
  * CHAR() and VARCHAR() types are part of the ANSI SQL standard. CHAR()
@@ -806,3 +806,95 @@

     return result;
 }
+
+/*
+ * Temp. aux. functions for XMLAGG SQL/XML function.
+ * In the future, this should be adapted for XML type.
+ *
+ */
+
+/* TODO this (struct and next 2 funcs) should be moved from here */
+typedef struct
+{
+  int32 size;  /* varlena requirment */
+  int max;
+  int offset;
+  bool isNull;
+  char data[1];
+} data;
+
+
+static data *
+makeData(AggState *aggstate, int sz)
+{
+    data *d = (data *) MemoryContextAlloc(aggstate->aggcontext, sz+sizeof(data));
+    d->size = sz+sizeof(data);
+    d->max = sz;
+    d->offset = 0;
+    d->data[0] = '\0';
+    d->isNull = true;
+    return d;
+}
+
+static data *
+reallocData(AggState *aggstate, data *d, int sz)
+{
+    data *nd = makeData(aggstate, sz);
+    memcpy(nd->data, d->data, d->offset);
+    nd->offset = d->offset;
+    nd->isNull = d->isNull;
+    return nd;
+}
+
+
+Datum
+text_xmlagg_accum(PG_FUNCTION_ARGS)
+{
+    data     *d;
+    int     len;
+    text     *str;
+
+    if (PG_ARGISNULL(0))
+        d = NULL;
+    else
+        d = (data *) PG_GETARG_POINTER(0);
+    if (!d)
+        d = makeData((AggState *) fcinfo->context, 1000);
+    if (!PG_ARGISNULL(1))
+    {
+        str = PG_GETARG_TEXT_P(1);
+        d->isNull = false;
+        len = VARSIZE(str) - VARHDRSZ;
+        while (d->max < d->offset + len)
+        {
+                int nmax = d->max *2;
+                data *dn = reallocData((AggState *) fcinfo->context, d, nmax);
+                d = dn;
+        }
+        memcpy(&d->data[d->offset], VARDATA(str), len);
+        d->offset += len;
+    }
+
+  PG_RETURN_POINTER(d);
+}
+
+Datum
+text_xmlagg(PG_FUNCTION_ARGS)
+{
+    data     *d;
+    text     *str;
+
+    if (PG_ARGISNULL(0))
+        elog(ERROR, "internal error");
+
+    d = (data *) PG_GETARG_POINTER(0);
+    if (d->isNull)
+        PG_RETURN_NULL();
+    else
+    {
+        str = palloc(d->offset+VARHDRSZ);
+        VARATT_SIZEP(str) = d->offset+VARHDRSZ;
+        memcpy(VARDATA(str), d->data, d->offset);
+        PG_RETURN_TEXT_P(str);
+    }
+}
Index: src/backend/utils/adt/ruleutils.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v
retrieving revision 1.232
diff -u -r1.232 ruleutils.c
--- src/backend/utils/adt/ruleutils.c    21 Aug 2006 00:57:25 -0000    1.232
+++ src/backend/utils/adt/ruleutils.c    4 Sep 2006 23:32:42 -0000
@@ -2984,6 +2984,7 @@
         case T_RowExpr:
         case T_CoalesceExpr:
         case T_MinMaxExpr:
+        case T_XmlExpr:
         case T_NullIfExpr:
         case T_Aggref:
         case T_FuncExpr:
@@ -3092,6 +3093,7 @@
                 case T_RowExpr:    /* other separators */
                 case T_CoalesceExpr:    /* own parentheses */
                 case T_MinMaxExpr:        /* own parentheses */
+                case T_XmlExpr:            /* own parentheses */
                 case T_NullIfExpr:        /* other separators */
                 case T_Aggref:    /* own parentheses */
                 case T_CaseExpr:        /* other separators */
@@ -3140,6 +3142,7 @@
                 case T_RowExpr:    /* other separators */
                 case T_CoalesceExpr:    /* own parentheses */
                 case T_MinMaxExpr:        /* own parentheses */
+                case T_XmlExpr:            /* own parentheses */
                 case T_NullIfExpr:        /* other separators */
                 case T_Aggref:    /* own parentheses */
                 case T_CaseExpr:        /* other separators */
@@ -3767,6 +3770,43 @@
             }
             break;

+        case T_XmlExpr:
+            {
+                XmlExpr *xexpr = (XmlExpr *) node;
+                switch (xexpr->op)
+                {
+                    case IS_XMLCOMMENT:
+                        appendStringInfo(buf,"XMLCOMMENT(");
+                        break;
+                    case IS_XMLCONCAT:
+                        appendStringInfo(buf,"XMLCONCAT(");
+                        break;
+                    case IS_XMLELEMENT:
+                        appendStringInfo(buf,"XMLELEMENT(");
+                        break;
+                    case IS_XMLFOREST:
+                        appendStringInfo(buf,"XMLFOREST(");
+                        break;
+                    case IS_XMLPI:
+                        appendStringInfo(buf,"XMLPI(");
+                        break;
+                    case IS_XMLROOT:
+                        appendStringInfo(buf,"XMLROOT(");
+                        break;
+                    case IS_XMLSERIALIZE:
+                        appendStringInfo(buf,"XMLSERIALIZE(");
+                        break;
+                    case IS_XMLAGG:
+                    case IS_XMLUNKNOWN:  /* quite compiler warnings */
+                        break;
+                }
+                get_rule_expr((Node *) xexpr->nargs, context, true);
+                get_rule_expr((Node *) xexpr->xml_args, context, true);
+                get_rule_expr((Node *) xexpr->args, context, true);
+                appendStringInfoChar(buf, ')');
+            }
+            break;
+
         case T_NullIfExpr:
             {
                 NullIfExpr *nullifexpr = (NullIfExpr *) node;
Index: src/backend/parser/gram.y
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.565
diff -u -r2.565 gram.y
--- src/backend/parser/gram.y    3 Sep 2006 22:37:05 -0000    2.565
+++ src/backend/parser/gram.y    4 Sep 2006 23:32:27 -0000
@@ -107,6 +107,10 @@
 static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
 static Node *doNegate(Node *n, int location);
 static void doNegateFloat(Value *v);
+static XmlExpr *makeXmlExpr(XmlExprOp op, char *name,
+                                List *xml_attr, List *xml_args,
+                                List *args, XmlParams *params);
+static XmlParams *setXmlParam(XmlParams *params, XmlParamOp op, char *value);

 %}

@@ -144,6 +148,10 @@

     InsertStmt            *istmt;
     VariableSetStmt        *vsetstmt;
+
+    XmlExpr                *xmlexpr;
+    XmlParams            *xmlparams;
+    XmlParam            xmlparam;
 }

 %type <node>    stmt schema_stmt
@@ -346,6 +354,12 @@
 %type <str>        OptTableSpace OptConsTableSpace OptTableSpaceOwner
 %type <list>    opt_check_option

+%type <target>    n_expr_el
+%type <xmlexpr>    xmlexpr xml_args
+%type <list>    xmlexpr_list n_expr_list
+%type <xmlparams> xmlroot_par_list
+%type <xmlparam> xmlroot_param
+

 /*
  * If you make any token changes, update the keyword table in
@@ -399,7 +413,7 @@

     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

@@ -418,7 +432,7 @@

     SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
     SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
-    SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT
+    SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE START STATEMENT
     STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SUPERUSER_P SYMMETRIC
     SYSID SYSTEM_P

@@ -430,10 +444,13 @@
     UPDATE USER USING

     VACUUM VALID VALIDATOR VALUES VARCHAR VARYING
-    VERBOSE VIEW VOLATILE
+    VERBOSE VERSION VIEW VOLATILE

     WHEN WHERE WITH WITHOUT WORK WRITE

+    XMLAGG XMLATTRIBUTES XMLCOMMENT XMLCONCAT XMLELEMENT XMLFOREST
+    XMLPI XMLROOT XMLSERIALIZE
+
     YEAR_P

     ZONE
@@ -7889,6 +7906,139 @@
                     v->op = IS_LEAST;
                     $$ = (Node *)v;
                 }
+            | XMLSERIALIZE '(' xmlexpr ')'
+                {
+                    $$ = (Node *)
+                    makeXmlExpr(IS_XMLSERIALIZE, NULL, NULL, list_make1($3), NULL, NULL);
+                }
+        ;
+
+/*
+*  Supporting SQL/XML functions, use only for publishing. For storing results
+*  to tables and using them in pub. functions is neccessery support xml datatype,
+*  one part of xmlexpr will be col with xml value.
+*/
+
+xmlexpr:    XMLAGG '(' a_expr ')' /* for nested xmlagg */
+                {
+                    $$ = makeXmlExpr(IS_XMLAGG, NULL, NULL, NULL, list_make1($3), NULL);
+                }
+            | XMLAGG '(' xmlexpr ')'
+                {
+                    $$ = makeXmlExpr(IS_XMLAGG, NULL, NULL, list_make1($3), NULL, NULL);
+                }
+            | XMLCOMMENT '(' a_expr ')'
+                {
+                    $$ = makeXmlExpr(IS_XMLCOMMENT, NULL, NULL, NULL, list_make1($3), NULL);
+                }
+            | XMLCONCAT '(' xmlexpr_list ')'
+                {
+                    $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NULL, $3, NULL, NULL);
+                }
+            | XMLELEMENT '(' NAME ColLabel ',' xml_args ')'
+                {
+                    $6->params = setXmlParam($6->params, IS_XMLNAME, $4);
+                    $6->op = IS_XMLELEMENT;
+                    $$ = $6;
+                }
+            | XMLELEMENT '(' NAME ColLabel ')'
+                {
+                    $$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, NULL, NULL, NULL);
+                }
+
+            | XMLELEMENT '(' NAME ColLabel ',' XMLATTRIBUTES '(' n_expr_list ')' ',' xml_args ')'
+                {
+                    $11->params = setXmlParam($11->params, IS_XMLNAME, $4);
+                    $11->nargs = $8;
+                    $11->op = IS_XMLELEMENT;
+                    $$ = $11;
+                }
+            | XMLELEMENT '(' NAME ColLabel ',' XMLATTRIBUTES '(' n_expr_list ')' ')'
+                {
+                    $$ = makeXmlExpr(IS_XMLELEMENT, $4, $8, NULL, NULL, NULL);
+                }
+            | XMLFOREST '(' n_expr_list ')'
+                {
+                    $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NULL, NULL, NULL);
+                }
+            | XMLPI '(' NAME ColLabel ')'
+                {
+                    $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NULL, NULL, NULL);
+                }
+            | XMLPI '(' NAME ColLabel ',' a_expr ')'
+                {
+                    $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NULL, list_make1($6), NULL);
+                }
+            | XMLROOT '(' xmlexpr ',' xmlroot_par_list ')'
+                {
+                    $$ = makeXmlExpr(IS_XMLROOT, NULL, NULL, list_make1($3), NULL, $5);
+                }
+            | XMLROOT '(' xmlexpr ')'
+                {
+                    $$ = makeXmlExpr(IS_XMLROOT, NULL, NULL, list_make1($3), NULL, NULL);
+                }
+        ;
+
+
+xmlroot_par_list:    xmlroot_param                    { $$ = setXmlParam(NULL, $1.op, $1.value); }
+            | xmlroot_par_list ',' xmlroot_param    { $$ = setXmlParam($1, $3.op, $3.value); }
+        ;
+
+
+xmlroot_param:        VERSION Sconst
+                {
+                    $$.op = IS_XMLVERSION;
+                    $$.value = $2;
+                }
+            | ENCODING Sconst
+                {
+                    $$.op = IS_XMLENCODING;
+                    $$.value = $2;
+                }
+            | STANDALONE Sconst
+                {
+                    $$.op = IS_XMLSTANDALONE;
+                    $$.value = $2;
+                }
+        ;
+
+xml_args:    xmlexpr_list ',' a_expr
+                {
+                    $$ = makeXmlExpr(IS_XMLUNKNOWN, NULL, NULL, $1, list_make1($3), NULL);
+                }
+            | a_expr
+                {
+                    $$ = makeXmlExpr(IS_XMLUNKNOWN, NULL, NULL, NULL, list_make1($1), NULL);
+                }
+            | xmlexpr_list
+                {
+                    $$ = makeXmlExpr(IS_XMLUNKNOWN, NULL, NULL, $1, NULL, NULL);
+                }
+        ;
+
+xmlexpr_list:        xmlexpr                    { $$ = list_make1($1); }
+            | xmlexpr_list ',' xmlexpr        { $$ = lappend($1, $3); }
+        ;
+
+n_expr_list:        n_expr_el                { $$ = list_make1($1); }
+            | n_expr_list ',' n_expr_el        { $$ = lappend($1, $3); }
+        ;
+
+n_expr_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;
+                }
         ;

 /*
@@ -8290,6 +8440,20 @@
                     $$->val = (Node *)n;
                     $$->location = @1;
                 }
+            | xmlexpr AS ColLabel
+                {
+                    $$ = makeNode(ResTarget);
+                    $$->name = $3;
+                    $$->indirection = NIL;
+                    $$->val = (Node *)$1;
+                }
+            | xmlexpr
+                {
+                    $$ = makeNode(ResTarget);
+                    $$->name = NULL;
+                    $$->indirection = NIL;
+                    $$->val = (Node *)$1;
+                }
         ;


@@ -8661,6 +8825,7 @@
             | MODE
             | MONTH_P
             | MOVE
+            | NAME
             | NAMES
             | NEXT
             | NO
@@ -8721,6 +8886,7 @@
             | SHOW
             | SIMPLE
             | STABLE
+            | STANDALONE
             | START
             | STATEMENT
             | STATISTICS
@@ -8750,6 +8916,7 @@
             | VALID
             | VALIDATOR
             | VARYING
+            | VERSION
             | VIEW
             | VOLATILE
             | WITH
@@ -8809,6 +8976,15 @@
             | TRIM
             | VALUES
             | VARCHAR
+            | XMLAGG
+            | XMLATTRIBUTES
+            | XMLELEMENT
+            | XMLCOMMENT
+            | XMLCONCAT
+            | XMLFOREST
+            | XMLPI
+            | XMLROOT
+            | XMLSERIALIZE
         ;

 /* Function identifier --- keywords that can be function names.
@@ -9380,10 +9556,56 @@
     }
 }

+static XmlParams *
+setXmlParam(XmlParams *params, XmlParamOp op, char *value)
+{
+    if (value == NULL)
+        return params;
+
+    if (params == NULL)
+    {
+        params = makeNode(XmlParams);
+        params->encoding = NULL;
+        params->name = NULL;
+        params->version = NULL;
+        params->standalone = NULL;
+    }
+    switch (op)
+    {
+        case IS_XMLENCODING:
+            params->encoding = value;
+            break;
+        case IS_XMLVERSION:
+            params->version = value;
+            break;
+        case IS_XMLNAME:
+            params->name = value;
+            break;
+        case IS_XMLSTANDALONE:
+            params->standalone = value;
+            break;
+    }
+    return params;
+}
+
+static XmlExpr *
+makeXmlExpr(XmlExprOp op, char *name, List *nargs, List *xml_args,
+    List *args, XmlParams *params)
+{
+    XmlExpr *x = makeNode(XmlExpr);
+    x->op = op;
+    x->nargs = nargs;
+    x->xml_args = xml_args;
+    x->args = args;
+    x->level = 0;
+    x->params = setXmlParam(params, IS_XMLNAME, name);
+    return x;
+}
+
 /*
  * Must undefine base_yylex before including scan.c, since we want it
  * to create the function base_yylex not filtered_base_yylex.
  */
 #undef base_yylex

-#include "scan.c"
+#include "scan.c"
\ No newline at end of file
Index: src/backend/parser/parse_target.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_target.c,v
retrieving revision 1.148
diff -u -r1.148 parse_target.c
--- src/backend/parser/parse_target.c    14 Aug 2006 23:39:32 -0000    1.148
+++ src/backend/parser/parse_target.c    4 Sep 2006 23:32:34 -0000
@@ -1315,6 +1315,39 @@
                     return 2;
             }
             break;
+        case T_XmlExpr:
+            /* make SQL/XML functions act like a regular function */
+            switch (((XmlExpr*) node)->op)
+            {
+                case IS_XMLCOMMENT:
+                    *name = "xmlcomment";
+                    return 2;
+                case IS_XMLCONCAT:
+                    *name = "xmlconcat";
+                    return 2;
+                case IS_XMLELEMENT:
+                    *name = "xmlelement";
+                    return 2;
+                case IS_XMLFOREST:
+                    *name = "xmlforest";
+                    return 2;
+                case IS_XMLPI:
+                    *name = "xmlpi";
+                    return 2;
+                case IS_XMLROOT:
+                    *name = "xmlroot";
+                    return 2;
+                case IS_XMLSERIALIZE:
+                    *name = "xmlserialize";
+                    return 2;
+                case IS_XMLUNKNOWN:
+                    *name = "unknown xml function";
+                    return 2;
+                case IS_XMLAGG:
+                    *name = "xmlagg";
+                    return 2;
+            }
+            break;
         default:
             break;
     }
Index: src/backend/parser/parse_expr.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_expr.c,v
retrieving revision 1.197
diff -u -r1.197 parse_expr.c
--- src/backend/parser/parse_expr.c    12 Aug 2006 20:05:55 -0000    1.197
+++ src/backend/parser/parse_expr.c    4 Sep 2006 23:32:29 -0000
@@ -55,6 +55,8 @@
 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 *transformXmlList(ParseState *pstate, List *list, int level);
 static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
 static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
 static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
@@ -71,6 +73,7 @@
 static Expr *make_distinct_op(ParseState *pstate, List *opname,
                  Node *ltree, Node *rtree, int location);

+extern char *FigureColname(Node *e);

 /*
  * transformExpr -
@@ -218,6 +221,10 @@
             result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr);
             break;

+        case T_XmlExpr:
+            result = transformXmlExpr(pstate, (XmlExpr *) expr);
+            break;
+
         case T_NullTest:
             {
                 NullTest   *n = (NullTest *) expr;
@@ -1368,6 +1375,98 @@
 }

 static Node *
+transformList(ParseState *pstate, List *list)
+{
+    List *newlist = NIL;
+    ListCell *arg;
+    foreach(arg, list)
+    {
+        Node *e = (Node*)lfirst(arg);
+        Node *te = transformExpr(pstate, e);
+        newlist = lappend(newlist, te);
+    }
+    return (Node *)newlist;
+}
+
+static Node *
+transformXmlList(ParseState *pstate, List *list, int level)
+{
+    List         *newlist = NIL;
+    ListCell     *arg;
+    foreach(arg, list)
+    {
+        Node *te;
+        Node *e = (Node *) lfirst(arg);
+        ((XmlExpr *)e)->level = level;
+        te = transformExpr(pstate, e);
+        newlist = lappend(newlist, te);
+    }
+    return (Node *) newlist;
+}
+
+static Node *
+transformNPList(ParseState *pstate, List *list)
+{
+    List         *newlist = NIL;
+    ListCell     *arg;
+    foreach(arg, list)
+    {
+        ResTarget     *r = (ResTarget *) lfirst(arg);
+        Node         *expr = transformExpr(pstate, r->val);
+        char         *colname = r->name;
+        if (colname == NULL)
+            colname = FigureColname(r->val);
+        newlist = lappend(newlist,
+                    makeTargetEntry((Expr *) expr, 0, colname, false));
+    }
+    return (Node *)newlist;
+}
+
+static Node *
+transformXmlExpr(ParseState *pstate, XmlExpr *x)
+{
+    XmlExpr *newx = makeNode(XmlExpr);
+
+    if (x->op == IS_XMLAGG)
+    {
+        /* set level */
+        if (x->xml_args)
+        {
+            FuncCall     *n;
+            XmlExpr     *p = (XmlExpr *) linitial(x->xml_args);
+            p->level = x->level + 1;
+            n = makeNode(FuncCall);
+            n->funcname = SystemFuncName("xmlagg");
+            n->args = x->xml_args;
+            n->agg_star = FALSE;
+            n->agg_distinct = FALSE;
+            return transformExpr(pstate, (Node *) n);
+
+        }
+        else
+        {
+            FuncCall *n = makeNode(FuncCall);
+            n->funcname = SystemFuncName("xmlagg");
+            n->args = x->args;
+            n->agg_star = FALSE;
+            n->agg_distinct = FALSE;
+
+            return transformExpr(pstate, (Node *) n);
+        }
+    }
+
+    newx->nargs = (List *)transformNPList(pstate, x->nargs);
+    newx->xml_args = (List *)transformXmlList(pstate, x->xml_args, x->level+1);
+    newx->args = (List *)transformList(pstate, x->args);
+
+    newx->params = x->params;
+    newx->op = x->op;
+    newx->level = x->level;
+
+    return (Node *) newx;
+}
+
+static Node *
 transformBooleanTest(ParseState *pstate, BooleanTest *b)
 {
     const char *clausename;
@@ -1399,10 +1498,7 @@
     }

     b->arg = (Expr *) transformExpr(pstate, (Node *) b->arg);
-
-    b->arg = (Expr *) coerce_to_boolean(pstate,
-                                        (Node *) b->arg,
-                                        clausename);
+    b->arg = (Expr *) coerce_to_boolean(pstate, (Node *) b->arg, clausename);

     return (Node *) b;
 }
@@ -1657,6 +1753,9 @@
         case T_MinMaxExpr:
             type = ((MinMaxExpr *) expr)->minmaxtype;
             break;
+        case T_XmlExpr:
+            type = TEXTOID;
+            break;
         case T_NullIfExpr:
             type = exprType((Node *) linitial(((NullIfExpr *) expr)->args));
             break;
Index: src/backend/parser/keywords.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/parser/keywords.c,v
retrieving revision 1.176
diff -u -r1.176 keywords.c
--- src/backend/parser/keywords.c    25 Aug 2006 04:06:52 -0000    1.176
+++ src/backend/parser/keywords.c    4 Sep 2006 23:32:28 -0000
@@ -217,6 +217,7 @@
     {"mode", MODE},
     {"month", MONTH_P},
     {"move", MOVE},
+    {"name", NAME},
     {"names", NAMES},
     {"national", NATIONAL},
     {"natural", NATURAL},
@@ -313,6 +314,7 @@
     {"smallint", SMALLINT},
     {"some", SOME},
     {"stable", STABLE},
+    {"standalone", STANDALONE},
     {"start", START},
     {"statement", STATEMENT},
     {"statistics", STATISTICS},
@@ -360,6 +362,7 @@
     {"varchar", VARCHAR},
     {"varying", VARYING},
     {"verbose", VERBOSE},
+    {"version", VERSION},
     {"view", VIEW},
     {"volatile", VOLATILE},
     {"when", WHEN},
@@ -368,6 +371,15 @@
     {"without", WITHOUT},
     {"work", WORK},
     {"write", WRITE},
+    {"xmlagg", XMLAGG},
+    {"xmlattributes", XMLATTRIBUTES},
+    {"xmlcomment", XMLCOMMENT},
+    {"xmlconcat", XMLCONCAT},
+    {"xmlelement", XMLELEMENT},
+    {"xmlforest", XMLFOREST},
+    {"xmlpi", XMLPI},
+    {"xmlroot", XMLROOT},
+    {"xmlserialize", XMLSERIALIZE},
     {"year", YEAR_P},
     {"zone", ZONE},
 };
Index: src/backend/nodes/readfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/readfuncs.c,v
retrieving revision 1.195
diff -u -r1.195 readfuncs.c
--- src/backend/nodes/readfuncs.c    12 Aug 2006 02:52:04 -0000    1.195
+++ src/backend/nodes/readfuncs.c    4 Sep 2006 23:32:05 -0000
@@ -707,6 +707,34 @@
     READ_DONE();
 }

+static XmlParams *
+_readXmlParams(void)
+{
+    READ_LOCALS(XmlParams);
+
+    READ_STRING_FIELD(name);
+    READ_STRING_FIELD(encoding);
+    READ_STRING_FIELD(version);
+    READ_STRING_FIELD(standalone);
+
+    READ_DONE();
+}
+
+static XmlExpr *
+_readXmlExpr(void)
+{
+    READ_LOCALS(XmlExpr);
+
+    READ_ENUM_FIELD(op, XmlExprOp);
+    READ_NODE_FIELD(xml_args);
+    READ_NODE_FIELD(nargs);
+    READ_NODE_FIELD(args);
+    READ_NODE_FIELD(params);
+    READ_INT_FIELD(level);
+
+    READ_DONE();
+}
+
 /*
  * _readNullIfExpr
  */
@@ -1007,6 +1035,10 @@
         return_value = _readCoalesceExpr();
     else if (MATCH("MINMAX", 6))
         return_value = _readMinMaxExpr();
+    else if (MATCH("XMLPARAMS", 9))
+        return_value = _readXmlParams();
+    else if (MATCH("XMLEXPR", 7))
+        return_value = _readXmlExpr();
     else if (MATCH("NULLIFEXPR", 10))
         return_value = _readNullIfExpr();
     else if (MATCH("NULLTEST", 8))
Index: src/backend/nodes/outfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/outfuncs.c,v
retrieving revision 1.284
diff -u -r1.284 outfuncs.c
--- src/backend/nodes/outfuncs.c    25 Aug 2006 04:06:50 -0000    1.284
+++ src/backend/nodes/outfuncs.c    4 Sep 2006 23:32:02 -0000
@@ -890,6 +890,19 @@
 }

 static void
+_outXmlExpr(StringInfo str, XmlExpr *node)
+{
+    WRITE_NODE_TYPE("XMLEXPR");
+
+    WRITE_ENUM_FIELD(op, XmlExprOp);
+    WRITE_NODE_FIELD(xml_args);
+    WRITE_NODE_FIELD(nargs);
+    WRITE_NODE_FIELD(args);
+    WRITE_NODE_FIELD(params);
+    WRITE_INT_FIELD(level);
+}
+
+static void
 _outNullIfExpr(StringInfo str, NullIfExpr *node)
 {
     WRITE_NODE_TYPE("NULLIFEXPR");
@@ -2008,6 +2021,9 @@
             case T_MinMaxExpr:
                 _outMinMaxExpr(str, obj);
                 break;
+            case T_XmlExpr:
+                _outXmlExpr(str, obj);
+                break;
             case T_NullIfExpr:
                 _outNullIfExpr(str, obj);
                 break;
Index: src/backend/nodes/equalfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v
retrieving revision 1.284
diff -u -r1.284 equalfuncs.c
--- src/backend/nodes/equalfuncs.c    30 Aug 2006 23:34:21 -0000    1.284
+++ src/backend/nodes/equalfuncs.c    4 Sep 2006 23:32:01 -0000
@@ -454,6 +454,28 @@
 }

 static bool
+_equalXmlParams(XmlParams *a, XmlParams *b)
+{
+    COMPARE_STRING_FIELD(name);
+    COMPARE_STRING_FIELD(version);
+    COMPARE_STRING_FIELD(encoding);
+    COMPARE_STRING_FIELD(standalone);
+}
+
+static bool
+_equalXmlExpr(XmlExpr *a, XmlExpr *b)
+{
+    COMPARE_SCALAR_FIELD(op);
+    COMPARE_NODE_FIELD(xml_args);
+    COMPARE_NODE_FIELD(args);
+    COMPARE_NODE_FIELD(nargs);
+    COMPARE_NODE_FIELD(params);
+    COMPARE_SCALAR_FIELD(level);
+
+    return true;
+}
+
+static bool
 _equalNullIfExpr(NullIfExpr *a, NullIfExpr *b)
 {
     COMPARE_SCALAR_FIELD(opno);
@@ -1959,6 +1981,12 @@
         case T_MinMaxExpr:
             retval = _equalMinMaxExpr(a, b);
             break;
+        case T_XmlParams:
+            retval = _equalXmlParams(a, b);
+            break;
+        case T_XmlExpr:
+            retval = _equalXmlExpr(a, b);
+            break;
         case T_NullIfExpr:
             retval = _equalNullIfExpr(a, b);
             break;
Index: src/backend/nodes/copyfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v
retrieving revision 1.350
diff -u -r1.350 copyfuncs.c
--- src/backend/nodes/copyfuncs.c    30 Aug 2006 23:34:21 -0000    1.350
+++ src/backend/nodes/copyfuncs.c    4 Sep 2006 23:31:57 -0000
@@ -1091,6 +1091,36 @@
 }

 /*
+ * _copyXmlExpr
+ */
+
+static XmlParams *
+_copyXmlParams(XmlParams *from)
+{
+    XmlParams *newnode = makeNode(XmlParams);
+    COPY_STRING_FIELD(name);
+    COPY_STRING_FIELD(version);
+    COPY_STRING_FIELD(encoding);
+    COPY_STRING_FIELD(standalone);
+
+    return newnode;
+}
+
+static XmlExpr *
+_copyXmlExpr(XmlExpr *from)
+{
+    XmlExpr *newnode = makeNode(XmlExpr);
+    COPY_SCALAR_FIELD(op);
+    COPY_NODE_FIELD(xml_args);
+    COPY_NODE_FIELD(nargs);
+    COPY_NODE_FIELD(args);
+    COPY_NODE_FIELD(params);
+    COPY_SCALAR_FIELD(level);
+
+    return newnode;
+}
+
+/*
  * _copyNullIfExpr (same as OpExpr)
  */
 static NullIfExpr *
@@ -2957,6 +2987,12 @@
         case T_MinMaxExpr:
             retval = _copyMinMaxExpr(from);
             break;
+        case T_XmlParams:
+            retval = _copyXmlParams(from);
+            break;
+        case T_XmlExpr:
+            retval = _copyXmlExpr(from);
+            break;
         case T_NullIfExpr:
             retval = _copyNullIfExpr(from);
             break;
Index: src/backend/executor/execQual.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/executor/execQual.c,v
retrieving revision 1.193
diff -u -r1.193 execQual.c
--- src/backend/executor/execQual.c    27 Jul 2006 19:52:05 -0000    1.193
+++ src/backend/executor/execQual.c    4 Sep 2006 23:31:53 -0000
@@ -52,6 +52,9 @@
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/typcache.h"
+#include "lib/stringinfo.h"
+
+#include <string.h>


 /* static function decls */
@@ -119,6 +122,8 @@
 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(GenericExprState *nstate,
                  ExprContext *econtext,
                  bool *isNull, ExprDoneCond *isDone);
@@ -2613,6 +2618,230 @@
 }

 /* ----------------------------------------------------------------
+ *        ExecEvalXml
+ * ----------------------------------------------------------------
+ */
+
+static char *
+getXmlParam(XmlParams *params, XmlParamOp op)
+{
+    if (params == NULL)
+        return NULL;
+
+    switch (op)
+    {
+        case IS_XMLNAME:
+            return params->name;
+        case IS_XMLVERSION:
+            return params->version;
+        case IS_XMLENCODING:
+            return params->encoding;
+        case IS_XMLSTANDALONE:
+            return params->standalone;
+    }
+    return NULL;
+}
+
+static void
+appendStringInfoText(StringInfo str, const text *t)
+{
+    appendBinaryStringInfo(str, VARDATA(t), VARSIZE(t) - VARHDRSZ);
+}
+
+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->xml_args)
+                {
+                    ExprState     *e = (ExprState *) lfirst(arg);
+                    Datum         value = ExecEvalExpr(e, econtext, &isnull, NULL);
+                    if (!isnull)
+                    {
+                        appendStringInfoText(&buf, (text *)value);
+                        *isNull = false;
+                    }
+                }
+            }
+            break;
+        case IS_XMLELEMENT:
+            {
+                int state = 0, i = 0;
+                appendStringInfo(&buf, "<%s", getXmlParam(xmlExpr->params, IS_XMLNAME));
+                foreach(arg, xmlExpr->nargs)
+                {
+                    GenericExprState *gstate = (GenericExprState *) lfirst(arg);
+                    Datum value = ExecEvalExpr(gstate->arg, econtext, &isnull, NULL);
+                    if (!isnull)
+                    {
+                        char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->nargs_tcache[i], value));
+                        appendStringInfo(&buf, " %s=\"%s\"", xmlExpr->nargs_ncache[i], outstr);
+                        pfree(outstr);
+                    }
+                    i++;
+                }
+                foreach(arg, xmlExpr->xml_args)
+                {
+                    ExprState    *e = (ExprState *) lfirst(arg);
+                    Datum         value = ExecEvalExpr(e, econtext, &isnull, NULL);
+                    if (!isnull)
+                    {
+                        if (state == 0)
+                        {
+                            appendStringInfoChar(&buf, '>');
+                            state = 1;
+                        }
+                        appendStringInfoText(&buf, (text *)value);
+                    }
+                }
+                if (xmlExpr->args)
+                {
+                    ExprState     *expr = linitial(xmlExpr->args);
+                    Datum         value = ExecEvalExpr(expr, econtext, &isnull, NULL);
+
+                    if (!isnull)
+                    {
+                        char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->arg_typeId, 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>", getXmlParam(xmlExpr->params, IS_XMLNAME));
+
+            }
+            break;
+        case IS_XMLFOREST:
+            {
+                /* only if all argumets are null returns null */
+                int i = 0;
+                *isNull = true;
+                foreach(arg, xmlExpr->nargs)
+                 {
+                    GenericExprState *gstate = (GenericExprState *) lfirst(arg);
+                    Datum value = ExecEvalExpr(gstate->arg, econtext, &isnull, NULL);
+                    if (!isnull)
+                    {
+                        char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->nargs_tcache[i], value));
+                        appendStringInfo(&buf, "<%s>%s</%s>", xmlExpr->nargs_ncache[i], outstr,
xmlExpr->nargs_ncache[i]);
+                        pfree(outstr);
+                        *isNull = false;
+                    }
+                    i += 1;
+                }
+            }
+            break;
+         case IS_XMLCOMMENT:
+            {
+                bool         isnull;
+                char         *outstr;
+                ExprState     *arg = linitial(xmlExpr->args);
+                Datum         value = ExecEvalExpr(arg, econtext, &isnull, NULL);
+                /* In case of NULL input, return NULL, according SQL/XML standard */
+                if (isnull)
+                    *isNull = true;
+                else
+                {
+                    outstr = DatumGetCString(OidFunctionCall1(xmlExpr->arg_typeId, value));
+                    appendStringInfo(&buf, "<!--%s-->", outstr);
+                    pfree(outstr);
+                }
+            }
+            break;
+        case IS_XMLPI:
+            {
+                bool         isnull;
+                char        *piname = getXmlParam(xmlExpr->params, IS_XMLNAME);
+                int32        pinamelen = strlen(piname);
+                if (pinamelen > 2
+                    && (piname[0] == 'x' || piname[0] == 'X')
+                    && (piname[1] == 'm' || piname[1] == 'M')
+                    && (piname[2] == 'l' || piname[2] == 'L'))
+                {
+                    ereport(ERROR, (
+                        errmsg("invalid name of XML processing instruction"),
+                        errdetail("XML processing instruction name cannot start with 'xml' ('%s' provided)",
piname)));
+                }
+                appendStringInfo(&buf, "<?%s", piname);
+                if (xmlExpr->args != NULL)
+                {
+                    char         *outstr;
+                    ExprState     *arg = linitial(xmlExpr->args);
+                    Datum         value = ExecEvalExpr(arg, econtext, &isnull, NULL);
+                    /* In case of NULL input, return NULL, according SQL/XML standard */
+                    if (isnull)
+                        *isNull = true;
+                    else
+                    {
+                        outstr = DatumGetCString(OidFunctionCall1(xmlExpr->arg_typeId, value));
+                        appendStringInfo(&buf, " %s", outstr);
+                        pfree(outstr);
+                    }
+                }
+                appendStringInfo(&buf, "?>");
+            }
+            break;
+        case IS_XMLROOT:
+            {
+                ExprState     *xarg = linitial(xmlExpr->xml_args);
+                Datum         value = ExecEvalExpr(xarg, econtext, &isnull, NULL);
+
+                appendStringInfo(&buf,"<?xml");
+                if (getXmlParam(xmlExpr->params, IS_XMLVERSION))
+                    appendStringInfo(&buf, " version=\"%s\"", getXmlParam(xmlExpr->params, IS_XMLVERSION));
+                if (getXmlParam(xmlExpr->params, IS_XMLENCODING))
+                    appendStringInfo(&buf, " encoding=\"%s\"", getXmlParam(xmlExpr->params,IS_XMLENCODING));
+                if (getXmlParam(xmlExpr->params, IS_XMLSTANDALONE))
+                    appendStringInfo(&buf, " standalone=\"%s\"", getXmlParam(xmlExpr->params,IS_XMLSTANDALONE));
+                appendStringInfo(&buf, "?>");
+                appendStringInfoText(&buf, (text *) value);
+            }
+            break;
+        case IS_XMLSERIALIZE:
+            {
+                ExprState    *arg = linitial(xmlExpr->xml_args);
+                Datum         value = ExecEvalExpr(arg, econtext, isNull, NULL);
+                PG_RETURN_TEXT_P(value);
+            }
+            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);
+}
+
+/* ----------------------------------------------------------------
  *        ExecEvalNullIf
  *
  * Note that this is *always* derived from the equals operator,
@@ -3594,6 +3823,77 @@
                 state = (ExprState *) mstate;
             }
             break;
+        case T_XmlExpr:
+            {
+                List            *outlist;
+                ListCell        *arg;
+                XmlExpr            *xexpr = (XmlExpr *) node;
+                XmlExprState    *xstate = makeNode(XmlExprState);
+                int                i = 0;
+                Oid                typid;
+
+                xstate->level = xexpr->level;
+                xstate->params = xexpr->params;
+
+                xstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalXml;
+                xstate->op = xexpr->op;
+
+                outlist = NIL;
+                if (xexpr->nargs)
+                {
+                    xstate->nargs_tcache = (Oid *) palloc(list_length(xexpr->nargs) * sizeof(int));
+                    xstate->nargs_ncache = (char **) palloc(list_length(xexpr->nargs) * sizeof(char *));
+
+                    i = 0;
+                    foreach(arg, xexpr->nargs)
+                    {
+                        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), &typid, &tpisvarlena);
+                        xstate->nargs_ncache[i] = tle->resname;
+                        xstate->nargs_tcache[i++] = typid;
+                    }
+                }
+                else
+                {
+                    xstate->nargs_tcache = NULL;
+                    xstate->nargs_ncache = NULL;
+                }
+                xstate->nargs = outlist;
+
+                outlist = NIL;
+                if (xexpr->xml_args)
+                {
+                    foreach(arg, xexpr->xml_args)
+                    {
+                        Expr        *e = (Expr *) lfirst(arg);
+                        ExprState    *estate = ExecInitExpr(e, parent);
+
+                        outlist = lappend(outlist, estate);
+                    }
+                }
+                xstate->xml_args = outlist;
+
+                outlist = NIL;
+                foreach(arg, xexpr->args)
+                {
+                    bool         tpisvarlena;
+                    ExprState     *estate;
+                    Expr         *e = (Expr *) lfirst(arg);
+                    getTypeOutputInfo(exprType((Node *)e), &typid, &tpisvarlena);
+                    estate = ExecInitExpr(e, parent);
+                    outlist = lappend(outlist, estate);
+                }
+                xstate->arg_typeId = typid;
+                xstate->args = outlist;
+
+                state = (ExprState *) xstate;
+            }
+            break;
         case T_NullIfExpr:
             {
                 NullIfExpr *nullifexpr = (NullIfExpr *) node;
Index: doc/src/sgml/func.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql/doc/src/sgml/func.sgml,v
retrieving revision 1.333
diff -u -r1.333 func.sgml
--- doc/src/sgml/func.sgml    4 Sep 2006 21:47:25 -0000    1.333
+++ doc/src/sgml/func.sgml    4 Sep 2006 23:31:46 -0000
@@ -10530,8 +10530,129 @@
    </para>

   </sect1>
-</chapter>
+  <sect1 id="functions-sqlxml">
+   <title>SQL/XML publishing functions</title>

+   <sect2>
+    <title><literal>XMLAGG</literal></title>
+
+   <indexterm>
+    <primary>XMLAGG</primary>
+   </indexterm>
+
+ <synopsis>
+ <function>XMLAGG</function>(<replaceable>xml expr</replaceable>)
+ </synopsis>
+
+    <para>
+     This combines a collection of rows, each containing a single XML
+     value, to create a single value containing an XML forest.
+    </para>
+    </sect2>
+
+   <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 expr</replaceable><optional>, xml expr</optional><optional>,
...</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>,
XMLATTRIBUTES(<replaceable>value</replaceable><optional>AS <replaceable>label</replaceable></optional><optional>, ...
</optional>)</optional>
+ <optional>, xml expr list</optional>
+ <optional><replaceable>, value</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>(<replaceable>text</replaceable>)
+ </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 expr</replaceable>
+ <optional>, VERSION|ENCODING|STANDALONE = <replaceable>text<replaceable>, ... </optional>)
+ </synopsis>
+
+    <para>
+     Creates the root node of an XML document.
+    </para>
+  </sect2>
+
+ </sect1>
+</chapter>
 <!-- Keep this comment at the end of the file
 Local variables:
 mode:sgml
@@ -10547,4 +10668,4 @@
 sgml-local-catalogs:("/usr/lib/sgml/catalog")
 sgml-local-ecat-files:nil
 End:
--->
+-->
\ No newline at end of file

pgsql-patches by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: [HACKERS] Interval aggregate regression failure
Next
From: Andrew - Supernews
Date:
Subject: Re: [HACKERS] DOC: catalog.sgml