1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-17 06:41:09 +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:
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

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