mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
Add a bunch of new error location reports to parse-analysis error messages.
There are still some weak spots around JOIN USING and relation alias lists, but most errors reported within backend/parser/ now have locations.
This commit is contained in:
@@ -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.378 2008/08/28 23:09:47 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.379 2008/09/01 20:42:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -36,16 +36,10 @@
|
||||
#include "parser/parse_relation.h"
|
||||
#include "parser/parse_target.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "rewrite/rewriteManip.h"
|
||||
#include "utils/rel.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Oid *paramTypes;
|
||||
int numParams;
|
||||
} check_parameter_resolution_context;
|
||||
|
||||
|
||||
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
|
||||
static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
|
||||
static List *transformInsertRow(ParseState *pstate, List *exprlist,
|
||||
@@ -62,9 +56,9 @@ static Query *transformDeclareCursorStmt(ParseState *pstate,
|
||||
DeclareCursorStmt *stmt);
|
||||
static Query *transformExplainStmt(ParseState *pstate,
|
||||
ExplainStmt *stmt);
|
||||
static void transformLockingClause(Query *qry, LockingClause *lc);
|
||||
static bool check_parameter_resolution_walker(Node *node,
|
||||
check_parameter_resolution_context *context);
|
||||
static void transformLockingClause(ParseState *pstate,
|
||||
Query *qry, LockingClause *lc);
|
||||
static bool check_parameter_resolution_walker(Node *node, ParseState *pstate);
|
||||
|
||||
|
||||
/*
|
||||
@@ -122,21 +116,15 @@ parse_analyze_varparams(Node *parseTree, const char *sourceText,
|
||||
|
||||
query = transformStmt(pstate, parseTree);
|
||||
|
||||
/* make sure all is well with parameter types */
|
||||
if (pstate->p_numparams > 0)
|
||||
check_parameter_resolution_walker((Node *) query, pstate);
|
||||
|
||||
*paramTypes = pstate->p_paramtypes;
|
||||
*numParams = pstate->p_numparams;
|
||||
|
||||
free_parsestate(pstate);
|
||||
|
||||
/* make sure all is well with parameter types */
|
||||
if (*numParams > 0)
|
||||
{
|
||||
check_parameter_resolution_context context;
|
||||
|
||||
context.paramTypes = *paramTypes;
|
||||
context.numParams = *numParams;
|
||||
check_parameter_resolution_walker((Node *) query, &context);
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@@ -383,13 +371,16 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
free_parsestate(sub_pstate);
|
||||
|
||||
/* The grammar should have produced a SELECT, but it might have INTO */
|
||||
Assert(IsA(selectQuery, Query));
|
||||
Assert(selectQuery->commandType == CMD_SELECT);
|
||||
Assert(selectQuery->utilityStmt == NULL);
|
||||
if (!IsA(selectQuery, Query) ||
|
||||
selectQuery->commandType != CMD_SELECT ||
|
||||
selectQuery->utilityStmt != NULL)
|
||||
elog(ERROR, "unexpected non-SELECT command in INSERT ... SELECT");
|
||||
if (selectQuery->intoClause)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("INSERT ... SELECT cannot specify INTO")));
|
||||
errmsg("INSERT ... SELECT cannot specify INTO"),
|
||||
parser_errposition(pstate,
|
||||
exprLocation((Node *) selectQuery->intoClause))));
|
||||
|
||||
/*
|
||||
* Make the source be a subquery in the INSERT's rangetable, and add
|
||||
@@ -477,7 +468,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("VALUES lists must all be the same length")));
|
||||
errmsg("VALUES lists must all be the same length"),
|
||||
parser_errposition(pstate,
|
||||
exprLocation((Node *) sublist))));
|
||||
}
|
||||
|
||||
/* Prepare row for assignment to target table */
|
||||
@@ -496,7 +489,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
if (pstate->p_joinlist != NIL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("VALUES must not contain table references")));
|
||||
errmsg("VALUES must not contain table references"),
|
||||
parser_errposition(pstate,
|
||||
locate_var_of_level((Node *) exprsLists, 0))));
|
||||
|
||||
/*
|
||||
* Another thing we can't currently support is NEW/OLD references in
|
||||
@@ -509,7 +504,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("VALUES must not contain OLD or NEW references"),
|
||||
errhint("Use SELECT ... UNION ALL ... instead.")));
|
||||
errhint("Use SELECT ... UNION ALL ... instead."),
|
||||
parser_errposition(pstate,
|
||||
locate_var_of_level((Node *) exprsLists, 0))));
|
||||
|
||||
/*
|
||||
* Generate the VALUES RTE
|
||||
@@ -524,7 +521,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
/*
|
||||
* Generate list of Vars referencing the RTE
|
||||
*/
|
||||
expandRTE(rte, rtr->rtindex, 0, false, NULL, &exprList);
|
||||
expandRTE(rte, rtr->rtindex, 0, -1, false, NULL, &exprList);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -603,7 +600,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
if (pstate->p_hasAggs)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
errmsg("cannot use aggregate function in VALUES")));
|
||||
errmsg("cannot use aggregate function in VALUES"),
|
||||
parser_errposition(pstate,
|
||||
locate_agg_of_level((Node *) qry, 0))));
|
||||
|
||||
return qry;
|
||||
}
|
||||
@@ -633,12 +632,18 @@ transformInsertRow(ParseState *pstate, List *exprlist,
|
||||
if (list_length(exprlist) > list_length(icolumns))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("INSERT has more expressions than target columns")));
|
||||
errmsg("INSERT has more expressions than target columns"),
|
||||
parser_errposition(pstate,
|
||||
exprLocation(list_nth(exprlist,
|
||||
list_length(icolumns))))));
|
||||
if (stmtcols != NIL &&
|
||||
list_length(exprlist) < list_length(icolumns))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("INSERT has more target columns than expressions")));
|
||||
errmsg("INSERT has more target columns than expressions"),
|
||||
parser_errposition(pstate,
|
||||
exprLocation(list_nth(icolumns,
|
||||
list_length(exprlist))))));
|
||||
|
||||
/*
|
||||
* Prepare columns for assignment to target table.
|
||||
@@ -770,7 +775,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
|
||||
foreach(l, stmt->lockingClause)
|
||||
{
|
||||
transformLockingClause(qry, (LockingClause *) lfirst(l));
|
||||
transformLockingClause(pstate, qry, (LockingClause *) lfirst(l));
|
||||
}
|
||||
|
||||
return qry;
|
||||
@@ -838,7 +843,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("VALUES lists must all be the same length")));
|
||||
errmsg("VALUES lists must all be the same length"),
|
||||
parser_errposition(pstate,
|
||||
exprLocation((Node *) sublist))));
|
||||
}
|
||||
|
||||
exprsLists = lappend(exprsLists, sublist);
|
||||
@@ -902,7 +909,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
* Generate a targetlist as though expanding "*"
|
||||
*/
|
||||
Assert(pstate->p_next_resno == 1);
|
||||
qry->targetList = expandRelAttrs(pstate, rte, rtr->rtindex, 0);
|
||||
qry->targetList = expandRelAttrs(pstate, rte, rtr->rtindex, 0, -1);
|
||||
|
||||
/*
|
||||
* The grammar allows attaching ORDER BY, LIMIT, and FOR UPDATE to a
|
||||
@@ -940,7 +947,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
if (list_length(pstate->p_joinlist) != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("VALUES must not contain table references")));
|
||||
errmsg("VALUES must not contain table references"),
|
||||
parser_errposition(pstate,
|
||||
locate_var_of_level((Node *) newExprsLists, 0))));
|
||||
|
||||
/*
|
||||
* Another thing we can't currently support is NEW/OLD references in rules
|
||||
@@ -953,7 +962,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("VALUES must not contain OLD or NEW references"),
|
||||
errhint("Use SELECT ... UNION ALL ... instead.")));
|
||||
errhint("Use SELECT ... UNION ALL ... instead."),
|
||||
parser_errposition(pstate,
|
||||
locate_var_of_level((Node *) newExprsLists, 0))));
|
||||
|
||||
qry->rtable = pstate->p_rtable;
|
||||
qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
|
||||
@@ -963,7 +974,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
if (pstate->p_hasAggs)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
errmsg("cannot use aggregate function in VALUES")));
|
||||
errmsg("cannot use aggregate function in VALUES"),
|
||||
parser_errposition(pstate,
|
||||
locate_agg_of_level((Node *) newExprsLists, 0))));
|
||||
|
||||
return qry;
|
||||
}
|
||||
@@ -1155,7 +1168,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("invalid UNION/INTERSECT/EXCEPT ORDER BY clause"),
|
||||
errdetail("Only result column names can be used, not expressions or functions."),
|
||||
errhint("Add the expression/function to every SELECT, or move the UNION into a FROM clause.")));
|
||||
errhint("Add the expression/function to every SELECT, or move the UNION into a FROM clause."),
|
||||
parser_errposition(pstate,
|
||||
exprLocation(list_nth(qry->targetList, tllen)))));
|
||||
|
||||
qry->limitOffset = transformLimitClause(pstate, limitOffset,
|
||||
"OFFSET");
|
||||
@@ -1185,7 +1200,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
|
||||
foreach(l, lockingClause)
|
||||
{
|
||||
transformLockingClause(qry, (LockingClause *) lfirst(l));
|
||||
transformLockingClause(pstate, qry, (LockingClause *) lfirst(l));
|
||||
}
|
||||
|
||||
return qry;
|
||||
@@ -1198,9 +1213,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
* 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.
|
||||
* internal recursion of this function. At the upper levels 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,
|
||||
@@ -1216,7 +1231,10 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
|
||||
if (stmt->intoClause)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT")));
|
||||
errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT"),
|
||||
parser_errposition(pstate,
|
||||
exprLocation((Node *) stmt->intoClause))));
|
||||
|
||||
/* We don't support FOR UPDATE/SHARE with set ops at the moment. */
|
||||
if (stmt->lockingClause)
|
||||
ereport(ERROR,
|
||||
@@ -1273,25 +1291,21 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
|
||||
if (contain_vars_of_level((Node *) selectQuery, 1))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
||||
errmsg("UNION/INTERSECT/EXCEPT member statement cannot refer to other relations of same query level")));
|
||||
errmsg("UNION/INTERSECT/EXCEPT member statement cannot refer to other relations of same query level"),
|
||||
parser_errposition(pstate,
|
||||
locate_var_of_level((Node *) selectQuery, 1))));
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract information about the result columns.
|
||||
* Extract a list of the result expressions for upper-level checking.
|
||||
*/
|
||||
*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);
|
||||
if (!tle->resjunk)
|
||||
*colInfo = lappend(*colInfo, tle->expr);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1356,12 +1370,12 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
|
||||
op->groupClauses = NIL;
|
||||
forboth(lci, lcolinfo, rci, rcolinfo)
|
||||
{
|
||||
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 *lcolinfo = (Node *) lfirst(lci);
|
||||
Node *rcolinfo = (Node *) lfirst(rci);
|
||||
Oid lcoltype = exprType(lcolinfo);
|
||||
Oid rcoltype = exprType(rcolinfo);
|
||||
int32 lcoltypmod = exprTypmod(lcolinfo);
|
||||
int32 rcoltypmod = exprTypmod(rcolinfo);
|
||||
Node *bestexpr;
|
||||
SetToDefault *rescolinfo;
|
||||
Oid rescoltype;
|
||||
@@ -1379,18 +1393,16 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
|
||||
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);
|
||||
(void) coerce_to_common_type(pstate, lcolinfo,
|
||||
rescoltype, context);
|
||||
(void) coerce_to_common_type(pstate, rcolinfo,
|
||||
rescoltype, context);
|
||||
|
||||
/* emit results */
|
||||
rescolinfo = makeNode(SetToDefault);
|
||||
rescolinfo->typeId = rescoltype;
|
||||
rescolinfo->typeMod = rescoltypmod;
|
||||
rescolinfo->location = ((SetToDefault *) bestexpr)->location;
|
||||
rescolinfo->location = exprLocation(bestexpr);
|
||||
*colInfo = lappend(*colInfo, rescolinfo);
|
||||
|
||||
op->colTypes = lappend_oid(op->colTypes, rescoltype);
|
||||
@@ -1406,12 +1418,18 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
|
||||
SortGroupClause *grpcl = makeNode(SortGroupClause);
|
||||
Oid sortop;
|
||||
Oid eqop;
|
||||
ParseCallbackState pcbstate;
|
||||
|
||||
setup_parser_errposition_callback(&pcbstate, pstate,
|
||||
rescolinfo->location);
|
||||
|
||||
/* determine the eqop and optional sortop */
|
||||
get_sort_group_operators(rescoltype,
|
||||
false, true, false,
|
||||
&sortop, &eqop, NULL);
|
||||
|
||||
cancel_parser_errposition_callback(&pcbstate);
|
||||
|
||||
/* we don't have a tlist yet, so can't assign sortgrouprefs */
|
||||
grpcl->tleSortGroupRef = 0;
|
||||
grpcl->eqop = eqop;
|
||||
@@ -1510,7 +1528,9 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
|
||||
if (pstate->p_hasAggs)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
errmsg("cannot use aggregate function in UPDATE")));
|
||||
errmsg("cannot use aggregate function in UPDATE"),
|
||||
parser_errposition(pstate,
|
||||
locate_agg_of_level((Node *) qry, 0))));
|
||||
|
||||
/*
|
||||
* Now we are done with SELECT-like processing, and can get on with
|
||||
@@ -1607,13 +1627,28 @@ transformReturningList(ParseState *pstate, List *returningList)
|
||||
if (pstate->p_hasAggs)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
errmsg("cannot use aggregate function in RETURNING")));
|
||||
errmsg("cannot use aggregate function in RETURNING"),
|
||||
parser_errposition(pstate,
|
||||
locate_agg_of_level((Node *) rlist, 0))));
|
||||
|
||||
/* no new relation references please */
|
||||
if (list_length(pstate->p_rtable) != length_rtable)
|
||||
{
|
||||
int vlocation = -1;
|
||||
int relid;
|
||||
|
||||
/* try to locate such a reference to point to */
|
||||
for (relid = length_rtable + 1; relid <= list_length(pstate->p_rtable); relid++)
|
||||
{
|
||||
vlocation = locate_var_of_relation((Node *) rlist, relid, 0);
|
||||
if (vlocation >= 0)
|
||||
break;
|
||||
}
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("RETURNING cannot contain references to other relations")));
|
||||
errmsg("RETURNING cannot contain references to other relations"),
|
||||
parser_errposition(pstate, vlocation)));
|
||||
}
|
||||
|
||||
/* mark column origins */
|
||||
markTargetListOrigins(pstate, rlist);
|
||||
@@ -1653,16 +1688,19 @@ transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt)
|
||||
|
||||
result = transformStmt(pstate, stmt->query);
|
||||
|
||||
/* Grammar should not have allowed anything but SELECT */
|
||||
if (!IsA(result, Query) ||
|
||||
result->commandType != CMD_SELECT ||
|
||||
result->utilityStmt != NULL)
|
||||
elog(ERROR, "unexpected non-SELECT command in cursor statement");
|
||||
elog(ERROR, "unexpected non-SELECT command in DECLARE CURSOR");
|
||||
|
||||
/* But we must explicitly disallow DECLARE CURSOR ... SELECT INTO */
|
||||
if (result->intoClause)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
|
||||
errmsg("DECLARE CURSOR cannot specify INTO")));
|
||||
errmsg("DECLARE CURSOR cannot specify INTO"),
|
||||
parser_errposition(pstate,
|
||||
exprLocation((Node *) result->intoClause))));
|
||||
|
||||
/* FOR UPDATE and WITH HOLD are not compatible */
|
||||
if (result->rowMarks != NIL && (stmt->options & CURSOR_OPT_HOLD))
|
||||
@@ -1761,10 +1799,10 @@ CheckSelectLocking(Query *qry)
|
||||
* This basically involves replacing names by integer relids.
|
||||
*
|
||||
* NB: if you need to change this, see also markQueryForLocking()
|
||||
* in rewriteHandler.c.
|
||||
* in rewriteHandler.c, and isLockedRel() in parse_relation.c.
|
||||
*/
|
||||
static void
|
||||
transformLockingClause(Query *qry, LockingClause *lc)
|
||||
transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc)
|
||||
{
|
||||
List *lockedRels = lc->lockedRels;
|
||||
ListCell *l;
|
||||
@@ -1801,7 +1839,7 @@ transformLockingClause(Query *qry, LockingClause *lc)
|
||||
* FOR UPDATE/SHARE of subquery is propagated to all of
|
||||
* subquery's rels
|
||||
*/
|
||||
transformLockingClause(rte->subquery, allrels);
|
||||
transformLockingClause(pstate, rte->subquery, allrels);
|
||||
break;
|
||||
default:
|
||||
/* ignore JOIN, SPECIAL, FUNCTION RTEs */
|
||||
@@ -1814,7 +1852,14 @@ transformLockingClause(Query *qry, LockingClause *lc)
|
||||
/* just the named tables */
|
||||
foreach(l, lockedRels)
|
||||
{
|
||||
char *relname = strVal(lfirst(l));
|
||||
RangeVar *thisrel = (RangeVar *) lfirst(l);
|
||||
|
||||
/* For simplicity we insist on unqualified alias names here */
|
||||
if (thisrel->catalogname || thisrel->schemaname)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("SELECT FOR UPDATE/SHARE must specify unqualified relation names"),
|
||||
parser_errposition(pstate, thisrel->location)));
|
||||
|
||||
i = 0;
|
||||
foreach(rt, qry->rtable)
|
||||
@@ -1822,7 +1867,7 @@ transformLockingClause(Query *qry, LockingClause *lc)
|
||||
RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
|
||||
|
||||
++i;
|
||||
if (strcmp(rte->eref->aliasname, relname) == 0)
|
||||
if (strcmp(rte->eref->aliasname, thisrel->relname) == 0)
|
||||
{
|
||||
switch (rte->rtekind)
|
||||
{
|
||||
@@ -1837,27 +1882,31 @@ transformLockingClause(Query *qry, LockingClause *lc)
|
||||
* FOR UPDATE/SHARE of subquery is propagated to
|
||||
* all of subquery's rels
|
||||
*/
|
||||
transformLockingClause(rte->subquery, allrels);
|
||||
transformLockingClause(pstate, rte->subquery, allrels);
|
||||
break;
|
||||
case RTE_JOIN:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a join")));
|
||||
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a join"),
|
||||
parser_errposition(pstate, thisrel->location)));
|
||||
break;
|
||||
case RTE_SPECIAL:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to NEW or OLD")));
|
||||
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to NEW or OLD"),
|
||||
parser_errposition(pstate, thisrel->location)));
|
||||
break;
|
||||
case RTE_FUNCTION:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a function")));
|
||||
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a function"),
|
||||
parser_errposition(pstate, thisrel->location)));
|
||||
break;
|
||||
case RTE_VALUES:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to VALUES")));
|
||||
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to VALUES"),
|
||||
parser_errposition(pstate, thisrel->location)));
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized RTE type: %d",
|
||||
@@ -1871,7 +1920,8 @@ transformLockingClause(Query *qry, LockingClause *lc)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_TABLE),
|
||||
errmsg("relation \"%s\" in FOR UPDATE/SHARE clause not found in FROM clause",
|
||||
relname)));
|
||||
thisrel->relname),
|
||||
parser_errposition(pstate, thisrel->location)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1919,8 +1969,7 @@ applyLockingClause(Query *qry, Index rtindex, bool forUpdate, bool noWait)
|
||||
* and yet other instances seen later might have gotten coerced.
|
||||
*/
|
||||
static bool
|
||||
check_parameter_resolution_walker(Node *node,
|
||||
check_parameter_resolution_context *context)
|
||||
check_parameter_resolution_walker(Node *node, ParseState *pstate)
|
||||
{
|
||||
if (node == NULL)
|
||||
return false;
|
||||
@@ -1933,16 +1982,18 @@ check_parameter_resolution_walker(Node *node,
|
||||
int paramno = param->paramid;
|
||||
|
||||
if (paramno <= 0 || /* shouldn't happen, but... */
|
||||
paramno > context->numParams)
|
||||
paramno > pstate->p_numparams)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_PARAMETER),
|
||||
errmsg("there is no parameter $%d", paramno)));
|
||||
errmsg("there is no parameter $%d", paramno),
|
||||
parser_errposition(pstate, param->location)));
|
||||
|
||||
if (param->paramtype != context->paramTypes[paramno - 1])
|
||||
if (param->paramtype != pstate->p_paramtypes[paramno - 1])
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_AMBIGUOUS_PARAMETER),
|
||||
errmsg("could not determine data type of parameter $%d",
|
||||
paramno)));
|
||||
paramno),
|
||||
parser_errposition(pstate, param->location)));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1951,8 +2002,8 @@ check_parameter_resolution_walker(Node *node,
|
||||
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
|
||||
return query_tree_walker((Query *) node,
|
||||
check_parameter_resolution_walker,
|
||||
(void *) context, 0);
|
||||
(void *) pstate, 0);
|
||||
}
|
||||
return expression_tree_walker(node, check_parameter_resolution_walker,
|
||||
(void *) context);
|
||||
(void *) pstate);
|
||||
}
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.620 2008/08/30 01:39:14 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.621 2008/09/01 20:42:44 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -55,6 +55,7 @@
|
||||
#include "catalog/namespace.h"
|
||||
#include "commands/defrem.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "nodes/nodeFuncs.h"
|
||||
#include "parser/gramparse.h"
|
||||
#include "storage/lmgr.h"
|
||||
#include "utils/date.h"
|
||||
@@ -1215,7 +1216,8 @@ zone_value:
|
||||
if (($3 & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) != 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("time zone interval must be HOUR or HOUR TO MINUTE")));
|
||||
errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
|
||||
scanner_errposition(@3)));
|
||||
t->typmods = list_make1(makeIntConst($3, @3));
|
||||
}
|
||||
$$ = makeStringConstCast($2, @2, t);
|
||||
@@ -1227,7 +1229,8 @@ zone_value:
|
||||
&& (($6 & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) != 0))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("time zone interval must be HOUR or HOUR TO MINUTE")));
|
||||
errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
|
||||
scanner_errposition(@6)));
|
||||
t->typmods = list_make2(makeIntConst($6, @6),
|
||||
makeIntConst($3, @3));
|
||||
$$ = makeStringConstCast($5, @5, t);
|
||||
@@ -2286,7 +2289,8 @@ key_match: MATCH FULL
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("MATCH PARTIAL not yet implemented")));
|
||||
errmsg("MATCH PARTIAL not yet implemented"),
|
||||
scanner_errposition(@1)));
|
||||
$$ = FKCONSTR_MATCH_PARTIAL;
|
||||
}
|
||||
| MATCH SIMPLE
|
||||
@@ -2378,7 +2382,8 @@ CreateAsStmt:
|
||||
if (n->intoClause != NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("CREATE TABLE AS cannot specify INTO")));
|
||||
errmsg("CREATE TABLE AS cannot specify INTO"),
|
||||
scanner_errposition(exprLocation((Node *) n->intoClause))));
|
||||
$4->rel->istemp = $2;
|
||||
n->intoClause = $4;
|
||||
$$ = $6;
|
||||
@@ -2799,7 +2804,8 @@ ConstraintAttributeSpec:
|
||||
if ($1 == 0 && $2 != 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE")));
|
||||
errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
|
||||
scanner_errposition(@1)));
|
||||
$$ = $1 | $2;
|
||||
}
|
||||
| ConstraintTimeSpec
|
||||
@@ -2814,7 +2820,8 @@ ConstraintAttributeSpec:
|
||||
if ($2 == 0 && $1 != 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE")));
|
||||
errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
|
||||
scanner_errposition(@1)));
|
||||
$$ = $1 | $2;
|
||||
}
|
||||
| /*EMPTY*/
|
||||
@@ -2986,9 +2993,11 @@ DefineStmt:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("improper qualified name (too many dotted names): %s",
|
||||
NameListToString($3))));
|
||||
NameListToString($3)),
|
||||
scanner_errposition(@3)));
|
||||
break;
|
||||
}
|
||||
r->location = @3;
|
||||
n->typevar = r;
|
||||
n->coldeflist = $6;
|
||||
$$ = (Node *)n;
|
||||
@@ -3128,12 +3137,12 @@ opclass_item:
|
||||
n->number = $2;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| OPERATOR Iconst any_operator '(' oper_argtypes ')' opt_recheck
|
||||
| OPERATOR Iconst any_operator oper_argtypes opt_recheck
|
||||
{
|
||||
CreateOpClassItem *n = makeNode(CreateOpClassItem);
|
||||
n->itemtype = OPCLASS_ITEM_OPERATOR;
|
||||
n->name = $3;
|
||||
n->args = $5;
|
||||
n->args = $4;
|
||||
n->number = $2;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
@@ -3178,7 +3187,8 @@ opt_recheck: RECHECK
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("RECHECK is no longer supported"),
|
||||
errhint("Update your data type.")));
|
||||
errhint("Update your data type."),
|
||||
scanner_errposition(@1)));
|
||||
$$ = TRUE;
|
||||
}
|
||||
| /*EMPTY*/ { $$ = FALSE; }
|
||||
@@ -3445,14 +3455,13 @@ CommentStmt:
|
||||
n->comment = $7;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| COMMENT ON OPERATOR any_operator '(' oper_argtypes ')'
|
||||
IS comment_text
|
||||
| COMMENT ON OPERATOR any_operator oper_argtypes IS comment_text
|
||||
{
|
||||
CommentStmt *n = makeNode(CommentStmt);
|
||||
n->objtype = OBJECT_OPERATOR;
|
||||
n->objname = $4;
|
||||
n->objargs = $6;
|
||||
n->comment = $9;
|
||||
n->objargs = $5;
|
||||
n->comment = $7;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| COMMENT ON CONSTRAINT name ON any_name IS comment_text
|
||||
@@ -4088,8 +4097,8 @@ opt_class: any_name { $$ = $1; }
|
||||
;
|
||||
|
||||
opt_asc_desc: ASC { $$ = SORTBY_ASC; }
|
||||
| DESC { $$ = SORTBY_DESC; }
|
||||
| /*EMPTY*/ { $$ = SORTBY_DEFAULT; }
|
||||
| DESC { $$ = SORTBY_DESC; }
|
||||
| /*EMPTY*/ { $$ = SORTBY_DEFAULT; }
|
||||
;
|
||||
|
||||
opt_nulls_order: NULLS_FIRST { $$ = SORTBY_NULLS_FIRST; }
|
||||
@@ -4464,42 +4473,43 @@ RemoveAggrStmt:
|
||||
;
|
||||
|
||||
RemoveOperStmt:
|
||||
DROP OPERATOR any_operator '(' oper_argtypes ')' opt_drop_behavior
|
||||
DROP OPERATOR any_operator oper_argtypes opt_drop_behavior
|
||||
{
|
||||
RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
|
||||
n->kind = OBJECT_OPERATOR;
|
||||
n->name = $3;
|
||||
n->args = $5;
|
||||
n->behavior = $7;
|
||||
n->args = $4;
|
||||
n->behavior = $5;
|
||||
n->missing_ok = false;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| DROP OPERATOR IF_P EXISTS any_operator '(' oper_argtypes ')' opt_drop_behavior
|
||||
| DROP OPERATOR IF_P EXISTS any_operator oper_argtypes opt_drop_behavior
|
||||
{
|
||||
RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
|
||||
n->kind = OBJECT_OPERATOR;
|
||||
n->name = $5;
|
||||
n->args = $7;
|
||||
n->behavior = $9;
|
||||
n->args = $6;
|
||||
n->behavior = $7;
|
||||
n->missing_ok = true;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
||||
oper_argtypes:
|
||||
Typename
|
||||
'(' Typename ')'
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("missing argument"),
|
||||
errhint("Use NONE to denote the missing argument of a unary operator.")));
|
||||
errhint("Use NONE to denote the missing argument of a unary operator."),
|
||||
scanner_errposition(@3)));
|
||||
}
|
||||
| Typename ',' Typename
|
||||
{ $$ = list_make2($1, $3); }
|
||||
| NONE ',' Typename /* left unary */
|
||||
{ $$ = list_make2(NULL, $3); }
|
||||
| Typename ',' NONE /* right unary */
|
||||
{ $$ = list_make2($1, NULL); }
|
||||
| '(' Typename ',' Typename ')'
|
||||
{ $$ = list_make2($2, $4); }
|
||||
| '(' NONE ',' Typename ')' /* left unary */
|
||||
{ $$ = list_make2(NULL, $4); }
|
||||
| '(' Typename ',' NONE ')' /* right unary */
|
||||
{ $$ = list_make2($2, NULL); }
|
||||
;
|
||||
|
||||
any_operator:
|
||||
@@ -4939,13 +4949,13 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
|
||||
n->newowner = $7;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| ALTER OPERATOR any_operator '(' oper_argtypes ')' OWNER TO RoleId
|
||||
| ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleId
|
||||
{
|
||||
AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
|
||||
n->objectType = OBJECT_OPERATOR;
|
||||
n->object = $3;
|
||||
n->objarg = $5;
|
||||
n->newowner = $9;
|
||||
n->objarg = $4;
|
||||
n->newowner = $7;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId
|
||||
@@ -5108,7 +5118,7 @@ DropRuleStmt:
|
||||
/*****************************************************************************
|
||||
*
|
||||
* QUERY:
|
||||
* NOTIFY <qualified_name> can appear both in rule bodies and
|
||||
* NOTIFY <identifier> can appear both in rule bodies and
|
||||
* as a query-level command
|
||||
*
|
||||
*****************************************************************************/
|
||||
@@ -5116,9 +5126,7 @@ DropRuleStmt:
|
||||
NotifyStmt: NOTIFY ColId
|
||||
{
|
||||
NotifyStmt *n = makeNode(NotifyStmt);
|
||||
n->relation = makeNode(RangeVar);
|
||||
n->relation->relname = $2;
|
||||
n->relation->schemaname = NULL;
|
||||
n->conditionname = $2;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
@@ -5126,9 +5134,7 @@ NotifyStmt: NOTIFY ColId
|
||||
ListenStmt: LISTEN ColId
|
||||
{
|
||||
ListenStmt *n = makeNode(ListenStmt);
|
||||
n->relation = makeNode(RangeVar);
|
||||
n->relation->relname = $2;
|
||||
n->relation->schemaname = NULL;
|
||||
n->conditionname = $2;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
@@ -5137,15 +5143,13 @@ UnlistenStmt:
|
||||
UNLISTEN ColId
|
||||
{
|
||||
UnlistenStmt *n = makeNode(UnlistenStmt);
|
||||
n->relation = makeNode(RangeVar);
|
||||
n->relation->relname = $2;
|
||||
n->relation->schemaname = NULL;
|
||||
n->conditionname = $2;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| UNLISTEN '*'
|
||||
{
|
||||
UnlistenStmt *n = makeNode(UnlistenStmt);
|
||||
n->relation = NULL;
|
||||
n->conditionname = NULL;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
@@ -6119,7 +6123,8 @@ multiple_set_clause:
|
||||
if (list_length($2) != list_length($5))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("number of columns does not match number of values")));
|
||||
errmsg("number of columns does not match number of values"),
|
||||
scanner_errposition(@1)));
|
||||
forboth(col_cell, $2, val_cell, $5)
|
||||
{
|
||||
ResTarget *res_col = (ResTarget *) lfirst(col_cell);
|
||||
@@ -6419,6 +6424,7 @@ sortby: a_expr USING qual_all_Op opt_nulls_order
|
||||
$$->sortby_dir = SORTBY_USING;
|
||||
$$->sortby_nulls = $4;
|
||||
$$->useOp = $3;
|
||||
$$->location = @3;
|
||||
}
|
||||
| a_expr opt_asc_desc opt_nulls_order
|
||||
{
|
||||
@@ -6427,6 +6433,7 @@ sortby: a_expr USING qual_all_Op opt_nulls_order
|
||||
$$->sortby_dir = $2;
|
||||
$$->sortby_nulls = $3;
|
||||
$$->useOp = NIL;
|
||||
$$->location = -1; /* no operator */
|
||||
}
|
||||
;
|
||||
|
||||
@@ -6446,7 +6453,8 @@ select_limit:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("LIMIT #,# syntax is not supported"),
|
||||
errhint("Use separate LIMIT and OFFSET clauses.")));
|
||||
errhint("Use separate LIMIT and OFFSET clauses."),
|
||||
scanner_errposition(@1)));
|
||||
}
|
||||
;
|
||||
|
||||
@@ -6514,7 +6522,7 @@ for_locking_item:
|
||||
;
|
||||
|
||||
locked_rels_list:
|
||||
OF name_list { $$ = $2; }
|
||||
OF qualified_name_list { $$ = $2; }
|
||||
| /* EMPTY */ { $$ = NIL; }
|
||||
;
|
||||
|
||||
@@ -6629,12 +6637,14 @@ table_ref: relation_expr
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("VALUES in FROM must have an alias"),
|
||||
errhint("For example, FROM (VALUES ...) [AS] foo.")));
|
||||
errhint("For example, FROM (VALUES ...) [AS] foo."),
|
||||
scanner_errposition(@1)));
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("subquery in FROM must have an alias"),
|
||||
errhint("For example, FROM (SELECT ...) [AS] foo.")));
|
||||
errhint("For example, FROM (SELECT ...) [AS] foo."),
|
||||
scanner_errposition(@1)));
|
||||
$$ = NULL;
|
||||
}
|
||||
| select_with_parens alias_clause
|
||||
@@ -7089,7 +7099,8 @@ opt_float: '(' Iconst ')'
|
||||
if ($2 < 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("precision for type float must be at least 1 bit")));
|
||||
errmsg("precision for type float must be at least 1 bit"),
|
||||
scanner_errposition(@2)));
|
||||
else if ($2 <= 24)
|
||||
$$ = SystemTypeName("float4");
|
||||
else if ($2 <= 53)
|
||||
@@ -7097,7 +7108,8 @@ opt_float: '(' Iconst ')'
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("precision for type float must be less than 54 bits")));
|
||||
errmsg("precision for type float must be less than 54 bits"),
|
||||
scanner_errposition(@2)));
|
||||
}
|
||||
| /*EMPTY*/
|
||||
{
|
||||
@@ -7734,7 +7746,8 @@ a_expr: c_expr { $$ = $1; }
|
||||
*/
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("UNIQUE predicate is not yet implemented")));
|
||||
errmsg("UNIQUE predicate is not yet implemented"),
|
||||
scanner_errposition(@1)));
|
||||
}
|
||||
| a_expr IS DOCUMENT_P %prec IS
|
||||
{
|
||||
@@ -8874,6 +8887,7 @@ qualified_name:
|
||||
$$->catalogname = NULL;
|
||||
$$->schemaname = NULL;
|
||||
$$->relname = $1;
|
||||
$$->location = @1;
|
||||
}
|
||||
| relation_name indirection
|
||||
{
|
||||
@@ -8895,9 +8909,11 @@ qualified_name:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("improper qualified name (too many dotted names): %s",
|
||||
NameListToString(lcons(makeString($1), $2)))));
|
||||
NameListToString(lcons(makeString($1), $2))),
|
||||
scanner_errposition(@1)));
|
||||
break;
|
||||
}
|
||||
$$->location = @1;
|
||||
}
|
||||
;
|
||||
|
||||
@@ -9494,7 +9510,8 @@ SpecialRuleRelation:
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("OLD used in query that is not in a rule")));
|
||||
errmsg("OLD used in query that is not in a rule"),
|
||||
scanner_errposition(@1)));
|
||||
}
|
||||
| NEW
|
||||
{
|
||||
@@ -9503,7 +9520,8 @@ SpecialRuleRelation:
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("NEW used in query that is not in a rule")));
|
||||
errmsg("NEW used in query that is not in a rule"),
|
||||
scanner_errposition(@1)));
|
||||
}
|
||||
;
|
||||
|
||||
@@ -9689,13 +9707,15 @@ makeOverlaps(List *largs, List *rargs, int location)
|
||||
else if (list_length(largs) != 2)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("wrong number of parameters on left side of OVERLAPS expression")));
|
||||
errmsg("wrong number of parameters on left side of OVERLAPS expression"),
|
||||
scanner_errposition(location)));
|
||||
if (list_length(rargs) == 1)
|
||||
rargs = lappend(rargs, rargs);
|
||||
else if (list_length(rargs) != 2)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("wrong number of parameters on right side of OVERLAPS expression")));
|
||||
errmsg("wrong number of parameters on right side of OVERLAPS expression"),
|
||||
scanner_errposition(location)));
|
||||
n->args = list_concat(largs, rargs);
|
||||
n->agg_star = FALSE;
|
||||
n->agg_distinct = FALSE;
|
||||
@@ -9813,7 +9833,8 @@ insertSelectOptions(SelectStmt *stmt,
|
||||
if (stmt->sortClause)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("multiple ORDER BY clauses not allowed")));
|
||||
errmsg("multiple ORDER BY clauses not allowed"),
|
||||
scanner_errposition(exprLocation((Node *) sortClause))));
|
||||
stmt->sortClause = sortClause;
|
||||
}
|
||||
/* We can handle multiple locking clauses, though */
|
||||
@@ -9823,7 +9844,8 @@ insertSelectOptions(SelectStmt *stmt,
|
||||
if (stmt->limitOffset)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("multiple OFFSET clauses not allowed")));
|
||||
errmsg("multiple OFFSET clauses not allowed"),
|
||||
scanner_errposition(exprLocation(limitOffset))));
|
||||
stmt->limitOffset = limitOffset;
|
||||
}
|
||||
if (limitCount)
|
||||
@@ -9831,7 +9853,8 @@ insertSelectOptions(SelectStmt *stmt,
|
||||
if (stmt->limitCount)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("multiple LIMIT clauses not allowed")));
|
||||
errmsg("multiple LIMIT clauses not allowed"),
|
||||
scanner_errposition(exprLocation(limitCount))));
|
||||
stmt->limitCount = limitCount;
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.82 2008/08/28 23:09:47 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.83 2008/09/01 20:42:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -70,7 +70,9 @@ transformAggregateCall(ParseState *pstate, Aggref *agg)
|
||||
if (checkExprHasAggs((Node *) agg->args))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
errmsg("aggregate function calls cannot be nested")));
|
||||
errmsg("aggregate function calls cannot be nested"),
|
||||
parser_errposition(pstate,
|
||||
locate_agg_of_level((Node *) agg->args, 0))));
|
||||
}
|
||||
|
||||
if (min_varlevel < 0)
|
||||
@@ -117,11 +119,15 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
|
||||
if (checkExprHasAggs(qry->jointree->quals))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
errmsg("aggregates not allowed in WHERE clause")));
|
||||
errmsg("aggregates not allowed in WHERE clause"),
|
||||
parser_errposition(pstate,
|
||||
locate_agg_of_level(qry->jointree->quals, 0))));
|
||||
if (checkExprHasAggs((Node *) qry->jointree->fromlist))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
errmsg("aggregates not allowed in JOIN conditions")));
|
||||
errmsg("aggregates not allowed in JOIN conditions"),
|
||||
parser_errposition(pstate,
|
||||
locate_agg_of_level((Node *) qry->jointree->fromlist, 0))));
|
||||
|
||||
/*
|
||||
* No aggregates allowed in GROUP BY clauses, either.
|
||||
@@ -140,7 +146,9 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
|
||||
if (checkExprHasAggs(expr))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
errmsg("aggregates not allowed in GROUP BY clause")));
|
||||
errmsg("aggregates not allowed in GROUP BY clause"),
|
||||
parser_errposition(pstate,
|
||||
locate_agg_of_level(expr, 0))));
|
||||
groupClauses = lcons(expr, groupClauses);
|
||||
}
|
||||
|
||||
@@ -327,13 +335,14 @@ check_ungrouped_columns_walker(Node *node,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
errmsg("column \"%s.%s\" must appear in the GROUP BY clause or be used in an aggregate function",
|
||||
rte->eref->aliasname, attname)));
|
||||
rte->eref->aliasname, attname),
|
||||
parser_errposition(context->pstate, var->location)));
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
errmsg("subquery uses ungrouped column \"%s.%s\" from outer query",
|
||||
rte->eref->aliasname, attname)));
|
||||
|
||||
rte->eref->aliasname, attname),
|
||||
parser_errposition(context->pstate, var->location)));
|
||||
}
|
||||
|
||||
if (IsA(node, Query))
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.178 2008/08/30 01:39:14 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.179 2008/09/01 20:42:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -66,12 +66,13 @@ static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,
|
||||
Var *l_colvar, Var *r_colvar);
|
||||
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
|
||||
List **tlist, int clause);
|
||||
static int get_matching_location(int sortgroupref,
|
||||
List *sortgrouprefs, List *exprs);
|
||||
static List *addTargetToSortList(ParseState *pstate, TargetEntry *tle,
|
||||
List *sortlist, List *targetlist,
|
||||
SortByDir sortby_dir, SortByNulls sortby_nulls,
|
||||
List *sortby_opname, bool resolveUnknown);
|
||||
List *sortlist, List *targetlist, SortBy *sortby,
|
||||
bool resolveUnknown);
|
||||
static List *addTargetToGroupList(ParseState *pstate, TargetEntry *tle,
|
||||
List *grouplist, List *targetlist,
|
||||
List *grouplist, List *targetlist, int location,
|
||||
bool resolveUnknown);
|
||||
|
||||
|
||||
@@ -163,7 +164,8 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
|
||||
* free_parsestate() will eventually do the corresponding heap_close(),
|
||||
* but *not* release the lock.
|
||||
*/
|
||||
pstate->p_target_relation = heap_openrv(relation, RowExclusiveLock);
|
||||
pstate->p_target_relation = parserOpenTable(pstate, relation,
|
||||
RowExclusiveLock);
|
||||
|
||||
/*
|
||||
* Now build an RTE.
|
||||
@@ -390,7 +392,9 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
||||
errmsg("JOIN/ON clause refers to \"%s\", which is not part of JOIN",
|
||||
rt_fetch(varno, pstate->p_rtable)->eref->aliasname)));
|
||||
rt_fetch(varno, pstate->p_rtable)->eref->aliasname),
|
||||
parser_errposition(pstate,
|
||||
locate_var_of_relation(result, varno, 0))));
|
||||
}
|
||||
bms_free(clause_varnos);
|
||||
|
||||
@@ -431,12 +435,11 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
|
||||
/*
|
||||
* We require user to supply an alias for a subselect, per SQL92. To relax
|
||||
* this, we'd have to be prepared to gin up a unique alias for an
|
||||
* unlabeled subselect.
|
||||
* unlabeled subselect. (This is just elog, not ereport, because the
|
||||
* grammar should have enforced it already.)
|
||||
*/
|
||||
if (r->alias == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("subquery in FROM must have an alias")));
|
||||
elog(ERROR, "subquery in FROM must have an alias");
|
||||
|
||||
/*
|
||||
* Analyze and transform the subquery.
|
||||
@@ -447,13 +450,16 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
|
||||
* Check that we got something reasonable. Many of these conditions are
|
||||
* impossible given restrictions of the grammar, but check 'em anyway.
|
||||
*/
|
||||
if (query->commandType != CMD_SELECT ||
|
||||
if (!IsA(query, Query) ||
|
||||
query->commandType != CMD_SELECT ||
|
||||
query->utilityStmt != NULL)
|
||||
elog(ERROR, "expected SELECT query from subquery in FROM");
|
||||
if (query->intoClause != NULL)
|
||||
elog(ERROR, "unexpected non-SELECT command in subquery in FROM");
|
||||
if (query->intoClause)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("subquery in FROM cannot have SELECT INTO")));
|
||||
errmsg("subquery in FROM cannot have SELECT INTO"),
|
||||
parser_errposition(pstate,
|
||||
exprLocation((Node *) query->intoClause))));
|
||||
|
||||
/*
|
||||
* The subquery cannot make use of any variables from FROM items created
|
||||
@@ -473,7 +479,9 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
|
||||
if (contain_vars_of_level((Node *) query, 1))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
||||
errmsg("subquery in FROM cannot refer to other relations of same query level")));
|
||||
errmsg("subquery in FROM cannot refer to other relations of same query level"),
|
||||
parser_errposition(pstate,
|
||||
locate_var_of_level((Node *) query, 1))));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -522,7 +530,9 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
|
||||
if (contain_vars_of_level(funcexpr, 0))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
||||
errmsg("function expression in FROM cannot refer to other relations of same query level")));
|
||||
errmsg("function expression in FROM cannot refer to other relations of same query level"),
|
||||
parser_errposition(pstate,
|
||||
locate_var_of_level(funcexpr, 0))));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -534,7 +544,9 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
|
||||
if (checkExprHasAggs(funcexpr))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
errmsg("cannot use aggregate function in function expression in FROM")));
|
||||
errmsg("cannot use aggregate function in function expression in FROM"),
|
||||
parser_errposition(pstate,
|
||||
locate_agg_of_level(funcexpr, 0))));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -709,9 +721,9 @@ transformFromClauseItem(ParseState *pstate, Node *n,
|
||||
*
|
||||
* Note: expandRTE returns new lists, safe for me to modify
|
||||
*/
|
||||
expandRTE(l_rte, l_rtindex, 0, false,
|
||||
expandRTE(l_rte, l_rtindex, 0, -1, false,
|
||||
&l_colnames, &l_colvars);
|
||||
expandRTE(r_rte, r_rtindex, 0, false,
|
||||
expandRTE(r_rte, r_rtindex, 0, -1, false,
|
||||
&r_colnames, &r_colvars);
|
||||
|
||||
/*
|
||||
@@ -1109,7 +1121,9 @@ transformLimitClause(ParseState *pstate, Node *clause,
|
||||
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
||||
/* translator: %s is name of a SQL construct, eg LIMIT */
|
||||
errmsg("argument of %s must not contain variables",
|
||||
constructName)));
|
||||
constructName),
|
||||
parser_errposition(pstate,
|
||||
locate_var_of_level(qual, 0))));
|
||||
}
|
||||
if (checkExprHasAggs(qual))
|
||||
{
|
||||
@@ -1117,7 +1131,9 @@ transformLimitClause(ParseState *pstate, Node *clause,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
/* translator: %s is name of a SQL construct, eg LIMIT */
|
||||
errmsg("argument of %s must not contain aggregates",
|
||||
constructName)));
|
||||
constructName),
|
||||
parser_errposition(pstate,
|
||||
locate_agg_of_level(qual, 0))));
|
||||
}
|
||||
|
||||
return qual;
|
||||
@@ -1365,6 +1381,7 @@ transformGroupClause(ParseState *pstate, List *grouplist,
|
||||
if (!found)
|
||||
result = addTargetToGroupList(pstate, tle,
|
||||
result, *targetlist,
|
||||
exprLocation(gexpr),
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -1396,10 +1413,7 @@ transformSortClause(ParseState *pstate,
|
||||
targetlist, ORDER_CLAUSE);
|
||||
|
||||
sortlist = addTargetToSortList(pstate, tle,
|
||||
sortlist, *targetlist,
|
||||
sortby->sortby_dir,
|
||||
sortby->sortby_nulls,
|
||||
sortby->useOp,
|
||||
sortlist, *targetlist, sortby,
|
||||
resolveUnknown);
|
||||
}
|
||||
|
||||
@@ -1450,7 +1464,9 @@ transformDistinctClause(ParseState *pstate,
|
||||
if (tle->resjunk)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
||||
errmsg("for SELECT DISTINCT, ORDER BY expressions must appear in select list")));
|
||||
errmsg("for SELECT DISTINCT, ORDER BY expressions must appear in select list"),
|
||||
parser_errposition(pstate,
|
||||
exprLocation((Node *) tle->expr))));
|
||||
result = lappend(result, copyObject(scl));
|
||||
}
|
||||
|
||||
@@ -1466,6 +1482,7 @@ transformDistinctClause(ParseState *pstate,
|
||||
continue; /* ignore junk */
|
||||
result = addTargetToGroupList(pstate, tle,
|
||||
result, *targetlist,
|
||||
exprLocation((Node *) tle->expr),
|
||||
true);
|
||||
}
|
||||
|
||||
@@ -1490,28 +1507,29 @@ transformDistinctOnClause(ParseState *pstate, List *distinctlist,
|
||||
List **targetlist, List *sortClause)
|
||||
{
|
||||
List *result = NIL;
|
||||
ListCell *slitem;
|
||||
ListCell *dlitem;
|
||||
Bitmapset *refnos = NULL;
|
||||
int sortgroupref;
|
||||
List *sortgrouprefs = NIL;
|
||||
bool skipped_sortitem;
|
||||
ListCell *lc;
|
||||
ListCell *lc2;
|
||||
|
||||
/*
|
||||
* Add all the DISTINCT ON expressions to the tlist (if not already
|
||||
* present, they are added as resjunk items). Assign sortgroupref
|
||||
* numbers to them, and form a bitmapset of these numbers. (A
|
||||
* bitmapset is convenient here because we don't care about order
|
||||
* and we can discard duplicates.)
|
||||
* numbers to them, and make a list of these numbers. (NB: we rely
|
||||
* below on the sortgrouprefs list being one-for-one with the original
|
||||
* distinctlist. Also notice that we could have duplicate DISTINCT ON
|
||||
* expressions and hence duplicate entries in sortgrouprefs.)
|
||||
*/
|
||||
foreach(dlitem, distinctlist)
|
||||
foreach(lc, distinctlist)
|
||||
{
|
||||
Node *dexpr = (Node *) lfirst(dlitem);
|
||||
Node *dexpr = (Node *) lfirst(lc);
|
||||
int sortgroupref;
|
||||
TargetEntry *tle;
|
||||
|
||||
tle = findTargetlistEntry(pstate, dexpr,
|
||||
targetlist, DISTINCT_ON_CLAUSE);
|
||||
sortgroupref = assignSortGroupRef(tle, *targetlist);
|
||||
refnos = bms_add_member(refnos, sortgroupref);
|
||||
sortgrouprefs = lappend_int(sortgrouprefs, sortgroupref);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1523,16 +1541,20 @@ transformDistinctOnClause(ParseState *pstate, List *distinctlist,
|
||||
* skipped an ORDER BY item that wasn't in DISTINCT ON.
|
||||
*/
|
||||
skipped_sortitem = false;
|
||||
foreach(slitem, sortClause)
|
||||
foreach(lc, sortClause)
|
||||
{
|
||||
SortGroupClause *scl = (SortGroupClause *) lfirst(slitem);
|
||||
SortGroupClause *scl = (SortGroupClause *) lfirst(lc);
|
||||
|
||||
if (bms_is_member(scl->tleSortGroupRef, refnos))
|
||||
if (list_member_int(sortgrouprefs, scl->tleSortGroupRef))
|
||||
{
|
||||
if (skipped_sortitem)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
||||
errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions")));
|
||||
errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions"),
|
||||
parser_errposition(pstate,
|
||||
get_matching_location(scl->tleSortGroupRef,
|
||||
sortgrouprefs,
|
||||
distinctlist))));
|
||||
else
|
||||
result = lappend(result, copyObject(scl));
|
||||
}
|
||||
@@ -1549,8 +1571,10 @@ transformDistinctOnClause(ParseState *pstate, List *distinctlist,
|
||||
* better to throw an error or warning here. But historically we've
|
||||
* allowed it, so keep doing so.)
|
||||
*/
|
||||
while ((sortgroupref = bms_first_member(refnos)) >= 0)
|
||||
forboth(lc, distinctlist, lc2, sortgrouprefs)
|
||||
{
|
||||
Node *dexpr = (Node *) lfirst(lc);
|
||||
int sortgroupref = lfirst_int(lc2);
|
||||
TargetEntry *tle = get_sortgroupref_tle(sortgroupref, *targetlist);
|
||||
|
||||
if (targetIsInSortList(tle, InvalidOid, result))
|
||||
@@ -1558,15 +1582,44 @@ transformDistinctOnClause(ParseState *pstate, List *distinctlist,
|
||||
if (skipped_sortitem)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
|
||||
errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions")));
|
||||
errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions"),
|
||||
parser_errposition(pstate, exprLocation(dexpr))));
|
||||
result = addTargetToGroupList(pstate, tle,
|
||||
result, *targetlist,
|
||||
exprLocation(dexpr),
|
||||
true);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_matching_location
|
||||
* Get the exprLocation of the exprs member corresponding to the
|
||||
* (first) member of sortgrouprefs that equals sortgroupref.
|
||||
*
|
||||
* This is used so that we can point at a troublesome DISTINCT ON entry.
|
||||
* (Note that we need to use the original untransformed DISTINCT ON list
|
||||
* item, as whatever TLE it corresponds to will very possibly have a
|
||||
* parse location pointing to some matching entry in the SELECT list
|
||||
* or ORDER BY list.)
|
||||
*/
|
||||
static int
|
||||
get_matching_location(int sortgroupref, List *sortgrouprefs, List *exprs)
|
||||
{
|
||||
ListCell *lcs;
|
||||
ListCell *lce;
|
||||
|
||||
forboth(lcs, sortgrouprefs, lce, exprs)
|
||||
{
|
||||
if (lfirst_int(lcs) == sortgroupref)
|
||||
return exprLocation((Node *) lfirst(lce));
|
||||
}
|
||||
/* if no match, caller blew it */
|
||||
elog(ERROR, "get_matching_location: no matching sortgroupref");
|
||||
return -1; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
/*
|
||||
* addTargetToSortList
|
||||
* If the given targetlist entry isn't already in the SortGroupClause
|
||||
@@ -1582,14 +1635,15 @@ transformDistinctOnClause(ParseState *pstate, List *distinctlist,
|
||||
*/
|
||||
static List *
|
||||
addTargetToSortList(ParseState *pstate, TargetEntry *tle,
|
||||
List *sortlist, List *targetlist,
|
||||
SortByDir sortby_dir, SortByNulls sortby_nulls,
|
||||
List *sortby_opname, bool resolveUnknown)
|
||||
List *sortlist, List *targetlist, SortBy *sortby,
|
||||
bool resolveUnknown)
|
||||
{
|
||||
Oid restype = exprType((Node *) tle->expr);
|
||||
Oid sortop;
|
||||
Oid eqop;
|
||||
bool reverse;
|
||||
int location;
|
||||
ParseCallbackState pcbstate;
|
||||
|
||||
/* if tlist item is an UNKNOWN literal, change it to TEXT */
|
||||
if (restype == UNKNOWNOID && resolveUnknown)
|
||||
@@ -1602,8 +1656,21 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
|
||||
restype = TEXTOID;
|
||||
}
|
||||
|
||||
/*
|
||||
* Rather than clutter the API of get_sort_group_operators and the other
|
||||
* functions we're about to use, make use of error context callback to
|
||||
* mark any error reports with a parse position. We point to the operator
|
||||
* location if present, else to the expression being sorted. (NB: use
|
||||
* the original untransformed expression here; the TLE entry might well
|
||||
* point at a duplicate expression in the regular SELECT list.)
|
||||
*/
|
||||
location = sortby->location;
|
||||
if (location < 0)
|
||||
location = exprLocation(sortby->node);
|
||||
setup_parser_errposition_callback(&pcbstate, pstate, location);
|
||||
|
||||
/* determine the sortop, eqop, and directionality */
|
||||
switch (sortby_dir)
|
||||
switch (sortby->sortby_dir)
|
||||
{
|
||||
case SORTBY_DEFAULT:
|
||||
case SORTBY_ASC:
|
||||
@@ -1619,8 +1686,8 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
|
||||
reverse = true;
|
||||
break;
|
||||
case SORTBY_USING:
|
||||
Assert(sortby_opname != NIL);
|
||||
sortop = compatible_oper_opid(sortby_opname,
|
||||
Assert(sortby->useOp != NIL);
|
||||
sortop = compatible_oper_opid(sortby->useOp,
|
||||
restype,
|
||||
restype,
|
||||
false);
|
||||
@@ -1635,17 +1702,19 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("operator %s is not a valid ordering operator",
|
||||
strVal(llast(sortby_opname))),
|
||||
strVal(llast(sortby->useOp))),
|
||||
errhint("Ordering operators must be \"<\" or \">\" members of btree operator families.")));
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized sortby_dir: %d", sortby_dir);
|
||||
elog(ERROR, "unrecognized sortby_dir: %d", sortby->sortby_dir);
|
||||
sortop = InvalidOid; /* keep compiler quiet */
|
||||
eqop = InvalidOid;
|
||||
reverse = false;
|
||||
break;
|
||||
}
|
||||
|
||||
cancel_parser_errposition_callback(&pcbstate);
|
||||
|
||||
/* avoid making duplicate sortlist entries */
|
||||
if (!targetIsInSortList(tle, sortop, sortlist))
|
||||
{
|
||||
@@ -1656,7 +1725,7 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
|
||||
sortcl->eqop = eqop;
|
||||
sortcl->sortop = sortop;
|
||||
|
||||
switch (sortby_nulls)
|
||||
switch (sortby->sortby_nulls)
|
||||
{
|
||||
case SORTBY_NULLS_DEFAULT:
|
||||
/* NULLS FIRST is default for DESC; other way for ASC */
|
||||
@@ -1669,7 +1738,8 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
|
||||
sortcl->nulls_first = false;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized sortby_nulls: %d", sortby_nulls);
|
||||
elog(ERROR, "unrecognized sortby_nulls: %d",
|
||||
sortby->sortby_nulls);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1690,6 +1760,11 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
|
||||
* the TLE is considered "already in the list" if it appears there with any
|
||||
* sorting semantics.
|
||||
*
|
||||
* location is the parse location to be fingered in event of trouble. Note
|
||||
* that we can't rely on exprLocation(tle->expr), because that might point
|
||||
* to a SELECT item that matches the GROUP BY item; it'd be pretty confusing
|
||||
* to report such a location.
|
||||
*
|
||||
* If resolveUnknown is TRUE, convert TLEs of type UNKNOWN to TEXT. If not,
|
||||
* do nothing (which implies the search for an equality operator will fail).
|
||||
* pstate should be provided if resolveUnknown is TRUE, but can be NULL
|
||||
@@ -1699,7 +1774,7 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
|
||||
*/
|
||||
static List *
|
||||
addTargetToGroupList(ParseState *pstate, TargetEntry *tle,
|
||||
List *grouplist, List *targetlist,
|
||||
List *grouplist, List *targetlist, int location,
|
||||
bool resolveUnknown)
|
||||
{
|
||||
Oid restype = exprType((Node *) tle->expr);
|
||||
@@ -1721,12 +1796,17 @@ addTargetToGroupList(ParseState *pstate, TargetEntry *tle,
|
||||
if (!targetIsInSortList(tle, InvalidOid, grouplist))
|
||||
{
|
||||
SortGroupClause *grpcl = makeNode(SortGroupClause);
|
||||
ParseCallbackState pcbstate;
|
||||
|
||||
setup_parser_errposition_callback(&pcbstate, pstate, location);
|
||||
|
||||
/* determine the eqop and optional sortop */
|
||||
get_sort_group_operators(restype,
|
||||
false, true, false,
|
||||
&sortop, &eqop, NULL);
|
||||
|
||||
cancel_parser_errposition_callback(&pcbstate);
|
||||
|
||||
grpcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
|
||||
grpcl->eqop = eqop;
|
||||
grpcl->sortop = sortop;
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.165 2008/08/28 23:09:47 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.166 2008/09/01 20:42:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -180,6 +180,7 @@ coerce_type(ParseState *pstate, Node *node,
|
||||
Oid baseTypeId;
|
||||
int32 baseTypeMod;
|
||||
Type targetType;
|
||||
ParseCallbackState pcbstate;
|
||||
|
||||
/*
|
||||
* If the target type is a domain, we want to call its base type's
|
||||
@@ -207,6 +208,12 @@ coerce_type(ParseState *pstate, Node *node,
|
||||
else
|
||||
newcon->location = location;
|
||||
|
||||
/*
|
||||
* Set up to point at the constant's text if the input routine
|
||||
* throws an error.
|
||||
*/
|
||||
setup_parser_errposition_callback(&pcbstate, pstate, con->location);
|
||||
|
||||
/*
|
||||
* We pass typmod -1 to the input routine, primarily because existing
|
||||
* input routines follow implicit-coercion semantics for length
|
||||
@@ -223,6 +230,8 @@ coerce_type(ParseState *pstate, Node *node,
|
||||
else
|
||||
newcon->constvalue = stringTypeDatum(targetType, NULL, -1);
|
||||
|
||||
cancel_parser_errposition_callback(&pcbstate);
|
||||
|
||||
result = (Node *) newcon;
|
||||
|
||||
/* If target is a domain, apply constraints. */
|
||||
@@ -257,7 +266,8 @@ coerce_type(ParseState *pstate, Node *node,
|
||||
paramno > toppstate->p_numparams)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_PARAMETER),
|
||||
errmsg("there is no parameter $%d", paramno)));
|
||||
errmsg("there is no parameter $%d", paramno),
|
||||
parser_errposition(pstate, param->location)));
|
||||
|
||||
if (toppstate->p_paramtypes[paramno - 1] == UNKNOWNOID)
|
||||
{
|
||||
@@ -277,7 +287,8 @@ coerce_type(ParseState *pstate, Node *node,
|
||||
paramno),
|
||||
errdetail("%s versus %s",
|
||||
format_type_be(toppstate->p_paramtypes[paramno - 1]),
|
||||
format_type_be(targetTypeId))));
|
||||
format_type_be(targetTypeId)),
|
||||
parser_errposition(pstate, param->location)));
|
||||
}
|
||||
|
||||
param->paramtype = targetTypeId;
|
||||
@@ -819,10 +830,11 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
|
||||
{
|
||||
int rtindex = ((Var *) node)->varno;
|
||||
int sublevels_up = ((Var *) node)->varlevelsup;
|
||||
int vlocation = ((Var *) node)->location;
|
||||
RangeTblEntry *rte;
|
||||
|
||||
rte = GetRTEByRangeTablePosn(pstate, rtindex, sublevels_up);
|
||||
expandRTE(rte, rtindex, sublevels_up, false,
|
||||
expandRTE(rte, rtindex, sublevels_up, vlocation, false,
|
||||
NULL, &args);
|
||||
}
|
||||
else
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.233 2008/08/30 01:39:14 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.234 2008/09/01 20:42:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -122,7 +122,7 @@ transformExpr(ParseState *pstate, Node *expr)
|
||||
A_Const *con = (A_Const *) expr;
|
||||
Value *val = &con->val;
|
||||
|
||||
result = (Node *) make_const(val, con->location);
|
||||
result = (Node *) make_const(pstate, val, con->location);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -454,6 +454,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
|
||||
* "rel.*".
|
||||
*/
|
||||
if (refnameRangeTblEntry(pstate, NULL, name1,
|
||||
cref->location,
|
||||
&levels_up) != NULL)
|
||||
node = transformWholeRowRef(pstate, NULL, name1,
|
||||
cref->location);
|
||||
@@ -621,7 +622,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
|
||||
* return a pointer to it.
|
||||
*/
|
||||
static Oid *
|
||||
find_param_type(ParseState *pstate, int paramno)
|
||||
find_param_type(ParseState *pstate, int paramno, int location)
|
||||
{
|
||||
Oid *result;
|
||||
|
||||
@@ -635,14 +636,15 @@ find_param_type(ParseState *pstate, int paramno)
|
||||
if (paramno <= 0) /* probably can't happen? */
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_PARAMETER),
|
||||
errmsg("there is no parameter $%d", paramno)));
|
||||
errmsg("there is no parameter $%d", paramno),
|
||||
parser_errposition(pstate, location)));
|
||||
if (paramno > pstate->p_numparams)
|
||||
{
|
||||
if (!pstate->p_variableparams)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_PARAMETER),
|
||||
errmsg("there is no parameter $%d",
|
||||
paramno)));
|
||||
errmsg("there is no parameter $%d", paramno),
|
||||
parser_errposition(pstate, location)));
|
||||
/* Okay to enlarge param array */
|
||||
if (pstate->p_paramtypes)
|
||||
pstate->p_paramtypes = (Oid *) repalloc(pstate->p_paramtypes,
|
||||
@@ -672,7 +674,7 @@ static Node *
|
||||
transformParamRef(ParseState *pstate, ParamRef *pref)
|
||||
{
|
||||
int paramno = pref->number;
|
||||
Oid *pptype = find_param_type(pstate, paramno);
|
||||
Oid *pptype = find_param_type(pstate, paramno, pref->location);
|
||||
Param *param;
|
||||
|
||||
param = makeNode(Param);
|
||||
@@ -1235,10 +1237,22 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
|
||||
|
||||
pstate->p_hasSubLinks = true;
|
||||
qtree = parse_sub_analyze(sublink->subselect, pstate);
|
||||
if (qtree->commandType != CMD_SELECT ||
|
||||
qtree->utilityStmt != NULL ||
|
||||
qtree->intoClause != NULL)
|
||||
elog(ERROR, "bad query in sub-select");
|
||||
|
||||
/*
|
||||
* Check that we got something reasonable. Many of these conditions are
|
||||
* impossible given restrictions of the grammar, but check 'em anyway.
|
||||
*/
|
||||
if (!IsA(qtree, Query) ||
|
||||
qtree->commandType != CMD_SELECT ||
|
||||
qtree->utilityStmt != NULL)
|
||||
elog(ERROR, "unexpected non-SELECT command in SubLink");
|
||||
if (qtree->intoClause)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("subquery cannot have SELECT INTO"),
|
||||
parser_errposition(pstate,
|
||||
exprLocation((Node *) qtree->intoClause))));
|
||||
|
||||
sublink->subselect = (Node *) qtree;
|
||||
|
||||
if (sublink->subLinkType == EXISTS_SUBLINK)
|
||||
@@ -1445,7 +1459,8 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("could not find element type for data type %s",
|
||||
format_type_be(array_type))));
|
||||
format_type_be(array_type)),
|
||||
parser_errposition(pstate, a->location)));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1455,7 +1470,8 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("could not find array type for data type %s",
|
||||
format_type_be(element_type))));
|
||||
format_type_be(element_type)),
|
||||
parser_errposition(pstate, a->location)));
|
||||
}
|
||||
coerce_hard = false;
|
||||
}
|
||||
@@ -1823,7 +1839,7 @@ transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr)
|
||||
/* If a parameter is used, it must be of type REFCURSOR */
|
||||
if (cexpr->cursor_name == NULL)
|
||||
{
|
||||
Oid *pptype = find_param_type(pstate, cexpr->cursor_param);
|
||||
Oid *pptype = find_param_type(pstate, cexpr->cursor_param, -1);
|
||||
|
||||
if (pstate->p_variableparams && *pptype == UNKNOWNOID)
|
||||
{
|
||||
@@ -1866,12 +1882,12 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
|
||||
|
||||
/* Look up the referenced RTE, creating it if needed */
|
||||
|
||||
rte = refnameRangeTblEntry(pstate, schemaname, relname,
|
||||
rte = refnameRangeTblEntry(pstate, schemaname, relname, location,
|
||||
&sublevels_up);
|
||||
|
||||
if (rte == NULL)
|
||||
rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname),
|
||||
location);
|
||||
rte = addImplicitRTE(pstate,
|
||||
makeRangeVar(schemaname, relname, location));
|
||||
|
||||
vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.206 2008/08/28 23:09:47 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.207 2008/09/01 20:42:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -270,7 +270,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("could not find array type for data type %s",
|
||||
format_type_be(newa->element_typeid))));
|
||||
format_type_be(newa->element_typeid)),
|
||||
parser_errposition(pstate, exprLocation((Node *) vargs))));
|
||||
newa->multidims = false;
|
||||
newa->location = exprLocation((Node *) vargs);
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.102 2008/08/28 23:09:47 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.103 2008/09/01 20:42:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -29,6 +29,9 @@
|
||||
#include "utils/varbit.h"
|
||||
|
||||
|
||||
static void pcb_error_callback(void *arg);
|
||||
|
||||
|
||||
/*
|
||||
* make_parsestate
|
||||
* Allocate and initialize a new ParseState.
|
||||
@@ -112,6 +115,62 @@ parser_errposition(ParseState *pstate, int location)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* setup_parser_errposition_callback
|
||||
* Arrange for non-parser errors to report an error position
|
||||
*
|
||||
* Sometimes the parser calls functions that aren't part of the parser
|
||||
* subsystem and can't reasonably be passed a ParseState; yet we would
|
||||
* like any errors thrown in those functions to be tagged with a parse
|
||||
* error location. Use this function to set up an error context stack
|
||||
* entry that will accomplish that. Usage pattern:
|
||||
*
|
||||
* declare a local variable "ParseCallbackState pcbstate"
|
||||
* ...
|
||||
* setup_parser_errposition_callback(&pcbstate, pstate, location);
|
||||
* call function that might throw error;
|
||||
* cancel_parser_errposition_callback(&pcbstate);
|
||||
*/
|
||||
void
|
||||
setup_parser_errposition_callback(ParseCallbackState *pcbstate,
|
||||
ParseState *pstate, int location)
|
||||
{
|
||||
/* Setup error traceback support for ereport() */
|
||||
pcbstate->pstate = pstate;
|
||||
pcbstate->location = location;
|
||||
pcbstate->errcontext.callback = pcb_error_callback;
|
||||
pcbstate->errcontext.arg = (void *) pcbstate;
|
||||
pcbstate->errcontext.previous = error_context_stack;
|
||||
error_context_stack = &pcbstate->errcontext;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cancel a previously-set-up errposition callback.
|
||||
*/
|
||||
void
|
||||
cancel_parser_errposition_callback(ParseCallbackState *pcbstate)
|
||||
{
|
||||
/* Pop the error context stack */
|
||||
error_context_stack = pcbstate->errcontext.previous;
|
||||
}
|
||||
|
||||
/*
|
||||
* Error context callback for inserting parser error location.
|
||||
*
|
||||
* Note that this will be called for *any* error occurring while the
|
||||
* callback is installed. We avoid inserting an irrelevant error location
|
||||
* if the error is a query cancel --- are there any other important cases?
|
||||
*/
|
||||
static void
|
||||
pcb_error_callback(void *arg)
|
||||
{
|
||||
ParseCallbackState *pcbstate = (ParseCallbackState *) arg;
|
||||
|
||||
if (geterrcode() != ERRCODE_QUERY_CANCELED)
|
||||
(void) parser_errposition(pcbstate->pstate, pcbstate->location);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* make_var
|
||||
* Build a Var node for an attribute identified by RTE and attrno
|
||||
@@ -344,14 +403,15 @@ transformArraySubscripts(ParseState *pstate,
|
||||
* too many examples that fail if we try.
|
||||
*/
|
||||
Const *
|
||||
make_const(Value *value, int location)
|
||||
make_const(ParseState *pstate, Value *value, int location)
|
||||
{
|
||||
Const *con;
|
||||
Datum val;
|
||||
int64 val64;
|
||||
Oid typeid;
|
||||
int typelen;
|
||||
bool typebyval;
|
||||
Const *con;
|
||||
ParseCallbackState pcbstate;
|
||||
|
||||
switch (nodeTag(value))
|
||||
{
|
||||
@@ -392,10 +452,13 @@ make_const(Value *value, int location)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* arrange to report location if numeric_in() fails */
|
||||
setup_parser_errposition_callback(&pcbstate, pstate, location);
|
||||
val = DirectFunctionCall3(numeric_in,
|
||||
CStringGetDatum(strVal(value)),
|
||||
ObjectIdGetDatum(InvalidOid),
|
||||
Int32GetDatum(-1));
|
||||
cancel_parser_errposition_callback(&pcbstate);
|
||||
|
||||
typeid = NUMERICOID;
|
||||
typelen = -1; /* variable len */
|
||||
@@ -417,10 +480,13 @@ make_const(Value *value, int location)
|
||||
break;
|
||||
|
||||
case T_BitString:
|
||||
/* arrange to report location if bit_in() fails */
|
||||
setup_parser_errposition_callback(&pcbstate, pstate, location);
|
||||
val = DirectFunctionCall3(bit_in,
|
||||
CStringGetDatum(strVal(value)),
|
||||
ObjectIdGetDatum(InvalidOid),
|
||||
Int32GetDatum(-1));
|
||||
cancel_parser_errposition_callback(&pcbstate);
|
||||
typeid = BITOID;
|
||||
typelen = -1;
|
||||
typebyval = false;
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.134 2008/08/28 23:09:48 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.135 2008/09/01 20:42:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -36,20 +36,20 @@
|
||||
bool add_missing_from;
|
||||
|
||||
static RangeTblEntry *scanNameSpaceForRefname(ParseState *pstate,
|
||||
const char *refname);
|
||||
static RangeTblEntry *scanNameSpaceForRelid(ParseState *pstate, Oid relid);
|
||||
const char *refname, int location);
|
||||
static RangeTblEntry *scanNameSpaceForRelid(ParseState *pstate, Oid relid,
|
||||
int location);
|
||||
static bool isLockedRel(ParseState *pstate, char *refname);
|
||||
static void expandRelation(Oid relid, Alias *eref,
|
||||
int rtindex, int sublevels_up,
|
||||
bool include_dropped,
|
||||
int location, bool include_dropped,
|
||||
List **colnames, List **colvars);
|
||||
static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
|
||||
int rtindex, int sublevels_up,
|
||||
bool include_dropped,
|
||||
int location, bool include_dropped,
|
||||
List **colnames, List **colvars);
|
||||
static int specialAttNum(const char *attname);
|
||||
static void warnAutoRange(ParseState *pstate, RangeVar *relation,
|
||||
int location);
|
||||
static void warnAutoRange(ParseState *pstate, RangeVar *relation);
|
||||
|
||||
|
||||
/*
|
||||
@@ -77,6 +77,7 @@ RangeTblEntry *
|
||||
refnameRangeTblEntry(ParseState *pstate,
|
||||
const char *schemaname,
|
||||
const char *refname,
|
||||
int location,
|
||||
int *sublevels_up)
|
||||
{
|
||||
Oid relId = InvalidOid;
|
||||
@@ -99,9 +100,9 @@ refnameRangeTblEntry(ParseState *pstate,
|
||||
RangeTblEntry *result;
|
||||
|
||||
if (OidIsValid(relId))
|
||||
result = scanNameSpaceForRelid(pstate, relId);
|
||||
result = scanNameSpaceForRelid(pstate, relId, location);
|
||||
else
|
||||
result = scanNameSpaceForRefname(pstate, refname);
|
||||
result = scanNameSpaceForRefname(pstate, refname, location);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
@@ -122,7 +123,7 @@ refnameRangeTblEntry(ParseState *pstate,
|
||||
* if no match. Raise error if multiple matches.
|
||||
*/
|
||||
static RangeTblEntry *
|
||||
scanNameSpaceForRefname(ParseState *pstate, const char *refname)
|
||||
scanNameSpaceForRefname(ParseState *pstate, const char *refname, int location)
|
||||
{
|
||||
RangeTblEntry *result = NULL;
|
||||
ListCell *l;
|
||||
@@ -137,7 +138,8 @@ scanNameSpaceForRefname(ParseState *pstate, const char *refname)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_AMBIGUOUS_ALIAS),
|
||||
errmsg("table reference \"%s\" is ambiguous",
|
||||
refname)));
|
||||
refname),
|
||||
parser_errposition(pstate, location)));
|
||||
result = rte;
|
||||
}
|
||||
}
|
||||
@@ -154,7 +156,7 @@ scanNameSpaceForRefname(ParseState *pstate, const char *refname)
|
||||
* acts the way it does.
|
||||
*/
|
||||
static RangeTblEntry *
|
||||
scanNameSpaceForRelid(ParseState *pstate, Oid relid)
|
||||
scanNameSpaceForRelid(ParseState *pstate, Oid relid, int location)
|
||||
{
|
||||
RangeTblEntry *result = NULL;
|
||||
ListCell *l;
|
||||
@@ -172,7 +174,8 @@ scanNameSpaceForRelid(ParseState *pstate, Oid relid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_AMBIGUOUS_ALIAS),
|
||||
errmsg("table reference %u is ambiguous",
|
||||
relid)));
|
||||
relid),
|
||||
parser_errposition(pstate, location)));
|
||||
result = rte;
|
||||
}
|
||||
}
|
||||
@@ -466,14 +469,15 @@ qualifiedNameToVar(ParseState *pstate,
|
||||
RangeTblEntry *rte;
|
||||
int sublevels_up;
|
||||
|
||||
rte = refnameRangeTblEntry(pstate, schemaname, refname, &sublevels_up);
|
||||
rte = refnameRangeTblEntry(pstate, schemaname, refname, location,
|
||||
&sublevels_up);
|
||||
|
||||
if (rte == NULL)
|
||||
{
|
||||
if (!implicitRTEOK)
|
||||
return NULL;
|
||||
rte = addImplicitRTE(pstate, makeRangeVar(schemaname, refname),
|
||||
location);
|
||||
rte = addImplicitRTE(pstate,
|
||||
makeRangeVar(schemaname, refname, location));
|
||||
}
|
||||
|
||||
return scanRTEForColumn(pstate, rte, colname, location);
|
||||
@@ -607,6 +611,28 @@ buildScalarFunctionAlias(Node *funcexpr, char *funcname,
|
||||
eref->colnames = list_make1(makeString(eref->aliasname));
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a table during parse analysis
|
||||
*
|
||||
* This is essentially just the same as heap_openrv(), except that it
|
||||
* arranges to include the RangeVar's parse location in any resulting error.
|
||||
*
|
||||
* Note: properly, lockmode should be declared LOCKMODE not int, but that
|
||||
* would require importing storage/lock.h into parse_relation.h. Since
|
||||
* LOCKMODE is typedef'd as int anyway, that seems like overkill.
|
||||
*/
|
||||
Relation
|
||||
parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode)
|
||||
{
|
||||
Relation rel;
|
||||
ParseCallbackState pcbstate;
|
||||
|
||||
setup_parser_errposition_callback(&pcbstate, pstate, relation->location);
|
||||
rel = heap_openrv(relation, lockmode);
|
||||
cancel_parser_errposition_callback(&pcbstate);
|
||||
return rel;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an entry for a relation to the pstate's range table (p_rtable).
|
||||
*
|
||||
@@ -638,7 +664,7 @@ addRangeTableEntry(ParseState *pstate,
|
||||
* depending on whether we're doing SELECT FOR UPDATE/SHARE.
|
||||
*/
|
||||
lockmode = isLockedRel(pstate, refname) ? RowShareLock : AccessShareLock;
|
||||
rel = heap_openrv(relation, lockmode);
|
||||
rel = parserOpenTable(pstate, relation, lockmode);
|
||||
rte->relid = RelationGetRelid(rel);
|
||||
|
||||
/*
|
||||
@@ -859,14 +885,16 @@ addRangeTableEntryForFunction(ParseState *pstate,
|
||||
if (functypclass != TYPEFUNC_RECORD)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("a column definition list is only allowed for functions returning \"record\"")));
|
||||
errmsg("a column definition list is only allowed for functions returning \"record\""),
|
||||
parser_errposition(pstate, exprLocation(funcexpr))));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (functypclass == TYPEFUNC_RECORD)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("a column definition list is required for functions returning \"record\"")));
|
||||
errmsg("a column definition list is required for functions returning \"record\""),
|
||||
parser_errposition(pstate, exprLocation(funcexpr))));
|
||||
}
|
||||
|
||||
if (functypclass == TYPEFUNC_COMPOSITE)
|
||||
@@ -901,7 +929,8 @@ addRangeTableEntryForFunction(ParseState *pstate,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
||||
errmsg("column \"%s\" cannot be declared SETOF",
|
||||
attrname)));
|
||||
attrname),
|
||||
parser_errposition(pstate, n->typename->location)));
|
||||
attrtype = typenameTypeId(pstate, n->typename, &attrtypmod);
|
||||
eref->colnames = lappend(eref->colnames, makeString(attrname));
|
||||
rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype);
|
||||
@@ -912,7 +941,8 @@ addRangeTableEntryForFunction(ParseState *pstate,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("function \"%s\" in FROM has unsupported return type %s",
|
||||
funcname, format_type_be(funcrettype))));
|
||||
funcname, format_type_be(funcrettype)),
|
||||
parser_errposition(pstate, exprLocation(funcexpr))));
|
||||
|
||||
/*----------
|
||||
* Flags:
|
||||
@@ -1107,9 +1137,9 @@ isLockedRel(ParseState *pstate, char *refname)
|
||||
|
||||
foreach(l2, lc->lockedRels)
|
||||
{
|
||||
char *rname = strVal(lfirst(l2));
|
||||
RangeVar *thisrel = (RangeVar *) lfirst(l2);
|
||||
|
||||
if (strcmp(refname, rname) == 0)
|
||||
if (strcmp(refname, thisrel->relname) == 0)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1150,12 +1180,12 @@ addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
|
||||
* a conflicting name.
|
||||
*/
|
||||
RangeTblEntry *
|
||||
addImplicitRTE(ParseState *pstate, RangeVar *relation, int location)
|
||||
addImplicitRTE(ParseState *pstate, RangeVar *relation)
|
||||
{
|
||||
RangeTblEntry *rte;
|
||||
|
||||
/* issue warning or error as needed */
|
||||
warnAutoRange(pstate, relation, location);
|
||||
warnAutoRange(pstate, relation);
|
||||
|
||||
/*
|
||||
* Note that we set inFromCl true, so that the RTE will be listed
|
||||
@@ -1179,9 +1209,9 @@ addImplicitRTE(ParseState *pstate, RangeVar *relation, int location)
|
||||
* results. If include_dropped is TRUE then empty strings and NULL constants
|
||||
* (not Vars!) are returned for dropped columns.
|
||||
*
|
||||
* rtindex and sublevels_up are the varno and varlevelsup values to use
|
||||
* in the created Vars. Ordinarily rtindex should match the actual position
|
||||
* of the RTE in its rangetable.
|
||||
* rtindex, sublevels_up, and location are the varno, varlevelsup, and location
|
||||
* values to use in the created Vars. Ordinarily rtindex should match the
|
||||
* actual position of the RTE in its rangetable.
|
||||
*
|
||||
* The output lists go into *colnames and *colvars.
|
||||
* If only one of the two kinds of output list is needed, pass NULL for the
|
||||
@@ -1189,7 +1219,7 @@ addImplicitRTE(ParseState *pstate, RangeVar *relation, int location)
|
||||
*/
|
||||
void
|
||||
expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
|
||||
bool include_dropped,
|
||||
int location, bool include_dropped,
|
||||
List **colnames, List **colvars)
|
||||
{
|
||||
int varattno;
|
||||
@@ -1203,7 +1233,8 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
|
||||
{
|
||||
case RTE_RELATION:
|
||||
/* Ordinary relation RTE */
|
||||
expandRelation(rte->relid, rte->eref, rtindex, sublevels_up,
|
||||
expandRelation(rte->relid, rte->eref,
|
||||
rtindex, sublevels_up, location,
|
||||
include_dropped, colnames, colvars);
|
||||
break;
|
||||
case RTE_SUBQUERY:
|
||||
@@ -1239,6 +1270,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
|
||||
exprType((Node *) te->expr),
|
||||
exprTypmod((Node *) te->expr),
|
||||
sublevels_up);
|
||||
varnode->location = location;
|
||||
|
||||
*colvars = lappend(*colvars, varnode);
|
||||
}
|
||||
@@ -1259,7 +1291,8 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
|
||||
{
|
||||
/* Composite data type, e.g. a table's row type */
|
||||
Assert(tupdesc);
|
||||
expandTupleDesc(tupdesc, rte->eref, rtindex, sublevels_up,
|
||||
expandTupleDesc(tupdesc, rte->eref,
|
||||
rtindex, sublevels_up, location,
|
||||
include_dropped, colnames, colvars);
|
||||
}
|
||||
else if (functypclass == TYPEFUNC_SCALAR)
|
||||
@@ -1276,6 +1309,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
|
||||
varnode = makeVar(rtindex, 1,
|
||||
funcrettype, -1,
|
||||
sublevels_up);
|
||||
varnode->location = location;
|
||||
|
||||
*colvars = lappend(*colvars, varnode);
|
||||
}
|
||||
@@ -1302,6 +1336,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
|
||||
attrtype,
|
||||
attrtypmod,
|
||||
sublevels_up);
|
||||
varnode->location = location;
|
||||
*colvars = lappend(*colvars, varnode);
|
||||
}
|
||||
}
|
||||
@@ -1343,6 +1378,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
|
||||
exprType(col),
|
||||
exprTypmod(col),
|
||||
sublevels_up);
|
||||
varnode->location = location;
|
||||
*colvars = lappend(*colvars, varnode);
|
||||
}
|
||||
}
|
||||
@@ -1401,6 +1437,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
|
||||
exprType(avar),
|
||||
exprTypmod(avar),
|
||||
sublevels_up);
|
||||
varnode->location = location;
|
||||
|
||||
*colvars = lappend(*colvars, varnode);
|
||||
}
|
||||
@@ -1417,14 +1454,15 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
|
||||
*/
|
||||
static void
|
||||
expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
|
||||
bool include_dropped,
|
||||
int location, bool include_dropped,
|
||||
List **colnames, List **colvars)
|
||||
{
|
||||
Relation rel;
|
||||
|
||||
/* Get the tupledesc and turn it over to expandTupleDesc */
|
||||
rel = relation_open(relid, AccessShareLock);
|
||||
expandTupleDesc(rel->rd_att, eref, rtindex, sublevels_up, include_dropped,
|
||||
expandTupleDesc(rel->rd_att, eref, rtindex, sublevels_up,
|
||||
location, include_dropped,
|
||||
colnames, colvars);
|
||||
relation_close(rel, AccessShareLock);
|
||||
}
|
||||
@@ -1435,7 +1473,7 @@ expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
|
||||
static void
|
||||
expandTupleDesc(TupleDesc tupdesc, Alias *eref,
|
||||
int rtindex, int sublevels_up,
|
||||
bool include_dropped,
|
||||
int location, bool include_dropped,
|
||||
List **colnames, List **colvars)
|
||||
{
|
||||
int maxattrs = tupdesc->natts;
|
||||
@@ -1482,6 +1520,7 @@ expandTupleDesc(TupleDesc tupdesc, Alias *eref,
|
||||
varnode = makeVar(rtindex, attr->attnum,
|
||||
attr->atttypid, attr->atttypmod,
|
||||
sublevels_up);
|
||||
varnode->location = location;
|
||||
|
||||
*colvars = lappend(*colvars, varnode);
|
||||
}
|
||||
@@ -1491,15 +1530,15 @@ expandTupleDesc(TupleDesc tupdesc, Alias *eref,
|
||||
/*
|
||||
* expandRelAttrs -
|
||||
* Workhorse for "*" expansion: produce a list of targetentries
|
||||
* for the attributes of the rte
|
||||
* for the attributes of the RTE
|
||||
*
|
||||
* As with expandRTE, rtindex/sublevels_up determine the varno/varlevelsup
|
||||
* fields of the Vars produced. pstate->p_next_resno determines the resnos
|
||||
* assigned to the TLEs.
|
||||
* fields of the Vars produced, and location sets their location.
|
||||
* pstate->p_next_resno determines the resnos assigned to the TLEs.
|
||||
*/
|
||||
List *
|
||||
expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
|
||||
int rtindex, int sublevels_up)
|
||||
int rtindex, int sublevels_up, int location)
|
||||
{
|
||||
List *names,
|
||||
*vars;
|
||||
@@ -1507,7 +1546,7 @@ expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
|
||||
*var;
|
||||
List *te_list = NIL;
|
||||
|
||||
expandRTE(rte, rtindex, sublevels_up, false,
|
||||
expandRTE(rte, rtindex, sublevels_up, location, false,
|
||||
&names, &vars);
|
||||
|
||||
forboth(name, names, var, vars)
|
||||
@@ -1523,7 +1562,7 @@ expandRelAttrs(ParseState *pstate, RangeTblEntry *rte,
|
||||
te_list = lappend(te_list, te);
|
||||
}
|
||||
|
||||
Assert(name == NULL && var == NULL); /* lists not the same length? */
|
||||
Assert(name == NULL && var == NULL); /* lists not the same length? */
|
||||
|
||||
return te_list;
|
||||
}
|
||||
@@ -1966,7 +2005,7 @@ attnumTypeId(Relation rd, int attid)
|
||||
* a warning.
|
||||
*/
|
||||
static void
|
||||
warnAutoRange(ParseState *pstate, RangeVar *relation, int location)
|
||||
warnAutoRange(ParseState *pstate, RangeVar *relation)
|
||||
{
|
||||
RangeTblEntry *rte;
|
||||
int sublevels_up;
|
||||
@@ -1991,6 +2030,7 @@ warnAutoRange(ParseState *pstate, RangeVar *relation, int location)
|
||||
if (rte && rte->alias &&
|
||||
strcmp(rte->eref->aliasname, relation->relname) != 0 &&
|
||||
refnameRangeTblEntry(pstate, NULL, rte->eref->aliasname,
|
||||
relation->location,
|
||||
&sublevels_up) == rte)
|
||||
badAlias = rte->eref->aliasname;
|
||||
|
||||
@@ -2006,7 +2046,7 @@ warnAutoRange(ParseState *pstate, RangeVar *relation, int location)
|
||||
badAlias) :
|
||||
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
|
||||
rte->eref->aliasname)),
|
||||
parser_errposition(pstate, location)));
|
||||
parser_errposition(pstate, relation->location)));
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_TABLE),
|
||||
@@ -2015,7 +2055,7 @@ warnAutoRange(ParseState *pstate, RangeVar *relation, int location)
|
||||
relation->relname) :
|
||||
errmsg("missing FROM-clause entry for table \"%s\"",
|
||||
relation->relname)),
|
||||
parser_errposition(pstate, location)));
|
||||
parser_errposition(pstate, relation->location)));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2033,6 +2073,6 @@ warnAutoRange(ParseState *pstate, RangeVar *relation, int location)
|
||||
(rte ?
|
||||
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
|
||||
rte->eref->aliasname) : 0)),
|
||||
parser_errposition(pstate, location)));
|
||||
parser_errposition(pstate, relation->location)));
|
||||
}
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.163 2008/08/30 01:39:14 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.164 2008/09/01 20:42:44 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -45,7 +45,7 @@ static Node *transformAssignmentIndirection(ParseState *pstate,
|
||||
int location);
|
||||
static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
|
||||
bool targetlist);
|
||||
static List *ExpandAllTables(ParseState *pstate);
|
||||
static List *ExpandAllTables(ParseState *pstate, int location);
|
||||
static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
|
||||
bool targetlist);
|
||||
static int FigureColnameInternal(Node *node, char **name);
|
||||
@@ -836,7 +836,7 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
|
||||
* need not handle the targetlist==false case here.
|
||||
*/
|
||||
Assert(targetlist);
|
||||
return ExpandAllTables(pstate);
|
||||
return ExpandAllTables(pstate, cref->location);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -889,11 +889,12 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
|
||||
break;
|
||||
}
|
||||
|
||||
rte = refnameRangeTblEntry(pstate, schemaname, relname,
|
||||
rte = refnameRangeTblEntry(pstate, schemaname, relname, cref->location,
|
||||
&sublevels_up);
|
||||
if (rte == NULL)
|
||||
rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname),
|
||||
cref->location);
|
||||
rte = addImplicitRTE(pstate,
|
||||
makeRangeVar(schemaname, relname,
|
||||
cref->location));
|
||||
|
||||
/* Require read access --- see comments in setTargetTable() */
|
||||
rte->requiredPerms |= ACL_SELECT;
|
||||
@@ -901,12 +902,13 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
|
||||
rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
|
||||
|
||||
if (targetlist)
|
||||
return expandRelAttrs(pstate, rte, rtindex, sublevels_up);
|
||||
return expandRelAttrs(pstate, rte, rtindex, sublevels_up,
|
||||
cref->location);
|
||||
else
|
||||
{
|
||||
List *vars;
|
||||
|
||||
expandRTE(rte, rtindex, sublevels_up, false,
|
||||
expandRTE(rte, rtindex, sublevels_up, cref->location, false,
|
||||
NULL, &vars);
|
||||
return vars;
|
||||
}
|
||||
@@ -923,7 +925,7 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
|
||||
* etc.
|
||||
*/
|
||||
static List *
|
||||
ExpandAllTables(ParseState *pstate)
|
||||
ExpandAllTables(ParseState *pstate, int location)
|
||||
{
|
||||
List *target = NIL;
|
||||
ListCell *l;
|
||||
@@ -932,7 +934,8 @@ ExpandAllTables(ParseState *pstate)
|
||||
if (!pstate->p_varnamespace)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("SELECT * with no tables specified is not valid")));
|
||||
errmsg("SELECT * with no tables specified is not valid"),
|
||||
parser_errposition(pstate, location)));
|
||||
|
||||
foreach(l, pstate->p_varnamespace)
|
||||
{
|
||||
@@ -943,7 +946,8 @@ ExpandAllTables(ParseState *pstate)
|
||||
rte->requiredPerms |= ACL_SELECT;
|
||||
|
||||
target = list_concat(target,
|
||||
expandRelAttrs(pstate, rte, rtindex, 0));
|
||||
expandRelAttrs(pstate, rte, rtindex, 0,
|
||||
location));
|
||||
}
|
||||
|
||||
return target;
|
||||
@@ -1014,12 +1018,16 @@ ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind,
|
||||
((Var *) expr)->varattno == InvalidAttrNumber)
|
||||
{
|
||||
Var *var = (Var *) expr;
|
||||
Var *newvar;
|
||||
|
||||
fieldnode = (Node *) makeVar(var->varno,
|
||||
i + 1,
|
||||
att->atttypid,
|
||||
att->atttypmod,
|
||||
var->varlevelsup);
|
||||
newvar = makeVar(var->varno,
|
||||
i + 1,
|
||||
att->atttypid,
|
||||
att->atttypmod,
|
||||
var->varlevelsup);
|
||||
newvar->location = var->location;
|
||||
|
||||
fieldnode = (Node *) newvar;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1088,7 +1096,7 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
|
||||
*lvar;
|
||||
int i;
|
||||
|
||||
expandRTE(rte, var->varno, 0, false,
|
||||
expandRTE(rte, var->varno, 0, var->location, false,
|
||||
&names, &vars);
|
||||
|
||||
tupleDesc = CreateTemplateTupleDesc(list_length(vars), false);
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.98 2008/08/30 01:39:14 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.99 2008/09/01 20:42:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -69,7 +69,7 @@ LookupTypeName(ParseState *pstate, const TypeName *typename,
|
||||
else if (typename->pct_type)
|
||||
{
|
||||
/* Handle %TYPE reference to type of an existing field */
|
||||
RangeVar *rel = makeRangeVar(NULL, NULL);
|
||||
RangeVar *rel = makeRangeVar(NULL, NULL, typename->location);
|
||||
char *field = NULL;
|
||||
Oid relid;
|
||||
AttrNumber attnum;
|
||||
@@ -122,7 +122,7 @@ LookupTypeName(ParseState *pstate, const TypeName *typename,
|
||||
/* this construct should never have an array indicator */
|
||||
Assert(typename->arrayBounds == NIL);
|
||||
|
||||
/* emit nuisance notice */
|
||||
/* emit nuisance notice (intentionally not errposition'd) */
|
||||
ereport(NOTICE,
|
||||
(errmsg("type reference %s converted to %s",
|
||||
TypeNameToString(typename),
|
||||
@@ -247,6 +247,7 @@ typenameTypeMod(ParseState *pstate, const TypeName *typename, Type typ)
|
||||
int n;
|
||||
ListCell *l;
|
||||
ArrayType *arrtypmod;
|
||||
ParseCallbackState pcbstate;
|
||||
|
||||
/* Return prespecified typmod if no typmod expressions */
|
||||
if (typename->typmods == NIL)
|
||||
@@ -321,9 +322,14 @@ typenameTypeMod(ParseState *pstate, const TypeName *typename, Type typ)
|
||||
arrtypmod = construct_array(datums, n, CSTRINGOID,
|
||||
-2, false, 'c');
|
||||
|
||||
/* arrange to report location if type's typmodin function fails */
|
||||
setup_parser_errposition_callback(&pcbstate, pstate, typename->location);
|
||||
|
||||
result = DatumGetInt32(OidFunctionCall1(typmodin,
|
||||
PointerGetDatum(arrtypmod)));
|
||||
|
||||
cancel_parser_errposition_callback(&pcbstate);
|
||||
|
||||
pfree(datums);
|
||||
pfree(arrtypmod);
|
||||
|
||||
|
@@ -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.16 2008/08/28 23:09:48 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.17 2008/09/01 20:42:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -346,7 +346,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
|
||||
* TABLE.
|
||||
*/
|
||||
seqstmt = makeNode(CreateSeqStmt);
|
||||
seqstmt->sequence = makeRangeVar(snamespace, sname);
|
||||
seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
|
||||
seqstmt->options = NIL;
|
||||
|
||||
cxt->blist = lappend(cxt->blist, seqstmt);
|
||||
@@ -357,7 +357,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
|
||||
* done after this CREATE/ALTER TABLE.
|
||||
*/
|
||||
altseqstmt = makeNode(AlterSeqStmt);
|
||||
altseqstmt->sequence = makeRangeVar(snamespace, sname);
|
||||
altseqstmt->sequence = makeRangeVar(snamespace, sname, -1);
|
||||
attnamelist = list_make3(makeString(snamespace),
|
||||
makeString(cxt->relation->relname),
|
||||
makeString(column->colname));
|
||||
@@ -548,7 +548,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
|
||||
bool including_indexes = false;
|
||||
ListCell *elem;
|
||||
|
||||
relation = heap_openrv(inhRelation->relation, AccessShareLock);
|
||||
relation = parserOpenTable(pstate, inhRelation->relation, AccessShareLock);
|
||||
|
||||
if (relation->rd_rel->relkind != RELKIND_RELATION)
|
||||
ereport(ERROR,
|
||||
|
@@ -24,7 +24,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.145 2008/08/29 13:02:32 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.146 2008/09/01 20:42:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -77,7 +77,8 @@ static void addlit(char *ytext, int yleng);
|
||||
static void addlitchar(unsigned char ychar);
|
||||
static char *litbufdup(void);
|
||||
|
||||
static int lexer_errposition(void);
|
||||
#define lexer_errposition() scanner_errposition(yylloc)
|
||||
|
||||
static void check_escape_warning(void);
|
||||
static void check_string_escape_warning(unsigned char ychar);
|
||||
|
||||
@@ -756,22 +757,27 @@ other .
|
||||
%%
|
||||
|
||||
/*
|
||||
* lexer_errposition
|
||||
* Report a lexical-analysis-time cursor position, if possible.
|
||||
* scanner_errposition
|
||||
* Report a lexer or grammar error cursor position, if possible.
|
||||
*
|
||||
* This is expected to be used within an ereport() call. The return value
|
||||
* is a dummy (always 0, in fact).
|
||||
*
|
||||
* Note that this can only be used for messages from the lexer itself,
|
||||
* since it depends on scanbuf to still be valid.
|
||||
* Note that this can only be used for messages emitted during raw parsing
|
||||
* (essentially, scan.l and gram.y), since it requires scanbuf to still be
|
||||
* valid.
|
||||
*/
|
||||
static int
|
||||
lexer_errposition(void)
|
||||
int
|
||||
scanner_errposition(int location)
|
||||
{
|
||||
int pos;
|
||||
|
||||
Assert(scanbuf != NULL); /* else called from wrong place */
|
||||
if (location < 0)
|
||||
return 0; /* no-op if location is unknown */
|
||||
|
||||
/* Convert byte offset to character number */
|
||||
pos = pg_mbstrlen_with_len(scanbuf, yylloc) + 1;
|
||||
pos = pg_mbstrlen_with_len(scanbuf, location) + 1;
|
||||
/* And pass it to the ereport mechanism */
|
||||
return errposition(pos);
|
||||
}
|
||||
@@ -849,6 +855,7 @@ scanner_finish(void)
|
||||
{
|
||||
yy_delete_buffer(scanbufhandle);
|
||||
pfree(scanbuf);
|
||||
scanbuf = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user