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:
Peter Eisentraut 2007-02-03 14:06:56 +00:00
parent 25dc46334b
commit ec020e1ceb
23 changed files with 344 additions and 99 deletions

View File

@ -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;

View File

@ -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));

View File

@ -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",

View File

@ -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:

View File

@ -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();
}

View File

@ -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; }
;
/*

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.378 2007/01/31 19:33:54 neilc Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.379 2007/02/03 14:06:55 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200701311
#define CATALOG_VERSION_NO 200702031
#endif

View File

@ -10,7 +10,7 @@
*
* Copyright (c) 2002-2007, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.30 2007/01/31 19:33:54 neilc Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.31 2007/02/03 14:06:55 petere Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -300,7 +300,7 @@ DATA(insert ( 1266 25 939 i ));
DATA(insert ( 25 1266 938 e ));
DATA(insert ( 1700 25 1688 i ));
DATA(insert ( 25 1700 1686 e ));
DATA(insert ( 142 25 0 e ));
DATA(insert ( 142 25 2922 e ));
DATA(insert ( 25 142 2896 e ));
/*
@ -340,7 +340,7 @@ DATA(insert ( 1266 1043 939 a ));
DATA(insert ( 1043 1266 938 e ));
DATA(insert ( 1700 1043 1688 a ));
DATA(insert ( 1043 1700 1686 e ));
DATA(insert ( 142 1043 0 e ));
DATA(insert ( 142 1043 2922 e ));
DATA(insert ( 1043 142 2896 e ));
/*
@ -381,7 +381,7 @@ DATA(insert ( 1266 1042 939 a ));
DATA(insert ( 1042 1266 938 e ));
DATA(insert ( 1700 1042 1688 a ));
DATA(insert ( 1042 1700 1686 e ));
DATA(insert ( 142 1042 0 e ));
DATA(insert ( 142 1042 2922 e ));
/*
* Length-coercion functions

View File

@ -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/include/catalog/pg_proc.h,v 1.441 2007/01/28 16:16:52 neilc Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.442 2007/02/03 14:06:55 petere Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@ -4045,6 +4045,8 @@ DATA(insert OID = 2900 ( xmlconcat2 PGNSP PGUID 12 1 0 f f f f i 2 142 "1
DESCR("aggregate transition function");
DATA(insert OID = 2901 ( xmlagg PGNSP PGUID 12 1 0 t f f f i 1 142 "142" _null_ _null_ _null_ aggregate_dummy - _null_ ));
DESCR("concatenate XML values");
DATA(insert OID = 2922 ( text PGNSP PGUID 12 1 0 f f t f s 1 25 "142" _null_ _null_ _null_ xmltotext - _null_ ));
DESCR("serialize an XML value to a character string");
/* uuid */
DATA(insert OID = 2952 ( uuid_in PGNSP PGUID 12 1 0 f f t f i 1 2950 "2275" _null_ _null_ _null_ uuid_in - _null_ ));

View File

@ -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/include/nodes/nodes.h,v 1.193 2007/01/23 05:07:18 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.194 2007/02/03 14:06:55 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -331,6 +331,7 @@ typedef enum NodeTag
T_FunctionParameter,
T_LockingClause,
T_RowMarkClause,
T_XmlSerialize,
/*
* TAGS FOR RANDOM OTHER STUFF

View File

@ -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/include/nodes/parsenodes.h,v 1.339 2007/01/23 05:07:18 tgl Exp $
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.340 2007/02/03 14:06:55 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -485,6 +485,17 @@ typedef struct LockingClause
bool noWait; /* NOWAIT option */
} LockingClause;
/*
* XMLSERIALIZE
*/
typedef struct XmlSerialize
{
NodeTag type;
XmlOptionType xmloption;
Node *expr;
TypeName *typename;
} XmlSerialize;
/****************************************************************************
* Nodes for a Query tree

View File

@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.123 2007/01/14 13:11:54 petere Exp $
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.124 2007/02/03 14:06:56 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -726,9 +726,16 @@ typedef enum XmlExprOp
IS_XMLPARSE, /* XMLPARSE(text, is_doc, preserve_ws) */
IS_XMLPI, /* XMLPI(name [, args]) */
IS_XMLROOT, /* XMLROOT(xml, version, standalone) */
IS_XMLSERIALIZE, /* XMLSERIALIZE(is_document, xmlval) */
IS_DOCUMENT /* xmlval IS DOCUMENT */
} XmlExprOp;
typedef enum
{
XMLOPTION_DOCUMENT,
XMLOPTION_CONTENT
} XmlOptionType;
typedef struct XmlExpr
{
Expr xpr;
@ -737,6 +744,9 @@ typedef struct XmlExpr
List *named_args; /* non-XML expressions for xml_attributes */
List *arg_names; /* parallel list of Value strings */
List *args; /* list of expressions */
XmlOptionType xmloption; /* DOCUMENT or CONTENT */
Oid type; /* target type for XMLSERIALIZE */
int32 typmod;
} XmlExpr;
/*

View File

@ -11,7 +11,7 @@
*
* Copyright (c) 2003-2007, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.22 2007/01/05 22:19:59 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/errcodes.h,v 1.23 2007/02/03 14:06:56 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -148,6 +148,7 @@
#define ERRCODE_INVALID_BINARY_REPRESENTATION MAKE_SQLSTATE('2','2', 'P','0','3')
#define ERRCODE_BAD_COPY_FILE_FORMAT MAKE_SQLSTATE('2','2', 'P','0','4')
#define ERRCODE_UNTRANSLATABLE_CHARACTER MAKE_SQLSTATE('2','2', 'P','0','5')
#define ERRCODE_NOT_AN_XML_DOCUMENT MAKE_SQLSTATE('2', '2', '0', '0', 'L')
#define ERRCODE_INVALID_XML_DOCUMENT MAKE_SQLSTATE('2', '2', '0', '0', 'M')
#define ERRCODE_INVALID_XML_CONTENT MAKE_SQLSTATE('2', '2', '0', '0', 'N')
#define ERRCODE_INVALID_XML_COMMENT MAKE_SQLSTATE('2', '2', '0', '0', 'S')

View File

@ -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/include/utils/xml.h,v 1.13 2007/01/25 11:53:51 petere Exp $
* $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.14 2007/02/03 14:06:56 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -17,10 +17,12 @@
#include "fmgr.h"
#include "nodes/execnodes.h"
#include "nodes/primnodes.h"
typedef struct varlena xmltype;
#define DatumGetXmlP(X) ((xmltype *) PG_DETOAST_DATUM(X))
#define XmlPGetDatum(X) PointerGetDatum(X)
#define PG_GETARG_XML_P(n) DatumGetXmlP(PG_GETARG_DATUM(n))
#define PG_RETURN_XML_P(x) PG_RETURN_POINTER(x)
@ -32,6 +34,7 @@ extern Datum xml_send(PG_FUNCTION_ARGS);
extern Datum xmlcomment(PG_FUNCTION_ARGS);
extern Datum xmlconcat2(PG_FUNCTION_ARGS);
extern Datum texttoxml(PG_FUNCTION_ARGS);
extern Datum xmltotext(PG_FUNCTION_ARGS);
extern Datum xmlvalidate(PG_FUNCTION_ARGS);
typedef enum
@ -44,10 +47,11 @@ typedef enum
extern xmltype *xmlconcat(List *args);
extern xmltype *xmlelement(XmlExprState *xmlExpr, ExprContext *econtext);
extern xmltype *xmlparse(text *data, bool is_doc, bool preserve_whitespace);
extern xmltype *xmlparse(text *data, XmlOptionType xmloption, bool preserve_whitespace);
extern xmltype *xmlpi(char *target, text *arg, bool arg_is_null, bool *result_is_null);
extern xmltype *xmlroot(xmltype *data, text *version, int standalone);
extern bool xml_is_document(xmltype *arg);
extern text *xmltotext_with_xmloption(xmltype *data, XmlOptionType xmloption_arg);
extern char *map_sql_identifier_to_xml_name(char *ident, bool fully_escaped);
extern char *map_xml_name_to_sql_identifier(char *name);
@ -61,12 +65,6 @@ typedef enum
extern XmlBinaryType xmlbinary;
typedef enum
{
XMLOPTION_DOCUMENT,
XMLOPTION_CONTENT
} XmlOptionType;
extern XmlOptionType xmloption;
#endif /* XML_H */

View File

@ -288,8 +288,6 @@ WHERE c.castfunc = p.oid AND
-- those are binary-compatible while the reverse way goes through rtrim().
-- As of 8.2, this finds the cast from cidr to inet, because that is a
-- trivial binary coercion while the other way goes through inet_to_cidr().
-- As of 8.3, this finds casts from xml to text, varchar, and bpchar,
-- because the other direction has to go through xmlparse().
SELECT *
FROM pg_cast c
WHERE c.castfunc = 0 AND
@ -302,10 +300,7 @@ WHERE c.castfunc = 0 AND
25 | 1042 | 0 | i
1043 | 1042 | 0 | i
650 | 869 | 0 | i
142 | 25 | 0 | e
142 | 1043 | 0 | e
142 | 1042 | 0 | e
(6 rows)
(3 rows)
-- **************** pg_operator ****************
-- Look for illegal values in pg_operator fields.

View File

@ -275,13 +275,21 @@ SELECT xmlroot (
<?xml version="1.0" standalone="yes"?><gazonk name="val" num="2"><qux>foo</qux></gazonk>
(1 row)
SELECT xmlserialize(content data as character varying) FROM xmltest;
data
SELECT xmlserialize(content data as character varying(20)) FROM xmltest;
xmlserialize
--------------------
<value>one</value>
<value>two</value>
(2 rows)
SELECT xmlserialize(content 'good' as char(10));
xmlserialize
--------------
good
(1 row)
SELECT xmlserialize(document 'bad' as text);
ERROR: not an XML document
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
?column?
----------
@ -368,3 +376,27 @@ EXECUTE foo ('good');
<foo/>good
(1 row)
-- Test backwards parsing
CREATE VIEW xmlview1 AS SELECT xmlcomment('test');
CREATE VIEW xmlview2 AS SELECT xmlconcat('hello', 'you');
CREATE VIEW xmlview3 AS SELECT xmlelement(name element, xmlattributes (1 as ":one:", 'deuce' as two), 'content&');
CREATE VIEW xmlview4 AS SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
CREATE VIEW xmlview5 AS SELECT xmlparse(content '<abc>x</abc>');
CREATE VIEW xmlview6 AS SELECT xmlpi(name foo, 'bar');
CREATE VIEW xmlview7 AS SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10));
CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text);
SELECT table_name, view_definition FROM information_schema.views WHERE table_name LIKE 'xmlview%';
table_name | view_definition
------------+--------------------------------------------------------------------------------------------------------------------------------
xmlview1 | SELECT xmlcomment('test'::text) AS xmlcomment;
xmlview2 | SELECT XMLCONCAT('hello'::"xml", 'you'::"xml") AS "xmlconcat";
xmlview3 | SELECT XMLELEMENT(NAME element, XMLATTRIBUTES(1 AS ":one:", 'deuce' AS two), 'content&') AS "xmlelement";
xmlview4 | SELECT XMLELEMENT(NAME employee, XMLFOREST(emp."name" AS "name", emp.age AS age, emp.salary AS pay)) AS "xmlelement" FROM emp;
xmlview5 | SELECT XMLPARSE(CONTENT '<abc>x</abc>'::text STRIP WHITESPACE) AS "xmlparse";
xmlview6 | SELECT XMLPI(NAME foo, 'bar'::text) AS "xmlpi";
xmlview7 | SELECT XMLROOT('<foo/>'::"xml", VERSION NO VALUE, STANDALONE YES) AS "xmlroot";
xmlview8 | SELECT (XMLSERIALIZE(CONTENT 'good'::"xml" AS character(10)))::character(10) AS "xmlserialize";
xmlview9 | SELECT XMLSERIALIZE(CONTENT 'good'::"xml" AS text) AS "xmlserialize";
(9 rows)

View File

@ -122,11 +122,15 @@ SELECT xmlroot (
standalone yes
);
ERROR: no XML support in this installation
SELECT xmlserialize(content data as character varying) FROM xmltest;
data
------
SELECT xmlserialize(content data as character varying(20)) FROM xmltest;
xmlserialize
--------------
(0 rows)
SELECT xmlserialize(content 'good' as char(10));
ERROR: no XML support in this installation
SELECT xmlserialize(document 'bad' as text);
ERROR: no XML support in this installation
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
ERROR: no XML support in this installation
SELECT xml '<foo>bar</foo><bar>foo</bar>' IS DOCUMENT;
@ -168,3 +172,27 @@ EXECUTE foo ('<bar/>');
ERROR: prepared statement "foo" does not exist
EXECUTE foo ('good');
ERROR: prepared statement "foo" does not exist
-- Test backwards parsing
CREATE VIEW xmlview1 AS SELECT xmlcomment('test');
CREATE VIEW xmlview2 AS SELECT xmlconcat('hello', 'you');
ERROR: no XML support in this installation
CREATE VIEW xmlview3 AS SELECT xmlelement(name element, xmlattributes (1 as ":one:", 'deuce' as two), 'content&');
ERROR: no XML support in this installation
CREATE VIEW xmlview4 AS SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
ERROR: no XML support in this installation
CREATE VIEW xmlview5 AS SELECT xmlparse(content '<abc>x</abc>');
CREATE VIEW xmlview6 AS SELECT xmlpi(name foo, 'bar');
ERROR: no XML support in this installation
CREATE VIEW xmlview7 AS SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
ERROR: no XML support in this installation
CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10));
ERROR: no XML support in this installation
CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text);
ERROR: no XML support in this installation
SELECT table_name, view_definition FROM information_schema.views WHERE table_name LIKE 'xmlview%';
table_name | view_definition
------------+-------------------------------------------------------------------------------
xmlview1 | SELECT xmlcomment('test'::text) AS xmlcomment;
xmlview5 | SELECT XMLPARSE(CONTENT '<abc>x</abc>'::text STRIP WHITESPACE) AS "xmlparse";
(2 rows)

View File

@ -238,9 +238,6 @@ WHERE c.castfunc = p.oid AND
-- As of 8.2, this finds the cast from cidr to inet, because that is a
-- trivial binary coercion while the other way goes through inet_to_cidr().
-- As of 8.3, this finds casts from xml to text, varchar, and bpchar,
-- because the other direction has to go through xmlparse().
SELECT *
FROM pg_cast c
WHERE c.castfunc = 0 AND

View File

@ -68,6 +68,7 @@ SELECT xmlpi(name foo, null);
SELECT xmlpi(name xmlstuff, null);
SELECT xmlpi(name foo, ' bar');
SELECT xmlroot(xml '<foo/>', version no value, standalone no value);
SELECT xmlroot(xml '<foo/>', version '2.0');
SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
@ -95,7 +96,9 @@ SELECT xmlroot (
);
SELECT xmlserialize(content data as character varying) FROM xmltest;
SELECT xmlserialize(content data as character varying(20)) FROM xmltest;
SELECT xmlserialize(content 'good' as char(10));
SELECT xmlserialize(document 'bad' as text);
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
@ -125,3 +128,18 @@ EXECUTE foo ('bad');
SET XML OPTION CONTENT;
EXECUTE foo ('<bar/>');
EXECUTE foo ('good');
-- Test backwards parsing
CREATE VIEW xmlview1 AS SELECT xmlcomment('test');
CREATE VIEW xmlview2 AS SELECT xmlconcat('hello', 'you');
CREATE VIEW xmlview3 AS SELECT xmlelement(name element, xmlattributes (1 as ":one:", 'deuce' as two), 'content&');
CREATE VIEW xmlview4 AS SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
CREATE VIEW xmlview5 AS SELECT xmlparse(content '<abc>x</abc>');
CREATE VIEW xmlview6 AS SELECT xmlpi(name foo, 'bar');
CREATE VIEW xmlview7 AS SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10));
CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text);
SELECT table_name, view_definition FROM information_schema.views WHERE table_name LIKE 'xmlview%';