Index: doc/src/sgml/func.sgml =================================================================== RCS file: /projects/cvsroot/pgsql/doc/src/sgml/func.sgml,v retrieving revision 1.286 diff -c -r1.286 func.sgml *** doc/src/sgml/func.sgml 16 Sep 2005 05:35:39 -0000 1.286 --- doc/src/sgml/func.sgml 2 Oct 2005 23:50:12 -0000 *************** *** 9707,9712 **** --- 9707,9836 ---- + + + SQL/XML public functions + + + <literal>XMLAGG</literal> + + + XMLAGG + + + + XMLAGG(xml expr) + + + + This combines a collection of rows, each containing a single XML + value, to create a single value containing an XML forest. + + + + + <literal>XMLCOMMENT</literal> + + + XMLCOMMENT + + + + XMLCOMMENT(text) + + + + Creates an XML comment. + + + + + + <literal>XMLCONCAT</literal> + + + XMLCONCAT + + + + XMLCONCAT(xml expr, xml expr) + + + + Combines a list of individual XML values to create a + single value containing an XML forest. + + + + + <literal>XMLELEMENT</literal> + + + XMLELEMENT + + + + XMLELEMENT(Name name, XMLATTRIBUTES(value AS label, ... ) + , xml expr list + , value) + + + + Creates an XML element, allowing the name to be specified. + + + + + <literal>XMLFOREST</literal> + + + XMLFOREST + + + + XMLFOREST(value AS label, ...) + + + + Creates XML elements from columns, using the name of each + column as the name of the corresponding element. + + + + + <literal>XMLPI</literal> + + + XMLPI + + + + XMLPI(text) + + + + Creates an XML processing instruction. + + + + + <literal>XMLROOT</literal> + + + XMLROOT + + + + XMLROOT(xml expr + , VERSION|ENCODING|STANDALONE = text, ... ) + + + + Creates the root node of an XML document. + + + + ", outstr); ! if (xmlExpr->op == IS_XMLPI) ! appendStringInfo(&buf, "", outstr); ! pfree(outstr); ! } ! break; ! case IS_XMLROOT: ! { ! ExprState *xarg = linitial(xmlExpr->xml_args); ! Datum value = ExecEvalExpr(xarg, econtext, &isnull, NULL); ! ! appendStringInfo(&buf,"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 * *************** *** 3296,3301 **** --- 3491,3565 ---- 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 = (int*)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); + + outlist = lappend(outlist, estate); + TargetEntry *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; + Expr *e = (Expr *) lfirst(arg); + getTypeOutputInfo(exprType((Node *)e), &typid, &tpisvarlena); + ExprState *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: src/backend/nodes/copyfuncs.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v retrieving revision 1.315 diff -c -r1.315 copyfuncs.c *** src/backend/nodes/copyfuncs.c 1 Aug 2005 20:31:08 -0000 1.315 --- src/backend/nodes/copyfuncs.c 2 Oct 2005 23:50:17 -0000 *************** *** 1063,1068 **** --- 1063,1098 ---- } /* + * _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 * *************** *** 2843,2848 **** --- 2873,2884 ---- 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/nodes/equalfuncs.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v retrieving revision 1.252 diff -c -r1.252 equalfuncs.c *** src/backend/nodes/equalfuncs.c 1 Aug 2005 20:31:08 -0000 1.252 --- src/backend/nodes/equalfuncs.c 2 Oct 2005 23:50:18 -0000 *************** *** 460,465 **** --- 460,488 ---- return true; } + + 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) { *************** *** 1899,1904 **** --- 1922,1933 ---- 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/outfuncs.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/nodes/outfuncs.c,v retrieving revision 1.260 diff -c -r1.260 outfuncs.c *** src/backend/nodes/outfuncs.c 27 Aug 2005 22:13:43 -0000 1.260 --- src/backend/nodes/outfuncs.c 2 Oct 2005 23:50:19 -0000 *************** *** 875,880 **** --- 875,904 ---- } static void + _outXmlParams(StringInfo str, XmlParams *node) + { + WRITE_NODE_TYPE("XMLPARAMS"); + + WRITE_STRING_FIELD(name); + WRITE_STRING_FIELD(encoding); + WRITE_STRING_FIELD(version); + WRITE_STRING_FIELD(standalone); + } + + 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"); *************** *** 1925,1930 **** --- 1949,1957 ---- 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/readfuncs.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/nodes/readfuncs.c,v retrieving revision 1.181 diff -c -r1.181 readfuncs.c *** src/backend/nodes/readfuncs.c 1 Aug 2005 20:31:08 -0000 1.181 --- src/backend/nodes/readfuncs.c 2 Oct 2005 23:50:20 -0000 *************** *** 81,87 **** /* Read a float field */ #define READ_FLOAT_FIELD(fldname) \ ! token = pg_strtok(&length); /* skip :fldname */ \ token = pg_strtok(&length); /* get field value */ \ local_node->fldname = atof(token) --- 81,87 ---- /* Read a float field */ #define READ_FLOAT_FIELD(fldname) \ ! /* skip :fldname */ \ token = pg_strtok(&length); /* get field value */ \ local_node->fldname = atof(token) *************** *** 674,679 **** --- 674,707 ---- 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 */ *************** *** 1000,1005 **** --- 1028,1037 ---- 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/optimizer/util/clauses.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v retrieving revision 1.200 diff -c -r1.200 clauses.c *** src/backend/optimizer/util/clauses.c 3 Jul 2005 21:14:17 -0000 1.200 --- src/backend/optimizer/util/clauses.c 2 Oct 2005 23:50:22 -0000 *************** *** 546,551 **** --- 546,553 ---- return false; if (IsA(node, NullIfExpr)) return false; + if (IsA(node, XmlExpr)) + return false; return expression_tree_walker(node, expression_returns_set_walker, context); *************** *** 853,858 **** --- 855,862 ---- return true; if (IsA(node, NullIfExpr)) return true; + if (IsA(node, XmlExpr)) + return true; if (IsA(node, NullTest)) return true; if (IsA(node, BooleanTest)) *************** *** 2944,2949 **** --- 2948,2964 ---- return walker(((MinMaxExpr *) node)->args, context); case T_NullIfExpr: return walker(((NullIfExpr *) 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_NullTest: return walker(((NullTest *) node)->arg, context); case T_BooleanTest: *************** *** 3422,3427 **** --- 3437,3454 ---- 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_NullTest: { NullTest *ntest = (NullTest *) node; Index: src/backend/parser/gram.y =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/parser/gram.y,v retrieving revision 2.511 diff -c -r2.511 gram.y *** src/backend/parser/gram.y 23 Sep 2005 22:25:25 -0000 2.511 --- src/backend/parser/gram.y 2 Oct 2005 23:50:28 -0000 *************** *** 91,96 **** --- 91,101 ---- Node *limitOffset, Node *limitCount); static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg); static Node *doNegate(Node *n); + 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); + static void doNegateFloat(Value *v); %} *************** *** 128,133 **** --- 133,141 ---- InsertStmt *istmt; VariableSetStmt *vsetstmt; + XmlExpr *xmlexpr; + XmlParams *xmlparams; + XmlParam xmlparam; } %type stmt schema_stmt *************** *** 325,330 **** --- 333,345 ---- %type constraints_set_mode %type OptTableSpace OptConsTableSpace OptTableSpaceOwner + %type n_expr_el + %type xmlexpr xml_args + %type xmlexpr_list n_expr_list + %type xmlroot_par_list + %type xmlroot_param + + /* * If you make any token changes, update the keyword table in *************** *** 377,383 **** MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE ! NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NUMERIC --- 392,398 ---- MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE ! 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 *************** *** 398,404 **** SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SUPERUSER_P SYMMETRIC ! SYSID SYSTEM_P TABLE TABLESPACE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP TO TOAST TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P --- 413,419 ---- SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SUPERUSER_P SYMMETRIC ! SYSID SYSTEM_P STANDALONE TABLE TABLESPACE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP TO TOAST TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P *************** *** 408,416 **** UPDATE USER USING VACUUM VALID VALIDATOR VALUES VARCHAR VARYING ! VERBOSE VIEW VOLATILE WHEN WHERE WITH WITHOUT WORK WRITE YEAR_P --- 423,434 ---- UPDATE USER USING VACUUM VALID VALIDATOR VALUES VARCHAR VARYING ! VERBOSE VERSION VIEW VOLATILE WHEN WHERE WITH WITHOUT WORK WRITE + + XMLAGG XMLATTRIBUTES XMLCOMMENT XMLCONCAT XMLELEMENT XMLFOREST + XMLPI XMLROOT XMLSERIALIZE YEAR_P *************** *** 7408,7413 **** --- 7426,7560 ---- 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 '(' a_expr ')' + { + $$ = makeXmlExpr(IS_XMLPI, NULL, NULL, NULL, list_make1($3), 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; + } ; /* *************** *** 7770,7775 **** --- 7917,7936 ---- $$->indirection = NIL; $$->val = (Node *)n; } + | xmlexpr AS ColLabel + { + $$ = makeNode(ResTarget); + $$->name = $3; + $$->indirection = NIL; + $$->val = (Node *)$1; + } + | xmlexpr + { + $$ = makeNode(ResTarget); + $$->name = NULL; + $$->indirection = NIL; + $$->val = (Node *)$1; + } ; update_target_list: *************** *** 8240,8245 **** --- 8401,8407 ---- | SHOW | SIMPLE | STABLE + | STANDALONE | START | STATEMENT | STATISTICS *************** *** 8279,8284 **** --- 8441,8448 ---- | WRITE | YEAR_P | ZONE + | NAME + | VERSION ; /* Column identifier --- keywords that can be column, table, etc names. *************** *** 8329,8334 **** --- 8493,8507 ---- | TREAT | TRIM | VARCHAR + | XMLAGG + | XMLATTRIBUTES + | XMLELEMENT + | XMLCOMMENT + | XMLCONCAT + | XMLFOREST + | XMLROOT + | XMLSERIALIZE + | XMLPI ; /* Function identifier --- keywords that can be function names. *************** *** 8914,8917 **** --- 9087,9138 ---- } } + 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; + } + + #include "scan.c" Index: src/backend/parser/keywords.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/parser/keywords.c,v retrieving revision 1.165 diff -c -r1.165 keywords.c *** src/backend/parser/keywords.c 23 Aug 2005 22:40:27 -0000 1.165 --- src/backend/parser/keywords.c 2 Oct 2005 23:50:28 -0000 *************** *** 213,218 **** --- 213,219 ---- {"mode", MODE}, {"month", MONTH_P}, {"move", MOVE}, + {"name", NAME}, {"names", NAMES}, {"national", NATIONAL}, {"natural", NATURAL}, *************** *** 306,311 **** --- 307,313 ---- {"smallint", SMALLINT}, {"some", SOME}, {"stable", STABLE}, + {"standalone", STANDALONE}, {"start", START}, {"statement", STATEMENT}, {"statistics", STATISTICS}, *************** *** 354,359 **** --- 356,362 ---- {"varchar", VARCHAR}, {"varying", VARYING}, {"verbose", VERBOSE}, + {"version", VERSION}, {"view", VIEW}, {"volatile", VOLATILE}, {"when", WHEN}, *************** *** 362,367 **** --- 365,379 ---- {"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/parser/parse_expr.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_expr.c,v retrieving revision 1.184 diff -c -r1.184 parse_expr.c *** src/backend/parser/parse_expr.c 26 Jun 2005 22:05:39 -0000 1.184 --- src/backend/parser/parse_expr.c 2 Oct 2005 23:50:30 -0000 *************** *** 54,59 **** --- 54,60 ---- static Node *transformRowExpr(ParseState *pstate, RowExpr *r); static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c); static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m); + static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x); static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b); static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref); static Node *transformWholeRowRef(ParseState *pstate, char *schemaname, *************** *** 70,75 **** --- 71,77 ---- static Expr *make_distinct_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree); + extern char *FigureColname(Node *e); /* * transformExpr - *************** *** 213,219 **** case T_MinMaxExpr: result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr); break; ! case T_NullTest: { NullTest *n = (NullTest *) expr; --- 215,225 ---- case T_MinMaxExpr: result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr); break; ! ! case T_XmlExpr: ! result = transformXmlExpr(pstate, (XmlExpr *) expr); ! break; ! case T_NullTest: { NullTest *n = (NullTest *) expr; *************** *** 1272,1277 **** --- 1278,1382 ---- return (Node *) newm; } + + 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 *e = (Node*)lfirst(arg); + ((XmlExpr *)e)->level = level; + Node *te = transformExpr(pstate, e); + newlist = lappend(newlist, te); + } + return (Node *)newlist; + } + + + /* transformation named expressions */ + + 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) + { + XmlExpr *p = (XmlExpr *) linitial(x->xml_args); + p->level = x->level + 1; + + FuncCall *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); + + } + } + + + /* Mechanismem transformace dokazu vnutit podrizenym xmlfunkcim level, + * v budoucnu napriklad ukazatel na hash s tagy a attributy */ + + 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) { *************** *** 1549,1554 **** --- 1654,1662 ---- 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/parse_target.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_target.c,v retrieving revision 1.137 diff -c -r1.137 parse_target.c *** src/backend/parser/parse_target.c 26 Jun 2005 22:05:40 -0000 1.137 --- src/backend/parser/parse_target.c 2 Oct 2005 23:50:30 -0000 *************** *** 1135,1140 **** --- 1135,1173 ---- 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/utils/adt/ruleutils.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v retrieving revision 1.205 diff -c -r1.205 ruleutils.c *** src/backend/utils/adt/ruleutils.c 1 Aug 2005 20:31:12 -0000 1.205 --- src/backend/utils/adt/ruleutils.c 2 Oct 2005 23:50:34 -0000 *************** *** 2793,2798 **** --- 2793,2799 ---- case T_CoalesceExpr: case T_MinMaxExpr: case T_NullIfExpr: + case T_XmlExpr: case T_Aggref: case T_FuncExpr: /* function-like: name(..) or name[..] */ *************** *** 2901,2906 **** --- 2902,2908 ---- case T_CoalesceExpr: /* own parentheses */ case T_MinMaxExpr: /* own parentheses */ case T_NullIfExpr: /* other separators */ + case T_XmlExpr: /* own parentheses */ case T_Aggref: /* own parentheses */ case T_CaseExpr: /* other separators */ return true; *************** *** 2949,2954 **** --- 2951,2957 ---- case T_CoalesceExpr: /* own parentheses */ case T_MinMaxExpr: /* own parentheses */ case T_NullIfExpr: /* other separators */ + case T_XmlExpr: /* own parentheses */ case T_Aggref: /* own parentheses */ case T_CaseExpr: /* other separators */ return true; *************** *** 3531,3537 **** appendStringInfoChar(buf, ')'); } break; ! case T_NullTest: { NullTest *ntest = (NullTest *) node; --- 3534,3576 ---- appendStringInfoChar(buf, ')'); } 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_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_NullTest: { NullTest *ntest = (NullTest *) node; Index: src/backend/utils/adt/varchar.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/varchar.c,v retrieving revision 1.112 diff -c -r1.112 varchar.c *** src/backend/utils/adt/varchar.c 29 Jul 2005 12:59:15 -0000 1.112 --- src/backend/utils/adt/varchar.c 2 Oct 2005 23:50:34 -0000 *************** *** 25,30 **** --- 25,31 ---- #include "mb/pg_wchar.h" + #include "nodes/execnodes.h" /* * CHAR() and VARCHAR() types are part of the ANSI SQL standard. CHAR() *************** *** 805,807 **** --- 806,896 ---- return result; } + + /* + * Temp. aux. func for xmlagg function + * + */ + + + 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; + 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)) + { + text *str = PG_GETARG_TEXT_P(1); + d->isNull = false; + int 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; + + if (PG_ARGISNULL(0)) + elog(ERROR, "internal error"); + + d = (data *) PG_GETARG_POINTER(0); + if (d->isNull) + PG_RETURN_NULL(); + else + { + text *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/include/catalog/pg_aggregate.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_aggregate.h,v retrieving revision 1.51 diff -c -r1.51 pg_aggregate.h *** src/include/catalog/pg_aggregate.h 14 Apr 2005 01:38:20 -0000 1.51 --- src/include/catalog/pg_aggregate.h 2 Oct 2005 23:50:35 -0000 *************** *** 175,180 **** --- 175,183 ---- DATA(insert ( 2242 bitand - 0 1560 _null_ )); DATA(insert ( 2243 bitor - 0 1560 _null_ )); + /* xmlagg */ + DATA(insert ( 1079 text_xmlagg_accum text_xmlagg 0 25 _null_ )); + /* * prototypes for functions in pg_aggregate.c */ Index: src/include/catalog/pg_proc.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/catalog/pg_proc.h,v retrieving revision 1.385 diff -c -r1.385 pg_proc.h *** src/include/catalog/pg_proc.h 16 Sep 2005 05:35:40 -0000 1.385 --- src/include/catalog/pg_proc.h 2 Oct 2005 23:50:42 -0000 *************** *** 807,813 **** DESCR("convert name to char(n)"); DATA(insert OID = 409 ( name PGNSP PGUID 12 f f t f i 1 19 "1042" _null_ _null_ _null_ bpchar_name - _null_ )); DESCR("convert char(n) to name"); - DATA(insert OID = 440 ( hashgettuple PGNSP PGUID 12 f f t f v 2 16 "2281 2281" _null_ _null_ _null_ hashgettuple - _null_ )); DESCR("hash(internal)"); DATA(insert OID = 637 ( hashgetmulti PGNSP PGUID 12 f f t f v 4 16 "2281 2281 2281 2281" _null_ _null_ _null_ hashgetmulti - _null_ )); --- 807,812 ---- *************** *** 2710,2715 **** --- 2709,2719 ---- DESCR("AVG(int4) transition function"); DATA(insert OID = 1964 ( int8_avg PGNSP PGUID 12 f f t f i 1 1700 "1016" _null_ _null_ _null_ int8_avg - _null_ )); DESCR("AVG(int) aggregate final function"); + DATA(insert OID = 1136 ( text_xmlagg_accum PGNSP PGUID 12 f f f f i 2 25 "25 25" _null_ _null_ _null_ text_xmlagg_accum - _null_ )); + DESCR("trans fce for fast string"); + DATA(insert OID = 1137 ( text_xmlagg PGNSP PGUID 12 f f t f i 1 25 "25" _null_ _null_ _null_ text_xmlagg - _null_ )); + DESCR("final fce for fast string"); + /* 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_ )); *************** *** 3135,3140 **** --- 3139,3146 ---- DATA(insert OID = 2158 ( stddev PGNSP PGUID 12 t f f f i 1 701 "701" _null_ _null_ _null_ aggregate_dummy - _null_ )); DATA(insert OID = 2159 ( stddev PGNSP PGUID 12 t f f f i 1 1700 "1700" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 1079 ( xmlagg PGNSP PGUID 12 t f f f i 1 25 "25" _null_ _null_ _null_ aggregate_dummy - _null_ )); + DATA(insert OID = 2160 ( text_pattern_lt PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_lt - _null_ )); DATA(insert OID = 2161 ( text_pattern_le PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_le - _null_ )); DATA(insert OID = 2162 ( text_pattern_eq PGNSP PGUID 12 f f t f i 2 16 "25 25" _null_ _null_ _null_ text_pattern_eq - _null_ )); Index: src/include/nodes/execnodes.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/nodes/execnodes.h,v retrieving revision 1.138 diff -c -r1.138 execnodes.h *** src/include/nodes/execnodes.h 25 Sep 2005 19:37:35 -0000 1.138 --- src/include/nodes/execnodes.h 2 Oct 2005 23:50:43 -0000 *************** *** 686,691 **** --- 686,710 ---- } MinMaxExprState; /* ---------------- + * MinMaxExprState 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/nodes.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/nodes/nodes.h,v retrieving revision 1.175 diff -c -r1.175 nodes.h *** src/include/nodes/nodes.h 1 Aug 2005 20:31:15 -0000 1.175 --- src/include/nodes/nodes.h 2 Oct 2005 23:50:44 -0000 *************** *** 137,142 **** --- 137,144 ---- T_RangeTblRef, T_JoinExpr, T_FromExpr, + T_XmlExpr, + T_XmlParams, /* * TAGS FOR EXPRESSION STATE NODES (execnodes.h) *************** *** 163,169 **** T_MinMaxExprState, T_CoerceToDomainState, T_DomainConstraintState, ! /* * TAGS FOR PLANNER NODES (relation.h) */ --- 165,172 ---- T_MinMaxExprState, T_CoerceToDomainState, T_DomainConstraintState, ! T_XmlExprState, ! /* * TAGS FOR PLANNER NODES (relation.h) */ Index: src/include/nodes/primnodes.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/nodes/primnodes.h,v retrieving revision 1.108 diff -c -r1.108 primnodes.h *** src/include/nodes/primnodes.h 26 Jun 2005 22:05:41 -0000 1.108 --- src/include/nodes/primnodes.h 2 Oct 2005 23:50:44 -0000 *************** *** 675,680 **** --- 675,731 ---- } 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 *************** *** 940,943 **** --- 991,995 ---- Node *quals; /* qualifiers on join, if any */ } FromExpr; + #endif /* PRIMNODES_H */