1
0
mirror of https://github.com/postgres/postgres.git synced 2025-09-02 04:21:28 +03:00

Extend the parser location infrastructure to include a location field in

most node types used in expression trees (both before and after parse
analysis).  This allows us to place an error cursor in many situations
where we formerly could not, because the information wasn't available
beyond the very first level of parse analysis.  There's a fair amount
of work still to be done to persuade individual ereport() calls to actually
include an error location, but this gets the initdb-forcing part of the
work out of the way; and the situation is already markedly better than
before for complaints about unimplementable implicit casts, such as
CASE and UNION constructs with incompatible alternative data types.
Per my proposal of a few days ago.
This commit is contained in:
Tom Lane
2008-08-28 23:09:48 +00:00
parent 6734182c16
commit a2794623d2
44 changed files with 1295 additions and 502 deletions

View File

@@ -17,7 +17,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.377 2008/08/25 22:42:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.378 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,9 +53,8 @@ static List *transformInsertRow(ParseState *pstate, List *exprlist,
static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
static Query *transformValuesClause(ParseState *pstate, SelectStmt *stmt);
static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
static void getSetColTypes(ParseState *pstate, Node *node,
List **colTypes, List **colTypmods);
static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
List **colInfo);
static void applyColumnNames(List *dst, List *src);
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
static List *transformReturningList(ParseState *pstate, List *returningList);
@@ -789,7 +788,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
{
Query *qry = makeNode(Query);
List *exprsLists = NIL;
List **coltype_lists = NULL;
List **colexprs = NULL;
Oid *coltypes = NULL;
int sublist_length = -1;
List *newExprsLists;
@@ -831,8 +830,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
{
/* Remember post-transformation length of first sublist */
sublist_length = list_length(sublist);
/* and allocate arrays for column-type info */
coltype_lists = (List **) palloc0(sublist_length * sizeof(List *));
/* and allocate arrays for per-column info */
colexprs = (List **) palloc0(sublist_length * sizeof(List *));
coltypes = (Oid *) palloc0(sublist_length * sizeof(Oid));
}
else if (sublist_length != list_length(sublist))
@@ -844,6 +843,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
exprsLists = lappend(exprsLists, sublist);
/* Check for DEFAULT and build per-column expression lists */
i = 0;
foreach(lc2, sublist)
{
@@ -852,8 +852,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
if (IsA(col, SetToDefault))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("DEFAULT can only appear in a VALUES list within INSERT")));
coltype_lists[i] = lappend_oid(coltype_lists[i], exprType(col));
errmsg("DEFAULT can only appear in a VALUES list within INSERT"),
parser_errposition(pstate, exprLocation(col))));
colexprs[i] = lappend(colexprs[i], col);
i++;
}
}
@@ -864,7 +865,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
*/
for (i = 0; i < sublist_length; i++)
{
coltypes[i] = select_common_type(coltype_lists[i], "VALUES");
coltypes[i] = select_common_type(pstate, colexprs[i], "VALUES", NULL);
}
newExprsLists = NIL;
@@ -985,6 +986,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
int leftmostRTI;
Query *leftmostQuery;
SetOperationStmt *sostmt;
List *socolinfo;
List *intoColNames = NIL;
List *sortClause;
Node *limitOffset;
@@ -1047,7 +1049,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
/*
* Recursively transform the components of the tree.
*/
sostmt = (SetOperationStmt *) transformSetOperationTree(pstate, stmt);
sostmt = (SetOperationStmt *) transformSetOperationTree(pstate, stmt,
&socolinfo);
Assert(sostmt && IsA(sostmt, SetOperationStmt));
qry->setOperations = (Node *) sostmt;
@@ -1191,9 +1194,17 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
/*
* transformSetOperationTree
* Recursively transform leaves and internal nodes of a set-op tree
*
* In addition to returning the transformed node, we return a list of
* expression nodes showing the type, typmod, and location (for error messages)
* of each output column of the set-op node. This is used only during the
* internal recursion of this function. We use SetToDefault nodes for
* this purpose, since they carry exactly the fields needed, but any other
* expression node type would do as well.
*/
static Node *
transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
List **colInfo)
{
bool isLeaf;
@@ -1240,6 +1251,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
char selectName[32];
RangeTblEntry *rte;
RangeTblRef *rtr;
ListCell *tl;
/*
* Transform SelectStmt into a Query.
@@ -1264,6 +1276,24 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
errmsg("UNION/INTERSECT/EXCEPT member statement cannot refer to other relations of same query level")));
}
/*
* Extract information about the result columns.
*/
*colInfo = NIL;
foreach(tl, selectQuery->targetList)
{
TargetEntry *tle = (TargetEntry *) lfirst(tl);
SetToDefault *cinfo;
if (tle->resjunk)
continue;
cinfo = makeNode(SetToDefault);
cinfo->typeId = exprType((Node *) tle->expr);
cinfo->typeMod = exprTypmod((Node *) tle->expr);
cinfo->location = exprLocation((Node *) tle->expr);
*colInfo = lappend(*colInfo, cinfo);
}
/*
* Make the leaf query be a subquery in the top-level rangetable.
*/
@@ -1287,14 +1317,10 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
{
/* Process an internal node (set operation node) */
SetOperationStmt *op = makeNode(SetOperationStmt);
List *lcoltypes;
List *rcoltypes;
List *lcoltypmods;
List *rcoltypmods;
ListCell *lct;
ListCell *rct;
ListCell *lcm;
ListCell *rcm;
List *lcolinfo;
List *rcolinfo;
ListCell *lci;
ListCell *rci;
const char *context;
context = (stmt->op == SETOP_UNION ? "UNION" :
@@ -1307,46 +1333,66 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
/*
* Recursively transform the child nodes.
*/
op->larg = transformSetOperationTree(pstate, stmt->larg);
op->rarg = transformSetOperationTree(pstate, stmt->rarg);
op->larg = transformSetOperationTree(pstate, stmt->larg,
&lcolinfo);
op->rarg = transformSetOperationTree(pstate, stmt->rarg,
&rcolinfo);
/*
* Verify that the two children have the same number of non-junk
* columns, and determine the types of the merged output columns.
*/
getSetColTypes(pstate, op->larg, &lcoltypes, &lcoltypmods);
getSetColTypes(pstate, op->rarg, &rcoltypes, &rcoltypmods);
if (list_length(lcoltypes) != list_length(rcoltypes))
if (list_length(lcolinfo) != list_length(rcolinfo))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("each %s query must have the same number of columns",
context)));
Assert(list_length(lcoltypes) == list_length(lcoltypmods));
Assert(list_length(rcoltypes) == list_length(rcoltypmods));
context),
parser_errposition(pstate,
exprLocation((Node *) rcolinfo))));
*colInfo = NIL;
op->colTypes = NIL;
op->colTypmods = NIL;
op->groupClauses = NIL;
/* don't have a "foreach4", so chase two of the lists by hand */
lcm = list_head(lcoltypmods);
rcm = list_head(rcoltypmods);
forboth(lct, lcoltypes, rct, rcoltypes)
forboth(lci, lcolinfo, rci, rcolinfo)
{
Oid lcoltype = lfirst_oid(lct);
Oid rcoltype = lfirst_oid(rct);
int32 lcoltypmod = lfirst_int(lcm);
int32 rcoltypmod = lfirst_int(rcm);
SetToDefault *lcolinfo = (SetToDefault *) lfirst(lci);
SetToDefault *rcolinfo = (SetToDefault *) lfirst(rci);
Oid lcoltype = lcolinfo->typeId;
Oid rcoltype = rcolinfo->typeId;
int32 lcoltypmod = lcolinfo->typeMod;
int32 rcoltypmod = rcolinfo->typeMod;
Node *bestexpr;
SetToDefault *rescolinfo;
Oid rescoltype;
int32 rescoltypmod;
/* select common type, same as CASE et al */
rescoltype = select_common_type(list_make2_oid(lcoltype, rcoltype),
context);
rescoltype = select_common_type(pstate,
list_make2(lcolinfo, rcolinfo),
context,
&bestexpr);
/* if same type and same typmod, use typmod; else default */
if (lcoltype == rcoltype && lcoltypmod == rcoltypmod)
rescoltypmod = lcoltypmod;
else
rescoltypmod = -1;
/* verify the coercions are actually possible */
if (lcoltype != UNKNOWNOID)
(void) coerce_to_common_type(pstate, (Node *) lcolinfo,
rescoltype, context);
if (rcoltype != UNKNOWNOID)
(void) coerce_to_common_type(pstate, (Node *) rcolinfo,
rescoltype, context);
/* emit results */
rescolinfo = makeNode(SetToDefault);
rescolinfo->typeId = rescoltype;
rescolinfo->typeMod = rescoltypmod;
rescolinfo->location = ((SetToDefault *) bestexpr)->location;
*colInfo = lappend(*colInfo, rescolinfo);
op->colTypes = lappend_oid(op->colTypes, rescoltype);
op->colTypmods = lappend_int(op->colTypmods, rescoltypmod);
@@ -1374,59 +1420,12 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
op->groupClauses = lappend(op->groupClauses, grpcl);
}
lcm = lnext(lcm);
rcm = lnext(rcm);
}
return (Node *) op;
}
}
/*
* getSetColTypes
* Get output column types/typmods of an (already transformed) set-op node
*/
static void
getSetColTypes(ParseState *pstate, Node *node,
List **colTypes, List **colTypmods)
{
*colTypes = NIL;
*colTypmods = NIL;
if (IsA(node, RangeTblRef))
{
RangeTblRef *rtr = (RangeTblRef *) node;
RangeTblEntry *rte = rt_fetch(rtr->rtindex, pstate->p_rtable);
Query *selectQuery = rte->subquery;
ListCell *tl;
Assert(selectQuery != NULL);
/* Get types of non-junk columns */
foreach(tl, selectQuery->targetList)
{
TargetEntry *tle = (TargetEntry *) lfirst(tl);
if (tle->resjunk)
continue;
*colTypes = lappend_oid(*colTypes,
exprType((Node *) tle->expr));
*colTypmods = lappend_int(*colTypmods,
exprTypmod((Node *) tle->expr));
}
}
else if (IsA(node, SetOperationStmt))
{
SetOperationStmt *op = (SetOperationStmt *) node;
/* Result already computed during transformation of node */
Assert(op->colTypes != NIL);
*colTypes = op->colTypes;
*colTypmods = op->colTypmods;
}
else
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
}
/*
* Attach column names from a ColumnDef list to a TargetEntry list
* (for CREATE TABLE AS)

View File

@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.618 2008/07/18 03:32:52 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.619 2008/08/28 23:09:47 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -90,15 +90,15 @@ static bool QueryIsRule = FALSE;
/*#define __YYSCLASS*/
static Node *makeColumnRef(char *relname, List *indirection, int location);
static Node *makeTypeCast(Node *arg, TypeName *typename);
static Node *makeStringConst(char *str);
static Node *makeStringConstCast(char *str, TypeName *typename);
static Node *makeIntConst(int val);
static Node *makeFloatConst(char *str);
static Node *makeBitStringConst(char *str);
static Node *makeNullAConst(void);
static Node *makeAConst(Value *v);
static Node *makeBoolAConst(bool state);
static Node *makeTypeCast(Node *arg, TypeName *typename, int location);
static Node *makeStringConst(char *str, int location);
static Node *makeStringConstCast(char *str, int location, TypeName *typename);
static Node *makeIntConst(int val, int location);
static Node *makeFloatConst(char *str, int location);
static Node *makeBitStringConst(char *str, int location);
static Node *makeNullAConst(int location);
static Node *makeAConst(Value *v, int location);
static Node *makeBoolAConst(bool state, int location);
static FuncCall *makeOverlaps(List *largs, List *rargs, int location);
static void check_qualified_name(List *names);
static List *check_func_name(List *names);
@@ -110,8 +110,9 @@ static void insertSelectOptions(SelectStmt *stmt,
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
static Node *doNegate(Node *n, int location);
static void doNegateFloat(Value *v);
static Node *makeAArrayExpr(List *elements);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args);
static Node *makeAArrayExpr(List *elements, int location);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
List *args, int location);
static List *mergeTableFuncParameters(List *func_args, List *columns);
static TypeName *TableFuncTypeName(List *columns);
@@ -1117,7 +1118,7 @@ set_rest: /* Generic SET syntaxes: */
n->kind = VAR_SET_VALUE;
n->name = "client_encoding";
if ($2 != NULL)
n->args = list_make1(makeStringConst($2));
n->args = list_make1(makeStringConst($2, @2));
else
n->kind = VAR_SET_DEFAULT;
$$ = n;
@@ -1127,7 +1128,7 @@ set_rest: /* Generic SET syntaxes: */
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "role";
n->args = list_make1(makeStringConst($2));
n->args = list_make1(makeStringConst($2, @2));
$$ = n;
}
| SESSION AUTHORIZATION ColId_or_Sconst
@@ -1135,7 +1136,7 @@ set_rest: /* Generic SET syntaxes: */
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "session_authorization";
n->args = list_make1(makeStringConst($3));
n->args = list_make1(makeStringConst($3, @3));
$$ = n;
}
| SESSION AUTHORIZATION DEFAULT
@@ -1150,7 +1151,7 @@ set_rest: /* Generic SET syntaxes: */
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "xmloption";
n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT"));
n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3));
$$ = n;
}
;
@@ -1168,11 +1169,11 @@ var_list: var_value { $$ = list_make1($1); }
;
var_value: opt_boolean
{ $$ = makeStringConst($1); }
{ $$ = makeStringConst($1, @1); }
| ColId_or_Sconst
{ $$ = makeStringConst($1); }
{ $$ = makeStringConst($1, @1); }
| NumericOnly
{ $$ = makeAConst($1); }
{ $$ = makeAConst($1, @1); }
;
iso_level: READ UNCOMMITTED { $$ = "read uncommitted"; }
@@ -1199,11 +1200,11 @@ opt_boolean:
zone_value:
Sconst
{
$$ = makeStringConst($1);
$$ = makeStringConst($1, @1);
}
| IDENT
{
$$ = makeStringConst($1);
$$ = makeStringConst($1, @1);
}
| ConstInterval Sconst opt_interval
{
@@ -1214,9 +1215,9 @@ zone_value:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("time zone interval must be HOUR or HOUR TO MINUTE")));
t->typmods = list_make1(makeIntConst($3));
t->typmods = list_make1(makeIntConst($3, @3));
}
$$ = makeStringConstCast($2, t);
$$ = makeStringConstCast($2, @2, t);
}
| ConstInterval '(' Iconst ')' Sconst opt_interval
{
@@ -1226,11 +1227,11 @@ zone_value:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("time zone interval must be HOUR or HOUR TO MINUTE")));
t->typmods = list_make2(makeIntConst($6),
makeIntConst($3));
$$ = makeStringConstCast($5, t);
t->typmods = list_make2(makeIntConst($6, @6),
makeIntConst($3, @3));
$$ = makeStringConstCast($5, @5, t);
}
| NumericOnly { $$ = makeAConst($1); }
| NumericOnly { $$ = makeAConst($1, @1); }
| DEFAULT { $$ = NULL; }
| LOCAL { $$ = NULL; }
;
@@ -5274,13 +5275,13 @@ opt_transaction: WORK {}
transaction_mode_item:
ISOLATION LEVEL iso_level
{ $$ = makeDefElem("transaction_isolation",
makeStringConst($3)); }
makeStringConst($3, @3)); }
| READ ONLY
{ $$ = makeDefElem("transaction_read_only",
makeIntConst(TRUE)); }
makeIntConst(TRUE, @1)); }
| READ WRITE
{ $$ = makeDefElem("transaction_read_only",
makeIntConst(FALSE)); }
makeIntConst(FALSE, @1)); }
;
/* Syntax with commas is SQL-spec, without commas is Postgres historical */
@@ -6461,7 +6462,7 @@ select_limit_value:
| ALL
{
/* LIMIT ALL is represented as a NULL constant */
$$ = makeNullAConst();
$$ = makeNullAConst(@1);
}
;
@@ -6963,13 +6964,13 @@ SimpleTypename:
{
$$ = $1;
if ($2 != INTERVAL_FULL_RANGE)
$$->typmods = list_make1(makeIntConst($2));
$$->typmods = list_make1(makeIntConst($2, @2));
}
| ConstInterval '(' Iconst ')' opt_interval
{
$$ = $1;
$$->typmods = list_make2(makeIntConst($5),
makeIntConst($3));
$$->typmods = list_make2(makeIntConst($5, @5),
makeIntConst($3, @3));
}
;
@@ -7155,7 +7156,7 @@ BitWithoutLength:
else
{
$$ = SystemTypeName("bit");
$$->typmods = list_make1(makeIntConst(1));
$$->typmods = list_make1(makeIntConst(1, -1));
}
$$->location = @1;
}
@@ -7207,7 +7208,7 @@ CharacterWithLength: character '(' Iconst ')' opt_charset
}
$$ = SystemTypeName($1);
$$->typmods = list_make1(makeIntConst($3));
$$->typmods = list_make1(makeIntConst($3, @3));
$$->location = @1;
}
;
@@ -7229,7 +7230,7 @@ CharacterWithoutLength: character opt_charset
/* char defaults to char(1), varchar to no limit */
if (strcmp($1, "bpchar") == 0)
$$->typmods = list_make1(makeIntConst(1));
$$->typmods = list_make1(makeIntConst(1, -1));
$$->location = @1;
}
@@ -7269,7 +7270,7 @@ ConstDatetime:
$$ = SystemTypeName("timestamptz");
else
$$ = SystemTypeName("timestamp");
$$->typmods = list_make1(makeIntConst($3));
$$->typmods = list_make1(makeIntConst($3, @3));
$$->location = @1;
}
| TIMESTAMP opt_timezone
@@ -7286,7 +7287,7 @@ ConstDatetime:
$$ = SystemTypeName("timetz");
else
$$ = SystemTypeName("time");
$$->typmods = list_make1(makeIntConst($3));
$$->typmods = list_make1(makeIntConst($3, @3));
$$->location = @1;
}
| TIME opt_timezone
@@ -7365,7 +7366,7 @@ opt_interval:
*/
a_expr: c_expr { $$ = $1; }
| a_expr TYPECAST Typename
{ $$ = makeTypeCast($1, $3); }
{ $$ = makeTypeCast($1, $3, @2); }
| a_expr AT TIME ZONE a_expr
{
FuncCall *n = makeNode(FuncCall);
@@ -7480,7 +7481,7 @@ a_expr: c_expr { $$ = $1; }
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("similar_escape");
n->args = list_make2($4, makeNullAConst());
n->args = list_make2($4, makeNullAConst(-1));
n->agg_star = FALSE;
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
@@ -7502,7 +7503,7 @@ a_expr: c_expr { $$ = $1; }
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("similar_escape");
n->args = list_make2($5, makeNullAConst());
n->args = list_make2($5, makeNullAConst(-1));
n->agg_star = FALSE;
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
@@ -7674,6 +7675,7 @@ a_expr: c_expr { $$ = $1; }
n->subLinkType = ANY_SUBLINK;
n->testexpr = $1;
n->operName = list_make1(makeString("="));
n->location = @2;
$$ = (Node *)n;
}
else
@@ -7693,6 +7695,7 @@ a_expr: c_expr { $$ = $1; }
n->subLinkType = ANY_SUBLINK;
n->testexpr = $1;
n->operName = list_make1(makeString("="));
n->location = @3;
/* Stick a NOT on top */
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n, @2);
}
@@ -7709,6 +7712,7 @@ a_expr: c_expr { $$ = $1; }
n->testexpr = $1;
n->operName = $2;
n->subselect = $4;
n->location = @2;
$$ = (Node *)n;
}
| a_expr subquery_Op sub_type '(' a_expr ')' %prec Op
@@ -7735,12 +7739,14 @@ a_expr: c_expr { $$ = $1; }
}
| a_expr IS DOCUMENT_P %prec IS
{
$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1));
$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
list_make1($1), @2);
}
| a_expr IS NOT DOCUMENT_P %prec IS
{
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1)),
makeXmlExpr(IS_DOCUMENT, NULL, NIL,
list_make1($1), @2),
@2);
}
;
@@ -7757,7 +7763,7 @@ a_expr: c_expr { $$ = $1; }
b_expr: c_expr
{ $$ = $1; }
| b_expr TYPECAST Typename
{ $$ = makeTypeCast($1, $3); }
{ $$ = makeTypeCast($1, $3, @2); }
| '+' b_expr %prec UMINUS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
| '-' b_expr %prec UMINUS
@@ -7805,12 +7811,14 @@ b_expr: c_expr
}
| b_expr IS DOCUMENT_P %prec IS
{
$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1));
$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
list_make1($1), @2);
}
| b_expr IS NOT DOCUMENT_P %prec IS
{
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1)),
makeXmlExpr(IS_DOCUMENT, NULL, NIL,
list_make1($1), @2),
@2);
}
;
@@ -7829,6 +7837,7 @@ c_expr: columnref { $$ = $1; }
{
ParamRef *p = makeNode(ParamRef);
p->number = $1;
p->location = @1;
if ($2)
{
A_Indirection *n = makeNode(A_Indirection);
@@ -7862,6 +7871,7 @@ c_expr: columnref { $$ = $1; }
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $1;
n->location = @1;
$$ = (Node *)n;
}
| EXISTS select_with_parens
@@ -7871,6 +7881,7 @@ c_expr: columnref { $$ = $1; }
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $2;
n->location = @1;
$$ = (Node *)n;
}
| ARRAY select_with_parens
@@ -7880,15 +7891,23 @@ c_expr: columnref { $$ = $1; }
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $2;
n->location = @1;
$$ = (Node *)n;
}
| ARRAY array_expr
{ $$ = $2; }
{
A_ArrayExpr *n = (A_ArrayExpr *) $2;
Assert(IsA(n, A_ArrayExpr));
/* point outermost A_ArrayExpr to the ARRAY keyword */
n->location = @1;
$$ = (Node *)n;
}
| row
{
RowExpr *r = makeNode(RowExpr);
r->args = $1;
r->row_typeid = InvalidOid; /* not analyzed yet */
r->location = @1;
$$ = (Node *)r;
}
;
@@ -8010,8 +8029,8 @@ func_expr: func_name '(' ')'
* to rely on it.)
*/
Node *n;
n = makeStringConstCast("now", SystemTypeName("text"));
$$ = makeTypeCast(n, SystemTypeName("date"));
n = makeStringConstCast("now", @1, SystemTypeName("text"));
$$ = makeTypeCast(n, SystemTypeName("date"), -1);
}
| CURRENT_TIME
{
@@ -8020,8 +8039,8 @@ func_expr: func_name '(' ')'
* See comments for CURRENT_DATE.
*/
Node *n;
n = makeStringConstCast("now", SystemTypeName("text"));
$$ = makeTypeCast(n, SystemTypeName("timetz"));
n = makeStringConstCast("now", @1, SystemTypeName("text"));
$$ = makeTypeCast(n, SystemTypeName("timetz"), -1);
}
| CURRENT_TIME '(' Iconst ')'
{
@@ -8031,10 +8050,10 @@ func_expr: func_name '(' ')'
*/
Node *n;
TypeName *d;
n = makeStringConstCast("now", SystemTypeName("text"));
n = makeStringConstCast("now", @1, SystemTypeName("text"));
d = SystemTypeName("timetz");
d->typmods = list_make1(makeIntConst($3));
$$ = makeTypeCast(n, d);
d->typmods = list_make1(makeIntConst($3, @3));
$$ = makeTypeCast(n, d, -1);
}
| CURRENT_TIMESTAMP
{
@@ -8059,10 +8078,10 @@ func_expr: func_name '(' ')'
*/
Node *n;
TypeName *d;
n = makeStringConstCast("now", SystemTypeName("text"));
n = makeStringConstCast("now", @1, SystemTypeName("text"));
d = SystemTypeName("timestamptz");
d->typmods = list_make1(makeIntConst($3));
$$ = makeTypeCast(n, d);
d->typmods = list_make1(makeIntConst($3, @3));
$$ = makeTypeCast(n, d, -1);
}
| LOCALTIME
{
@@ -8071,8 +8090,8 @@ func_expr: func_name '(' ')'
* See comments for CURRENT_DATE.
*/
Node *n;
n = makeStringConstCast("now", SystemTypeName("text"));
$$ = makeTypeCast((Node *)n, SystemTypeName("time"));
n = makeStringConstCast("now", @1, SystemTypeName("text"));
$$ = makeTypeCast((Node *)n, SystemTypeName("time"), -1);
}
| LOCALTIME '(' Iconst ')'
{
@@ -8082,10 +8101,10 @@ func_expr: func_name '(' ')'
*/
Node *n;
TypeName *d;
n = makeStringConstCast("now", SystemTypeName("text"));
n = makeStringConstCast("now", @1, SystemTypeName("text"));
d = SystemTypeName("time");
d->typmods = list_make1(makeIntConst($3));
$$ = makeTypeCast((Node *)n, d);
d->typmods = list_make1(makeIntConst($3, @3));
$$ = makeTypeCast((Node *)n, d, -1);
}
| LOCALTIMESTAMP
{
@@ -8094,8 +8113,8 @@ func_expr: func_name '(' ')'
* See comments for CURRENT_DATE.
*/
Node *n;
n = makeStringConstCast("now", SystemTypeName("text"));
$$ = makeTypeCast(n, SystemTypeName("timestamp"));
n = makeStringConstCast("now", @1, SystemTypeName("text"));
$$ = makeTypeCast(n, SystemTypeName("timestamp"), -1);
}
| LOCALTIMESTAMP '(' Iconst ')'
{
@@ -8105,10 +8124,10 @@ func_expr: func_name '(' ')'
*/
Node *n;
TypeName *d;
n = makeStringConstCast("now", SystemTypeName("text"));
n = makeStringConstCast("now", @1, SystemTypeName("text"));
d = SystemTypeName("timestamp");
d->typmods = list_make1(makeIntConst($3));
$$ = makeTypeCast(n, d);
d->typmods = list_make1(makeIntConst($3, @3));
$$ = makeTypeCast(n, d, -1);
}
| CURRENT_ROLE
{
@@ -8155,7 +8174,7 @@ func_expr: func_name '(' ')'
$$ = (Node *)n;
}
| CAST '(' a_expr AS Typename ')'
{ $$ = makeTypeCast($3, $5); }
{ $$ = makeTypeCast($3, $5, @1); }
| EXTRACT '(' extract_list ')'
{
FuncCall *n = makeNode(FuncCall);
@@ -8284,6 +8303,7 @@ func_expr: func_name '(' ')'
{
CoalesceExpr *c = makeNode(CoalesceExpr);
c->args = $3;
c->location = @1;
$$ = (Node *)c;
}
| GREATEST '(' expr_list ')'
@@ -8291,6 +8311,7 @@ func_expr: func_name '(' ')'
MinMaxExpr *v = makeNode(MinMaxExpr);
v->args = $3;
v->op = IS_GREATEST;
v->location = @1;
$$ = (Node *)v;
}
| LEAST '(' expr_list ')'
@@ -8298,52 +8319,54 @@ func_expr: func_name '(' ')'
MinMaxExpr *v = makeNode(MinMaxExpr);
v->args = $3;
v->op = IS_LEAST;
v->location = @1;
$$ = (Node *)v;
}
| XMLCONCAT '(' expr_list ')'
{
$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3);
$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ')'
{
$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL);
$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
{
$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL);
$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
{
$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6);
$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1);
}
| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
{
$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8);
$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
}
| XMLFOREST '(' xml_attribute_list ')'
{
$$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL);
$$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
}
| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
{
XmlExpr *x = (XmlExpr *) makeXmlExpr(IS_XMLPARSE, NULL, NIL,
list_make2($4,
makeBoolAConst($5)));
XmlExpr *x = (XmlExpr *)
makeXmlExpr(IS_XMLPARSE, NULL, NIL,
list_make2($4, makeBoolAConst($5, -1)),
@1);
x->xmloption = $3;
$$ = (Node *)x;
}
| XMLPI '(' NAME_P ColLabel ')'
{
$$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL);
$$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL, @1);
}
| XMLPI '(' NAME_P ColLabel ',' a_expr ')'
{
$$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6));
$$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6), @1);
}
| XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
{
$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
list_make3($3, $5, $6));
list_make3($3, $5, $6), @1);
}
| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
{
@@ -8351,6 +8374,7 @@ func_expr: func_name '(' ')'
n->xmloption = $3;
n->expr = $4;
n->typename = $6;
n->location = @1;
$$ = (Node *)n;
}
;
@@ -8361,17 +8385,17 @@ func_expr: func_name '(' ')'
xml_root_version: VERSION_P a_expr
{ $$ = $2; }
| VERSION_P NO VALUE_P
{ $$ = makeNullAConst(); }
{ $$ = makeNullAConst(-1); }
;
opt_xml_root_standalone: ',' STANDALONE_P YES_P
{ $$ = makeIntConst(XML_STANDALONE_YES); }
{ $$ = makeIntConst(XML_STANDALONE_YES, -1); }
| ',' STANDALONE_P NO
{ $$ = makeIntConst(XML_STANDALONE_NO); }
{ $$ = makeIntConst(XML_STANDALONE_NO, -1); }
| ',' STANDALONE_P NO VALUE_P
{ $$ = makeIntConst(XML_STANDALONE_NO_VALUE); }
{ $$ = makeIntConst(XML_STANDALONE_NO_VALUE, -1); }
| /*EMPTY*/
{ $$ = makeIntConst(XML_STANDALONE_OMITTED); }
{ $$ = makeIntConst(XML_STANDALONE_OMITTED, -1); }
;
xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; }
@@ -8495,15 +8519,15 @@ type_list: Typename { $$ = list_make1($1); }
array_expr: '[' expr_list ']'
{
$$ = makeAArrayExpr($2);
$$ = makeAArrayExpr($2, @1);
}
| '[' array_expr_list ']'
{
$$ = makeAArrayExpr($2);
$$ = makeAArrayExpr($2, @1);
}
| '[' ']'
{
$$ = makeAArrayExpr(NIL);
$$ = makeAArrayExpr(NIL, @1);
}
;
@@ -8515,7 +8539,7 @@ array_expr_list: array_expr { $$ = list_make1($1); }
extract_list:
extract_arg FROM a_expr
{
$$ = list_make2(makeStringConst($1), $3);
$$ = list_make2(makeStringConst($1, @1), $3);
}
| /*EMPTY*/ { $$ = NIL; }
;
@@ -8599,8 +8623,9 @@ substr_list:
* which it is likely to do if the second argument
* is unknown or doesn't have an implicit cast to int4.
*/
$$ = list_make3($1, makeIntConst(1),
makeTypeCast($2, SystemTypeName("int4")));
$$ = list_make3($1, makeIntConst(1, -1),
makeTypeCast($2,
SystemTypeName("int4"), -1));
}
| expr_list
{
@@ -8646,6 +8671,7 @@ case_expr: CASE case_arg when_clause_list case_default END_P
c->arg = (Expr *) $2;
c->args = $3;
c->defresult = (Expr *) $4;
c->location = @1;
$$ = (Node *)c;
}
;
@@ -8662,6 +8688,7 @@ when_clause:
CaseWhen *w = makeNode(CaseWhen);
w->expr = (Expr *) $2;
w->result = (Expr *) $4;
w->location = @1;
$$ = (Node *)w;
}
;
@@ -8738,7 +8765,12 @@ opt_asymmetric: ASYMMETRIC
ctext_expr:
a_expr { $$ = (Node *) $1; }
| DEFAULT { $$ = (Node *) makeNode(SetToDefault); }
| DEFAULT
{
SetToDefault *n = makeNode(SetToDefault);
n->location = @1;
$$ = (Node *) n;
}
;
ctext_expr_list:
@@ -8911,19 +8943,19 @@ func_name: type_function_name
*/
AexprConst: Iconst
{
$$ = makeIntConst($1);
$$ = makeIntConst($1, @1);
}
| FCONST
{
$$ = makeFloatConst($1);
$$ = makeFloatConst($1, @1);
}
| Sconst
{
$$ = makeStringConst($1);
$$ = makeStringConst($1, @1);
}
| BCONST
{
$$ = makeBitStringConst($1);
$$ = makeBitStringConst($1, @1);
}
| XCONST
{
@@ -8932,14 +8964,14 @@ AexprConst: Iconst
* a <general literal> shall not be a
* <bit string literal> or a <hex string literal>.
*/
$$ = makeBitStringConst($1);
$$ = makeBitStringConst($1, @1);
}
| func_name Sconst
{
/* generic type 'literal' syntax */
TypeName *t = makeTypeNameFromNameList($1);
t->location = @1;
$$ = makeStringConstCast($2, t);
$$ = makeStringConstCast($2, @2, t);
}
| func_name '(' expr_list ')' Sconst
{
@@ -8947,38 +8979,38 @@ AexprConst: Iconst
TypeName *t = makeTypeNameFromNameList($1);
t->typmods = $3;
t->location = @1;
$$ = makeStringConstCast($5, t);
$$ = makeStringConstCast($5, @5, t);
}
| ConstTypename Sconst
{
$$ = makeStringConstCast($2, $1);
$$ = makeStringConstCast($2, @2, $1);
}
| ConstInterval Sconst opt_interval
{
TypeName *t = $1;
/* precision is not specified, but fields may be... */
if ($3 != INTERVAL_FULL_RANGE)
t->typmods = list_make1(makeIntConst($3));
$$ = makeStringConstCast($2, t);
t->typmods = list_make1(makeIntConst($3, @3));
$$ = makeStringConstCast($2, @2, t);
}
| ConstInterval '(' Iconst ')' Sconst opt_interval
{
TypeName *t = $1;
t->typmods = list_make2(makeIntConst($6),
makeIntConst($3));
$$ = makeStringConstCast($5, t);
t->typmods = list_make2(makeIntConst($6, @6),
makeIntConst($3, @3));
$$ = makeStringConstCast($5, @5, t);
}
| TRUE_P
{
$$ = makeBoolAConst(TRUE);
$$ = makeBoolAConst(TRUE, @1);
}
| FALSE_P
{
$$ = makeBoolAConst(FALSE);
$$ = makeBoolAConst(FALSE, @1);
}
| NULL_P
{
$$ = makeNullAConst();
$$ = makeNullAConst(@1);
}
;
@@ -9522,94 +9554,100 @@ makeColumnRef(char *relname, List *indirection, int location)
}
static Node *
makeTypeCast(Node *arg, TypeName *typename)
makeTypeCast(Node *arg, TypeName *typename, int location)
{
TypeCast *n = makeNode(TypeCast);
n->arg = arg;
n->typename = typename;
n->location = location;
return (Node *) n;
}
static Node *
makeStringConst(char *str)
makeStringConst(char *str, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = str;
n->location = location;
return (Node *)n;
}
static Node *
makeStringConstCast(char *str, TypeName *typename)
makeStringConstCast(char *str, int location, TypeName *typename)
{
Node *s = makeStringConst(str);
Node *s = makeStringConst(str, location);
return makeTypeCast(s, typename);
return makeTypeCast(s, typename, -1);
}
static Node *
makeIntConst(int val)
makeIntConst(int val, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Integer;
n->val.val.ival = val;
n->location = location;
return (Node *)n;
}
static Node *
makeFloatConst(char *str)
makeFloatConst(char *str, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Float;
n->val.val.str = str;
n->location = location;
return (Node *)n;
}
static Node *
makeBitStringConst(char *str)
makeBitStringConst(char *str, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_BitString;
n->val.val.str = str;
n->location = location;
return (Node *)n;
}
static Node *
makeNullAConst(void)
makeNullAConst(int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
n->location = location;
return (Node *)n;
}
static Node *
makeAConst(Value *v)
makeAConst(Value *v, int location)
{
Node *n;
switch (v->type)
{
case T_Float:
n = makeFloatConst(v->val.str);
n = makeFloatConst(v->val.str, location);
break;
case T_Integer:
n = makeIntConst(v->val.ival);
n = makeIntConst(v->val.ival, location);
break;
case T_String:
default:
n = makeStringConst(v->val.str);
n = makeStringConst(v->val.str, location);
break;
}
@@ -9620,14 +9658,15 @@ makeAConst(Value *v)
* Create an A_Const string node and put it inside a boolean cast.
*/
static Node *
makeBoolAConst(bool state)
makeBoolAConst(bool state, int location)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = (state ? "t" : "f");
n->location = location;
return makeTypeCast((Node *)n, SystemTypeName("bool"));
return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
}
/* makeOverlaps()
@@ -9799,6 +9838,7 @@ SystemFuncName(char *name)
* Build a properly-qualified reference to a built-in type.
*
* typmod is defaulted, but may be changed afterwards by caller.
* Likewise for the location.
*/
TypeName *
SystemTypeName(char *name)
@@ -9827,6 +9867,9 @@ doNegate(Node *n, int location)
{
A_Const *con = (A_Const *)n;
/* report the constant's location as that of the '-' sign */
con->location = location;
if (con->val.type == T_Integer)
{
con->val.val.ival = -con->val.val.ival;
@@ -9863,16 +9906,18 @@ doNegateFloat(Value *v)
}
static Node *
makeAArrayExpr(List *elements)
makeAArrayExpr(List *elements, int location)
{
A_ArrayExpr *n = makeNode(A_ArrayExpr);
n->elements = elements;
n->location = location;
return (Node *) n;
}
static Node *
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
int location)
{
XmlExpr *x = makeNode(XmlExpr);
@@ -9885,6 +9930,9 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
x->named_args = named_args;
x->arg_names = NIL;
x->args = args;
/* xmloption, if relevant, must be filled in by caller */
/* type and typmod will be filled in during parse analysis */
x->location = location;
return (Node *) x;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.81 2008/08/25 22:42:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.82 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -396,6 +396,7 @@ build_aggregate_fnexprs(Oid *agg_input_types,
argp->paramid = -1;
argp->paramtype = agg_state_type;
argp->paramtypmod = -1;
argp->location = -1;
args = list_make1(argp);
@@ -406,6 +407,7 @@ build_aggregate_fnexprs(Oid *agg_input_types,
argp->paramid = -1;
argp->paramtype = agg_input_types[i];
argp->paramtypmod = -1;
argp->location = -1;
args = lappend(args, argp);
}
@@ -429,6 +431,7 @@ build_aggregate_fnexprs(Oid *agg_input_types,
argp->paramid = -1;
argp->paramtype = agg_state_type;
argp->paramtypmod = -1;
argp->location = -1;
args = list_make1(argp);
*finalfnexpr = (Expr *) makeFuncExpr(finalfn_oid,

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.176 2008/08/25 22:42:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.177 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -964,9 +964,10 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
outcoltypmod = l_colvar->vartypmod;
if (outcoltype != r_colvar->vartype)
{
outcoltype = select_common_type(list_make2_oid(l_colvar->vartype,
r_colvar->vartype),
"JOIN/USING");
outcoltype = select_common_type(pstate,
list_make2(l_colvar, r_colvar),
"JOIN/USING",
NULL);
outcoltypmod = -1; /* ie, unknown */
}
else if (outcoltypmod != r_colvar->vartypmod)
@@ -984,7 +985,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
if (l_colvar->vartype != outcoltype)
l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype,
outcoltype, outcoltypmod,
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
else if (l_colvar->vartypmod != outcoltypmod)
l_node = (Node *) makeRelabelType((Expr *) l_colvar,
outcoltype, outcoltypmod,
@@ -995,7 +996,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
if (r_colvar->vartype != outcoltype)
r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype,
outcoltype, outcoltypmod,
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
else if (r_colvar->vartypmod != outcoltypmod)
r_node = (Node *) makeRelabelType((Expr *) r_colvar,
outcoltype, outcoltypmod,
@@ -1038,6 +1039,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
c->coalescetype = outcoltype;
c->args = list_make2(l_node, r_node);
c->location = -1;
res_node = (Node *) c;
break;
}
@@ -1239,6 +1241,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
if (IsA(node, A_Const))
{
Value *val = &((A_Const *) node)->val;
int location = ((A_Const *) node)->location;
int targetlist_pos = 0;
int target_pos;
@@ -1247,7 +1250,9 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
(errcode(ERRCODE_SYNTAX_ERROR),
/* translator: %s is name of a SQL construct, eg ORDER BY */
errmsg("non-integer constant in %s",
clauseText[clause])));
clauseText[clause]),
parser_errposition(pstate, location)));
target_pos = intVal(val);
foreach(tl, *tlist)
{
@@ -1263,7 +1268,8 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
/* translator: %s is name of a SQL construct, eg ORDER BY */
errmsg("%s position %d is not in select list",
clauseText[clause], target_pos)));
clauseText[clause], target_pos),
parser_errposition(pstate, location)));
}
/*
@@ -1590,7 +1596,8 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
restype, TEXTOID, -1,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST);
COERCE_IMPLICIT_CAST,
-1);
restype = TEXTOID;
}
@@ -1704,7 +1711,8 @@ addTargetToGroupList(ParseState *pstate, TargetEntry *tle,
tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
restype, TEXTOID, -1,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST);
COERCE_IMPLICIT_CAST,
-1);
restype = TEXTOID;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.164 2008/08/25 22:42:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.165 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -32,18 +32,20 @@
static Node *coerce_type_typmod(Node *node,
Oid targetTypeId, int32 targetTypMod,
CoercionForm cformat, bool isExplicit,
bool hideInputCoercion);
CoercionForm cformat, int location,
bool isExplicit, bool hideInputCoercion);
static void hide_coercion_node(Node *node);
static Node *build_coercion_expression(Node *node,
CoercionPathType pathtype,
Oid funcId,
Oid targetTypeId, int32 targetTypMod,
CoercionForm cformat, bool isExplicit);
CoercionForm cformat, int location,
bool isExplicit);
static Node *coerce_record_to_complex(ParseState *pstate, Node *node,
Oid targetTypeId,
CoercionContext ccontext,
CoercionForm cformat);
CoercionForm cformat,
int location);
/*
@@ -65,12 +67,14 @@ static Node *coerce_record_to_complex(ParseState *pstate, Node *node,
* targettype - desired result type
* targettypmod - desired result typmod
* ccontext, cformat - context indicators to control coercions
* location - parse location of the coercion request, or -1 if unknown/implicit
*/
Node *
coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
Oid targettype, int32 targettypmod,
CoercionContext ccontext,
CoercionForm cformat)
CoercionForm cformat,
int location)
{
Node *result;
@@ -79,7 +83,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
result = coerce_type(pstate, expr, exprtype,
targettype, targettypmod,
ccontext, cformat);
ccontext, cformat, location);
/*
* If the target is a fixed-length type, it may need a length coercion as
@@ -88,7 +92,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
*/
result = coerce_type_typmod(result,
targettype, targettypmod,
cformat,
cformat, location,
(cformat != COERCE_IMPLICIT_CAST),
(result != expr && !IsA(result, Const)));
@@ -118,7 +122,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
Node *
coerce_type(ParseState *pstate, Node *node,
Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
CoercionContext ccontext, CoercionForm cformat)
CoercionContext ccontext, CoercionForm cformat, int location)
{
Node *result;
CoercionPathType pathtype;
@@ -195,6 +199,13 @@ coerce_type(ParseState *pstate, Node *node,
newcon->constlen = typeLen(targetType);
newcon->constbyval = typeByVal(targetType);
newcon->constisnull = con->constisnull;
/* Use the leftmost of the constant's and coercion's locations */
if (location < 0)
newcon->location = con->location;
else if (con->location >= 0 && con->location < location)
newcon->location = con->location;
else
newcon->location = location;
/*
* We pass typmod -1 to the input routine, primarily because existing
@@ -219,7 +230,7 @@ coerce_type(ParseState *pstate, Node *node,
result = coerce_to_domain(result,
baseTypeId, baseTypeMod,
targetTypeId,
cformat, false, false);
cformat, location, false, false);
ReleaseSysCache(targetType);
@@ -280,6 +291,11 @@ coerce_type(ParseState *pstate, Node *node,
*/
param->paramtypmod = -1;
/* Use the leftmost of the param's and coercion's locations */
if (location >= 0 &&
(param->location < 0 || location < param->location))
param->location = location;
return (Node *) param;
}
pathtype = find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
@@ -303,7 +319,7 @@ coerce_type(ParseState *pstate, Node *node,
result = build_coercion_expression(node, pathtype, funcId,
baseTypeId, baseTypeMod,
cformat,
cformat, location,
(cformat != COERCE_IMPLICIT_CAST));
/*
@@ -314,7 +330,7 @@ coerce_type(ParseState *pstate, Node *node,
if (targetTypeId != baseTypeId)
result = coerce_to_domain(result, baseTypeId, baseTypeMod,
targetTypeId,
cformat, true,
cformat, location, true,
exprIsLengthCoercion(result,
NULL));
}
@@ -330,7 +346,7 @@ coerce_type(ParseState *pstate, Node *node,
* then we won't need a RelabelType node.
*/
result = coerce_to_domain(node, InvalidOid, -1, targetTypeId,
cformat, false, false);
cformat, location, false, false);
if (result == node)
{
/*
@@ -339,9 +355,12 @@ coerce_type(ParseState *pstate, Node *node,
* later? Would work if both types have same interpretation of
* typmod, which is likely but not certain.
*/
result = (Node *) makeRelabelType((Expr *) result,
targetTypeId, -1,
cformat);
RelabelType *r = makeRelabelType((Expr *) result,
targetTypeId, -1,
cformat);
r->location = location;
result = (Node *) r;
}
}
return result;
@@ -351,7 +370,7 @@ coerce_type(ParseState *pstate, Node *node,
{
/* Coerce a RECORD to a specific complex type */
return coerce_record_to_complex(pstate, node, targetTypeId,
ccontext, cformat);
ccontext, cformat, location);
}
if (targetTypeId == RECORDOID &&
ISCOMPLEX(inputTypeId))
@@ -372,6 +391,7 @@ coerce_type(ParseState *pstate, Node *node,
r->arg = (Expr *) node;
r->resulttype = targetTypeId;
r->convertformat = cformat;
r->location = location;
return (Node *) r;
}
/* If we get here, caller blew it */
@@ -483,6 +503,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
* has not bothered to look this up)
* 'typeId': target type to coerce to
* 'cformat': coercion format
* 'location': coercion request location
* 'hideInputCoercion': if true, hide the input coercion under this one.
* 'lengthCoercionDone': if true, caller already accounted for length,
* ie the input is already of baseTypMod as well as baseTypeId.
@@ -491,7 +512,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
*/
Node *
coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
CoercionForm cformat, bool hideInputCoercion,
CoercionForm cformat, int location,
bool hideInputCoercion,
bool lengthCoercionDone)
{
CoerceToDomain *result;
@@ -525,7 +547,7 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
{
if (baseTypeMod >= 0)
arg = coerce_type_typmod(arg, baseTypeId, baseTypeMod,
COERCE_IMPLICIT_CAST,
COERCE_IMPLICIT_CAST, location,
(cformat != COERCE_IMPLICIT_CAST),
false);
}
@@ -540,6 +562,7 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
result->resulttype = typeId;
result->resulttypmod = -1; /* currently, always -1 for domains */
result->coercionformat = cformat;
result->location = location;
return (Node *) result;
}
@@ -568,8 +591,8 @@ coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod, Oid typeId,
*/
static Node *
coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
CoercionForm cformat, bool isExplicit,
bool hideInputCoercion)
CoercionForm cformat, int location,
bool isExplicit, bool hideInputCoercion)
{
CoercionPathType pathtype;
Oid funcId;
@@ -591,7 +614,8 @@ coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
node = build_coercion_expression(node, pathtype, funcId,
targetTypeId, targetTypMod,
cformat, isExplicit);
cformat, location,
isExplicit);
}
return node;
@@ -640,7 +664,8 @@ build_coercion_expression(Node *node,
CoercionPathType pathtype,
Oid funcId,
Oid targetTypeId, int32 targetTypMod,
CoercionForm cformat, bool isExplicit)
CoercionForm cformat, int location,
bool isExplicit)
{
int nargs = 0;
@@ -677,6 +702,7 @@ build_coercion_expression(Node *node,
if (pathtype == COERCION_PATH_FUNC)
{
/* We build an ordinary FuncExpr with special arguments */
FuncExpr *fexpr;
List *args;
Const *cons;
@@ -710,7 +736,9 @@ build_coercion_expression(Node *node,
args = lappend(args, cons);
}
return (Node *) makeFuncExpr(funcId, targetTypeId, args, cformat);
fexpr = makeFuncExpr(funcId, targetTypeId, args, cformat);
fexpr->location = location;
return (Node *) fexpr;
}
else if (pathtype == COERCION_PATH_ARRAYCOERCE)
{
@@ -729,6 +757,7 @@ build_coercion_expression(Node *node,
acoerce->resulttypmod = (nargs >= 2) ? targetTypMod : -1;
acoerce->isExplicit = isExplicit;
acoerce->coerceformat = cformat;
acoerce->location = location;
return (Node *) acoerce;
}
@@ -742,6 +771,7 @@ build_coercion_expression(Node *node,
iocoerce->arg = (Expr *) node;
iocoerce->resulttype = targetTypeId;
iocoerce->coerceformat = cformat;
iocoerce->location = location;
return (Node *) iocoerce;
}
@@ -765,7 +795,8 @@ static Node *
coerce_record_to_complex(ParseState *pstate, Node *node,
Oid targetTypeId,
CoercionContext ccontext,
CoercionForm cformat)
CoercionForm cformat,
int location)
{
RowExpr *rowexpr;
TupleDesc tupdesc;
@@ -799,7 +830,8 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast type %s to %s",
format_type_be(RECORDOID),
format_type_be(targetTypeId))));
format_type_be(targetTypeId)),
parser_coercion_errposition(pstate, location, node)));
tupdesc = lookup_rowtype_tupdesc(targetTypeId, -1);
newargs = NIL;
@@ -808,6 +840,7 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
for (i = 0; i < tupdesc->natts; i++)
{
Node *expr;
Node *cexpr;
Oid exprtype;
/* Fill in NULLs for dropped columns in rowtype */
@@ -827,17 +860,19 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
errmsg("cannot cast type %s to %s",
format_type_be(RECORDOID),
format_type_be(targetTypeId)),
errdetail("Input has too few columns.")));
errdetail("Input has too few columns."),
parser_coercion_errposition(pstate, location, node)));
expr = (Node *) lfirst(arg);
exprtype = exprType(expr);
expr = coerce_to_target_type(pstate,
expr, exprtype,
tupdesc->attrs[i]->atttypid,
tupdesc->attrs[i]->atttypmod,
ccontext,
COERCE_IMPLICIT_CAST);
if (expr == NULL)
cexpr = coerce_to_target_type(pstate,
expr, exprtype,
tupdesc->attrs[i]->atttypid,
tupdesc->attrs[i]->atttypmod,
ccontext,
COERCE_IMPLICIT_CAST,
-1);
if (cexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast type %s to %s",
@@ -846,8 +881,9 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
errdetail("Cannot cast type %s to %s in column %d.",
format_type_be(exprtype),
format_type_be(tupdesc->attrs[i]->atttypid),
ucolno)));
newargs = lappend(newargs, expr);
ucolno),
parser_coercion_errposition(pstate, location, expr)));
newargs = lappend(newargs, cexpr);
ucolno++;
arg = lnext(arg);
}
@@ -857,7 +893,8 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
errmsg("cannot cast type %s to %s",
format_type_be(RECORDOID),
format_type_be(targetTypeId)),
errdetail("Input has too many columns.")));
errdetail("Input has too many columns."),
parser_coercion_errposition(pstate, location, node)));
ReleaseTupleDesc(tupdesc);
@@ -865,6 +902,7 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
rowexpr->args = newargs;
rowexpr->row_typeid = targetTypeId;
rowexpr->row_format = cformat;
rowexpr->location = location;
return (Node *) rowexpr;
}
@@ -886,16 +924,21 @@ coerce_to_boolean(ParseState *pstate, Node *node,
if (inputTypeId != BOOLOID)
{
node = coerce_to_target_type(pstate, node, inputTypeId,
BOOLOID, -1,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
if (node == NULL)
Node *newnode;
newnode = coerce_to_target_type(pstate, node, inputTypeId,
BOOLOID, -1,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
-1);
if (newnode == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
/* translator: first %s is name of a SQL construct, eg WHERE */
errmsg("argument of %s must be type boolean, not type %s",
constructName, format_type_be(inputTypeId))));
errmsg("argument of %s must be type boolean, not type %s",
constructName, format_type_be(inputTypeId)),
parser_errposition(pstate, exprLocation(node))));
node = newnode;
}
if (expression_returns_set(node))
@@ -903,7 +946,8 @@ coerce_to_boolean(ParseState *pstate, Node *node,
(errcode(ERRCODE_DATATYPE_MISMATCH),
/* translator: %s is name of a SQL construct, eg WHERE */
errmsg("argument of %s must not return a set",
constructName)));
constructName),
parser_errposition(pstate, exprLocation(node))));
return node;
}
@@ -927,18 +971,23 @@ coerce_to_specific_type(ParseState *pstate, Node *node,
if (inputTypeId != targetTypeId)
{
node = coerce_to_target_type(pstate, node, inputTypeId,
targetTypeId, -1,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
if (node == NULL)
Node *newnode;
newnode = coerce_to_target_type(pstate, node, inputTypeId,
targetTypeId, -1,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
-1);
if (newnode == 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 %s, not type %s",
constructName,
format_type_be(targetTypeId),
format_type_be(inputTypeId))));
format_type_be(inputTypeId)),
parser_errposition(pstate, exprLocation(node))));
node = newnode;
}
if (expression_returns_set(node))
@@ -946,32 +995,62 @@ coerce_to_specific_type(ParseState *pstate, Node *node,
(errcode(ERRCODE_DATATYPE_MISMATCH),
/* translator: %s is name of a SQL construct, eg LIMIT */
errmsg("argument of %s must not return a set",
constructName)));
constructName),
parser_errposition(pstate, exprLocation(node))));
return node;
}
/* select_common_type()
* Determine the common supertype of a list of input expression types.
/*
* parser_coercion_errposition - report coercion error location, if possible
*
* We prefer to point at the coercion request (CAST, ::, etc) if possible;
* but there may be no such location in the case of an implicit coercion.
* In that case point at the input expression.
*
* XXX possibly this is more generally useful than coercion errors;
* if so, should rename and place with parser_errposition.
*/
int
parser_coercion_errposition(ParseState *pstate,
int coerce_location,
Node *input_expr)
{
if (coerce_location >= 0)
return parser_errposition(pstate, coerce_location);
else
return parser_errposition(pstate, exprLocation(input_expr));
}
/*
* select_common_type()
* Determine the common supertype of a list of input expressions.
* This is used for determining the output type of CASE and UNION
* constructs.
*
* 'typeids' is a nonempty list of type OIDs. Note that earlier items
* 'exprs' is a *nonempty* list of expressions. Note that earlier items
* in the list will be preferred if there is doubt.
* 'context' is a phrase to use in the error message if we fail to select
* a usable type.
* 'which_expr': if not NULL, receives a pointer to the particular input
* expression from which the result type was taken.
*/
Oid
select_common_type(List *typeids, const char *context)
select_common_type(ParseState *pstate, List *exprs, const char *context,
Node **which_expr)
{
Node *pexpr;
Oid ptype;
TYPCATEGORY pcategory;
bool pispreferred;
ListCell *type_item;
ListCell *lc;
Assert(typeids != NIL);
ptype = linitial_oid(typeids);
Assert(exprs != NIL);
pexpr = (Node *) linitial(exprs);
lc = lnext(list_head(exprs));
ptype = exprType(pexpr);
/*
* If all input types are valid and exactly the same, just pick that type.
@@ -980,24 +1059,34 @@ select_common_type(List *typeids, const char *context)
*/
if (ptype != UNKNOWNOID)
{
for_each_cell(type_item, lnext(list_head(typeids)))
for_each_cell(lc, lc)
{
Oid ntype = lfirst_oid(type_item);
Node *nexpr = (Node *) lfirst(lc);
Oid ntype = exprType(nexpr);
if (ntype != ptype)
break;
}
if (type_item == NULL) /* got to the end of the list? */
if (lc == NULL) /* got to the end of the list? */
{
if (which_expr)
*which_expr = pexpr;
return ptype;
}
}
/* Nope, so set up for the full algorithm */
/*
* Nope, so set up for the full algorithm. Note that at this point,
* lc points to the first list item with type different from pexpr's;
* we need not re-examine any items the previous loop advanced over.
*/
ptype = getBaseType(ptype);
get_type_category_preferred(ptype, &pcategory, &pispreferred);
for_each_cell(type_item, lnext(list_head(typeids)))
for_each_cell(lc, lc)
{
Oid ntype = getBaseType(lfirst_oid(type_item));
Node *nexpr = (Node *) lfirst(lc);
Oid ntype = getBaseType(exprType(nexpr));
/* move on to next one if no new information... */
if (ntype != UNKNOWNOID && ntype != ptype)
@@ -1009,6 +1098,7 @@ select_common_type(List *typeids, const char *context)
if (ptype == UNKNOWNOID)
{
/* so far, only unknowns so take anything... */
pexpr = nexpr;
ptype = ntype;
pcategory = ncategory;
pispreferred = nispreferred;
@@ -1020,13 +1110,13 @@ select_common_type(List *typeids, const char *context)
*/
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
/*------
translator: first %s is name of a SQL construct, eg CASE */
errmsg("%s types %s and %s cannot be matched",
context,
format_type_be(ptype),
format_type_be(ntype))));
format_type_be(ntype)),
parser_errposition(pstate, exprLocation(nexpr))));
}
else if (!pispreferred &&
can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) &&
@@ -1036,6 +1126,7 @@ select_common_type(List *typeids, const char *context)
* take new type if can coerce to it implicitly but not the
* other way; but if we have a preferred type, stay on it.
*/
pexpr = nexpr;
ptype = ntype;
pcategory = ncategory;
pispreferred = nispreferred;
@@ -1057,10 +1148,13 @@ select_common_type(List *typeids, const char *context)
if (ptype == UNKNOWNOID)
ptype = TEXTOID;
if (which_expr)
*which_expr = pexpr;
return ptype;
}
/* coerce_to_common_type()
/*
* coerce_to_common_type()
* Coerce an expression to the given type.
*
* This is used following select_common_type() to coerce the individual
@@ -1080,7 +1174,7 @@ coerce_to_common_type(ParseState *pstate, Node *node,
return node; /* no work */
if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT))
node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1,
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
else
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
@@ -1088,7 +1182,8 @@ coerce_to_common_type(ParseState *pstate, Node *node,
errmsg("%s could not convert type %s to %s",
context,
format_type_be(inputTypeId),
format_type_be(targetTypeId))));
format_type_be(targetTypeId)),
parser_errposition(pstate, exprLocation(node))));
return node;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.231 2008/08/25 22:42:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.232 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -63,8 +63,7 @@ static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
char *relname, int location);
static Node *transformIndirection(ParseState *pstate, Node *basenode,
List *indirection);
static Node *typecast_expression(ParseState *pstate, Node *expr,
TypeName *typename);
static Node *transformTypeCast(ParseState *pstate, TypeCast *tc);
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
List *largs, List *rargs, int location);
static Node *make_row_distinct_op(ParseState *pstate, List *opname,
@@ -123,7 +122,7 @@ transformExpr(ParseState *pstate, Node *expr)
A_Const *con = (A_Const *) expr;
Value *val = &con->val;
result = (Node *) make_const(val);
result = (Node *) make_const(val, con->location);
break;
}
@@ -145,7 +144,6 @@ transformExpr(ParseState *pstate, Node *expr)
case T_TypeCast:
{
TypeCast *tc = (TypeCast *) expr;
Node *arg;
/*
* If the subject of the typecast is an ARRAY[] construct
@@ -179,8 +177,7 @@ transformExpr(ParseState *pstate, Node *expr)
*/
}
arg = transformExpr(pstate, tc->arg);
result = typecast_expression(pstate, arg, tc->typename);
result = transformTypeCast(pstate, tc);
break;
}
@@ -425,6 +422,14 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
strcmp(name, "value") == 0)
{
node = (Node *) copyObject(pstate->p_value_substitute);
/*
* Try to propagate location knowledge. This should
* be extended if p_value_substitute can ever take on
* other node types.
*/
if (IsA(node, CoerceToDomainValue))
((CoerceToDomainValue *) node)->location = cref->location;
break;
}
@@ -631,6 +636,7 @@ transformParamRef(ParseState *pstate, ParamRef *pref)
param->paramid = paramno;
param->paramtype = *pptype;
param->paramtypmod = -1;
param->location = pref->location;
return (Node *) param;
}
@@ -691,6 +697,7 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
s->subLinkType = ROWCOMPARE_SUBLINK;
s->testexpr = lexpr;
s->operName = a->name;
s->location = a->location;
result = transformExpr(pstate, (Node *) s);
}
else if (lexpr && IsA(lexpr, RowExpr) &&
@@ -734,7 +741,8 @@ transformAExprAnd(ParseState *pstate, A_Expr *a)
rexpr = coerce_to_boolean(pstate, rexpr, "AND");
return (Node *) makeBoolExpr(AND_EXPR,
list_make2(lexpr, rexpr));
list_make2(lexpr, rexpr),
a->location);
}
static Node *
@@ -747,7 +755,8 @@ transformAExprOr(ParseState *pstate, A_Expr *a)
rexpr = coerce_to_boolean(pstate, rexpr, "OR");
return (Node *) makeBoolExpr(OR_EXPR,
list_make2(lexpr, rexpr));
list_make2(lexpr, rexpr),
a->location);
}
static Node *
@@ -758,7 +767,8 @@ transformAExprNot(ParseState *pstate, A_Expr *a)
rexpr = coerce_to_boolean(pstate, rexpr, "NOT");
return (Node *) makeBoolExpr(NOT_EXPR,
list_make1(rexpr));
list_make1(rexpr),
a->location);
}
static Node *
@@ -849,6 +859,7 @@ transformAExprOf(ParseState *pstate, A_Expr *a)
* in a boolean constant node.
*/
Node *lexpr = transformExpr(pstate, a->lexpr);
Const *result;
ListCell *telem;
Oid ltype,
rtype;
@@ -870,7 +881,12 @@ transformAExprOf(ParseState *pstate, A_Expr *a)
if (strcmp(strVal(linitial(a->name)), "<>") == 0)
matched = (!matched);
return makeBoolConst(matched, false);
result = (Const *) makeBoolConst(matched, false);
/* Make the result have the original input's parse location */
result->location = exprLocation((Node *) a);
return (Node *) result;
}
static Node *
@@ -878,7 +894,6 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
{
Node *lexpr;
List *rexprs;
List *typeids;
bool useOr;
bool haveRowExpr;
Node *result;
@@ -903,7 +918,6 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
*/
lexpr = transformExpr(pstate, a->lexpr);
haveRowExpr = (lexpr && IsA(lexpr, RowExpr));
typeids = list_make1_oid(exprType(lexpr));
rexprs = NIL;
foreach(l, (List *) a->rexpr)
{
@@ -911,7 +925,6 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
haveRowExpr |= (rexpr && IsA(rexpr, RowExpr));
rexprs = lappend(rexprs, rexpr);
typeids = lappend_oid(typeids, exprType(rexpr));
}
/*
@@ -922,6 +935,7 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
*/
if (!haveRowExpr && list_length(rexprs) != 1)
{
List *allexprs;
Oid scalar_type;
Oid array_type;
@@ -929,8 +943,11 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
* Select a common type for the array elements. Note that since the
* LHS' type is first in the list, it will be preferred when there is
* doubt (eg, when all the RHS items are unknown literals).
*
* Note: use list_concat here not lcons, to avoid damaging rexprs.
*/
scalar_type = select_common_type(typeids, "IN");
allexprs = list_concat(list_make1(lexpr), rexprs);
scalar_type = select_common_type(pstate, allexprs, "IN", NULL);
/* Do we have an array type to use? */
array_type = get_array_type(scalar_type);
@@ -958,6 +975,7 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
newa->element_typeid = scalar_type;
newa->elements = aexprs;
newa->multidims = false;
newa->location = -1;
return (Node *) make_scalar_array_op(pstate,
a->name,
@@ -1003,7 +1021,8 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
result = cmp;
else
result = (Node *) makeBoolExpr(useOr ? OR_EXPR : AND_EXPR,
list_make2(result, cmp));
list_make2(result, cmp),
a->location);
}
return result;
@@ -1041,7 +1060,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
Node *arg;
CaseTestExpr *placeholder;
List *newargs;
List *typeids;
List *resultexprs;
ListCell *l;
Node *defresult;
Oid ptype;
@@ -1079,7 +1098,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
/* transform the list of arguments */
newargs = NIL;
typeids = NIL;
resultexprs = NIL;
foreach(l, c->args)
{
CaseWhen *w = (CaseWhen *) lfirst(l);
@@ -1095,7 +1114,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=",
(Node *) placeholder,
warg,
-1);
w->location);
}
neww->expr = (Expr *) transformExpr(pstate, warg);
@@ -1105,9 +1124,10 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
warg = (Node *) w->result;
neww->result = (Expr *) transformExpr(pstate, warg);
neww->location = w->location;
newargs = lappend(newargs, neww);
typeids = lappend_oid(typeids, exprType((Node *) neww->result));
resultexprs = lappend(resultexprs, neww->result);
}
newc->args = newargs;
@@ -1119,6 +1139,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
n->location = -1;
defresult = (Node *) n;
}
newc->defresult = (Expr *) transformExpr(pstate, defresult);
@@ -1128,9 +1149,9 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
* determining preferred type. This is how the code worked before, but it
* seems a little bogus to me --- tgl
*/
typeids = lcons_oid(exprType((Node *) newc->defresult), typeids);
resultexprs = lcons(newc->defresult, resultexprs);
ptype = select_common_type(typeids, "CASE");
ptype = select_common_type(pstate, resultexprs, "CASE", NULL);
Assert(OidIsValid(ptype));
newc->casetype = ptype;
@@ -1153,6 +1174,8 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
"CASE/WHEN");
}
newc->location = c->location;
return (Node *) newc;
}
@@ -1196,13 +1219,15 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
((TargetEntry *) lfirst(tlist_item))->resjunk)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery must return a column")));
errmsg("subquery must return a column"),
parser_errposition(pstate, sublink->location)));
while ((tlist_item = lnext(tlist_item)) != NULL)
{
if (!((TargetEntry *) lfirst(tlist_item))->resjunk)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery must return only one column")));
errmsg("subquery must return only one column"),
parser_errposition(pstate, sublink->location)));
}
/*
@@ -1247,6 +1272,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
param->paramid = tent->resno;
param->paramtype = exprType((Node *) tent->expr);
param->paramtypmod = exprTypmod((Node *) tent->expr);
param->location = -1;
right_list = lappend(right_list, param);
}
@@ -1259,11 +1285,13 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
if (list_length(left_list) < list_length(right_list))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery has too many columns")));
errmsg("subquery has too many columns"),
parser_errposition(pstate, sublink->location)));
if (list_length(left_list) > list_length(right_list))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery has too few columns")));
errmsg("subquery has too few columns"),
parser_errposition(pstate, sublink->location)));
/*
* Identify the combining operator(s) and generate a suitable
@@ -1273,7 +1301,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
sublink->operName,
left_list,
right_list,
-1);
sublink->location);
}
return result;
@@ -1293,7 +1321,6 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
ArrayExpr *newa = makeNode(ArrayExpr);
List *newelems = NIL;
List *newcoercedelems = NIL;
List *typeids = NIL;
ListCell *element;
Oid coerce_type;
bool coerce_hard;
@@ -1309,7 +1336,6 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
{
Node *e = (Node *) lfirst(element);
Node *newe;
Oid newe_type;
/*
* If an element is itself an A_ArrayExpr, recurse directly so that
@@ -1322,25 +1348,22 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
array_type,
element_type,
typmod);
newe_type = exprType(newe);
/* we certainly have an array here */
Assert(array_type == InvalidOid || array_type == newe_type);
Assert(array_type == InvalidOid || array_type == exprType(newe));
newa->multidims = true;
}
else
{
newe = transformExpr(pstate, e);
newe_type = exprType(newe);
/*
* Check for sub-array expressions, if we haven't already
* found one.
*/
if (!newa->multidims && type_is_array(newe_type))
if (!newa->multidims && type_is_array(exprType(newe)))
newa->multidims = true;
}
newelems = lappend(newelems, newe);
typeids = lappend_oid(typeids, newe_type);
}
/*
@@ -1359,15 +1382,16 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
else
{
/* Can't handle an empty array without a target type */
if (typeids == NIL)
if (newelems == NIL)
ereport(ERROR,
(errcode(ERRCODE_INDETERMINATE_DATATYPE),
errmsg("cannot determine type of empty array"),
errhint("Explicitly cast to the desired type, "
"for example ARRAY[]::integer[].")));
"for example ARRAY[]::integer[]."),
parser_errposition(pstate, a->location)));
/* Select a common type for the elements */
coerce_type = select_common_type(typeids, "ARRAY");
coerce_type = select_common_type(pstate, newelems, "ARRAY", NULL);
if (newa->multidims)
{
@@ -1414,13 +1438,15 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
coerce_type,
typmod,
COERCION_EXPLICIT,
COERCE_EXPLICIT_CAST);
COERCE_EXPLICIT_CAST,
-1);
if (newe == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast type %s to %s",
format_type_be(exprType(e)),
format_type_be(coerce_type))));
format_type_be(coerce_type)),
parser_errposition(pstate, exprLocation(e))));
}
else
newe = coerce_to_common_type(pstate, e,
@@ -1432,6 +1458,7 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
newa->array_typeid = array_type;
newa->element_typeid = element_type;
newa->elements = newcoercedelems;
newa->location = a->location;
return (Node *) newa;
}
@@ -1447,6 +1474,7 @@ transformRowExpr(ParseState *pstate, RowExpr *r)
/* Barring later casting, we consider the type RECORD */
newr->row_typeid = RECORDOID;
newr->row_format = COERCE_IMPLICIT_CAST;
newr->location = r->location;
return (Node *) newr;
}
@@ -1457,7 +1485,6 @@ transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c)
CoalesceExpr *newc = makeNode(CoalesceExpr);
List *newargs = NIL;
List *newcoercedargs = NIL;
List *typeids = NIL;
ListCell *args;
foreach(args, c->args)
@@ -1467,10 +1494,9 @@ transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c)
newe = transformExpr(pstate, e);
newargs = lappend(newargs, newe);
typeids = lappend_oid(typeids, exprType(newe));
}
newc->coalescetype = select_common_type(typeids, "COALESCE");
newc->coalescetype = select_common_type(pstate, newargs, "COALESCE", NULL);
/* Convert arguments if necessary */
foreach(args, newargs)
@@ -1485,6 +1511,7 @@ transformCoalesceExpr(ParseState *pstate, CoalesceExpr *c)
}
newc->args = newcoercedargs;
newc->location = c->location;
return (Node *) newc;
}
@@ -1494,7 +1521,7 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
MinMaxExpr *newm = makeNode(MinMaxExpr);
List *newargs = NIL;
List *newcoercedargs = NIL;
List *typeids = NIL;
const char *funcname = (m->op == IS_GREATEST) ? "GREATEST" : "LEAST";
ListCell *args;
newm->op = m->op;
@@ -1505,10 +1532,9 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
newe = transformExpr(pstate, e);
newargs = lappend(newargs, newe);
typeids = lappend_oid(typeids, exprType(newe));
}
newm->minmaxtype = select_common_type(typeids, "GREATEST/LEAST");
newm->minmaxtype = select_common_type(pstate, newargs, funcname, NULL);
/* Convert arguments if necessary */
foreach(args, newargs)
@@ -1518,11 +1544,12 @@ transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m)
newe = coerce_to_common_type(pstate, e,
newm->minmaxtype,
"GREATEST/LEAST");
funcname);
newcoercedargs = lappend(newcoercedargs, newe);
}
newm->args = newcoercedargs;
newm->location = m->location;
return (Node *) newm;
}
@@ -1538,6 +1565,8 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
newx->name = map_sql_identifier_to_xml_name(x->name, false, false);
else
newx->name = NULL;
newx->xmloption = x->xmloption;
newx->location = x->location;
/*
* gram.y built the named args as a list of ResTarget. Transform each,
@@ -1566,33 +1595,32 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
x->op == IS_XMLELEMENT
? errmsg("unnamed XML attribute value must be a column reference")
: errmsg("unnamed XML element value must be a column reference")));
? errmsg("unnamed XML attribute value must be a column reference")
: errmsg("unnamed XML element value must be a column reference"),
parser_errposition(pstate, r->location)));
argname = NULL; /* keep compiler quiet */
}
/* reject duplicate argnames in XMLELEMENT only */
if (x->op == IS_XMLELEMENT)
{
ListCell *lc2;
foreach(lc2, newx->arg_names)
{
if (strcmp(argname, strVal(lfirst(lc2))) == 0)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("XML attribute name \"%s\" appears more than once",
argname),
parser_errposition(pstate, r->location)));
}
}
newx->named_args = lappend(newx->named_args, expr);
newx->arg_names = lappend(newx->arg_names, makeString(argname));
}
newx->xmloption = x->xmloption;
if (x->op == IS_XMLELEMENT)
{
foreach(lc, newx->arg_names)
{
ListCell *lc2;
for_each_cell(lc2, lnext(lc))
{
if (strcmp(strVal(lfirst(lc)), strVal(lfirst(lc2))) == 0)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("XML attribute name \"%s\" appears more than once", strVal(lfirst(lc)))));
}
}
}
/* The other arguments are of varying types depending on the function */
newx->args = NIL;
i = 0;
@@ -1639,6 +1667,7 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
break;
case IS_XMLSERIALIZE:
/* not handled here */
Assert(false);
break;
case IS_DOCUMENT:
newe = coerce_to_specific_type(pstate, newe, XMLOID,
@@ -1655,9 +1684,10 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
static Node *
transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
{
Node *result;
XmlExpr *xexpr;
Oid targetType;
int32 targetTypmod;
XmlExpr *xexpr;
xexpr = makeNode(XmlExpr);
xexpr->op = IS_XMLSERIALIZE;
@@ -1669,6 +1699,7 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
targetType = typenameTypeId(pstate, xs->typename, &targetTypmod);
xexpr->xmloption = xs->xmloption;
xexpr->location = xs->location;
/* We actually only need these to be able to parse back the expression. */
xexpr->type = targetType;
xexpr->typmod = targetTypmod;
@@ -1679,8 +1710,18 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
* 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);
result = coerce_to_target_type(pstate, (Node *) xexpr,
TEXTOID, targetType, targetTypmod,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST,
-1);
if (result == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast XMLSERIALIZE result to %s",
format_type_be(targetType)),
parser_errposition(pstate, xexpr->location)));
return result;
}
static Node *
@@ -1773,7 +1814,7 @@ static Node *
transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
int location)
{
Node *result;
Var *result;
RangeTblEntry *rte;
int vnum;
int sublevels_up;
@@ -1800,22 +1841,22 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
if (!OidIsValid(toid))
elog(ERROR, "could not find type OID for relation %u",
rte->relid);
result = (Node *) makeVar(vnum,
InvalidAttrNumber,
toid,
-1,
sublevels_up);
result = makeVar(vnum,
InvalidAttrNumber,
toid,
-1,
sublevels_up);
break;
case RTE_FUNCTION:
toid = exprType(rte->funcexpr);
if (type_is_rowtype(toid))
{
/* func returns composite; same as relation case */
result = (Node *) makeVar(vnum,
InvalidAttrNumber,
toid,
-1,
sublevels_up);
result = makeVar(vnum,
InvalidAttrNumber,
toid,
-1,
sublevels_up);
}
else
{
@@ -1825,21 +1866,21 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
* seems a tad inconsistent, especially if "f.*" was
* explicitly written ...)
*/
result = (Node *) makeVar(vnum,
1,
toid,
-1,
sublevels_up);
result = makeVar(vnum,
1,
toid,
-1,
sublevels_up);
}
break;
case RTE_VALUES:
toid = RECORDOID;
/* returns composite; same as relation case */
result = (Node *) makeVar(vnum,
InvalidAttrNumber,
toid,
-1,
sublevels_up);
result = makeVar(vnum,
InvalidAttrNumber,
toid,
-1,
sublevels_up);
break;
default:
@@ -1849,48 +1890,64 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
* expanded to a RowExpr during planning, but that is not our
* concern here.)
*/
result = (Node *) makeVar(vnum,
InvalidAttrNumber,
RECORDOID,
-1,
sublevels_up);
result = makeVar(vnum,
InvalidAttrNumber,
RECORDOID,
-1,
sublevels_up);
break;
}
return result;
/* location is not filled in by makeVar */
result->location = location;
return (Node *) result;
}
/*
* Handle an explicit CAST construct.
*
* The given expr has already been transformed, but we need to lookup
* the type name and then apply any necessary coercion function(s).
* Transform the argument, then look up the type name and apply any necessary
* coercion function(s).
*/
static Node *
typecast_expression(ParseState *pstate, Node *expr, TypeName *typename)
transformTypeCast(ParseState *pstate, TypeCast *tc)
{
Node *result;
Node *expr = transformExpr(pstate, tc->arg);
Oid inputType = exprType(expr);
Oid targetType;
int32 targetTypmod;
int location;
targetType = typenameTypeId(pstate, typename, &targetTypmod);
targetType = typenameTypeId(pstate, tc->typename, &targetTypmod);
if (inputType == InvalidOid)
return expr; /* do nothing if NULL input */
expr = coerce_to_target_type(pstate, expr, inputType,
targetType, targetTypmod,
COERCION_EXPLICIT,
COERCE_EXPLICIT_CAST);
if (expr == NULL)
/*
* Location of the coercion is preferentially the location of the :: or
* CAST symbol, but if there is none then use the location of the type
* name (this can happen in TypeName 'string' syntax, for instance).
*/
location = tc->location;
if (location < 0)
location = tc->typename->location;
result = coerce_to_target_type(pstate, expr, inputType,
targetType, targetTypmod,
COERCION_EXPLICIT,
COERCE_EXPLICIT_CAST,
location);
if (result == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
errmsg("cannot cast type %s to %s",
format_type_be(inputType),
format_type_be(targetType)),
parser_errposition(pstate, typename->location)));
parser_coercion_errposition(pstate, location, expr)));
return expr;
return result;
}
/*
@@ -2043,9 +2100,9 @@ make_row_comparison_op(ParseState *pstate, List *opname,
* the system thinks BoolExpr is N-argument anyway.
*/
if (rctype == ROWCOMPARE_EQ)
return (Node *) makeBoolExpr(AND_EXPR, opexprs);
return (Node *) makeBoolExpr(AND_EXPR, opexprs, location);
if (rctype == ROWCOMPARE_NE)
return (Node *) makeBoolExpr(OR_EXPR, opexprs);
return (Node *) makeBoolExpr(OR_EXPR, opexprs, location);
/*
* Otherwise we need to choose exactly which opfamily to associate with
@@ -2138,7 +2195,8 @@ make_row_distinct_op(ParseState *pstate, List *opname,
result = cmp;
else
result = (Node *) makeBoolExpr(OR_EXPR,
list_make2(result, cmp));
list_make2(result, cmp),
location);
}
if (result == NULL)

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.205 2008/08/25 22:42:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.206 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -173,7 +173,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
*/
return coerce_type(pstate, linitial(fargs),
actual_arg_types[0], rettype, -1,
COERCION_EXPLICIT, COERCE_EXPLICIT_CALL);
COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location);
}
else if (fdresult == FUNCDETAIL_NORMAL)
{
@@ -272,6 +272,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
errmsg("could not find array type for data type %s",
format_type_be(newa->element_typeid))));
newa->multidims = false;
newa->location = exprLocation((Node *) vargs);
fargs = lappend(fargs, newa);
}
@@ -286,6 +287,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
funcexpr->funcretset = retset;
funcexpr->funcformat = COERCE_EXPLICIT_CALL;
funcexpr->args = fargs;
funcexpr->location = location;
retval = (Node *) funcexpr;
}
@@ -299,6 +301,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
aggref->args = fargs;
aggref->aggstar = agg_star;
aggref->aggdistinct = agg_distinct;
aggref->location = location;
/*
* Reject attempt to call a parameterless aggregate without (*)
@@ -1009,7 +1012,8 @@ make_fn_arguments(ParseState *pstate,
actual_arg_types[i],
declared_arg_types[i], -1,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST);
COERCE_IMPLICIT_CAST,
-1);
}
i++;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.101 2008/08/25 22:42:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.102 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -117,8 +117,9 @@ parser_errposition(ParseState *pstate, int location)
* Build a Var node for an attribute identified by RTE and attrno
*/
Var *
make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
make_var(ParseState *pstate, RangeTblEntry *rte, int attrno, int location)
{
Var *result;
int vnum,
sublevels_up;
Oid vartypeid;
@@ -126,7 +127,9 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
get_rte_attribute_type(rte, attrno, &vartypeid, &type_mod);
return makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up);
result = makeVar(vnum, attrno, vartypeid, type_mod, sublevels_up);
result->location = location;
return result;
}
/*
@@ -243,11 +246,13 @@ transformArraySubscripts(ParseState *pstate,
subexpr, exprType(subexpr),
INT4OID, -1,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
COERCE_IMPLICIT_CAST,
-1);
if (subexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array subscript must have type integer")));
errmsg("array subscript must have type integer"),
parser_errposition(pstate, exprLocation(ai->lidx))));
}
else
{
@@ -267,11 +272,13 @@ transformArraySubscripts(ParseState *pstate,
subexpr, exprType(subexpr),
INT4OID, -1,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
COERCE_IMPLICIT_CAST,
-1);
if (subexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array subscript must have type integer")));
errmsg("array subscript must have type integer"),
parser_errposition(pstate, exprLocation(ai->uidx))));
upperIndexpr = lappend(upperIndexpr, subexpr);
}
@@ -283,20 +290,24 @@ transformArraySubscripts(ParseState *pstate,
{
Oid typesource = exprType(assignFrom);
Oid typeneeded = isSlice ? arrayType : elementType;
Node *newFrom;
assignFrom = coerce_to_target_type(pstate,
assignFrom, typesource,
typeneeded, elementTypMod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
if (assignFrom == NULL)
newFrom = coerce_to_target_type(pstate,
assignFrom, typesource,
typeneeded, elementTypMod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
-1);
if (newFrom == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("array assignment requires type %s"
" but expression is of type %s",
format_type_be(typeneeded),
format_type_be(typesource)),
errhint("You will need to rewrite or cast the expression.")));
errhint("You will need to rewrite or cast the expression."),
parser_errposition(pstate, exprLocation(assignFrom))));
assignFrom = newFrom;
}
/*
@@ -333,7 +344,7 @@ transformArraySubscripts(ParseState *pstate,
* too many examples that fail if we try.
*/
Const *
make_const(Value *value)
make_const(Value *value, int location)
{
Datum val;
int64 val64;
@@ -423,6 +434,7 @@ make_const(Value *value)
(Datum) 0,
true,
false);
con->location = location;
return con;
default:
@@ -436,6 +448,7 @@ make_const(Value *value)
val,
false,
typebyval);
con->location = location;
return con;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.104 2008/08/25 22:42:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.105 2008/08/28 23:09:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -857,6 +857,7 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
result->opresulttype = rettype;
result->opretset = get_func_retset(opform->oprcode);
result->args = args;
result->location = location;
ReleaseSysCache(tup);
@@ -984,6 +985,7 @@ make_scalar_array_op(ParseState *pstate, List *opname,
result->opfuncid = opform->oprcode;
result->useOr = useOr;
result->args = args;
result->location = location;
ReleaseSysCache(tup);

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.133 2008/08/25 22:42:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.134 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -362,7 +362,7 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname,
errmsg("column reference \"%s\" is ambiguous",
colname),
parser_errposition(pstate, location)));
result = (Node *) make_var(pstate, rte, attnum);
result = (Node *) make_var(pstate, rte, attnum, location);
/* Require read access */
rte->requiredPerms |= ACL_SELECT;
}
@@ -390,7 +390,7 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname,
Int16GetDatum(attnum),
0, 0))
{
result = (Node *) make_var(pstate, rte, attnum);
result = (Node *) make_var(pstate, rte, attnum, location);
/* Require read access */
rte->requiredPerms |= ACL_SELECT;
}

View File

@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.161 2008/08/25 22:42:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.162 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -318,7 +318,7 @@ markTargetListOrigin(ParseState *pstate, TargetEntry *tle,
* colname target column name (ie, name of attribute to be assigned to)
* attrno target attribute number
* indirection subscripts/field names for target column, if any
* location error cursor position, or -1
* location error cursor position for the target column, or -1
*
* Returns the modified expression.
*/
@@ -403,7 +403,8 @@ transformAssignedExpr(ParseState *pstate,
*/
colVar = (Node *) make_var(pstate,
pstate->p_target_rangetblentry,
attrno);
attrno,
location);
}
expr = (Expr *)
@@ -428,7 +429,8 @@ transformAssignedExpr(ParseState *pstate,
(Node *) expr, type_id,
attrtype, attrtypmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
COERCE_IMPLICIT_CAST,
-1);
if (expr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -677,7 +679,8 @@ transformAssignmentIndirection(ParseState *pstate,
rhs, exprType(rhs),
targetTypeId, targetTypMod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST);
COERCE_IMPLICIT_CAST,
-1);
if (result == NULL)
{
if (targetIsArray)

View File

@@ -19,7 +19,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.15 2008/08/25 22:42:33 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.16 2008/08/28 23:09:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -380,9 +380,11 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
snamenode = makeNode(A_Const);
snamenode->val.type = T_String;
snamenode->val.val.str = qstring;
snamenode->location = -1;
castnode = makeNode(TypeCast);
castnode->typename = SystemTypeName("regclass");
castnode->arg = (Node *) snamenode;
castnode->location = -1;
funccallnode = makeNode(FuncCall);
funccallnode->funcname = SystemFuncName("nextval");
funccallnode->args = list_make1(castnode);