aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/execQual.c415
-rw-r--r--src/backend/nodes/copyfuncs.c41
-rw-r--r--src/backend/nodes/equalfuncs.c31
-rw-r--r--src/backend/nodes/outfuncs.c31
-rw-r--r--src/backend/nodes/readfuncs.c39
-rw-r--r--src/backend/optimizer/util/clauses.c24
-rw-r--r--src/backend/parser/gram.y191
-rw-r--r--src/backend/parser/keywords.c20
-rw-r--r--src/backend/parser/parse_clause.c4
-rw-r--r--src/backend/parser/parse_coerce.c101
-rw-r--r--src/backend/parser/parse_expr.c167
-rw-r--r--src/backend/parser/parse_target.c11
-rw-r--r--src/backend/utils/adt/ruleutils.c164
-rw-r--r--src/backend/utils/adt/xml.c137
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/catalog/pg_proc.h14
-rw-r--r--src/include/nodes/execnodes.h30
-rw-r--r--src/include/nodes/nodes.h6
-rw-r--r--src/include/nodes/primnodes.h49
-rw-r--r--src/include/parser/parse_coerce.h11
-rw-r--r--src/include/utils/xml.h10
-rw-r--r--src/pl/plpgsql/src/pl_exec.c14
-rw-r--r--src/pl/plpgsql/src/plerrcodes.h18
-rw-r--r--src/test/regress/expected/opr_sanity.out2
-rw-r--r--src/test/regress/sql/opr_sanity.sql2
25 files changed, 855 insertions, 681 deletions
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 1e9865c3007..145da9b4636 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.201 2006/12/23 00:43:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.202 2006/12/24 00:29:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -117,11 +117,11 @@ static Datum ExecEvalCoalesce(CoalesceExprState *coalesceExpr,
static Datum ExecEvalMinMax(MinMaxExprState *minmaxExpr,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone);
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(NullTestState *nstate,
ExprContext *econtext,
bool *isNull, ExprDoneCond *isDone);
@@ -2639,6 +2639,237 @@ ExecEvalMinMax(MinMaxExprState *minmaxExpr, ExprContext *econtext,
}
/* ----------------------------------------------------------------
+ * ExecEvalXml
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
+ bool *isNull, ExprDoneCond *isDone)
+{
+ XmlExpr *xexpr = (XmlExpr *) xmlExpr->xprstate.expr;
+ text *result;
+ StringInfoData buf;
+ Datum value;
+ bool isnull;
+ char *str;
+ ListCell *arg;
+ ListCell *narg;
+ bool found_arg;
+ int i;
+
+ if (isDone)
+ *isDone = ExprSingleResult;
+ *isNull = true; /* until we get a result */
+
+ switch (xexpr->op)
+ {
+ case IS_XMLCONCAT:
+ initStringInfo(&buf);
+ foreach(arg, xmlExpr->args)
+ {
+ ExprState *e = (ExprState *) lfirst(arg);
+
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (!isnull)
+ {
+ /* we know the value is XML type */
+ str = DatumGetCString(DirectFunctionCall1(xml_out,
+ value));
+ appendStringInfoString(&buf, str);
+ pfree(str);
+ *isNull = false;
+ }
+ }
+ break;
+
+ case IS_XMLELEMENT:
+ initStringInfo(&buf);
+ *isNull = false;
+ appendStringInfo(&buf, "<%s", xexpr->name);
+ i = 0;
+ forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
+ {
+ ExprState *e = (ExprState *) lfirst(arg);
+ char *argname = strVal(lfirst(narg));
+
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (!isnull)
+ {
+ str = OutputFunctionCall(&xmlExpr->named_outfuncs[i],
+ value);
+ appendStringInfo(&buf, " %s=\"%s\"", argname, str);
+ pfree(str);
+ }
+ i++;
+ }
+
+ found_arg = false;
+ foreach(arg, xmlExpr->args)
+ {
+ ExprState *e = (ExprState *) lfirst(arg);
+
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (!isnull)
+ {
+ if (!found_arg)
+ {
+ appendStringInfoChar(&buf, '>');
+ found_arg = true;
+ }
+
+ /* we know the value is XML type */
+ str = DatumGetCString(DirectFunctionCall1(xml_out,
+ value));
+ appendStringInfoString(&buf, str);
+ pfree(str);
+ }
+ }
+
+ if (!found_arg)
+ appendStringInfo(&buf, "/>");
+ else
+ appendStringInfo(&buf, "</%s>", xexpr->name);
+ break;
+
+ case IS_XMLFOREST:
+ initStringInfo(&buf);
+ i = 0;
+ forboth(arg, xmlExpr->named_args, narg, xexpr->arg_names)
+ {
+ ExprState *e = (ExprState *) lfirst(arg);
+ char *argname = strVal(lfirst(narg));
+
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (!isnull)
+ {
+ str = OutputFunctionCall(&xmlExpr->named_outfuncs[i],
+ value);
+ appendStringInfo(&buf, "<%s>%s</%s>",
+ argname, str, argname);
+ pfree(str);
+ *isNull = false;
+ }
+ i++;
+ }
+ break;
+
+ /* The remaining cases don't need to set up buf */
+ case IS_XMLPARSE:
+ {
+ ExprState *e;
+ text *data;
+ bool is_document;
+ bool preserve_whitespace;
+
+ /* arguments are known to be text, bool, bool */
+ Assert(list_length(xmlExpr->args) == 3);
+
+ e = (ExprState *) linitial(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull)
+ return (Datum) 0;
+ data = DatumGetTextP(value);
+
+ e = (ExprState *) lsecond(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull) /* probably can't happen */
+ return (Datum) 0;
+ is_document = DatumGetBool(value);
+
+ e = (ExprState *) lthird(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull) /* probably can't happen */
+ return (Datum) 0;
+ preserve_whitespace = DatumGetBool(value);
+
+ *isNull = false;
+
+ return PointerGetDatum(xmlparse(data,
+ is_document,
+ preserve_whitespace));
+ }
+ break;
+
+ case IS_XMLPI:
+ {
+ ExprState *e;
+ text *arg;
+
+ /* optional argument is known to be text */
+ Assert(list_length(xmlExpr->args) <= 1);
+
+ if (xmlExpr->args)
+ {
+ e = (ExprState *) linitial(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull)
+ return (Datum) 0;
+ arg = DatumGetTextP(value);
+ }
+ else
+ arg = NULL;
+
+ *isNull = false;
+
+ return PointerGetDatum(xmlpi(xexpr->name, arg));
+ }
+ break;
+
+ case IS_XMLROOT:
+ {
+ ExprState *e;
+ xmltype *data;
+ text *version;
+ int standalone;
+
+ /* arguments are known to be xml, text, bool */
+ Assert(list_length(xmlExpr->args) == 3);
+
+ e = (ExprState *) linitial(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull)
+ return (Datum) 0;
+ data = DatumGetXmlP(value);
+
+ e = (ExprState *) lsecond(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull)
+ version = NULL;
+ else
+ version = DatumGetTextP(value);
+
+ e = (ExprState *) lthird(xmlExpr->args);
+ value = ExecEvalExpr(e, econtext, &isnull, NULL);
+ if (isnull)
+ standalone = 0;
+ else
+ standalone = (DatumGetBool(value) ? 1 : -1);
+
+ *isNull = false;
+
+ return PointerGetDatum(xmlroot(data,
+ version,
+ standalone));
+ }
+ break;
+ }
+
+ if (*isNull)
+ result = NULL;
+ else
+ {
+ int len = buf.len + VARHDRSZ;
+
+ result = palloc(len);
+ VARATT_SIZEP(result) = len;
+ memcpy(VARDATA(result), buf.data, buf.len);
+ }
+
+ pfree(buf.data);
+ return PointerGetDatum(result);
+}
+
+/* ----------------------------------------------------------------
* ExecEvalNullIf
*
* Note that this is *always* derived from the equals operator,
@@ -2881,120 +3112,6 @@ ExecEvalBooleanTest(GenericExprState *bstate,
}
}
-/* ----------------------------------------------------------------
- * ExecEvalXml
- * ----------------------------------------------------------------
- */
-
-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->args)
- {
- ExprState *e = (ExprState *) lfirst(arg);
- Datum value = ExecEvalExpr(e, econtext, &isnull, NULL);
-
- if (!isnull)
- {
- appendStringInfoString(&buf, DatumGetCString(OidFunctionCall1(xmlExpr->arg_typeout, value)));
- *isNull = false;
- }
- }
- break;
-
- case IS_XMLELEMENT:
- {
- int state = 0, i = 0;
- appendStringInfo(&buf, "<%s", xmlExpr->name);
- foreach(arg, xmlExpr->named_args)
- {
- GenericExprState *gstate = (GenericExprState *) lfirst(arg);
- Datum value = ExecEvalExpr(gstate->arg, econtext, &isnull, NULL);
- if (!isnull)
- {
- char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->named_args_tcache[i], value));
- appendStringInfo(&buf, " %s=\"%s\"", xmlExpr->named_args_ncache[i], outstr);
- pfree(outstr);
- }
- i++;
- }
- if (xmlExpr->args)
- {
- ExprState *expr = linitial(xmlExpr->args);
- Datum value = ExecEvalExpr(expr, econtext, &isnull, NULL);
-
- if (!isnull)
- {
- char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->arg_typeout, 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>", xmlExpr->name);
-
- }
- break;
-
- case IS_XMLFOREST:
- {
- /* only if all argumets are null returns null */
- int i = 0;
- *isNull = true;
- foreach(arg, xmlExpr->named_args)
- {
- GenericExprState *gstate = (GenericExprState *) lfirst(arg);
- Datum value = ExecEvalExpr(gstate->arg, econtext, &isnull, NULL);
- if (!isnull)
- {
- char *outstr = DatumGetCString(OidFunctionCall1(xmlExpr->named_args_tcache[i], value));
- appendStringInfo(&buf, "<%s>%s</%s>", xmlExpr->named_args_ncache[i], outstr, xmlExpr->named_args_ncache[i]);
- pfree(outstr);
- *isNull = false;
- }
- i += 1;
- }
- }
- 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);
-}
-
/*
* ExecEvalCoerceToDomain
*
@@ -3794,59 +3911,45 @@ ExecInitExpr(Expr *node, PlanState *parent)
break;
case T_XmlExpr:
{
- List *outlist;
- ListCell *arg;
XmlExpr *xexpr = (XmlExpr *) node;
XmlExprState *xstate = makeNode(XmlExprState);
- int i = 0;
- Oid typeout;
-
- xstate->name = xexpr->name;
-
+ List *outlist;
+ ListCell *arg;
+ int i;
+
xstate->xprstate.evalfunc = (ExprStateEvalFunc) ExecEvalXml;
- xstate->op = xexpr->op;
-
+ xstate->named_outfuncs = (FmgrInfo *)
+ palloc0(list_length(xexpr->named_args) * sizeof(FmgrInfo));
outlist = NIL;
- if (xexpr->named_args)
- {
- xstate->named_args_tcache = (Oid *) palloc(list_length(xexpr->named_args) * sizeof(int));
- xstate->named_args_ncache = (char **) palloc(list_length(xexpr->named_args) * sizeof(char *));
-
- i = 0;
- foreach(arg, xexpr->named_args)
- {
- 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), &typeout, &tpisvarlena);
- xstate->named_args_ncache[i] = tle->resname;
- xstate->named_args_tcache[i] = typeout;
- i++;
- }
- }
- else
+ i = 0;
+ foreach(arg, xexpr->named_args)
{
- xstate->named_args_tcache = NULL;
- xstate->named_args_ncache = NULL;
+ Expr *e = (Expr *) lfirst(arg);
+ ExprState *estate;
+ Oid typOutFunc;
+ bool typIsVarlena;
+
+ estate = ExecInitExpr(e, parent);
+ outlist = lappend(outlist, estate);
+
+ getTypeOutputInfo(exprType((Node *) e),
+ &typOutFunc, &typIsVarlena);
+ fmgr_info(typOutFunc, &xstate->named_outfuncs[i]);
+ i++;
}
xstate->named_args = outlist;
- outlist = NIL;
+ outlist = NIL;
foreach(arg, xexpr->args)
{
- bool tpisvarlena;
- ExprState *estate;
- Expr *e = (Expr *) lfirst(arg);
- getTypeOutputInfo(exprType((Node *)e), &typeout, &tpisvarlena);
+ Expr *e = (Expr *) lfirst(arg);
+ ExprState *estate;
+
estate = ExecInitExpr(e, parent);
outlist = lappend(outlist, estate);
}
- xstate->arg_typeout = typeout;
xstate->args = outlist;
-
+
state = (ExprState *) xstate;
}
break;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index ca841cb181a..d46ed57d830 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.356 2006/12/23 00:43:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.357 2006/12/24 00:29:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1094,6 +1094,23 @@ _copyMinMaxExpr(MinMaxExpr *from)
}
/*
+ * _copyXmlExpr
+ */
+static XmlExpr *
+_copyXmlExpr(XmlExpr *from)
+{
+ XmlExpr *newnode = makeNode(XmlExpr);
+
+ COPY_SCALAR_FIELD(op);
+ COPY_STRING_FIELD(name);
+ COPY_NODE_FIELD(named_args);
+ COPY_NODE_FIELD(arg_names);
+ COPY_NODE_FIELD(args);
+
+ return newnode;
+}
+
+/*
* _copyNullIfExpr (same as OpExpr)
*/
static NullIfExpr *
@@ -1139,22 +1156,6 @@ _copyBooleanTest(BooleanTest *from)
}
/*
- * _copyXmlExpr
- */
-static XmlExpr *
-_copyXmlExpr(XmlExpr *from)
-{
- XmlExpr *newnode = makeNode(XmlExpr);
-
- COPY_SCALAR_FIELD(op);
- COPY_STRING_FIELD(name);
- COPY_NODE_FIELD(named_args);
- COPY_NODE_FIELD(args);
-
- return newnode;
-}
-
-/*
* _copyCoerceToDomain
*/
static CoerceToDomain *
@@ -2977,6 +2978,9 @@ copyObject(void *from)
case T_MinMaxExpr:
retval = _copyMinMaxExpr(from);
break;
+ case T_XmlExpr:
+ retval = _copyXmlExpr(from);
+ break;
case T_NullIfExpr:
retval = _copyNullIfExpr(from);
break;
@@ -2986,9 +2990,6 @@ copyObject(void *from)
case T_BooleanTest:
retval = _copyBooleanTest(from);
break;
- case T_XmlExpr:
- retval = _copyXmlExpr(from);
- break;
case T_CoerceToDomain:
retval = _copyCoerceToDomain(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index a7c4ef4e2a8..29bff448c7f 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.290 2006/12/23 00:43:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.291 2006/12/24 00:29:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -455,6 +455,18 @@ _equalMinMaxExpr(MinMaxExpr *a, MinMaxExpr *b)
}
static bool
+_equalXmlExpr(XmlExpr *a, XmlExpr *b)
+{
+ COMPARE_SCALAR_FIELD(op);
+ COMPARE_STRING_FIELD(name);
+ COMPARE_NODE_FIELD(named_args);
+ COMPARE_NODE_FIELD(arg_names);
+ COMPARE_NODE_FIELD(args);
+
+ return true;
+}
+
+static bool
_equalNullIfExpr(NullIfExpr *a, NullIfExpr *b)
{
COMPARE_SCALAR_FIELD(opno);
@@ -496,17 +508,6 @@ _equalBooleanTest(BooleanTest *a, BooleanTest *b)
}
static bool
-_equalXmlExpr(XmlExpr *a, XmlExpr *b)
-{
- COMPARE_SCALAR_FIELD(op);
- COMPARE_STRING_FIELD(name);
- COMPARE_NODE_FIELD(named_args);
- COMPARE_NODE_FIELD(args);
-
- return true;
-}
-
-static bool
_equalCoerceToDomain(CoerceToDomain *a, CoerceToDomain *b)
{
COMPARE_NODE_FIELD(arg);
@@ -1971,6 +1972,9 @@ equal(void *a, void *b)
case T_MinMaxExpr:
retval = _equalMinMaxExpr(a, b);
break;
+ case T_XmlExpr:
+ retval = _equalXmlExpr(a, b);
+ break;
case T_NullIfExpr:
retval = _equalNullIfExpr(a, b);
break;
@@ -1980,9 +1984,6 @@ equal(void *a, void *b)
case T_BooleanTest:
retval = _equalBooleanTest(a, b);
break;
- case T_XmlExpr:
- retval = _equalXmlExpr(a, b);
- break;
case T_CoerceToDomain:
retval = _equalCoerceToDomain(a, b);
break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index b18b6988cfa..4911d6ed404 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.288 2006/12/23 00:43:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.289 2006/12/24 00:29:18 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@@ -893,6 +893,18 @@ _outMinMaxExpr(StringInfo str, MinMaxExpr *node)
}
static void
+_outXmlExpr(StringInfo str, XmlExpr *node)
+{
+ WRITE_NODE_TYPE("XMLEXPR");
+
+ WRITE_ENUM_FIELD(op, XmlExprOp);
+ WRITE_STRING_FIELD(name);
+ WRITE_NODE_FIELD(named_args);
+ WRITE_NODE_FIELD(arg_names);
+ WRITE_NODE_FIELD(args);
+}
+
+static void
_outNullIfExpr(StringInfo str, NullIfExpr *node)
{
WRITE_NODE_TYPE("NULLIFEXPR");
@@ -923,17 +935,6 @@ _outBooleanTest(StringInfo str, BooleanTest *node)
}
static void
-_outXmlExpr(StringInfo str, XmlExpr *node)
-{
- WRITE_NODE_TYPE("XMLEXPR");
-
- WRITE_ENUM_FIELD(op, XmlExprOp);
- WRITE_STRING_FIELD(name);
- WRITE_NODE_FIELD(named_args);
- WRITE_NODE_FIELD(args);
-}
-
-static void
_outCoerceToDomain(StringInfo str, CoerceToDomain *node)
{
WRITE_NODE_TYPE("COERCETODOMAIN");
@@ -2026,6 +2027,9 @@ _outNode(StringInfo str, void *obj)
case T_MinMaxExpr:
_outMinMaxExpr(str, obj);
break;
+ case T_XmlExpr:
+ _outXmlExpr(str, obj);
+ break;
case T_NullIfExpr:
_outNullIfExpr(str, obj);
break;
@@ -2035,9 +2039,6 @@ _outNode(StringInfo str, void *obj)
case T_BooleanTest:
_outBooleanTest(str, obj);
break;
- case T_XmlExpr:
- _outXmlExpr(str, obj);
- break;
case T_CoerceToDomain:
_outCoerceToDomain(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 37b39439eb0..781eeee14f1 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.198 2006/12/23 00:43:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.199 2006/12/24 00:29:18 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
@@ -709,6 +709,23 @@ _readMinMaxExpr(void)
}
/*
+ * _readXmlExpr
+ */
+static XmlExpr *
+_readXmlExpr(void)
+{
+ READ_LOCALS(XmlExpr);
+
+ READ_ENUM_FIELD(op, XmlExprOp);
+ READ_STRING_FIELD(name);
+ READ_NODE_FIELD(named_args);
+ READ_NODE_FIELD(arg_names);
+ READ_NODE_FIELD(args);
+
+ READ_DONE();
+}
+
+/*
* _readNullIfExpr
*/
static NullIfExpr *
@@ -765,22 +782,6 @@ _readBooleanTest(void)
}
/*
- * _readXmlExpr
- */
-static XmlExpr *
-_readXmlExpr(void)
-{
- READ_LOCALS(XmlExpr);
-
- READ_ENUM_FIELD(op, XmlExprOp);
- READ_STRING_FIELD(name);
- READ_NODE_FIELD(named_args);
- READ_NODE_FIELD(args);
-
- READ_DONE();
-}
-
-/*
* _readCoerceToDomain
*/
static CoerceToDomain *
@@ -1024,14 +1025,14 @@ parseNodeString(void)
return_value = _readCoalesceExpr();
else if (MATCH("MINMAX", 6))
return_value = _readMinMaxExpr();
+ else if (MATCH("XMLEXPR", 7))
+ return_value = _readXmlExpr();
else if (MATCH("NULLIFEXPR", 10))
return_value = _readNullIfExpr();
else if (MATCH("NULLTEST", 8))
return_value = _readNullTest();
else if (MATCH("BOOLEANTEST", 11))
return_value = _readBooleanTest();
- else if (MATCH("XMLEXPR", 7))
- return_value = _readXmlExpr();
else if (MATCH("COERCETODOMAIN", 14))
return_value = _readCoerceToDomain();
else if (MATCH("COERCETODOMAINVALUE", 19))
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 0f720c40e93..5ad97aabc34 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.225 2006/12/23 00:43:10 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.226 2006/12/24 00:29:18 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -557,10 +557,10 @@ expression_returns_set_walker(Node *node, void *context)
return false;
if (IsA(node, MinMaxExpr))
return false;
- if (IsA(node, NullIfExpr))
- return false;
if (IsA(node, XmlExpr))
return false;
+ if (IsA(node, NullIfExpr))
+ return false;
return expression_tree_walker(node, expression_returns_set_walker,
context);
@@ -872,14 +872,14 @@ contain_nonstrict_functions_walker(Node *node, void *context)
return true;
if (IsA(node, MinMaxExpr))
return true;
+ if (IsA(node, XmlExpr))
+ return true;
if (IsA(node, NullIfExpr))
return true;
if (IsA(node, NullTest))
return true;
if (IsA(node, BooleanTest))
return true;
- if (IsA(node, XmlExpr))
- return true;
return expression_tree_walker(node, contain_nonstrict_functions_walker,
context);
}
@@ -3328,22 +3328,23 @@ expression_tree_walker(Node *node,
return walker(((CoalesceExpr *) node)->args, context);
case T_MinMaxExpr:
return walker(((MinMaxExpr *) node)->args, context);
- case T_NullIfExpr:
- return walker(((NullIfExpr *) node)->args, context);
- case T_NullTest:
- return walker(((NullTest *) node)->arg, context);
- case T_BooleanTest:
- return walker(((BooleanTest *) node)->arg, context);
case T_XmlExpr:
{
XmlExpr *xexpr = (XmlExpr *) node;
if (walker(xexpr->named_args, context))
return true;
+ /* we assume walker doesn't care about arg_names */
if (walker(xexpr->args, context))
return true;
}
break;
+ case T_NullIfExpr:
+ return walker(((NullIfExpr *) node)->args, context);
+ case T_NullTest:
+ return walker(((NullTest *) node)->arg, context);
+ case T_BooleanTest:
+ return walker(((BooleanTest *) node)->arg, context);
case T_CoerceToDomain:
return walker(((CoerceToDomain *) node)->arg, context);
case T_TargetEntry:
@@ -3874,6 +3875,7 @@ expression_tree_mutator(Node *node,
FLATCOPY(newnode, xexpr, XmlExpr);
MUTATE(newnode->named_args, xexpr->named_args, List *);
+ /* assume mutator does not care about arg_names */
MUTATE(newnode->args, xexpr->args, List *);
return (Node *) newnode;
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index cc400407363..a1511870f28 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.569 2006/12/21 16:05:14 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.570 2006/12/24 00:29:18 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -348,8 +348,8 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
%type <target> xml_attribute_el
%type <list> xml_attribute_list xml_attributes
-%type <node> xml_root_version
-%type <ival> opt_xml_root_standalone document_or_content xml_whitespace_option
+%type <node> xml_root_version opt_xml_root_standalone
+%type <boolean> document_or_content xml_whitespace_option
/*
@@ -371,13 +371,13 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
COMMITTED CONCURRENTLY CONNECTION CONSTRAINT CONSTRAINTS
- CONTENT CONVERSION_P CONVERT COPY CREATE CREATEDB
+ CONTENT_P CONVERSION_P CONVERT COPY CREATE CREATEDB
CREATEROLE CREATEUSER CROSS CSV CURRENT_DATE CURRENT_ROLE CURRENT_TIME
CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS
- DESC DISABLE_P DISTINCT DO DOCUMENT DOMAIN_P DOUBLE_P DROP
+ DESC DISABLE_P DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ESCAPE EXCEPT EXCLUDING
EXCLUSIVE EXECUTE EXISTS EXPLAIN EXTERNAL EXTRACT
@@ -404,7 +404,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
- NAME NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
+ NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NO NOCREATEDB
NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NUMERIC
@@ -423,9 +423,9 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
SAVEPOINT SCHEMA SCROLL SECOND_P SECURITY SELECT SEQUENCE
SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
- SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE START STATEMENT
- STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP SUBSTRING SUPERUSER_P SYMMETRIC
- SYSID SYSTEM_P
+ SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE_P START STATEMENT
+ STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SUPERUSER_P
+ SYMMETRIC SYSID SYSTEM_P
TABLE TABLESPACE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP
TO TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
@@ -434,15 +434,15 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN UNLISTEN UNTIL
UPDATE USER USING
- VACUUM VALID VALIDATOR VALUE VALUES VARCHAR VARYING
- VERBOSE VERSION VIEW VOLATILE
+ VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARYING
+ VERBOSE VERSION_P VIEW VOLATILE
- WHEN WHERE WHITESPACE WITH WITHOUT WORK WRITE
+ WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE
XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
XMLPI XMLROOT XMLSERIALIZE
- YEAR_P YES
+ YEAR_P YES_P
ZONE
@@ -493,7 +493,8 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
* left-associativity among the JOIN rules themselves.
*/
%left JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
-%right PRESERVE STRIP
+/* kluge to keep xml_whitespace_option from causing shift/reduce conflicts */
+%right PRESERVE STRIP_P
%%
/*
@@ -7880,95 +7881,54 @@ func_expr: func_name '(' ')'
}
| XMLCONCAT '(' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NULL, $3);
+ $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3);
}
- | XMLELEMENT '(' NAME ColLabel ')'
+ | XMLELEMENT '(' NAME_P ColLabel ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, NULL);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL);
}
- | XMLELEMENT '(' NAME ColLabel ',' xml_attributes ')'
+ | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NULL);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL);
}
- | XMLELEMENT '(' NAME ColLabel ',' expr_list ')'
+ | XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, $6);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6);
}
- | XMLELEMENT '(' NAME ColLabel ',' xml_attributes ',' expr_list ')'
+ | XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
{
$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8);
}
| XMLFOREST '(' xml_attribute_list ')'
{
- $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NULL);
+ $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL);
}
| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
{
- FuncCall *n = makeNode(FuncCall);
- n->funcname = SystemFuncName("xmlparse");
- n->args = list_make3(makeBoolAConst($3 == DOCUMENT), $4, makeBoolAConst($5 == PRESERVE));
- n->agg_star = FALSE;
- n->agg_distinct = FALSE;
- n->location = @1;
- $$ = (Node *)n;
+ $$ = makeXmlExpr(IS_XMLPARSE, NULL, NIL,
+ list_make3($4,
+ makeBoolAConst($3),
+ makeBoolAConst($5)));
}
- | XMLPI '(' NAME ColLabel ')'
+ | XMLPI '(' NAME_P ColLabel ')'
{
- FuncCall *n = makeNode(FuncCall);
- n->funcname = SystemFuncName("xmlpi");
- n->args = list_make1(makeStringConst($4, NULL));
- n->agg_star = FALSE;
- n->agg_distinct = FALSE;
- n->location = @1;
- $$ = (Node *)n;
+ $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL);
}
- | XMLPI '(' NAME ColLabel ',' a_expr ')'
+ | XMLPI '(' NAME_P ColLabel ',' a_expr ')'
{
- FuncCall *n = makeNode(FuncCall);
- n->funcname = SystemFuncName("xmlpi");
- n->args = list_make2(makeStringConst($4, NULL), $6);
- n->agg_star = FALSE;
- n->agg_distinct = FALSE;
- n->location = @1;
- $$ = (Node *)n;
+ $$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6));
}
| XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
{
- FuncCall *n = makeNode(FuncCall);
- Node *ver;
- A_Const *sa;
-
- if ($5)
- ver = $5;
- else
- {
- A_Const *val;
-
- val = makeNode(A_Const);
- val->val.type = T_Null;
- ver = (Node *) val;
- }
-
- if ($6)
- sa = makeBoolAConst($6 == 1);
- else
- {
- sa = makeNode(A_Const);
- sa->val.type = T_Null;
- }
-
- n->funcname = SystemFuncName("xmlroot");
- n->args = list_make3($3, ver, sa);
- n->agg_star = FALSE;
- n->agg_distinct = FALSE;
- n->location = @1;
- $$ = (Node *)n;
+ $$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
+ list_make3($3, $5, $6));
}
| XMLSERIALIZE '(' document_or_content a_expr AS Typename ')'
{
/*
* FIXME: This should be made distinguishable from
- * CAST (for reverse compilation at least).
+ * CAST (for reverse compilation at least). Also,
+ * what about the document/content option??
*/
$$ = makeTypeCast($4, $6);
}
@@ -7977,17 +7937,35 @@ func_expr: func_name '(' ')'
/*
* SQL/XML support
*/
-xml_root_version: VERSION a_expr { $$ = $2; }
- | VERSION NO VALUE { $$ = NULL; }
+xml_root_version: VERSION_P a_expr
+ { $$ = $2; }
+ | VERSION_P NO VALUE_P
+ {
+ A_Const *val = makeNode(A_Const);
+ val->val.type = T_Null;
+ $$ = (Node *) val;
+ }
;
-opt_xml_root_standalone: ',' STANDALONE YES { $$ = 1; }
- | ',' STANDALONE NO { $$ = -1; }
- | ',' STANDALONE NO VALUE { $$ = 0; }
- | /*EMPTY*/ { $$ = 0; }
+opt_xml_root_standalone: ',' STANDALONE_P YES_P
+ { $$ = (Node *) makeBoolAConst(true); }
+ | ',' STANDALONE_P NO
+ { $$ = (Node *) makeBoolAConst(false); }
+ | ',' STANDALONE_P NO VALUE_P
+ {
+ A_Const *val = makeNode(A_Const);
+ val->val.type = T_Null;
+ $$ = (Node *) val;
+ }
+ | /*EMPTY*/
+ {
+ A_Const *val = makeNode(A_Const);
+ val->val.type = T_Null;
+ $$ = (Node *) val;
+ }
;
-xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; }
+xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; }
;
xml_attribute_list: xml_attribute_el { $$ = list_make1($1); }
@@ -8000,7 +7978,7 @@ xml_attribute_el: a_expr AS ColLabel
$$->name = $3;
$$->indirection = NULL;
$$->val = (Node *) $1;
-
+ $$->location = @1;
}
| a_expr
{
@@ -8008,16 +7986,21 @@ xml_attribute_el: a_expr AS ColLabel
$$->name = NULL;
$$->indirection = NULL;
$$->val = (Node *) $1;
+ $$->location = @1;
}
;
-document_or_content: DOCUMENT { $$ = DOCUMENT; }
- | CONTENT { $$ = CONTENT; }
+document_or_content: DOCUMENT_P { $$ = TRUE; }
+ | CONTENT_P { $$ = FALSE; }
;
-xml_whitespace_option: PRESERVE WHITESPACE { $$ = PRESERVE; }
- | STRIP WHITESPACE { $$ = STRIP; }
- | /*EMPTY*/ { $$ = STRIP; }
+/*
+ * XXX per SQL spec, the default should be STRIP WHITESPACE, but since we
+ * haven't implemented that yet, temporarily default to PRESERVE.
+ */
+xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = TRUE; }
+ | STRIP_P WHITESPACE_P { $$ = FALSE; }
+ | /*EMPTY*/ { $$ = TRUE; }
;
/*
@@ -8712,7 +8695,7 @@ unreserved_keyword:
| CONCURRENTLY
| CONNECTION
| CONSTRAINTS
- | CONTENT
+ | CONTENT_P
| CONVERSION_P
| COPY
| CREATEDB
@@ -8732,7 +8715,7 @@ unreserved_keyword:
| DELIMITER
| DELIMITERS
| DISABLE_P
- | DOCUMENT
+ | DOCUMENT_P
| DOMAIN_P
| DOUBLE_P
| DROP
@@ -8792,7 +8775,7 @@ unreserved_keyword:
| MODE
| MONTH_P
| MOVE
- | NAME
+ | NAME_P
| NAMES
| NEXT
| NO
@@ -8853,18 +8836,18 @@ unreserved_keyword:
| SHOW
| SIMPLE
| STABLE
- | STANDALONE
+ | STANDALONE_P
| START
| STATEMENT
| STATISTICS
| STDIN
| STDOUT
| STORAGE
- | STRIP
+ | STRICT_P
+ | STRIP_P
| SUPERUSER_P
| SYSID
| SYSTEM_P
- | STRICT_P
| TABLESPACE
| TEMP
| TEMPLATE
@@ -8883,18 +8866,18 @@ unreserved_keyword:
| VACUUM
| VALID
| VALIDATOR
+ | VALUE_P
| VARYING
- | VERSION
+ | VERSION_P
| VIEW
- | VALUE
| VOLATILE
- | WHITESPACE
+ | WHITESPACE_P
| WITH
| WITHOUT
| WORK
| WRITE
| YEAR_P
- | YES
+ | YES_P
| ZONE
;
@@ -8948,8 +8931,8 @@ col_name_keyword:
| VALUES
| VARCHAR
| XMLATTRIBUTES
- | XMLELEMENT
| XMLCONCAT
+ | XMLELEMENT
| XMLFOREST
| XMLPARSE
| XMLPI
@@ -9492,10 +9475,16 @@ doNegateFloat(Value *v)
static Node *
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
{
- XmlExpr *x = makeNode(XmlExpr);
+ XmlExpr *x = makeNode(XmlExpr);
+
x->op = op;
x->name = name;
+ /*
+ * named_args is a list of ResTarget; it'll be split apart into separate
+ * expression and name lists in transformXmlExpr().
+ */
x->named_args = named_args;
+ x->arg_names = NIL;
x->args = args;
return (Node *) x;
}
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index b5e49e955fc..4865d360b3e 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.178 2006/12/21 16:05:14 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.179 2006/12/24 00:29:18 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -89,7 +89,7 @@ static const ScanKeyword ScanKeywords[] = {
{"connection", CONNECTION},
{"constraint", CONSTRAINT},
{"constraints", CONSTRAINTS},
- {"content", CONTENT},
+ {"content", CONTENT_P},
{"conversion", CONVERSION_P},
{"convert", CONVERT},
{"copy", COPY},
@@ -124,7 +124,7 @@ static const ScanKeyword ScanKeywords[] = {
{"disable", DISABLE_P},
{"distinct", DISTINCT},
{"do", DO},
- {"document", DOCUMENT},
+ {"document", DOCUMENT_P},
{"domain", DOMAIN_P},
{"double", DOUBLE_P},
{"drop", DROP},
@@ -220,7 +220,7 @@ static const ScanKeyword ScanKeywords[] = {
{"mode", MODE},
{"month", MONTH_P},
{"move", MOVE},
- {"name", NAME},
+ {"name", NAME_P},
{"names", NAMES},
{"national", NATIONAL},
{"natural", NATURAL},
@@ -317,7 +317,7 @@ static const ScanKeyword ScanKeywords[] = {
{"smallint", SMALLINT},
{"some", SOME},
{"stable", STABLE},
- {"standalone", STANDALONE},
+ {"standalone", STANDALONE_P},
{"start", START},
{"statement", STATEMENT},
{"statistics", STATISTICS},
@@ -325,7 +325,7 @@ static const ScanKeyword ScanKeywords[] = {
{"stdout", STDOUT},
{"storage", STORAGE},
{"strict", STRICT_P},
- {"strip", STRIP},
+ {"strip", STRIP_P},
{"substring", SUBSTRING},
{"superuser", SUPERUSER_P},
{"symmetric", SYMMETRIC},
@@ -362,17 +362,17 @@ static const ScanKeyword ScanKeywords[] = {
{"vacuum", VACUUM},
{"valid", VALID},
{"validator", VALIDATOR},
- {"value", VALUE},
+ {"value", VALUE_P},
{"values", VALUES},
{"varchar", VARCHAR},
{"varying", VARYING},
{"verbose", VERBOSE},
- {"version", VERSION},
+ {"version", VERSION_P},
{"view", VIEW},
{"volatile", VOLATILE},
{"when", WHEN},
{"where", WHERE},
- {"whitespace", WHITESPACE},
+ {"whitespace", WHITESPACE_P},
{"with", WITH},
{"without", WITHOUT},
{"work", WORK},
@@ -386,7 +386,7 @@ static const ScanKeyword ScanKeywords[] = {
{"xmlroot", XMLROOT},
{"xmlserialize", XMLSERIALIZE},
{"year", YEAR_P},
- {"yes", YES},
+ {"yes", YES_P},
{"zone", ZONE},
};
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 996c724d1ce..145caab101a 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.159 2006/11/28 12:54:41 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.160 2006/12/24 00:29:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1094,7 +1094,7 @@ transformLimitClause(ParseState *pstate, Node *clause,
qual = transformExpr(pstate, clause);
- qual = coerce_to_bigint(pstate, qual, constructName);
+ qual = coerce_to_specific_type(pstate, qual, INT8OID, constructName);
/*
* LIMIT can't refer to any vars or aggregates of the current query; we
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 5670ed4fe74..45c8e97be1d 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.148 2006/12/21 16:05:14 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.149 2006/12/24 00:29:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -840,8 +840,8 @@ coerce_to_boolean(ParseState *pstate, Node *node,
}
/*
- * coerce_to_integer()
- * Coerce an argument of a construct that requires integer input.
+ * coerce_to_specific_type()
+ * Coerce an argument of a construct that requires a specific data type.
* Also check that input is not a set.
*
* Returns the possibly-transformed node tree.
@@ -850,103 +850,26 @@ coerce_to_boolean(ParseState *pstate, Node *node,
* processing is wanted.
*/
Node *
-coerce_to_integer(ParseState *pstate, Node *node,
- const char *constructName)
-{
- Oid inputTypeId = exprType(node);
-
- if (inputTypeId != INT4OID)
- {
- node = coerce_to_target_type(pstate, node, inputTypeId,
- INT4OID, -1,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
- if (node == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- /* translator: first %s is name of a SQL construct, eg LIMIT */
- errmsg("argument of %s must be type integer, not type %s",
- constructName, format_type_be(inputTypeId))));
- }
-
- if (expression_returns_set(node))
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- /* translator: %s is name of a SQL construct, eg LIMIT */
- errmsg("argument of %s must not return a set",
- constructName)));
-
- return node;
-}
-
-/*
- * coerce_to_bigint()
- * Coerce an argument of a construct that requires int8 input.
- * Also check that input is not a set.
- *
- * Returns the possibly-transformed node tree.
- *
- * As with coerce_type, pstate may be NULL if no special unknown-Param
- * processing is wanted.
- */
-Node *
-coerce_to_bigint(ParseState *pstate, Node *node,
- const char *constructName)
-{
- Oid inputTypeId = exprType(node);
-
- if (inputTypeId != INT8OID)
- {
- node = coerce_to_target_type(pstate, node, inputTypeId,
- INT8OID, -1,
- COERCION_ASSIGNMENT,
- COERCE_IMPLICIT_CAST);
- if (node == NULL)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- /* translator: first %s is name of a SQL construct, eg LIMIT */
- errmsg("argument of %s must be type bigint, not type %s",
- constructName, format_type_be(inputTypeId))));
- }
-
- if (expression_returns_set(node))
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- /* translator: %s is name of a SQL construct, eg LIMIT */
- errmsg("argument of %s must not return a set",
- constructName)));
-
- return node;
-}
-
-/*
- * coerce_to_xml()
- * Coerce an argument of a construct that requires xml input.
- * Also check that input is not a set.
- *
- * Returns the possibly-transformed node tree.
- *
- * As with coerce_type, pstate may be NULL if no special unknown-Param
- * processing is wanted.
- */
-Node *
-coerce_to_xml(ParseState *pstate, Node *node,
- const char *constructName)
+coerce_to_specific_type(ParseState *pstate, Node *node,
+ Oid targetTypeId,
+ const char *constructName)
{
Oid inputTypeId = exprType(node);
- if (inputTypeId != XMLOID)
+ if (inputTypeId != targetTypeId)
{
node = coerce_to_target_type(pstate, node, inputTypeId,
- XMLOID, -1,
+ targetTypeId, -1,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
if (node == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
/* translator: first %s is name of a SQL construct, eg LIMIT */
- errmsg("argument of %s must be type xml, not type %s",
- constructName, format_type_be(inputTypeId))));
+ errmsg("argument of %s must be type %s, not type %s",
+ constructName,
+ format_type_be(targetTypeId),
+ format_type_be(inputTypeId))));
}
if (expression_returns_set(node))
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 2a48741b3a2..7dbbb9a33a8 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.201 2006/12/23 00:43:11 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.202 2006/12/24 00:29:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -220,6 +220,10 @@ transformExpr(ParseState *pstate, Node *expr)
result = transformMinMaxExpr(pstate, (MinMaxExpr *) expr);
break;
+ case T_XmlExpr:
+ result = transformXmlExpr(pstate, (XmlExpr *) expr);
+ break;
+
case T_NullTest:
{
NullTest *n = (NullTest *) expr;
@@ -234,10 +238,6 @@ transformExpr(ParseState *pstate, Node *expr)
result = transformBooleanTest(pstate, (BooleanTest *) expr);
break;
- case T_XmlExpr:
- result = transformXmlExpr(pstate, (XmlExpr *) expr);
- break;
-
/*********************************************
* Quietly accept node types that may be presented when we are
* called on an already-transformed tree.
@@ -1376,6 +1376,107 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
}
static Node *
+transformXmlExpr(ParseState *pstate, XmlExpr *x)
+{
+ XmlExpr *newx = makeNode(XmlExpr);
+ ListCell *lc;
+ int i;
+
+ newx->op = x->op;
+ if (x->name)
+ newx->name = map_sql_identifier_to_xml_name(x->name, false);
+ else
+ newx->name = NULL;
+
+ /*
+ * gram.y built the named args as a list of ResTarget. Transform each,
+ * and break the names out as a separate list.
+ */
+ newx->named_args = NIL;
+ newx->arg_names = NIL;
+
+ foreach(lc, x->named_args)
+ {
+ ResTarget *r = (ResTarget *) lfirst(lc);
+ Node *expr;
+ char *argname;
+
+ Assert(IsA(r, ResTarget));
+
+ expr = transformExpr(pstate, r->val);
+
+ if (r->name)
+ argname = map_sql_identifier_to_xml_name(r->name, false);
+ else if (IsA(r->val, ColumnRef))
+ argname = map_sql_identifier_to_xml_name(FigureColname(r->val),
+ true);
+ else
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ x->op == IS_XMLELEMENT
+ ? errmsg("unnamed attribute value must be a column reference")
+ : errmsg("unnamed element value must be a column reference")));
+ argname = NULL; /* keep compiler quiet */
+ }
+
+ newx->named_args = lappend(newx->named_args, expr);
+ newx->arg_names = lappend(newx->arg_names, makeString(argname));
+ }
+
+ /* The other arguments are of varying types depending on the function */
+ newx->args = NIL;
+ i = 0;
+ foreach(lc, x->args)
+ {
+ Node *e = (Node *) lfirst(lc);
+ Node *newe;
+
+ newe = transformExpr(pstate, e);
+ switch (x->op)
+ {
+ case IS_XMLCONCAT:
+ newe = coerce_to_specific_type(pstate, newe, XMLOID,
+ "XMLCONCAT");
+ break;
+ case IS_XMLELEMENT:
+ newe = coerce_to_specific_type(pstate, newe, XMLOID,
+ "XMLELEMENT");
+ break;
+ case IS_XMLFOREST:
+ newe = coerce_to_specific_type(pstate, newe, XMLOID,
+ "XMLFOREST");
+ break;
+ case IS_XMLPARSE:
+ if (i == 0)
+ newe = coerce_to_specific_type(pstate, newe, TEXTOID,
+ "XMLPARSE");
+ else
+ newe = coerce_to_boolean(pstate, newe, "XMLPARSE");
+ break;
+ case IS_XMLPI:
+ newe = coerce_to_specific_type(pstate, newe, TEXTOID,
+ "XMLPI");
+ break;
+ case IS_XMLROOT:
+ if (i == 0)
+ newe = coerce_to_specific_type(pstate, newe, XMLOID,
+ "XMLROOT");
+ else if (i == 1)
+ newe = coerce_to_specific_type(pstate, newe, TEXTOID,
+ "XMLROOT");
+ else
+ newe = coerce_to_boolean(pstate, newe, "XMLROOT");
+ break;
+ }
+ newx->args = lappend(newx->args, newe);
+ i++;
+ }
+
+ return (Node *) newx;
+}
+
+static Node *
transformBooleanTest(ParseState *pstate, BooleanTest *b)
{
const char *clausename;
@@ -1415,56 +1516,6 @@ transformBooleanTest(ParseState *pstate, BooleanTest *b)
return (Node *) b;
}
-static Node *
-transformXmlExpr(ParseState *pstate, XmlExpr *x)
-{
- ListCell *lc;
- XmlExpr *newx = makeNode(XmlExpr);
-
- newx->op = x->op;
- if (x->name)
- newx->name = map_sql_identifier_to_xml_name(x->name, false);
- else
- newx->name = NULL;
-
- foreach(lc, x->named_args)
- {
- ResTarget *r = (ResTarget *) lfirst(lc);
- Node *expr = transformExpr(pstate, r->val);
- char *argname = NULL;
-
- if (r->name)
- argname = map_sql_identifier_to_xml_name(r->name, false);
- else if (IsA(r->val, ColumnRef))
- argname = map_sql_identifier_to_xml_name(FigureColname(r->val), true);
- else
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- x->op == IS_XMLELEMENT
- ? errmsg("unnamed attribute value must be a column reference")
- : errmsg("unnamed element value must be a column reference")));
-
- newx->named_args = lappend(newx->named_args,
- makeTargetEntry((Expr *) expr, 0, argname, false));
- }
-
- foreach(lc, x->args)
- {
- Node *e = (Node *) lfirst(lc);
- Node *newe;
-
- newe = coerce_to_xml(pstate, transformExpr(pstate, e),
- (x->op == IS_XMLCONCAT
- ? "XMLCONCAT"
- : (x->op == IS_XMLELEMENT
- ? "XMLELEMENT"
- : "XMLFOREST")));
- newx->args = lappend(newx->args, newe);
- }
-
- return (Node *) newx;
-}
-
/*
* Construct a whole-row reference to represent the notation "relation.*".
*
@@ -1715,6 +1766,9 @@ exprType(Node *expr)
case T_MinMaxExpr:
type = ((MinMaxExpr *) expr)->minmaxtype;
break;
+ case T_XmlExpr:
+ type = XMLOID;
+ break;
case T_NullIfExpr:
type = exprType((Node *) linitial(((NullIfExpr *) expr)->args));
break;
@@ -1724,9 +1778,6 @@ exprType(Node *expr)
case T_BooleanTest:
type = BOOLOID;
break;
- case T_XmlExpr:
- type = XMLOID;
- break;
case T_CoerceToDomain:
type = ((CoerceToDomain *) expr)->resulttype;
break;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 906d96e45c6..ef4b9083ac6 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.150 2006/12/21 16:05:14 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.151 2006/12/24 00:29:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1328,6 +1328,15 @@ FigureColnameInternal(Node *node, char **name)
case IS_XMLFOREST:
*name = "xmlforest";
return 2;
+ case IS_XMLPARSE:
+ *name = "xmlparse";
+ return 2;
+ case IS_XMLPI:
+ *name = "xmlpi";
+ return 2;
+ case IS_XMLROOT:
+ *name = "xmlroot";
+ return 2;
}
break;
default:
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index b2ff95f457b..699b4a93704 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2,7 +2,7 @@
* ruleutils.c - Functions to convert stored expressions/querytrees
* back to source text
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.237 2006/12/23 00:43:11 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.238 2006/12/24 00:29:19 tgl Exp $
**********************************************************************/
#include "postgres.h"
@@ -2988,8 +2988,8 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_RowExpr:
case T_CoalesceExpr:
case T_MinMaxExpr:
- case T_NullIfExpr:
case T_XmlExpr:
+ case T_NullIfExpr:
case T_Aggref:
case T_FuncExpr:
/* function-like: name(..) or name[..] */
@@ -3097,8 +3097,8 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_RowExpr: /* other separators */
case T_CoalesceExpr: /* own parentheses */
case T_MinMaxExpr: /* own parentheses */
- case T_NullIfExpr: /* other separators */
case T_XmlExpr: /* own parentheses */
+ case T_NullIfExpr: /* other separators */
case T_Aggref: /* own parentheses */
case T_CaseExpr: /* other separators */
return true;
@@ -3146,8 +3146,8 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_RowExpr: /* other separators */
case T_CoalesceExpr: /* own parentheses */
case T_MinMaxExpr: /* own parentheses */
- case T_NullIfExpr: /* other separators */
case T_XmlExpr: /* own parentheses */
+ case T_NullIfExpr: /* other separators */
case T_Aggref: /* own parentheses */
case T_CaseExpr: /* other separators */
return true;
@@ -3779,6 +3779,140 @@ get_rule_expr(Node *node, deparse_context *context,
}
break;
+ case T_XmlExpr:
+ {
+ XmlExpr *xexpr = (XmlExpr *) node;
+ bool needcomma = false;
+ ListCell *arg;
+ ListCell *narg;
+ Const *con;
+
+ switch (xexpr->op)
+ {
+ case IS_XMLCONCAT:
+ appendStringInfoString(buf, "XMLCONCAT(");
+ break;
+ case IS_XMLELEMENT:
+ appendStringInfoString(buf, "XMLELEMENT(");
+ break;
+ case IS_XMLFOREST:
+ appendStringInfoString(buf, "XMLFOREST(");
+ break;
+ case IS_XMLPARSE:
+ appendStringInfoString(buf, "XMLPARSE(");
+ break;
+ case IS_XMLPI:
+ appendStringInfoString(buf, "XMLPI(");
+ break;
+ case IS_XMLROOT:
+ appendStringInfoString(buf, "XMLROOT(");
+ break;
+ }
+ if (xexpr->name)
+ {
+ /*
+ * XXX need to de-escape the name
+ */
+ appendStringInfo(buf, "NAME %s",
+ quote_identifier(xexpr->name));
+ needcomma = true;
+ }
+ if (xexpr->named_args)
+ {
+ if (xexpr->op != IS_XMLFOREST)
+ {
+ if (needcomma)
+ appendStringInfoString(buf, ", ");
+ appendStringInfoString(buf, "XMLATTRIBUTES(");
+ needcomma = false;
+ }
+ forboth(arg, xexpr->named_args, narg, xexpr->arg_names)
+ {
+ Node *e = (Node *) lfirst(arg);
+ char *argname = strVal(lfirst(narg));
+
+ if (needcomma)
+ appendStringInfoString(buf, ", ");
+ get_rule_expr((Node *) e, context, true);
+ /*
+ * XXX need to de-escape the name
+ */
+ appendStringInfo(buf, " AS %s",
+ quote_identifier(argname));
+ needcomma = true;
+ }
+ if (xexpr->op != IS_XMLFOREST)
+ appendStringInfoChar(buf, ')');
+ }
+ if (xexpr->args)
+ {
+ if (needcomma)
+ appendStringInfoString(buf, ", ");
+ switch (xexpr->op)
+ {
+ case IS_XMLCONCAT:
+ case IS_XMLELEMENT:
+ case IS_XMLFOREST:
+ case IS_XMLPI:
+ /* no extra decoration needed */
+ get_rule_expr((Node *) xexpr->args, context, true);
+ break;
+ case IS_XMLPARSE:
+ Assert(list_length(xexpr->args) == 3);
+
+ con = (Const *) lsecond(xexpr->args);
+ Assert(IsA(con, Const));
+ Assert(!con->constisnull);
+ if (DatumGetBool(con->constvalue))
+ appendStringInfoString(buf, "DOCUMENT ");
+ else
+ appendStringInfoString(buf, "CONTENT ");
+
+ get_rule_expr((Node *) linitial(xexpr->args),
+ context, true);
+
+ con = (Const *) lthird(xexpr->args);
+ Assert(IsA(con, Const));
+ Assert(!con->constisnull);
+ if (DatumGetBool(con->constvalue))
+ appendStringInfoString(buf,
+ " PRESERVE WHITESPACE");
+ else
+ appendStringInfoString(buf,
+ " STRIP WHITESPACE");
+ break;
+ case IS_XMLROOT:
+ Assert(list_length(xexpr->args) == 3);
+
+ get_rule_expr((Node *) linitial(xexpr->args),
+ context, true);
+
+ appendStringInfoString(buf, ", VERSION ");
+ con = (Const *) lsecond(xexpr->args);
+ if (IsA(con, Const) &&
+ con->constisnull)
+ appendStringInfoString(buf, "NO VALUE");
+ else
+ get_rule_expr((Node *) con, context, false);
+
+ con = (Const *) lthird(xexpr->args);
+ Assert(IsA(con, Const));
+ if (con->constisnull)
+ /* suppress STANDALONE NO VALUE */ ;
+ else if (DatumGetBool(con->constvalue))
+ appendStringInfoString(buf,
+ ", STANDALONE YES");
+ else
+ appendStringInfoString(buf,
+ ", STANDALONE NO");
+ break;
+ }
+
+ }
+ appendStringInfoChar(buf, ')');
+ }
+ break;
+
case T_NullIfExpr:
{
NullIfExpr *nullifexpr = (NullIfExpr *) node;
@@ -3849,28 +3983,6 @@ get_rule_expr(Node *node, deparse_context *context,
}
break;
- case T_XmlExpr:
- {
- XmlExpr *xexpr = (XmlExpr *) node;
-
- switch (xexpr->op)
- {
- case IS_XMLCONCAT:
- appendStringInfo(buf, "XMLCONCAT(");
- break;
- case IS_XMLELEMENT:
- appendStringInfo(buf, "XMLELEMENT(");
- break;
- case IS_XMLFOREST:
- appendStringInfo(buf, "XMLFOREST(");
- break;
- }
- get_rule_expr((Node *) xexpr->named_args, context, true);
- get_rule_expr((Node *) xexpr->args, context, true);
- appendStringInfoChar(buf, ')');
- }
- break;
-
case T_CoerceToDomain:
{
CoerceToDomain *ctest = (CoerceToDomain *) node;
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index d765c8657fb..a6dc1a6e5f0 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.2 2006/12/23 04:56:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.3 2006/12/24 00:29:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -41,15 +41,6 @@
#ifdef USE_LIBXML
-/*
- * A couple of useful macros (similar to ones from libxml/parse.c)
- */
-#define CMP4( s, c1, c2, c3, c4 ) \
- ( ((unsigned char *) s)[ 0 ] == c1 && ((unsigned char *) s)[ 1 ] == c2 && \
- ((unsigned char *) s)[ 2 ] == c3 && ((unsigned char *) s)[ 3 ] == c4 )
-#define CMP5( s, c1, c2, c3, c4, c5 ) \
- ( CMP4( s, c1, c2, c3, c4 ) && ((unsigned char *) s)[ 4 ] == c5 )
-
#define PG_XML_DEFAULT_URI "dummy.xml"
#define XML_ERRBUF_SIZE 200
@@ -177,31 +168,18 @@ xmlcomment(PG_FUNCTION_ARGS)
Datum
-xmlparse(PG_FUNCTION_ARGS)
+texttoxml(PG_FUNCTION_ARGS)
{
-#ifdef USE_LIBXML
- text *data;
- bool is_document;
- bool preserve_whitespace;
-
- data = PG_GETARG_TEXT_P(0);
+ text *data = PG_GETARG_TEXT_P(0);
- if (PG_NARGS() >= 2)
- is_document = PG_GETARG_BOOL(1);
- else
- is_document = false;
+ PG_RETURN_XML_P(xmlparse(data, false, true));
+}
- if (PG_NARGS() >= 3)
- preserve_whitespace = PG_GETARG_BOOL(2);
- else
- /*
- * Since the XMLPARSE grammar makes STRIP WHITESPACE the
- * default, this argument should really default to false. But
- * until we have actually implemented whitespace stripping,
- * this would be annoying.
- */
- preserve_whitespace = true;
+xmltype *
+xmlparse(text *data, bool is_document, bool preserve_whitespace)
+{
+#ifdef USE_LIBXML
if (!preserve_whitespace)
ereport(WARNING,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -213,111 +191,93 @@ xmlparse(PG_FUNCTION_ARGS)
* valies defined by internal DTD are applied'. As for external
* DTDs, we try to support them too, (see SQL/XML:10.16.7.e)
*/
- xml_parse(data, XML_PARSE_DTDATTR, is_document); /* assume that ERROR occurred if parsing failed */
+ xml_parse(data, XML_PARSE_DTDATTR, is_document);
- PG_RETURN_XML_P(data);
+ return (xmltype *) data;
#else
NO_XML_SUPPORT();
- return 0;
+ return NULL;
#endif
}
-Datum
-xmlpi(PG_FUNCTION_ARGS)
+xmltype *
+xmlpi(char *target, text *arg)
{
#ifdef USE_LIBXML
- char *target = NameStr(*PG_GETARG_NAME(0));
+ xmltype *result;
StringInfoData buf;
- if (strlen(target) >= 3
- && (target[0] == 'x' || target[0] == 'X')
- && (target[1] == 'm' || target[1] == 'M')
- && (target[2] == 'l' || target[2] == 'L'))
- {
+ if (pg_strncasecmp(target, "xml", 3) == 0)
ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
+ (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
errmsg("invalid XML processing instruction"),
errdetail("XML processing instruction target name cannot start with \"xml\".")));
- }
initStringInfo(&buf);
- appendStringInfo(&buf, "<?");
- appendStringInfoString(&buf, map_sql_identifier_to_xml_name(target, false));
- if (PG_NARGS() > 1)
+ appendStringInfo(&buf, "<?%s", target);
+
+ if (arg != NULL)
{
- text *arg = PG_GETARG_TEXT_P(1);
char *string;
- string = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(arg)));
- if (strstr(string, "?>"))
+ string = DatumGetCString(DirectFunctionCall1(textout,
+ PointerGetDatum(arg)));
+ if (strstr(string, "?>") != NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
errmsg("invalid XML processing instruction"),
errdetail("XML processing instruction cannot contain \"?>\".")));
- appendStringInfoString(&buf, " ");
+ appendStringInfoChar(&buf, ' ');
appendStringInfoString(&buf, string);
+ pfree(string);
}
appendStringInfoString(&buf, "?>");
- PG_RETURN_XML_P(stringinfo_to_xmltype(&buf));
+ result = stringinfo_to_xmltype(&buf);
+ pfree(buf.data);
+ return result;
#else
NO_XML_SUPPORT();
- return 0;
+ return NULL;
#endif
}
-Datum
-xmlroot(PG_FUNCTION_ARGS)
+xmltype *
+xmlroot(xmltype *data, text *version, int standalone)
{
#ifdef USE_LIBXML
- xmltype *data;
- text *version;
- int standalone;
+ xmltype *result;
StringInfoData buf;
- if (PG_ARGISNULL(0))
- PG_RETURN_NULL();
- else
- data = PG_GETARG_XML_P(0);
-
- if (PG_ARGISNULL(1))
- version = NULL;
- else
- version = PG_GETARG_TEXT_P(1);
-
- if (PG_ARGISNULL(2))
- standalone = 0;
- else
- {
- bool tmp = PG_GETARG_BOOL(2);
- standalone = (tmp ? 1 : -1);
- }
+ initStringInfo(&buf);
/*
* FIXME: This is probably supposed to be cleverer if there
* already is an XML preamble.
*/
- initStringInfo(&buf);
-
appendStringInfo(&buf,"<?xml");
- if (version) {
+ if (version)
+ {
appendStringInfo(&buf, " version=\"");
appendStringInfoText(&buf, version);
appendStringInfo(&buf, "\"");
}
if (standalone)
- appendStringInfo(&buf, " standalone=\"%s\"", (standalone == 1 ? "yes" : "no"));
+ appendStringInfo(&buf, " standalone=\"%s\"",
+ (standalone == 1 ? "yes" : "no"));
appendStringInfo(&buf, "?>");
appendStringInfoText(&buf, (text *) data);
- PG_RETURN_XML_P(stringinfo_to_xmltype(&buf));
+ result = stringinfo_to_xmltype(&buf);
+ pfree(buf.data);
+ return result;
#else
NO_XML_SUPPORT();
- return 0;
+ return NULL;
#endif
}
@@ -456,7 +416,7 @@ xml_parse(text *data, int opts, bool is_document)
/* first, we try to parse the string as XML doc, then, as XML chunk */
ereport(DEBUG3, (errmsg("string to parse: %s", string)));
- if (len > 4 && CMP5(string, '<', '?', 'x', 'm', 'l'))
+ if (len >= 5 && strncmp((char *) string, "<?xml", 5) == 0)
{
/* consider it as DOCUMENT */
doc = xmlCtxtReadMemory(ctxt, (char *) string, len,
@@ -918,10 +878,8 @@ map_sql_identifier_to_xml_name(char *ident, bool fully_escaped)
appendStringInfo(&buf, "_x003A_");
else if (*p == '_' && *(p+1) == 'x')
appendStringInfo(&buf, "_x005F_");
- else if (fully_escaped && p == ident
- && ( *p == 'x' || *p == 'X')
- && ( *(p+1) == 'm' || *(p+1) == 'M')
- && ( *(p+2) == 'l' || *(p+2) == 'L'))
+ else if (fully_escaped && p == ident &&
+ pg_strncasecmp(p, "xml", 3) == 0)
{
if (*p == 'x')
appendStringInfo(&buf, "_x0078_");
@@ -932,9 +890,10 @@ map_sql_identifier_to_xml_name(char *ident, bool fully_escaped)
{
pg_wchar u = sqlchar_to_unicode(p);
- if (!is_valid_xml_namechar(u)
- || (p == ident && !is_valid_xml_namefirst(u)))
- appendStringInfo(&buf, "_x%04X_", (unsigned int) u);
+ if ((p == ident)
+ ? !is_valid_xml_namefirst(u)
+ : !is_valid_xml_namechar(u))
+ appendStringInfo(&buf, "_x%04X_", (unsigned int) u);
else
appendBinaryStringInfo(&buf, p, pg_mblen(p));
}
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index f0a840a3dde..68f5a639347 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.365 2006/12/23 00:43:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.366 2006/12/24 00:29:19 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200612221
+#define CATALOG_VERSION_NO 200612231
#endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 974a2db360c..0a3ccc07f6c 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.431 2006/12/21 16:05:15 petere Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.432 2006/12/24 00:29:19 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@@ -3983,17 +3983,9 @@ DATA(insert OID = 2894 ( xml_out PGNSP PGUID 12 f f t f i 1 2275 "142" _nul
DESCR("I/O");
DATA(insert OID = 2895 ( xmlcomment PGNSP PGUID 12 f f t f i 1 142 "25" _null_ _null_ _null_ xmlcomment - _null_ ));
DESCR("generate an XML comment");
-DATA(insert OID = 2896 ( xmlparse PGNSP PGUID 12 f f t f i 1 142 "25" _null_ _null_ _null_ xmlparse - _null_ ));
+DATA(insert OID = 2896 ( xml PGNSP PGUID 12 f f t f i 1 142 "25" _null_ _null_ _null_ texttoxml - _null_ ));
DESCR("perform a non-validating parse of a character string to produce an XML value");
-DATA(insert OID = 2897 ( xmlparse PGNSP PGUID 12 f f t f i 3 142 "25 16 16" _null_ _null_ _null_ xmlparse - _null_ ));
-DESCR("perform a non-validating parse of a character string to produce an XML value");
-DATA(insert OID = 2898 ( xmlpi PGNSP PGUID 12 f f t f i 1 142 "19" _null_ _null_ _null_ xmlpi - _null_ ));
-DESCR("generate an XML processing instruction");
-DATA(insert OID = 2899 ( xmlpi PGNSP PGUID 12 f f t f i 2 142 "19 25" _null_ _null_ _null_ xmlpi - _null_ ));
-DESCR("generate an XML processing instruction");
-DATA(insert OID = 2900 ( xmlroot PGNSP PGUID 12 f f f f i 3 142 "142 25 16" _null_ _null_ _null_ xmlroot - _null_ ));
-DESCR("create an XML value by modifying the properties of the XML root information item of another XML value");
-DATA(insert OID = 2901 ( xmlvalidate PGNSP PGUID 12 f f t f i 2 16 "142 25" _null_ _null_ _null_ xmlvalidate - _null_ ));
+DATA(insert OID = 2897 ( xmlvalidate PGNSP PGUID 12 f f t f i 2 16 "142 25" _null_ _null_ _null_ xmlvalidate - _null_ ));
DESCR("validate an XML value");
/*
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index 1db920aa0c1..f8e8f15a5db 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.163 2006/12/21 16:05:16 petere Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.164 2006/12/24 00:29:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -711,6 +711,18 @@ typedef struct MinMaxExprState
} MinMaxExprState;
/* ----------------
+ * XmlExprState node
+ * ----------------
+ */
+typedef struct XmlExprState
+{
+ ExprState xprstate;
+ List *named_args; /* ExprStates for named arguments */
+ FmgrInfo *named_outfuncs; /* array of output fns for named arguments */
+ List *args; /* ExprStates for other arguments */
+} XmlExprState;
+
+/* ----------------
* NullTestState node
* ----------------
*/
@@ -724,22 +736,6 @@ typedef struct NullTestState
} NullTestState;
/* ----------------
- * XmlExprState node
- * ----------------
- */
-typedef struct XmlExprState
-{
- ExprState xprstate;
- XmlExprOp op;
- char *name;
- List *named_args;
- List *args;
- Oid *named_args_tcache;
- char **named_args_ncache;
- Oid arg_typeout;
-} XmlExprState;
-
-/* ----------------
* CoerceToDomainState node
* ----------------
*/
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index eb6ba18adab..fa9dff9d961 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.189 2006/12/21 16:05:16 petere Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.190 2006/12/24 00:29:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -130,6 +130,7 @@ typedef enum NodeTag
T_RowCompareExpr,
T_CoalesceExpr,
T_MinMaxExpr,
+ T_XmlExpr,
T_NullIfExpr,
T_NullTest,
T_BooleanTest,
@@ -140,7 +141,6 @@ typedef enum NodeTag
T_RangeTblRef,
T_JoinExpr,
T_FromExpr,
- T_XmlExpr,
/*
* TAGS FOR EXPRESSION STATE NODES (execnodes.h)
@@ -166,10 +166,10 @@ typedef enum NodeTag
T_RowCompareExprState,
T_CoalesceExprState,
T_MinMaxExprState,
+ T_XmlExprState,
T_NullTestState,
T_CoerceToDomainState,
T_DomainConstraintState,
- T_XmlExprState,
/*
* TAGS FOR PLANNER NODES (relation.h)
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 5946300c975..bd2c39040fc 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.120 2006/12/23 00:43:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.121 2006/12/24 00:29:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -712,6 +712,33 @@ typedef struct MinMaxExpr
} MinMaxExpr;
/*
+ * XmlExpr - various SQL/XML functions requiring special grammar productions
+ *
+ * 'name' carries the "NAME foo" argument (already XML-escaped).
+ * 'named_args' and 'arg_names' represent an xml_attribute list.
+ * 'args' carries all other arguments.
+ */
+typedef enum XmlExprOp
+{
+ IS_XMLCONCAT, /* XMLCONCAT(args) */
+ IS_XMLELEMENT, /* XMLELEMENT(name, xml_attributes, args) */
+ IS_XMLFOREST, /* XMLFOREST(xml_attributes) */
+ IS_XMLPARSE, /* XMLPARSE(text, is_doc, preserve_ws) */
+ IS_XMLPI, /* XMLPI(name [, args]) */
+ IS_XMLROOT /* XMLROOT(xml, version, standalone) */
+} XmlExprOp;
+
+typedef struct XmlExpr
+{
+ Expr xpr;
+ XmlExprOp op; /* xml function ID */
+ char *name; /* name in xml(NAME foo ...) syntaxes */
+ List *named_args; /* non-XML expressions for xml_attributes */
+ List *arg_names; /* parallel list of Value strings */
+ List *args; /* list of expressions */
+} XmlExpr;
+
+/*
* NullIfExpr - a NULLIF expression
*
* Like DistinctExpr, this is represented the same as an OpExpr referencing
@@ -766,26 +793,6 @@ typedef struct BooleanTest
} BooleanTest;
/*
- * XmlExpr - holder for SQL/XML functions XMLCONCAT,
- * XMLELEMENT, XMLFOREST
- */
-typedef enum XmlExprOp
-{
- IS_XMLCONCAT,
- IS_XMLELEMENT,
- IS_XMLFOREST,
-} XmlExprOp;
-
-typedef struct XmlExpr
-{
- Expr xpr;
- XmlExprOp op; /* xml expression type */
- char *name; /* element name */
- List *named_args;
- List *args;
-} XmlExpr;
-
-/*
* CoerceToDomain
*
* CoerceToDomain represents the operation of coercing a value to a domain
diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h
index 9c077095e9e..08573abd1ef 100644
--- a/src/include/parser/parse_coerce.h
+++ b/src/include/parser/parse_coerce.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.67 2006/12/21 16:05:16 petere Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.68 2006/12/24 00:29:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -55,12 +55,9 @@ extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod,
extern Node *coerce_to_boolean(ParseState *pstate, Node *node,
const char *constructName);
-extern Node *coerce_to_integer(ParseState *pstate, Node *node,
- const char *constructName);
-extern Node *coerce_to_bigint(ParseState *pstate, Node *node,
- const char *constructName);
-extern Node *coerce_to_xml(ParseState *pstate, Node *node,
- const char *constructName);
+extern Node *coerce_to_specific_type(ParseState *pstate, Node *node,
+ Oid targetTypeId,
+ const char *constructName);
extern Oid select_common_type(List *typeids, const char *context);
extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
index a353d8837c9..713bdaeb115 100644
--- a/src/include/utils/xml.h
+++ b/src/include/utils/xml.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.2 2006/12/23 04:56:50 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.3 2006/12/24 00:29:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,11 +27,13 @@ typedef struct varlena xmltype;
extern Datum xml_in(PG_FUNCTION_ARGS);
extern Datum xml_out(PG_FUNCTION_ARGS);
extern Datum xmlcomment(PG_FUNCTION_ARGS);
-extern Datum xmlparse(PG_FUNCTION_ARGS);
-extern Datum xmlpi(PG_FUNCTION_ARGS);
-extern Datum xmlroot(PG_FUNCTION_ARGS);
+extern Datum texttoxml(PG_FUNCTION_ARGS);
extern Datum xmlvalidate(PG_FUNCTION_ARGS);
+extern xmltype *xmlparse(text *data, bool is_doc, bool preserve_whitespace);
+extern xmltype *xmlpi(char *target, text *arg);
+extern xmltype *xmlroot(xmltype *data, text *version, int standalone);
+
extern char *map_sql_identifier_to_xml_name(char *ident, bool fully_escaped);
#endif /* XML_H */
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index c28c2c6c8f3..bff81520616 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.180 2006/10/04 00:30:13 momjian Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.181 2006/12/24 00:29:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -4493,6 +4493,18 @@ exec_simple_check_node(Node *node)
return TRUE;
}
+ case T_XmlExpr:
+ {
+ XmlExpr *expr = (XmlExpr *) node;
+
+ if (!exec_simple_check_node((Node *) expr->named_args))
+ return FALSE;
+ if (!exec_simple_check_node((Node *) expr->args))
+ return FALSE;
+
+ return TRUE;
+ }
+
case T_NullIfExpr:
{
NullIfExpr *expr = (NullIfExpr *) node;
diff --git a/src/pl/plpgsql/src/plerrcodes.h b/src/pl/plpgsql/src/plerrcodes.h
index 478bf3b0806..ba0c229ccd1 100644
--- a/src/pl/plpgsql/src/plerrcodes.h
+++ b/src/pl/plpgsql/src/plerrcodes.h
@@ -9,7 +9,7 @@
*
* Copyright (c) 2003-2006, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/plerrcodes.h,v 1.9 2006/06/16 23:29:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plerrcodes.h,v 1.10 2006/12/24 00:29:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -244,6 +244,22 @@
},
{
+ "invalid_xml_document", ERRCODE_INVALID_XML_DOCUMENT
+},
+
+{
+ "invalid_xml_content", ERRCODE_INVALID_XML_CONTENT
+},
+
+{
+ "invalid_xml_comment", ERRCODE_INVALID_XML_COMMENT
+},
+
+{
+ "invalid_xml_processing_instruction", ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION
+},
+
+{
"integrity_constraint_violation", ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION
},
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index a0e9483ebd0..7bfa35a46f8 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -74,7 +74,7 @@ WHERE p1.oid != p2.oid AND
SELECT p1.oid, p1.proname, p2.oid, p2.proname
FROM pg_proc AS p1, pg_proc AS p2
WHERE p1.oid < p2.oid AND
- p1.prosrc = p2.prosrc AND p1.prosrc NOT IN ('xmlparse', 'xmlpi') AND
+ p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
(p1.proisagg = false OR p2.proisagg = false) AND
(p1.prolang != p2.prolang OR
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index 4dd39eb164e..b8c184f784b 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -77,7 +77,7 @@ WHERE p1.oid != p2.oid AND
SELECT p1.oid, p1.proname, p2.oid, p2.proname
FROM pg_proc AS p1, pg_proc AS p2
WHERE p1.oid < p2.oid AND
- p1.prosrc = p2.prosrc AND p1.prosrc NOT IN ('xmlparse', 'xmlpi') AND
+ p1.prosrc = p2.prosrc AND
p1.prolang = 12 AND p2.prolang = 12 AND
(p1.proisagg = false OR p2.proisagg = false) AND
(p1.prolang != p2.prolang OR