1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-17 06:41:09 +03:00

Code review for XML patch. Instill a bit of sanity in the location of

the XmlExpr code in various lists, use a representation that has some hope
of reverse-listing correctly (though it's still a de-escaping function
shy of correctness), generally try to make it look more like Postgres
coding conventions.
This commit is contained in:
Tom Lane
2006-12-24 00:29:20 +00:00
parent 64974613c9
commit c957c0bac7
27 changed files with 883 additions and 686 deletions

View File

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

View File

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

View File

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

View File

@ -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)
coerce_to_specific_type(ParseState *pstate, Node *node,
Oid targetTypeId,
const char *constructName)
{
Oid inputTypeId = exprType(node);
if (inputTypeId != INT4OID)
if (inputTypeId != targetTypeId)
{
node = coerce_to_target_type(pstate, node, inputTypeId,
INT4OID, -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 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)
{
Oid inputTypeId = exprType(node);
if (inputTypeId != XMLOID)
{
node = coerce_to_target_type(pstate, node, inputTypeId,
XMLOID, -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))

View File

@ -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.
@ -1375,6 +1375,107 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
return (Node *) newm;
}
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)
{
@ -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;

View File

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