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