mirror of
https://github.com/postgres/postgres.git
synced 2025-11-12 05:01:15 +03:00
Implement XMLSERIALIZE for real. Analogously, make the xml to text cast
observe the xmloption. Reorganize the representation of the XML option in the parse tree and the API to make it easier to manage and understand. Add regression tests for parsing back XML expressions.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.211 2007/02/02 00:07:03 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.212 2007/02/03 14:06:53 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -2834,11 +2834,10 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
|
||||
{
|
||||
ExprState *e;
|
||||
text *data;
|
||||
bool is_document;
|
||||
bool preserve_whitespace;
|
||||
|
||||
/* arguments are known to be text, bool, bool */
|
||||
Assert(list_length(xmlExpr->args) == 3);
|
||||
/* arguments are known to be text, bool */
|
||||
Assert(list_length(xmlExpr->args) == 2);
|
||||
|
||||
e = (ExprState *) linitial(xmlExpr->args);
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
@@ -2848,12 +2847,6 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
|
||||
|
||||
e = (ExprState *) lsecond(xmlExpr->args);
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (isnull) /* probably can't happen */
|
||||
return (Datum) 0;
|
||||
is_document = DatumGetBool(value);
|
||||
|
||||
e = (ExprState *) lthird(xmlExpr->args);
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (isnull) /* probably can't happen */
|
||||
return (Datum) 0;
|
||||
preserve_whitespace = DatumGetBool(value);
|
||||
@@ -2861,7 +2854,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
|
||||
*isNull = false;
|
||||
|
||||
return PointerGetDatum(xmlparse(data,
|
||||
is_document,
|
||||
xexpr->xmloption,
|
||||
preserve_whitespace));
|
||||
}
|
||||
break;
|
||||
@@ -2900,7 +2893,7 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
|
||||
text *version;
|
||||
int standalone;
|
||||
|
||||
/* arguments are known to be xml, text, bool */
|
||||
/* arguments are known to be xml, text, int */
|
||||
Assert(list_length(xmlExpr->args) == 3);
|
||||
|
||||
e = (ExprState *) linitial(xmlExpr->args);
|
||||
@@ -2928,6 +2921,24 @@ ExecEvalXml(XmlExprState *xmlExpr, ExprContext *econtext,
|
||||
}
|
||||
break;
|
||||
|
||||
case IS_XMLSERIALIZE:
|
||||
{
|
||||
ExprState *e;
|
||||
|
||||
/* argument type is known to be xml */
|
||||
Assert(list_length(xmlExpr->args) == 1);
|
||||
|
||||
e = (ExprState *) linitial(xmlExpr->args);
|
||||
value = ExecEvalExpr(e, econtext, &isnull, NULL);
|
||||
if (isnull)
|
||||
return (Datum) 0;
|
||||
|
||||
*isNull = false;
|
||||
|
||||
return PointerGetDatum(xmltotext_with_xmloption(DatumGetXmlP(value), xexpr->xmloption));
|
||||
}
|
||||
break;
|
||||
|
||||
case IS_DOCUMENT:
|
||||
{
|
||||
ExprState *e;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.364 2007/01/23 05:07:17 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.365 2007/02/03 14:06:54 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1116,6 +1116,9 @@ _copyXmlExpr(XmlExpr *from)
|
||||
COPY_NODE_FIELD(named_args);
|
||||
COPY_NODE_FIELD(arg_names);
|
||||
COPY_NODE_FIELD(args);
|
||||
COPY_SCALAR_FIELD(xmloption);
|
||||
COPY_SCALAR_FIELD(type);
|
||||
COPY_SCALAR_FIELD(typmod);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
@@ -1723,6 +1726,18 @@ _copyLockingClause(LockingClause *from)
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static XmlSerialize *
|
||||
_copyXmlSerialize(XmlSerialize *from)
|
||||
{
|
||||
XmlSerialize *newnode = makeNode(XmlSerialize);
|
||||
|
||||
COPY_SCALAR_FIELD(xmloption);
|
||||
COPY_NODE_FIELD(expr);
|
||||
COPY_NODE_FIELD(typename);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static Query *
|
||||
_copyQuery(Query *from)
|
||||
{
|
||||
@@ -3430,6 +3445,9 @@ copyObject(void *from)
|
||||
case T_FuncWithArgs:
|
||||
retval = _copyFuncWithArgs(from);
|
||||
break;
|
||||
case T_XmlSerialize:
|
||||
retval = _copyXmlSerialize(from);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.297 2007/01/23 05:07:17 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.298 2007/02/03 14:06:54 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -462,6 +462,9 @@ _equalXmlExpr(XmlExpr *a, XmlExpr *b)
|
||||
COMPARE_NODE_FIELD(named_args);
|
||||
COMPARE_NODE_FIELD(arg_names);
|
||||
COMPARE_NODE_FIELD(args);
|
||||
COMPARE_SCALAR_FIELD(xmloption);
|
||||
COMPARE_SCALAR_FIELD(type);
|
||||
COMPARE_SCALAR_FIELD(typmod);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1830,6 +1833,15 @@ _equalFkConstraint(FkConstraint *a, FkConstraint *b)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalXmlSerialize(XmlSerialize *a, XmlSerialize *b)
|
||||
{
|
||||
COMPARE_SCALAR_FIELD(xmloption);
|
||||
COMPARE_NODE_FIELD(expr);
|
||||
COMPARE_NODE_FIELD(typename);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stuff from pg_list.h
|
||||
@@ -2411,6 +2423,9 @@ equal(void *a, void *b)
|
||||
case T_FuncWithArgs:
|
||||
retval = _equalFuncWithArgs(a, b);
|
||||
break;
|
||||
case T_XmlSerialize:
|
||||
retval = _equalXmlSerialize(a, b);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized node type: %d",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.295 2007/01/22 20:00:39 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.296 2007/02/03 14:06:54 petere Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Every node type that can appear in stored rules' parsetrees *must*
|
||||
@@ -933,6 +933,9 @@ _outXmlExpr(StringInfo str, XmlExpr *node)
|
||||
WRITE_NODE_FIELD(named_args);
|
||||
WRITE_NODE_FIELD(arg_names);
|
||||
WRITE_NODE_FIELD(args);
|
||||
WRITE_ENUM_FIELD(xmloption, XmlOptionType);
|
||||
WRITE_OID_FIELD(type);
|
||||
WRITE_INT_FIELD(typmod);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1521,6 +1524,16 @@ _outLockingClause(StringInfo str, LockingClause *node)
|
||||
WRITE_BOOL_FIELD(noWait);
|
||||
}
|
||||
|
||||
static void
|
||||
_outXmlSerialize(StringInfo str, XmlSerialize *node)
|
||||
{
|
||||
WRITE_NODE_TYPE("XMLSERIALIZE");
|
||||
|
||||
WRITE_ENUM_FIELD(xmloption, XmlOptionType);
|
||||
WRITE_NODE_FIELD(expr);
|
||||
WRITE_NODE_FIELD(typename);
|
||||
}
|
||||
|
||||
static void
|
||||
_outColumnDef(StringInfo str, ColumnDef *node)
|
||||
{
|
||||
@@ -2290,6 +2303,9 @@ _outNode(StringInfo str, void *obj)
|
||||
case T_LockingClause:
|
||||
_outLockingClause(str, obj);
|
||||
break;
|
||||
case T_XmlSerialize:
|
||||
_outXmlSerialize(str, obj);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.201 2007/01/09 02:14:12 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.202 2007/02/03 14:06:54 petere Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Path and Plan nodes do not have any readfuncs support, because we
|
||||
@@ -723,6 +723,9 @@ _readXmlExpr(void)
|
||||
READ_NODE_FIELD(named_args);
|
||||
READ_NODE_FIELD(arg_names);
|
||||
READ_NODE_FIELD(args);
|
||||
READ_ENUM_FIELD(xmloption, XmlOptionType);
|
||||
READ_OID_FIELD(type);
|
||||
READ_INT_FIELD(typmod);
|
||||
|
||||
READ_DONE();
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.578 2007/02/01 19:10:27 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.579 2007/02/03 14:06:54 petere Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -350,7 +350,8 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
|
||||
%type <target> xml_attribute_el
|
||||
%type <list> xml_attribute_list xml_attributes
|
||||
%type <node> xml_root_version opt_xml_root_standalone
|
||||
%type <boolean> document_or_content xml_whitespace_option
|
||||
%type <ival> document_or_content
|
||||
%type <boolean> xml_whitespace_option
|
||||
|
||||
|
||||
/*
|
||||
@@ -1117,7 +1118,7 @@ set_rest: var_name TO var_list_or_default
|
||||
{
|
||||
VariableSetStmt *n = makeNode(VariableSetStmt);
|
||||
n->name = "xmloption";
|
||||
n->args = list_make1(makeStringConst($3 ? "DOCUMENT" : "CONTENT", NULL));
|
||||
n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", NULL));
|
||||
$$ = n;
|
||||
}
|
||||
;
|
||||
@@ -7903,10 +7904,11 @@ func_expr: func_name '(' ')'
|
||||
}
|
||||
| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
|
||||
{
|
||||
$$ = makeXmlExpr(IS_XMLPARSE, NULL, NIL,
|
||||
list_make3($4,
|
||||
makeBoolAConst($3),
|
||||
makeBoolAConst($5)));
|
||||
XmlExpr *x = (XmlExpr *) makeXmlExpr(IS_XMLPARSE, NULL, NIL,
|
||||
list_make2($4,
|
||||
makeBoolAConst($5)));
|
||||
x->xmloption = $3;
|
||||
$$ = (Node *)x;
|
||||
}
|
||||
| XMLPI '(' NAME_P ColLabel ')'
|
||||
{
|
||||
@@ -7921,14 +7923,13 @@ func_expr: func_name '(' ')'
|
||||
$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
|
||||
list_make3($3, $5, $6));
|
||||
}
|
||||
| XMLSERIALIZE '(' document_or_content a_expr AS Typename ')'
|
||||
| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
|
||||
{
|
||||
/*
|
||||
* FIXME: This should be made distinguishable from
|
||||
* CAST (for reverse compilation at least). Also,
|
||||
* what about the document/content option??
|
||||
*/
|
||||
$$ = makeTypeCast($4, $6);
|
||||
XmlSerialize *n = makeNode(XmlSerialize);
|
||||
n->xmloption = $3;
|
||||
n->expr = $4;
|
||||
n->typename = $6;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
||||
@@ -7980,17 +7981,13 @@ xml_attribute_el: a_expr AS ColLabel
|
||||
}
|
||||
;
|
||||
|
||||
document_or_content: DOCUMENT_P { $$ = TRUE; }
|
||||
| CONTENT_P { $$ = FALSE; }
|
||||
document_or_content: DOCUMENT_P { $$ = XMLOPTION_DOCUMENT; }
|
||||
| CONTENT_P { $$ = XMLOPTION_CONTENT; }
|
||||
;
|
||||
|
||||
/*
|
||||
* XXX per SQL spec, the default should be STRIP WHITESPACE, but since we
|
||||
* haven't implemented that yet, temporarily default to PRESERVE.
|
||||
*/
|
||||
xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = TRUE; }
|
||||
| STRIP_P WHITESPACE_P { $$ = FALSE; }
|
||||
| /*EMPTY*/ { $$ = TRUE; }
|
||||
| /*EMPTY*/ { $$ = FALSE; }
|
||||
;
|
||||
|
||||
/*
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.209 2007/01/25 11:53:51 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.210 2007/02/03 14:06:54 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -57,6 +57,7 @@ static Node *transformRowExpr(ParseState *pstate, RowExpr *r);
|
||||
static Node *transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c);
|
||||
static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
|
||||
static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x);
|
||||
static Node *transformXmlSerialize(ParseState *pstate, XmlSerialize *xs);
|
||||
static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
|
||||
static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
|
||||
static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
|
||||
@@ -224,6 +225,10 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
result = transformXmlExpr(pstate, (XmlExpr *) expr);
|
||||
break;
|
||||
|
||||
case T_XmlSerialize:
|
||||
result = transformXmlSerialize(pstate, (XmlSerialize *) expr);
|
||||
break;
|
||||
|
||||
case T_NullTest:
|
||||
{
|
||||
NullTest *n = (NullTest *) expr;
|
||||
@@ -1424,6 +1429,8 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
|
||||
newx->arg_names = lappend(newx->arg_names, makeString(argname));
|
||||
}
|
||||
|
||||
newx->xmloption = x->xmloption;
|
||||
|
||||
if (x->op == IS_XMLELEMENT)
|
||||
{
|
||||
foreach(lc, newx->arg_names)
|
||||
@@ -1484,6 +1491,9 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
|
||||
newe = coerce_to_specific_type(pstate, newe, INT4OID,
|
||||
"XMLROOT");
|
||||
break;
|
||||
case IS_XMLSERIALIZE:
|
||||
/* not handled here */
|
||||
break;
|
||||
case IS_DOCUMENT:
|
||||
newe = coerce_to_specific_type(pstate, newe, XMLOID,
|
||||
"IS DOCUMENT");
|
||||
@@ -1496,6 +1506,38 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
|
||||
return (Node *) newx;
|
||||
}
|
||||
|
||||
static Node *
|
||||
transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
|
||||
{
|
||||
Oid targetType;
|
||||
int32 targetTypmod;
|
||||
XmlExpr *xexpr;
|
||||
|
||||
xexpr = makeNode(XmlExpr);
|
||||
xexpr->op = IS_XMLSERIALIZE;
|
||||
xexpr->args = list_make1(coerce_to_specific_type(pstate,
|
||||
transformExpr(pstate, xs->expr),
|
||||
XMLOID,
|
||||
"XMLSERIALIZE"));
|
||||
|
||||
targetType = typenameTypeId(pstate, xs->typename);
|
||||
targetTypmod = typenameTypeMod(pstate, xs->typename, targetType);
|
||||
|
||||
xexpr->xmloption = xs->xmloption;
|
||||
/* We actually only need these to be able to parse back the expression. */
|
||||
xexpr->type = targetType;
|
||||
xexpr->typmod = targetTypmod;
|
||||
|
||||
/*
|
||||
* The actual target type is determined this way. SQL allows char
|
||||
* and varchar as target types. We allow anything that can be
|
||||
* cast implicitly from text. This way, user-defined text-like
|
||||
* data types automatically fit in.
|
||||
*/
|
||||
return (Node *) coerce_to_target_type(pstate, (Node *) xexpr, TEXTOID, targetType, targetTypmod,
|
||||
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
|
||||
}
|
||||
|
||||
static Node *
|
||||
transformBooleanTest(ParseState *pstate, BooleanTest *b)
|
||||
{
|
||||
@@ -1789,6 +1831,8 @@ exprType(Node *expr)
|
||||
case T_XmlExpr:
|
||||
if (((XmlExpr *) expr)->op == IS_DOCUMENT)
|
||||
type = BOOLOID;
|
||||
else if (((XmlExpr *) expr)->op == IS_XMLSERIALIZE)
|
||||
type = TEXTOID;
|
||||
else
|
||||
type = XMLOID;
|
||||
break;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.153 2007/01/14 13:11:54 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.154 2007/02/03 14:06:54 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1337,11 +1337,17 @@ FigureColnameInternal(Node *node, char **name)
|
||||
case IS_XMLROOT:
|
||||
*name = "xmlroot";
|
||||
return 2;
|
||||
case IS_XMLSERIALIZE:
|
||||
*name = "xmlserialize";
|
||||
return 2;
|
||||
case IS_DOCUMENT:
|
||||
/* nothing */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case T_XmlSerialize:
|
||||
*name = "xmlserialize";
|
||||
return 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.247 2007/01/30 02:39:27 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.248 2007/02/03 14:06:54 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -3856,9 +3856,19 @@ get_rule_expr(Node *node, deparse_context *context,
|
||||
case IS_XMLROOT:
|
||||
appendStringInfoString(buf, "XMLROOT(");
|
||||
break;
|
||||
case IS_XMLSERIALIZE:
|
||||
appendStringInfoString(buf, "XMLSERIALIZE(");
|
||||
break;
|
||||
case IS_DOCUMENT:
|
||||
break;
|
||||
}
|
||||
if (xexpr->op == IS_XMLPARSE || xexpr->op == IS_XMLSERIALIZE)
|
||||
{
|
||||
if (xexpr->xmloption == XMLOPTION_DOCUMENT)
|
||||
appendStringInfoString(buf, "DOCUMENT ");
|
||||
else
|
||||
appendStringInfoString(buf, "CONTENT ");
|
||||
}
|
||||
if (xexpr->name)
|
||||
{
|
||||
appendStringInfo(buf, "NAME %s",
|
||||
@@ -3899,24 +3909,17 @@ get_rule_expr(Node *node, deparse_context *context,
|
||||
case IS_XMLELEMENT:
|
||||
case IS_XMLFOREST:
|
||||
case IS_XMLPI:
|
||||
case IS_XMLSERIALIZE:
|
||||
/* no extra decoration needed */
|
||||
get_rule_expr((Node *) xexpr->args, context, true);
|
||||
break;
|
||||
case IS_XMLPARSE:
|
||||
Assert(list_length(xexpr->args) == 3);
|
||||
|
||||
con = (Const *) lsecond(xexpr->args);
|
||||
Assert(IsA(con, Const));
|
||||
Assert(!con->constisnull);
|
||||
if (DatumGetBool(con->constvalue))
|
||||
appendStringInfoString(buf, "DOCUMENT ");
|
||||
else
|
||||
appendStringInfoString(buf, "CONTENT ");
|
||||
Assert(list_length(xexpr->args) == 2);
|
||||
|
||||
get_rule_expr((Node *) linitial(xexpr->args),
|
||||
context, true);
|
||||
|
||||
con = (Const *) lthird(xexpr->args);
|
||||
con = (Const *) lsecond(xexpr->args);
|
||||
Assert(IsA(con, Const));
|
||||
Assert(!con->constisnull);
|
||||
if (DatumGetBool(con->constvalue))
|
||||
@@ -3944,12 +3947,26 @@ get_rule_expr(Node *node, deparse_context *context,
|
||||
Assert(IsA(con, Const));
|
||||
if (con->constisnull)
|
||||
/* suppress STANDALONE NO VALUE */ ;
|
||||
else if (DatumGetBool(con->constvalue))
|
||||
appendStringInfoString(buf,
|
||||
", STANDALONE YES");
|
||||
else
|
||||
appendStringInfoString(buf,
|
||||
", STANDALONE NO");
|
||||
{
|
||||
switch (DatumGetInt32(con->constvalue))
|
||||
{
|
||||
case XML_STANDALONE_YES:
|
||||
appendStringInfoString(buf,
|
||||
", STANDALONE YES");
|
||||
break;
|
||||
case XML_STANDALONE_NO:
|
||||
appendStringInfoString(buf,
|
||||
", STANDALONE NO");
|
||||
break;
|
||||
case XML_STANDALONE_NO_VALUE:
|
||||
appendStringInfoString(buf,
|
||||
", STANDALONE NO VALUE");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IS_DOCUMENT:
|
||||
get_rule_expr_paren((Node *) xexpr->args, context, false, node);
|
||||
@@ -3957,6 +3974,9 @@ get_rule_expr(Node *node, deparse_context *context,
|
||||
}
|
||||
|
||||
}
|
||||
if (xexpr->op == IS_XMLSERIALIZE)
|
||||
appendStringInfo(buf, " AS %s", format_type_with_typemod(xexpr->type,
|
||||
xexpr->typmod));
|
||||
if (xexpr->op == IS_DOCUMENT)
|
||||
appendStringInfoString(buf, " IS DOCUMENT");
|
||||
else
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.24 2007/01/27 14:50:51 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.25 2007/02/03 14:06:55 petere Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -80,7 +80,7 @@ static void xml_ereport_by_code(int level, int sqlcode,
|
||||
static xmlChar *xml_text2xmlChar(text *in);
|
||||
static int parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **encoding, int *standalone);
|
||||
static bool print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int standalone);
|
||||
static xmlDocPtr xml_parse(text *data, bool is_document, bool preserve_whitespace, xmlChar *encoding);
|
||||
static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xmlChar *encoding);
|
||||
|
||||
#endif /* USE_LIBXML */
|
||||
|
||||
@@ -112,7 +112,7 @@ xml_in(PG_FUNCTION_ARGS)
|
||||
* Parse the data to check if it is well-formed XML data. Assume
|
||||
* that ERROR occurred if parsing failed.
|
||||
*/
|
||||
doc = xml_parse(vardata, (xmloption == XMLOPTION_DOCUMENT), true, NULL);
|
||||
doc = xml_parse(vardata, xmloption, true, NULL);
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
PG_RETURN_XML_P(vardata);
|
||||
@@ -211,7 +211,7 @@ xml_recv(PG_FUNCTION_ARGS)
|
||||
* Parse the data to check if it is well-formed XML data. Assume
|
||||
* that ERROR occurred if parsing failed.
|
||||
*/
|
||||
doc = xml_parse(result, (xmloption == XMLOPTION_DOCUMENT), true, encoding);
|
||||
doc = xml_parse(result, xmloption, true, encoding);
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
newstr = (char *) pg_do_encoding_conversion((unsigned char *) str,
|
||||
@@ -435,7 +435,29 @@ texttoxml(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *data = PG_GETARG_TEXT_P(0);
|
||||
|
||||
PG_RETURN_XML_P(xmlparse(data, (xmloption == XMLOPTION_DOCUMENT), true));
|
||||
PG_RETURN_XML_P(xmlparse(data, xmloption, true));
|
||||
}
|
||||
|
||||
|
||||
Datum
|
||||
xmltotext(PG_FUNCTION_ARGS)
|
||||
{
|
||||
xmltype *data = PG_GETARG_XML_P(0);
|
||||
|
||||
PG_RETURN_TEXT_P(xmltotext_with_xmloption(data, xmloption));
|
||||
}
|
||||
|
||||
|
||||
text *
|
||||
xmltotext_with_xmloption(xmltype *data, XmlOptionType xmloption_arg)
|
||||
{
|
||||
if (xmloption_arg == XMLOPTION_DOCUMENT && !xml_is_document(data))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_NOT_AN_XML_DOCUMENT),
|
||||
errmsg("not an XML document")));
|
||||
|
||||
/* It's actually binary compatible, save for the above check. */
|
||||
return (text *) data;
|
||||
}
|
||||
|
||||
|
||||
@@ -499,12 +521,12 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext)
|
||||
|
||||
|
||||
xmltype *
|
||||
xmlparse(text *data, bool is_document, bool preserve_whitespace)
|
||||
xmlparse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace)
|
||||
{
|
||||
#ifdef USE_LIBXML
|
||||
xmlDocPtr doc;
|
||||
|
||||
doc = xml_parse(data, is_document, preserve_whitespace, NULL);
|
||||
doc = xml_parse(data, xmloption_arg, preserve_whitespace, NULL);
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
return (xmltype *) data;
|
||||
@@ -723,7 +745,7 @@ xml_is_document(xmltype *arg)
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
doc = xml_parse((text *) arg, true, true, NULL);
|
||||
doc = xml_parse((text *) arg, XMLOPTION_DOCUMENT, true, NULL);
|
||||
result = true;
|
||||
}
|
||||
PG_CATCH();
|
||||
@@ -996,7 +1018,7 @@ print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int stan
|
||||
* TODO maybe, libxml2's xmlreader is better? (do not construct DOM, yet do not use SAX - see xml_reader.c)
|
||||
*/
|
||||
static xmlDocPtr
|
||||
xml_parse(text *data, bool is_document, bool preserve_whitespace, xmlChar *encoding)
|
||||
xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xmlChar *encoding)
|
||||
{
|
||||
int32 len;
|
||||
xmlChar *string;
|
||||
@@ -1024,7 +1046,7 @@ xml_parse(text *data, bool is_document, bool preserve_whitespace, xmlChar *encod
|
||||
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
|
||||
"could not allocate parser context");
|
||||
|
||||
if (is_document)
|
||||
if (xmloption_arg == XMLOPTION_DOCUMENT)
|
||||
{
|
||||
/*
|
||||
* Note, that here we try to apply DTD defaults
|
||||
|
||||
Reference in New Issue
Block a user