mirror of
https://github.com/postgres/postgres.git
synced 2025-07-17 06:41:09 +03:00
pgindent run for 8.2.
This commit is contained in:
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.351 2006/09/18 16:04:04 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.352 2006/10/04 00:29:55 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -99,7 +99,7 @@ static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
|
||||
static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
|
||||
List **extras_before, List **extras_after);
|
||||
static List *transformInsertRow(ParseState *pstate, List *exprlist,
|
||||
List *stmtcols, List *icolumns, List *attrnos);
|
||||
List *stmtcols, List *icolumns, List *attrnos);
|
||||
static List *transformReturningList(ParseState *pstate, List *returningList);
|
||||
static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
|
||||
static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt,
|
||||
@ -133,7 +133,7 @@ static void transformFKConstraints(ParseState *pstate,
|
||||
bool isAddConstraint);
|
||||
static void applyColumnNames(List *dst, List *src);
|
||||
static void getSetColTypes(ParseState *pstate, Node *node,
|
||||
List **colTypes, List **colTypmods);
|
||||
List **colTypes, List **colTypmods);
|
||||
static void transformLockingClause(Query *qry, LockingClause *lc);
|
||||
static void transformConstraintAttrs(List *constraintList);
|
||||
static void transformColumnType(ParseState *pstate, ColumnDef *column);
|
||||
@ -343,7 +343,7 @@ transformStmt(ParseState *pstate, Node *parseTree,
|
||||
|
||||
case T_CopyStmt:
|
||||
{
|
||||
CopyStmt *n = (CopyStmt *) parseTree;
|
||||
CopyStmt *n = (CopyStmt *) parseTree;
|
||||
|
||||
result = makeNode(Query);
|
||||
result->commandType = CMD_UTILITY;
|
||||
@ -552,8 +552,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
|
||||
|
||||
/*
|
||||
* We have three cases to deal with: DEFAULT VALUES (selectStmt == NULL),
|
||||
* VALUES list, or general SELECT input. We special-case VALUES, both
|
||||
* for efficiency and so we can handle DEFAULT specifications.
|
||||
* VALUES list, or general SELECT input. We special-case VALUES, both for
|
||||
* efficiency and so we can handle DEFAULT specifications.
|
||||
*/
|
||||
isGeneralSelect = (selectStmt && selectStmt->valuesLists == NIL);
|
||||
|
||||
@ -602,8 +602,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
|
||||
{
|
||||
/*
|
||||
* We have INSERT ... DEFAULT VALUES. We can handle this case by
|
||||
* emitting an empty targetlist --- all columns will be defaulted
|
||||
* when the planner expands the targetlist.
|
||||
* emitting an empty targetlist --- all columns will be defaulted when
|
||||
* the planner expands the targetlist.
|
||||
*/
|
||||
exprList = NIL;
|
||||
}
|
||||
@ -705,25 +705,25 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
|
||||
else if (list_length(selectStmt->valuesLists) > 1)
|
||||
{
|
||||
/*
|
||||
* Process INSERT ... VALUES with multiple VALUES sublists.
|
||||
* We generate a VALUES RTE holding the transformed expression
|
||||
* lists, and build up a targetlist containing Vars that reference
|
||||
* the VALUES RTE.
|
||||
* Process INSERT ... VALUES with multiple VALUES sublists. We
|
||||
* generate a VALUES RTE holding the transformed expression lists, and
|
||||
* build up a targetlist containing Vars that reference the VALUES
|
||||
* RTE.
|
||||
*/
|
||||
List *exprsLists = NIL;
|
||||
int sublist_length = -1;
|
||||
|
||||
foreach(lc, selectStmt->valuesLists)
|
||||
{
|
||||
List *sublist = (List *) lfirst(lc);
|
||||
List *sublist = (List *) lfirst(lc);
|
||||
|
||||
/* Do basic expression transformation (same as a ROW() expr) */
|
||||
sublist = transformExpressionList(pstate, sublist);
|
||||
|
||||
/*
|
||||
* All the sublists must be the same length, *after* transformation
|
||||
* (which might expand '*' into multiple items). The VALUES RTE
|
||||
* can't handle anything different.
|
||||
* All the sublists must be the same length, *after*
|
||||
* transformation (which might expand '*' into multiple items).
|
||||
* The VALUES RTE can't handle anything different.
|
||||
*/
|
||||
if (sublist_length < 0)
|
||||
{
|
||||
@ -747,8 +747,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
|
||||
|
||||
/*
|
||||
* There mustn't have been any table references in the expressions,
|
||||
* else strange things would happen, like Cartesian products of
|
||||
* those tables with the VALUES list ...
|
||||
* else strange things would happen, like Cartesian products of those
|
||||
* tables with the VALUES list ...
|
||||
*/
|
||||
if (pstate->p_joinlist != NIL)
|
||||
ereport(ERROR,
|
||||
@ -756,10 +756,10 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
|
||||
errmsg("VALUES must not contain table references")));
|
||||
|
||||
/*
|
||||
* Another thing we can't currently support is NEW/OLD references
|
||||
* in rules --- seems we'd need something like SQL99's LATERAL
|
||||
* construct to ensure that the values would be available while
|
||||
* evaluating the VALUES RTE. This is a shame. FIXME
|
||||
* Another thing we can't currently support is NEW/OLD references in
|
||||
* rules --- seems we'd need something like SQL99's LATERAL construct
|
||||
* to ensure that the values would be available while evaluating the
|
||||
* VALUES RTE. This is a shame. FIXME
|
||||
*/
|
||||
if (list_length(pstate->p_rtable) != 1 &&
|
||||
contain_vars_of_level((Node *) exprsLists, 0))
|
||||
@ -793,7 +793,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
|
||||
* INSERT INTO foo VALUES(bar.*)
|
||||
*
|
||||
* The sublist is just computed directly as the Query's targetlist,
|
||||
* with no VALUES RTE. So it works just like SELECT without FROM.
|
||||
* with no VALUES RTE. So it works just like SELECT without FROM.
|
||||
*----------
|
||||
*/
|
||||
List *valuesLists = selectStmt->valuesLists;
|
||||
@ -818,7 +818,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
|
||||
attnos = list_head(attrnos);
|
||||
foreach(lc, exprList)
|
||||
{
|
||||
Expr *expr = (Expr *) lfirst(lc);
|
||||
Expr *expr = (Expr *) lfirst(lc);
|
||||
ResTarget *col;
|
||||
TargetEntry *tle;
|
||||
|
||||
@ -836,10 +836,10 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have a RETURNING clause, we need to add the target relation
|
||||
* to the query namespace before processing it, so that Var references
|
||||
* in RETURNING will work. Also, remove any namespace entries added
|
||||
* in a sub-SELECT or VALUES list.
|
||||
* If we have a RETURNING clause, we need to add the target relation to
|
||||
* the query namespace before processing it, so that Var references in
|
||||
* RETURNING will work. Also, remove any namespace entries added in a
|
||||
* sub-SELECT or VALUES list.
|
||||
*/
|
||||
if (stmt->returningList)
|
||||
{
|
||||
@ -875,7 +875,7 @@ static List *
|
||||
transformInsertRow(ParseState *pstate, List *exprlist,
|
||||
List *stmtcols, List *icolumns, List *attrnos)
|
||||
{
|
||||
List *result;
|
||||
List *result;
|
||||
ListCell *lc;
|
||||
ListCell *icols;
|
||||
ListCell *attnos;
|
||||
@ -884,7 +884,7 @@ transformInsertRow(ParseState *pstate, List *exprlist,
|
||||
* Check length of expr list. It must not have more expressions than
|
||||
* there are target columns. We allow fewer, but only if no explicit
|
||||
* columns list was given (the remaining columns are implicitly
|
||||
* defaulted). Note we must check this *after* transformation because
|
||||
* defaulted). Note we must check this *after* transformation because
|
||||
* that could expand '*' into multiple items.
|
||||
*/
|
||||
if (list_length(exprlist) > list_length(icolumns))
|
||||
@ -905,7 +905,7 @@ transformInsertRow(ParseState *pstate, List *exprlist,
|
||||
attnos = list_head(attrnos);
|
||||
foreach(lc, exprlist)
|
||||
{
|
||||
Expr *expr = (Expr *) lfirst(lc);
|
||||
Expr *expr = (Expr *) lfirst(lc);
|
||||
ResTarget *col;
|
||||
|
||||
col = (ResTarget *) lfirst(icols);
|
||||
@ -1292,10 +1292,10 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
|
||||
TupleConstr *constr;
|
||||
AclResult aclresult;
|
||||
|
||||
bool including_defaults = false;
|
||||
bool including_constraints = false;
|
||||
bool including_indexes = false;
|
||||
ListCell *elem;
|
||||
bool including_defaults = false;
|
||||
bool including_constraints = false;
|
||||
bool including_indexes = false;
|
||||
ListCell *elem;
|
||||
|
||||
relation = heap_openrv(inhRelation->relation, AccessShareLock);
|
||||
|
||||
@ -1318,32 +1318,33 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
|
||||
constr = tupleDesc->constr;
|
||||
|
||||
foreach(elem, inhRelation->options)
|
||||
{
|
||||
int option = lfirst_int(elem);
|
||||
|
||||
switch (option)
|
||||
{
|
||||
int option = lfirst_int(elem);
|
||||
switch (option)
|
||||
{
|
||||
case CREATE_TABLE_LIKE_INCLUDING_DEFAULTS:
|
||||
including_defaults = true;
|
||||
break;
|
||||
case CREATE_TABLE_LIKE_EXCLUDING_DEFAULTS:
|
||||
including_defaults = false;
|
||||
break;
|
||||
case CREATE_TABLE_LIKE_INCLUDING_CONSTRAINTS:
|
||||
including_constraints = true;
|
||||
break;
|
||||
case CREATE_TABLE_LIKE_EXCLUDING_CONSTRAINTS:
|
||||
including_constraints = false;
|
||||
break;
|
||||
case CREATE_TABLE_LIKE_INCLUDING_INDEXES:
|
||||
including_indexes = true;
|
||||
break;
|
||||
case CREATE_TABLE_LIKE_EXCLUDING_INDEXES:
|
||||
including_indexes = false;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized CREATE TABLE LIKE option: %d", option);
|
||||
}
|
||||
case CREATE_TABLE_LIKE_INCLUDING_DEFAULTS:
|
||||
including_defaults = true;
|
||||
break;
|
||||
case CREATE_TABLE_LIKE_EXCLUDING_DEFAULTS:
|
||||
including_defaults = false;
|
||||
break;
|
||||
case CREATE_TABLE_LIKE_INCLUDING_CONSTRAINTS:
|
||||
including_constraints = true;
|
||||
break;
|
||||
case CREATE_TABLE_LIKE_EXCLUDING_CONSTRAINTS:
|
||||
including_constraints = false;
|
||||
break;
|
||||
case CREATE_TABLE_LIKE_INCLUDING_INDEXES:
|
||||
including_indexes = true;
|
||||
break;
|
||||
case CREATE_TABLE_LIKE_EXCLUDING_INDEXES:
|
||||
including_indexes = false;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized CREATE TABLE LIKE option: %d", option);
|
||||
}
|
||||
}
|
||||
|
||||
if (including_indexes)
|
||||
elog(ERROR, "TODO");
|
||||
@ -1418,14 +1419,16 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
|
||||
}
|
||||
}
|
||||
|
||||
if (including_constraints && tupleDesc->constr) {
|
||||
int ccnum;
|
||||
if (including_constraints && tupleDesc->constr)
|
||||
{
|
||||
int ccnum;
|
||||
AttrNumber *attmap = varattnos_map_schema(tupleDesc, cxt->columns);
|
||||
|
||||
for(ccnum = 0; ccnum < tupleDesc->constr->num_check; ccnum++) {
|
||||
char *ccname = tupleDesc->constr->check[ccnum].ccname;
|
||||
char *ccbin = tupleDesc->constr->check[ccnum].ccbin;
|
||||
Node *ccbin_node = stringToNode(ccbin);
|
||||
for (ccnum = 0; ccnum < tupleDesc->constr->num_check; ccnum++)
|
||||
{
|
||||
char *ccname = tupleDesc->constr->check[ccnum].ccname;
|
||||
char *ccbin = tupleDesc->constr->check[ccnum].ccbin;
|
||||
Node *ccbin_node = stringToNode(ccbin);
|
||||
Constraint *n = makeNode(Constraint);
|
||||
|
||||
change_varattnos_of_a_node(ccbin_node, attmap);
|
||||
@ -1435,7 +1438,7 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
|
||||
n->raw_expr = ccbin_node;
|
||||
n->cooked_expr = NULL;
|
||||
n->indexspace = NULL;
|
||||
cxt->ckconstraints = lappend(cxt->ckconstraints, (Node*)n);
|
||||
cxt->ckconstraints = lappend(cxt->ckconstraints, (Node *) n);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1888,7 +1891,7 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
|
||||
if (pstate->p_hasAggs)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
errmsg("cannot use aggregate function in rule WHERE condition")));
|
||||
errmsg("cannot use aggregate function in rule WHERE condition")));
|
||||
|
||||
/* save info about sublinks in where clause */
|
||||
qry->hasSubLinks = pstate->p_hasSubLinks;
|
||||
@ -2175,8 +2178,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
RangeTblEntry *rte;
|
||||
RangeTblRef *rtr;
|
||||
ListCell *lc;
|
||||
ListCell *lc2;
|
||||
int i;
|
||||
ListCell *lc2;
|
||||
int i;
|
||||
|
||||
qry->commandType = CMD_SELECT;
|
||||
|
||||
@ -2190,21 +2193,21 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
Assert(stmt->op == SETOP_NONE);
|
||||
|
||||
/*
|
||||
* For each row of VALUES, transform the raw expressions and gather
|
||||
* type information. This is also a handy place to reject DEFAULT
|
||||
* nodes, which the grammar allows for simplicity.
|
||||
* For each row of VALUES, transform the raw expressions and gather type
|
||||
* information. This is also a handy place to reject DEFAULT nodes, which
|
||||
* the grammar allows for simplicity.
|
||||
*/
|
||||
foreach(lc, stmt->valuesLists)
|
||||
{
|
||||
List *sublist = (List *) lfirst(lc);
|
||||
List *sublist = (List *) lfirst(lc);
|
||||
|
||||
/* Do basic expression transformation (same as a ROW() expr) */
|
||||
sublist = transformExpressionList(pstate, sublist);
|
||||
|
||||
/*
|
||||
* All the sublists must be the same length, *after* transformation
|
||||
* (which might expand '*' into multiple items). The VALUES RTE
|
||||
* can't handle anything different.
|
||||
* (which might expand '*' into multiple items). The VALUES RTE can't
|
||||
* handle anything different.
|
||||
*/
|
||||
if (sublist_length < 0)
|
||||
{
|
||||
@ -2226,7 +2229,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
i = 0;
|
||||
foreach(lc2, sublist)
|
||||
{
|
||||
Node *col = (Node *) lfirst(lc2);
|
||||
Node *col = (Node *) lfirst(lc2);
|
||||
|
||||
if (IsA(col, SetToDefault))
|
||||
ereport(ERROR,
|
||||
@ -2238,8 +2241,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
}
|
||||
|
||||
/*
|
||||
* Now resolve the common types of the columns, and coerce everything
|
||||
* to those types.
|
||||
* Now resolve the common types of the columns, and coerce everything to
|
||||
* those types.
|
||||
*/
|
||||
for (i = 0; i < sublist_length; i++)
|
||||
{
|
||||
@ -2249,13 +2252,13 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
newExprsLists = NIL;
|
||||
foreach(lc, exprsLists)
|
||||
{
|
||||
List *sublist = (List *) lfirst(lc);
|
||||
List *newsublist = NIL;
|
||||
List *sublist = (List *) lfirst(lc);
|
||||
List *newsublist = NIL;
|
||||
|
||||
i = 0;
|
||||
foreach(lc2, sublist)
|
||||
{
|
||||
Node *col = (Node *) lfirst(lc2);
|
||||
Node *col = (Node *) lfirst(lc2);
|
||||
|
||||
col = coerce_to_common_type(pstate, col, coltypes[i], "VALUES");
|
||||
newsublist = lappend(newsublist, col);
|
||||
@ -2283,8 +2286,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
qry->targetList = expandRelAttrs(pstate, rte, rtr->rtindex, 0);
|
||||
|
||||
/*
|
||||
* The grammar allows attaching ORDER BY, LIMIT, and FOR UPDATE
|
||||
* to a VALUES, so cope.
|
||||
* The grammar allows attaching ORDER BY, LIMIT, and FOR UPDATE to a
|
||||
* VALUES, so cope.
|
||||
*/
|
||||
qry->sortClause = transformSortClause(pstate,
|
||||
stmt->sortClause,
|
||||
@ -2299,7 +2302,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
if (stmt->lockingClause)
|
||||
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")));
|
||||
|
||||
/* handle any CREATE TABLE AS spec */
|
||||
if (stmt->into)
|
||||
@ -2313,10 +2316,10 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
}
|
||||
|
||||
/*
|
||||
* There mustn't have been any table references in the expressions,
|
||||
* else strange things would happen, like Cartesian products of
|
||||
* those tables with the VALUES list. We have to check this after
|
||||
* parsing ORDER BY et al since those could insert more junk.
|
||||
* There mustn't have been any table references in the expressions, else
|
||||
* strange things would happen, like Cartesian products of those tables
|
||||
* with the VALUES list. We have to check this after parsing ORDER BY et
|
||||
* al since those could insert more junk.
|
||||
*/
|
||||
if (list_length(pstate->p_joinlist) != 1)
|
||||
ereport(ERROR,
|
||||
@ -2324,10 +2327,10 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
|
||||
errmsg("VALUES must not contain table references")));
|
||||
|
||||
/*
|
||||
* Another thing we can't currently support is NEW/OLD references
|
||||
* in rules --- seems we'd need something like SQL99's LATERAL
|
||||
* construct to ensure that the values would be available while
|
||||
* evaluating the VALUES RTE. This is a shame. FIXME
|
||||
* Another thing we can't currently support is NEW/OLD references in rules
|
||||
* --- seems we'd need something like SQL99's LATERAL construct to ensure
|
||||
* that the values would be available while evaluating the VALUES RTE.
|
||||
* This is a shame. FIXME
|
||||
*/
|
||||
if (list_length(pstate->p_rtable) != 1 &&
|
||||
contain_vars_of_level((Node *) newExprsLists, 0))
|
||||
@ -2390,8 +2393,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
/*
|
||||
* Find leftmost leaf SelectStmt; extract the one-time-only items from it
|
||||
* and from the top-level node. (Most of the INTO options can be
|
||||
* transferred to the Query immediately, but intoColNames has to be
|
||||
* saved to apply below.)
|
||||
* transferred to the Query immediately, but intoColNames has to be saved
|
||||
* to apply below.)
|
||||
*/
|
||||
leftmostSelect = stmt->larg;
|
||||
while (leftmostSelect && leftmostSelect->op != SETOP_NONE)
|
||||
@ -2865,9 +2868,9 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
|
||||
qry->hasSubLinks = pstate->p_hasSubLinks;
|
||||
|
||||
/*
|
||||
* Top-level aggregates are simply disallowed in UPDATE, per spec.
|
||||
* (From an implementation point of view, this is forced because the
|
||||
* implicit ctid reference would otherwise be an ungrouped variable.)
|
||||
* Top-level aggregates are simply disallowed in UPDATE, per spec. (From
|
||||
* an implementation point of view, this is forced because the implicit
|
||||
* ctid reference would otherwise be an ungrouped variable.)
|
||||
*/
|
||||
if (pstate->p_hasAggs)
|
||||
ereport(ERROR,
|
||||
@ -2890,7 +2893,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
|
||||
{
|
||||
TargetEntry *tle = (TargetEntry *) lfirst(tl);
|
||||
ResTarget *origTarget;
|
||||
int attrno;
|
||||
int attrno;
|
||||
|
||||
if (tle->resjunk)
|
||||
{
|
||||
@ -2916,7 +2919,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
|
||||
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
||||
errmsg("column \"%s\" of relation \"%s\" does not exist",
|
||||
origTarget->name,
|
||||
RelationGetRelationName(pstate->p_target_relation)),
|
||||
RelationGetRelationName(pstate->p_target_relation)),
|
||||
parser_errposition(pstate, origTarget->location)));
|
||||
|
||||
updateTargetListEntry(pstate, tle, origTarget->name,
|
||||
@ -2948,9 +2951,9 @@ transformReturningList(ParseState *pstate, List *returningList)
|
||||
return NIL; /* nothing to do */
|
||||
|
||||
/*
|
||||
* We need to assign resnos starting at one in the RETURNING list.
|
||||
* Save and restore the main tlist's value of p_next_resno, just in
|
||||
* case someone looks at it later (probably won't happen).
|
||||
* We need to assign resnos starting at one in the RETURNING list. Save
|
||||
* and restore the main tlist's value of p_next_resno, just in case
|
||||
* someone looks at it later (probably won't happen).
|
||||
*/
|
||||
save_next_resno = pstate->p_next_resno;
|
||||
pstate->p_next_resno = 1;
|
||||
@ -2975,7 +2978,7 @@ transformReturningList(ParseState *pstate, List *returningList)
|
||||
if (list_length(pstate->p_rtable) != length_rtable)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("RETURNING may not contain references to other relations")));
|
||||
errmsg("RETURNING may not contain references to other relations")));
|
||||
|
||||
/* mark column origins */
|
||||
markTargetListOrigins(pstate, rlist);
|
||||
@ -3204,7 +3207,7 @@ static Query *
|
||||
transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt)
|
||||
{
|
||||
Query *result = makeNode(Query);
|
||||
List *argtype_oids; /* argtype OIDs in a list */
|
||||
List *argtype_oids; /* argtype OIDs in a list */
|
||||
Oid *argtoids = NULL; /* and as an array */
|
||||
int nargs;
|
||||
List *queries;
|
||||
@ -3233,10 +3236,9 @@ transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt)
|
||||
}
|
||||
|
||||
/*
|
||||
* Analyze the statement using these parameter types (any
|
||||
* parameters passed in from above us will not be visible to it),
|
||||
* allowing information about unknown parameters to be deduced
|
||||
* from context.
|
||||
* Analyze the statement using these parameter types (any parameters
|
||||
* passed in from above us will not be visible to it), allowing
|
||||
* information about unknown parameters to be deduced from context.
|
||||
*/
|
||||
queries = parse_analyze_varparams((Node *) stmt->query,
|
||||
pstate->p_sourcetext,
|
||||
@ -3250,8 +3252,8 @@ transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt)
|
||||
elog(ERROR, "unexpected extra stuff in prepared statement");
|
||||
|
||||
/*
|
||||
* Check that all parameter types were determined, and convert the
|
||||
* array of OIDs into a list for storage.
|
||||
* Check that all parameter types were determined, and convert the array
|
||||
* of OIDs into a list for storage.
|
||||
*/
|
||||
argtype_oids = NIL;
|
||||
for (i = 0; i < nargs; i++)
|
||||
@ -3360,7 +3362,7 @@ CheckSelectLocking(Query *qry)
|
||||
if (qry->havingQual != NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("SELECT FOR UPDATE/SHARE is not allowed with HAVING clause")));
|
||||
errmsg("SELECT FOR UPDATE/SHARE is not allowed with HAVING clause")));
|
||||
if (qry->hasAggs)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
@ -3500,15 +3502,15 @@ applyLockingClause(Query *qry, Index rtindex, bool forUpdate, bool noWait)
|
||||
if ((rc = get_rowmark(qry, rtindex)) != NULL)
|
||||
{
|
||||
/*
|
||||
* If the same RTE is specified both FOR UPDATE and FOR SHARE,
|
||||
* treat it as FOR UPDATE. (Reasonable, since you can't take
|
||||
* both a shared and exclusive lock at the same time; it'll
|
||||
* end up being exclusive anyway.)
|
||||
* If the same RTE is specified both FOR UPDATE and FOR SHARE, treat
|
||||
* it as FOR UPDATE. (Reasonable, since you can't take both a shared
|
||||
* and exclusive lock at the same time; it'll end up being exclusive
|
||||
* anyway.)
|
||||
*
|
||||
* We also consider that NOWAIT wins if it's specified both ways.
|
||||
* This is a bit more debatable but raising an error doesn't
|
||||
* seem helpful. (Consider for instance SELECT FOR UPDATE NOWAIT
|
||||
* from a view that internally contains a plain FOR UPDATE spec.)
|
||||
* We also consider that NOWAIT wins if it's specified both ways. This
|
||||
* is a bit more debatable but raising an error doesn't seem helpful.
|
||||
* (Consider for instance SELECT FOR UPDATE NOWAIT from a view that
|
||||
* internally contains a plain FOR UPDATE spec.)
|
||||
*/
|
||||
rc->forUpdate |= forUpdate;
|
||||
rc->noWait |= noWait;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.157 2006/08/14 23:39:32 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.158 2006/10/04 00:29:55 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -544,8 +544,8 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
|
||||
/*
|
||||
* If a coldeflist was supplied, ensure it defines a legal set of names
|
||||
* (no duplicates) and datatypes (no pseudo-types, for instance).
|
||||
* addRangeTableEntryForFunction looked up the type names but didn't
|
||||
* check them further than that.
|
||||
* addRangeTableEntryForFunction looked up the type names but didn't check
|
||||
* them further than that.
|
||||
*/
|
||||
if (r->coldeflist)
|
||||
{
|
||||
@ -1338,10 +1338,10 @@ transformGroupClause(ParseState *pstate, List *grouplist,
|
||||
ListCell *l;
|
||||
|
||||
/* Preprocess the grouping clause, lookup TLEs */
|
||||
foreach (l, grouplist)
|
||||
foreach(l, grouplist)
|
||||
{
|
||||
TargetEntry *tle;
|
||||
Oid restype;
|
||||
Oid restype;
|
||||
|
||||
tle = findTargetlistEntry(pstate, lfirst(l),
|
||||
targetlist, GROUP_CLAUSE);
|
||||
@ -1359,21 +1359,20 @@ transformGroupClause(ParseState *pstate, List *grouplist,
|
||||
}
|
||||
|
||||
/*
|
||||
* Now iterate through the ORDER BY clause. If we find a grouping
|
||||
* element that matches the ORDER BY element, append the grouping
|
||||
* element to the result set immediately. Otherwise, stop
|
||||
* iterating. The effect of this is to look for a prefix of the
|
||||
* ORDER BY list in the grouping clauses, and to move that prefix
|
||||
* to the front of the GROUP BY.
|
||||
* Now iterate through the ORDER BY clause. If we find a grouping element
|
||||
* that matches the ORDER BY element, append the grouping element to the
|
||||
* result set immediately. Otherwise, stop iterating. The effect of this
|
||||
* is to look for a prefix of the ORDER BY list in the grouping clauses,
|
||||
* and to move that prefix to the front of the GROUP BY.
|
||||
*/
|
||||
foreach (l, sortClause)
|
||||
foreach(l, sortClause)
|
||||
{
|
||||
SortClause *sc = (SortClause *) lfirst(l);
|
||||
ListCell *prev = NULL;
|
||||
ListCell *tl;
|
||||
bool found = false;
|
||||
SortClause *sc = (SortClause *) lfirst(l);
|
||||
ListCell *prev = NULL;
|
||||
ListCell *tl;
|
||||
bool found = false;
|
||||
|
||||
foreach (tl, tle_list)
|
||||
foreach(tl, tle_list)
|
||||
{
|
||||
TargetEntry *tle = (TargetEntry *) lfirst(tl);
|
||||
|
||||
@ -1399,17 +1398,17 @@ transformGroupClause(ParseState *pstate, List *grouplist,
|
||||
}
|
||||
|
||||
/*
|
||||
* Now add any remaining elements of the GROUP BY list in the
|
||||
* order we received them.
|
||||
* Now add any remaining elements of the GROUP BY list in the order we
|
||||
* received them.
|
||||
*
|
||||
* XXX: are there any additional criteria to consider when
|
||||
* ordering grouping clauses?
|
||||
* XXX: are there any additional criteria to consider when ordering
|
||||
* grouping clauses?
|
||||
*/
|
||||
foreach(l, tle_list)
|
||||
{
|
||||
TargetEntry *tle = (TargetEntry *) lfirst(l);
|
||||
GroupClause *gc;
|
||||
Oid sort_op;
|
||||
Oid sort_op;
|
||||
|
||||
/* avoid making duplicate grouplist entries */
|
||||
if (targetIsInSortList(tle, result))
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.143 2006/07/26 19:31:51 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.144 2006/10/04 00:29:55 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -163,11 +163,11 @@ coerce_type(ParseState *pstate, Node *node,
|
||||
|
||||
/*
|
||||
* If the target type is a domain, we want to call its base type's
|
||||
* input routine, not domain_in(). This is to avoid premature
|
||||
* failure when the domain applies a typmod: existing input
|
||||
* routines follow implicit-coercion semantics for length checks,
|
||||
* which is not always what we want here. The needed check will
|
||||
* be applied properly inside coerce_to_domain().
|
||||
* input routine, not domain_in(). This is to avoid premature failure
|
||||
* when the domain applies a typmod: existing input routines follow
|
||||
* implicit-coercion semantics for length checks, which is not always
|
||||
* what we want here. The needed check will be applied properly
|
||||
* inside coerce_to_domain().
|
||||
*/
|
||||
baseTypeMod = -1;
|
||||
baseTypeId = getBaseTypeAndTypmod(targetTypeId, &baseTypeMod);
|
||||
@ -180,13 +180,13 @@ coerce_type(ParseState *pstate, Node *node,
|
||||
newcon->constisnull = con->constisnull;
|
||||
|
||||
/*
|
||||
* We pass typmod -1 to the input routine, primarily because
|
||||
* existing input routines follow implicit-coercion semantics for
|
||||
* length checks, which is not always what we want here. Any
|
||||
* length constraint will be applied later by our caller.
|
||||
* We pass typmod -1 to the input routine, primarily because existing
|
||||
* input routines follow implicit-coercion semantics for length
|
||||
* checks, which is not always what we want here. Any length
|
||||
* constraint will be applied later by our caller.
|
||||
*
|
||||
* We assume here that UNKNOWN's internal representation is the
|
||||
* same as CSTRING.
|
||||
* We assume here that UNKNOWN's internal representation is the same
|
||||
* as CSTRING.
|
||||
*/
|
||||
if (!con->constisnull)
|
||||
newcon->constvalue = stringTypeDatum(targetType,
|
||||
@ -886,8 +886,8 @@ coerce_to_bigint(ParseState *pstate, Node *node,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
/* translator: first %s is name of a SQL construct, eg LIMIT */
|
||||
errmsg("argument of %s must be type bigint, not type %s",
|
||||
constructName, format_type_be(inputTypeId))));
|
||||
errmsg("argument of %s must be type bigint, not type %s",
|
||||
constructName, format_type_be(inputTypeId))));
|
||||
}
|
||||
|
||||
if (expression_returns_set(node))
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.197 2006/08/12 20:05:55 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.198 2006/10/04 00:29:55 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -65,7 +65,7 @@ static Node *transformIndirection(ParseState *pstate, Node *basenode,
|
||||
static Node *typecast_expression(ParseState *pstate, Node *expr,
|
||||
TypeName *typename);
|
||||
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
|
||||
List *largs, List *rargs, int location);
|
||||
List *largs, List *rargs, int location);
|
||||
static Node *make_row_distinct_op(ParseState *pstate, List *opname,
|
||||
RowExpr *lrow, RowExpr *rrow, int location);
|
||||
static Expr *make_distinct_op(ParseState *pstate, List *opname,
|
||||
@ -772,8 +772,8 @@ static Node *
|
||||
transformAExprOf(ParseState *pstate, A_Expr *a)
|
||||
{
|
||||
/*
|
||||
* Checking an expression for match to a list of type names.
|
||||
* Will result in a boolean constant node.
|
||||
* Checking an expression for match to a list of type names. Will result
|
||||
* in a boolean constant node.
|
||||
*/
|
||||
Node *lexpr = transformExpr(pstate, a->lexpr);
|
||||
ListCell *telem;
|
||||
@ -791,7 +791,7 @@ transformAExprOf(ParseState *pstate, A_Expr *a)
|
||||
}
|
||||
|
||||
/*
|
||||
* We have two forms: equals or not equals. Flip the sense of the result
|
||||
* We have two forms: equals or not equals. Flip the sense of the result
|
||||
* for not equals.
|
||||
*/
|
||||
if (strcmp(strVal(linitial(a->name)), "<>") == 0)
|
||||
@ -820,10 +820,10 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
|
||||
useOr = true;
|
||||
|
||||
/*
|
||||
* We try to generate a ScalarArrayOpExpr from IN/NOT IN, but this is
|
||||
* only possible if the inputs are all scalars (no RowExprs) and there
|
||||
* is a suitable array type available. If not, we fall back to a
|
||||
* boolean condition tree with multiple copies of the lefthand expression.
|
||||
* We try to generate a ScalarArrayOpExpr from IN/NOT IN, but this is only
|
||||
* possible if the inputs are all scalars (no RowExprs) and there is a
|
||||
* suitable array type available. If not, we fall back to a boolean
|
||||
* condition tree with multiple copies of the lefthand expression.
|
||||
*
|
||||
* First step: transform all the inputs, and detect whether any are
|
||||
* RowExprs.
|
||||
@ -834,7 +834,7 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
|
||||
rexprs = NIL;
|
||||
foreach(l, (List *) a->rexpr)
|
||||
{
|
||||
Node *rexpr = transformExpr(pstate, lfirst(l));
|
||||
Node *rexpr = transformExpr(pstate, lfirst(l));
|
||||
|
||||
haveRowExpr |= (rexpr && IsA(rexpr, RowExpr));
|
||||
rexprs = lappend(rexprs, rexpr);
|
||||
@ -842,10 +842,10 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
|
||||
}
|
||||
|
||||
/*
|
||||
* If not forced by presence of RowExpr, try to resolve a common
|
||||
* scalar type for all the expressions, and see if it has an array type.
|
||||
* (But if there's only one righthand expression, we may as well just
|
||||
* fall through and generate a simple = comparison.)
|
||||
* If not forced by presence of RowExpr, try to resolve a common scalar
|
||||
* type for all the expressions, and see if it has an array type. (But if
|
||||
* there's only one righthand expression, we may as well just fall through
|
||||
* and generate a simple = comparison.)
|
||||
*/
|
||||
if (!haveRowExpr && list_length(rexprs) != 1)
|
||||
{
|
||||
@ -853,9 +853,9 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
|
||||
Oid array_type;
|
||||
|
||||
/*
|
||||
* Select a common type for the array elements. Note that since
|
||||
* the LHS' type is first in the list, it will be preferred when
|
||||
* there is doubt (eg, when all the RHS items are unknown literals).
|
||||
* Select a common type for the array elements. Note that since the
|
||||
* LHS' type is first in the list, it will be preferred when there is
|
||||
* doubt (eg, when all the RHS items are unknown literals).
|
||||
*/
|
||||
scalar_type = select_common_type(typeids, "IN");
|
||||
|
||||
@ -864,8 +864,8 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
|
||||
if (array_type != InvalidOid)
|
||||
{
|
||||
/*
|
||||
* OK: coerce all the right-hand inputs to the common type
|
||||
* and build an ArrayExpr for them.
|
||||
* OK: coerce all the right-hand inputs to the common type and
|
||||
* build an ArrayExpr for them.
|
||||
*/
|
||||
List *aexprs;
|
||||
ArrayExpr *newa;
|
||||
@ -910,11 +910,11 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
|
||||
!IsA(rexpr, RowExpr))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("arguments of row IN must all be row expressions"),
|
||||
errmsg("arguments of row IN must all be row expressions"),
|
||||
parser_errposition(pstate, a->location)));
|
||||
cmp = make_row_comparison_op(pstate,
|
||||
a->name,
|
||||
(List *) copyObject(((RowExpr *) lexpr)->args),
|
||||
(List *) copyObject(((RowExpr *) lexpr)->args),
|
||||
((RowExpr *) rexpr)->args,
|
||||
a->location);
|
||||
}
|
||||
@ -1111,8 +1111,8 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
|
||||
if (sublink->subLinkType == EXISTS_SUBLINK)
|
||||
{
|
||||
/*
|
||||
* EXISTS needs no test expression or combining operator.
|
||||
* These fields should be null already, but make sure.
|
||||
* EXISTS needs no test expression or combining operator. These fields
|
||||
* should be null already, but make sure.
|
||||
*/
|
||||
sublink->testexpr = NULL;
|
||||
sublink->operName = NIL;
|
||||
@ -1140,8 +1140,8 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
|
||||
}
|
||||
|
||||
/*
|
||||
* EXPR and ARRAY need no test expression or combining operator.
|
||||
* These fields should be null already, but make sure.
|
||||
* EXPR and ARRAY need no test expression or combining operator. These
|
||||
* fields should be null already, but make sure.
|
||||
*/
|
||||
sublink->testexpr = NULL;
|
||||
sublink->operName = NIL;
|
||||
@ -1164,8 +1164,8 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
|
||||
left_list = list_make1(lefthand);
|
||||
|
||||
/*
|
||||
* Build a list of PARAM_SUBLINK nodes representing the
|
||||
* output columns of the subquery.
|
||||
* Build a list of PARAM_SUBLINK nodes representing the output columns
|
||||
* of the subquery.
|
||||
*/
|
||||
right_list = NIL;
|
||||
foreach(l, qtree->targetList)
|
||||
@ -1185,9 +1185,9 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
|
||||
}
|
||||
|
||||
/*
|
||||
* We could rely on make_row_comparison_op to complain if the
|
||||
* list lengths differ, but we prefer to generate a more specific
|
||||
* error message.
|
||||
* We could rely on make_row_comparison_op to complain if the list
|
||||
* lengths differ, but we prefer to generate a more specific error
|
||||
* message.
|
||||
*/
|
||||
if (list_length(left_list) < list_length(right_list))
|
||||
ereport(ERROR,
|
||||
@ -1968,8 +1968,8 @@ make_row_comparison_op(ParseState *pstate, List *opname,
|
||||
parser_errposition(pstate, location)));
|
||||
|
||||
/*
|
||||
* We can't compare zero-length rows because there is no principled
|
||||
* basis for figuring out what the operator is.
|
||||
* We can't compare zero-length rows because there is no principled basis
|
||||
* for figuring out what the operator is.
|
||||
*/
|
||||
if (nopers == 0)
|
||||
ereport(ERROR,
|
||||
@ -1978,8 +1978,8 @@ make_row_comparison_op(ParseState *pstate, List *opname,
|
||||
parser_errposition(pstate, location)));
|
||||
|
||||
/*
|
||||
* Identify all the pairwise operators, using make_op so that
|
||||
* behavior is the same as in the simple scalar case.
|
||||
* Identify all the pairwise operators, using make_op so that behavior is
|
||||
* the same as in the simple scalar case.
|
||||
*/
|
||||
opexprs = NIL;
|
||||
forboth(l, largs, r, rargs)
|
||||
@ -1999,9 +1999,9 @@ make_row_comparison_op(ParseState *pstate, List *opname,
|
||||
if (cmp->opresulttype != BOOLOID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("row comparison operator must yield type boolean, "
|
||||
"not type %s",
|
||||
format_type_be(cmp->opresulttype)),
|
||||
errmsg("row comparison operator must yield type boolean, "
|
||||
"not type %s",
|
||||
format_type_be(cmp->opresulttype)),
|
||||
parser_errposition(pstate, location)));
|
||||
if (expression_returns_set((Node *) cmp))
|
||||
ereport(ERROR,
|
||||
@ -2012,16 +2012,16 @@ make_row_comparison_op(ParseState *pstate, List *opname,
|
||||
}
|
||||
|
||||
/*
|
||||
* If rows are length 1, just return the single operator. In this
|
||||
* case we don't insist on identifying btree semantics for the operator
|
||||
* (but we still require it to return boolean).
|
||||
* If rows are length 1, just return the single operator. In this case we
|
||||
* don't insist on identifying btree semantics for the operator (but we
|
||||
* still require it to return boolean).
|
||||
*/
|
||||
if (nopers == 1)
|
||||
return (Node *) linitial(opexprs);
|
||||
|
||||
/*
|
||||
* Now we must determine which row comparison semantics (= <> < <= > >=)
|
||||
* apply to this set of operators. We look for btree opclasses containing
|
||||
* apply to this set of operators. We look for btree opclasses containing
|
||||
* the operators, and see which interpretations (strategy numbers) exist
|
||||
* for each operator.
|
||||
*/
|
||||
@ -2031,14 +2031,15 @@ make_row_comparison_op(ParseState *pstate, List *opname,
|
||||
i = 0;
|
||||
foreach(l, opexprs)
|
||||
{
|
||||
Bitmapset *this_strats;
|
||||
Bitmapset *this_strats;
|
||||
ListCell *j;
|
||||
|
||||
get_op_btree_interpretation(((OpExpr *) lfirst(l))->opno,
|
||||
&opclass_lists[i], &opstrat_lists[i]);
|
||||
|
||||
/*
|
||||
* convert strategy number list to a Bitmapset to make the intersection
|
||||
* calculation easy.
|
||||
* convert strategy number list to a Bitmapset to make the
|
||||
* intersection calculation easy.
|
||||
*/
|
||||
this_strats = NULL;
|
||||
foreach(j, opstrat_lists[i])
|
||||
@ -2074,21 +2075,21 @@ make_row_comparison_op(ParseState *pstate, List *opname,
|
||||
/*
|
||||
* Prefer the interpretation with the most default opclasses.
|
||||
*/
|
||||
int best_defaults = 0;
|
||||
bool multiple_best = false;
|
||||
int this_rctype;
|
||||
int best_defaults = 0;
|
||||
bool multiple_best = false;
|
||||
int this_rctype;
|
||||
|
||||
rctype = 0; /* keep compiler quiet */
|
||||
while ((this_rctype = bms_first_member(strats)) >= 0)
|
||||
{
|
||||
int ndefaults = 0;
|
||||
int ndefaults = 0;
|
||||
|
||||
for (i = 0; i < nopers; i++)
|
||||
{
|
||||
forboth(l, opclass_lists[i], r, opstrat_lists[i])
|
||||
{
|
||||
Oid opclass = lfirst_oid(l);
|
||||
int opstrat = lfirst_int(r);
|
||||
Oid opclass = lfirst_oid(l);
|
||||
int opstrat = lfirst_int(r);
|
||||
|
||||
if (opstrat == this_rctype &&
|
||||
opclass_is_default(opclass))
|
||||
@ -2116,12 +2117,12 @@ make_row_comparison_op(ParseState *pstate, List *opname,
|
||||
}
|
||||
|
||||
/*
|
||||
* For = and <> cases, we just combine the pairwise operators with
|
||||
* AND or OR respectively.
|
||||
* For = and <> cases, we just combine the pairwise operators with AND or
|
||||
* OR respectively.
|
||||
*
|
||||
* Note: this is presently the only place where the parser generates
|
||||
* BoolExpr with more than two arguments. Should be OK since the
|
||||
* rest of the system thinks BoolExpr is N-argument anyway.
|
||||
* BoolExpr with more than two arguments. Should be OK since the rest of
|
||||
* the system thinks BoolExpr is N-argument anyway.
|
||||
*/
|
||||
if (rctype == ROWCOMPARE_EQ)
|
||||
return (Node *) makeBoolExpr(AND_EXPR, opexprs);
|
||||
@ -2129,20 +2130,20 @@ make_row_comparison_op(ParseState *pstate, List *opname,
|
||||
return (Node *) makeBoolExpr(OR_EXPR, opexprs);
|
||||
|
||||
/*
|
||||
* Otherwise we need to determine exactly which opclass to associate
|
||||
* with each operator.
|
||||
* Otherwise we need to determine exactly which opclass to associate with
|
||||
* each operator.
|
||||
*/
|
||||
opclasses = NIL;
|
||||
for (i = 0; i < nopers; i++)
|
||||
{
|
||||
Oid best_opclass = 0;
|
||||
int ndefault = 0;
|
||||
int nmatch = 0;
|
||||
Oid best_opclass = 0;
|
||||
int ndefault = 0;
|
||||
int nmatch = 0;
|
||||
|
||||
forboth(l, opclass_lists[i], r, opstrat_lists[i])
|
||||
{
|
||||
Oid opclass = lfirst_oid(l);
|
||||
int opstrat = lfirst_int(r);
|
||||
Oid opclass = lfirst_oid(l);
|
||||
int opstrat = lfirst_int(r);
|
||||
|
||||
if (opstrat == rctype)
|
||||
{
|
||||
@ -2161,7 +2162,7 @@ make_row_comparison_op(ParseState *pstate, List *opname,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("could not determine interpretation of row comparison operator %s",
|
||||
strVal(llast(opname))),
|
||||
errdetail("There are multiple equally-plausible candidates."),
|
||||
errdetail("There are multiple equally-plausible candidates."),
|
||||
parser_errposition(pstate, location)));
|
||||
}
|
||||
|
||||
@ -2251,7 +2252,7 @@ make_distinct_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
|
||||
if (((OpExpr *) result)->opresulttype != BOOLOID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("IS DISTINCT FROM requires = operator to yield boolean"),
|
||||
errmsg("IS DISTINCT FROM requires = operator to yield boolean"),
|
||||
parser_errposition(pstate, location)));
|
||||
|
||||
/*
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.189 2006/07/27 19:52:05 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.190 2006/10/04 00:29:55 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -36,7 +36,7 @@
|
||||
static Node *ParseComplexProjection(ParseState *pstate, char *funcname,
|
||||
Node *first_arg, int location);
|
||||
static void unknown_attribute(ParseState *pstate, Node *relref, char *attname,
|
||||
int location);
|
||||
int location);
|
||||
|
||||
|
||||
/*
|
||||
@ -265,13 +265,13 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
||||
|
||||
/*
|
||||
* Reject attempt to call a parameterless aggregate without (*)
|
||||
* syntax. This is mere pedantry but some folks insisted ...
|
||||
* syntax. This is mere pedantry but some folks insisted ...
|
||||
*/
|
||||
if (fargs == NIL && !agg_star)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("%s(*) must be used to call a parameterless aggregate function",
|
||||
NameListToString(funcname)),
|
||||
errmsg("%s(*) must be used to call a parameterless aggregate function",
|
||||
NameListToString(funcname)),
|
||||
parser_errposition(pstate, location)));
|
||||
|
||||
/* parse_agg.c does additional aggregate-specific processing */
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.94 2006/08/02 01:59:47 joe Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.95 2006/10/04 00:29:56 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -61,15 +61,15 @@ make_parsestate(ParseState *parentParseState)
|
||||
* is a dummy (always 0, in fact).
|
||||
*
|
||||
* The locations stored in raw parsetrees are byte offsets into the source
|
||||
* string. We have to convert them to 1-based character indexes for reporting
|
||||
* to clients. (We do things this way to avoid unnecessary overhead in the
|
||||
* string. We have to convert them to 1-based character indexes for reporting
|
||||
* to clients. (We do things this way to avoid unnecessary overhead in the
|
||||
* normal non-error case: computing character indexes would be much more
|
||||
* expensive than storing token offsets.)
|
||||
*/
|
||||
int
|
||||
parser_errposition(ParseState *pstate, int location)
|
||||
{
|
||||
int pos;
|
||||
int pos;
|
||||
|
||||
/* No-op if location was not provided */
|
||||
if (location < 0)
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.89 2006/07/14 14:52:22 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.90 2006/10/04 00:29:56 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -29,7 +29,7 @@
|
||||
#include "utils/typcache.h"
|
||||
|
||||
|
||||
static Oid binary_oper_exact(List *opname, Oid arg1, Oid arg2);
|
||||
static Oid binary_oper_exact(List *opname, Oid arg1, Oid arg2);
|
||||
static FuncDetailCode oper_select_candidate(int nargs,
|
||||
Oid *input_typeids,
|
||||
FuncCandidateList candidates,
|
||||
@ -37,8 +37,8 @@ static FuncDetailCode oper_select_candidate(int nargs,
|
||||
static const char *op_signature_string(List *op, char oprkind,
|
||||
Oid arg1, Oid arg2);
|
||||
static void op_error(ParseState *pstate, List *op, char oprkind,
|
||||
Oid arg1, Oid arg2,
|
||||
FuncDetailCode fdresult, int location);
|
||||
Oid arg1, Oid arg2,
|
||||
FuncDetailCode fdresult, int location);
|
||||
static Expr *make_op_expr(ParseState *pstate, Operator op,
|
||||
Node *ltree, Node *rtree,
|
||||
Oid ltypeId, Oid rtypeId);
|
||||
@ -701,10 +701,9 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
|
||||
if (clist != NULL)
|
||||
{
|
||||
/*
|
||||
* The returned list has args in the form (0, oprright).
|
||||
* Move the useful data into args[0] to keep oper_select_candidate
|
||||
* simple. XXX we are assuming here that we may scribble on the
|
||||
* list!
|
||||
* The returned list has args in the form (0, oprright). Move the
|
||||
* useful data into args[0] to keep oper_select_candidate simple.
|
||||
* XXX we are assuming here that we may scribble on the list!
|
||||
*/
|
||||
FuncCandidateList clisti;
|
||||
|
||||
@ -872,7 +871,7 @@ make_scalar_array_op(ParseState *pstate, List *opname,
|
||||
if (!OidIsValid(rtypeId))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("op ANY/ALL (array) requires array on right side"),
|
||||
errmsg("op ANY/ALL (array) requires array on right side"),
|
||||
parser_errposition(pstate, location)));
|
||||
}
|
||||
|
||||
@ -902,12 +901,12 @@ make_scalar_array_op(ParseState *pstate, List *opname,
|
||||
if (rettype != BOOLOID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("op ANY/ALL (array) requires operator to yield boolean"),
|
||||
errmsg("op ANY/ALL (array) requires operator to yield boolean"),
|
||||
parser_errposition(pstate, location)));
|
||||
if (get_func_retset(opform->oprcode))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
||||
errmsg("op ANY/ALL (array) requires operator not to return a set"),
|
||||
errmsg("op ANY/ALL (array) requires operator not to return a set"),
|
||||
parser_errposition(pstate, location)));
|
||||
|
||||
/*
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.124 2006/08/02 01:59:47 joe Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.125 2006/10/04 00:29:56 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -48,7 +48,7 @@ static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
|
||||
List **colnames, List **colvars);
|
||||
static int specialAttNum(const char *attname);
|
||||
static void warnAutoRange(ParseState *pstate, RangeVar *relation,
|
||||
int location);
|
||||
int location);
|
||||
|
||||
|
||||
/*
|
||||
@ -970,7 +970,7 @@ addRangeTableEntryForValues(ParseState *pstate,
|
||||
numaliases = list_length(eref->colnames);
|
||||
while (numaliases < numcolumns)
|
||||
{
|
||||
char attrname[64];
|
||||
char attrname[64];
|
||||
|
||||
numaliases++;
|
||||
snprintf(attrname, sizeof(attrname), "column%d", numaliases);
|
||||
@ -1146,6 +1146,7 @@ addImplicitRTE(ParseState *pstate, RangeVar *relation, int location)
|
||||
|
||||
/* issue warning or error as needed */
|
||||
warnAutoRange(pstate, relation, location);
|
||||
|
||||
/*
|
||||
* Note that we set inFromCl true, so that the RTE will be listed
|
||||
* explicitly if the parsetree is ever decompiled by ruleutils.c. This
|
||||
@ -1311,7 +1312,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
|
||||
varattno = 0;
|
||||
foreach(lc, (List *) linitial(rte->values_lists))
|
||||
{
|
||||
Node *col = (Node *) lfirst(lc);
|
||||
Node *col = (Node *) lfirst(lc);
|
||||
|
||||
varattno++;
|
||||
if (colnames)
|
||||
@ -1676,13 +1677,13 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
|
||||
case RTE_VALUES:
|
||||
{
|
||||
/* Values RTE --- get type info from first sublist */
|
||||
List *collist = (List *) linitial(rte->values_lists);
|
||||
List *collist = (List *) linitial(rte->values_lists);
|
||||
Node *col;
|
||||
|
||||
if (attnum < 1 || attnum > list_length(collist))
|
||||
elog(ERROR, "values list %s does not have attribute %d",
|
||||
rte->eref->aliasname, attnum);
|
||||
col = (Node *) list_nth(collist, attnum-1);
|
||||
col = (Node *) list_nth(collist, attnum - 1);
|
||||
*vartype = exprType(col);
|
||||
*vartypmod = exprTypmod(col);
|
||||
}
|
||||
@ -1963,15 +1964,15 @@ warnAutoRange(ParseState *pstate, RangeVar *relation, int location)
|
||||
|
||||
/*
|
||||
* Check to see if there are any potential matches in the query's
|
||||
* rangetable. This affects the message we provide.
|
||||
* rangetable. This affects the message we provide.
|
||||
*/
|
||||
rte = searchRangeTable(pstate, relation);
|
||||
|
||||
/*
|
||||
* If we found a match that has an alias and the alias is visible in
|
||||
* the namespace, then the problem is probably use of the relation's
|
||||
* real name instead of its alias, ie "SELECT foo.* FROM foo f".
|
||||
* This mistake is common enough to justify a specific hint.
|
||||
* If we found a match that has an alias and the alias is visible in the
|
||||
* namespace, then the problem is probably use of the relation's real name
|
||||
* instead of its alias, ie "SELECT foo.* FROM foo f". This mistake is
|
||||
* common enough to justify a specific hint.
|
||||
*
|
||||
* If we found a match that doesn't meet those criteria, assume the
|
||||
* problem is illegal use of a relation outside its scope, as in the
|
||||
@ -1988,11 +1989,11 @@ warnAutoRange(ParseState *pstate, RangeVar *relation, int location)
|
||||
if (rte)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_TABLE),
|
||||
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
|
||||
relation->relname),
|
||||
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
|
||||
relation->relname),
|
||||
(badAlias ?
|
||||
errhint("Perhaps you meant to reference the table alias \"%s\".",
|
||||
badAlias) :
|
||||
errhint("Perhaps you meant to reference the table alias \"%s\".",
|
||||
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)));
|
||||
@ -2000,8 +2001,8 @@ warnAutoRange(ParseState *pstate, RangeVar *relation, int location)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_TABLE),
|
||||
(pstate->parentParseState ?
|
||||
errmsg("missing FROM-clause entry in subquery for table \"%s\"",
|
||||
relation->relname) :
|
||||
errmsg("missing FROM-clause entry in subquery for table \"%s\"",
|
||||
relation->relname) :
|
||||
errmsg("missing FROM-clause entry for table \"%s\"",
|
||||
relation->relname)),
|
||||
parser_errposition(pstate, location)));
|
||||
@ -2017,8 +2018,8 @@ warnAutoRange(ParseState *pstate, RangeVar *relation, int location)
|
||||
errmsg("adding missing FROM-clause entry for table \"%s\"",
|
||||
relation->relname)),
|
||||
(badAlias ?
|
||||
errhint("Perhaps you meant to reference the table alias \"%s\".",
|
||||
badAlias) :
|
||||
errhint("Perhaps you meant to reference the table alias \"%s\".",
|
||||
badAlias) :
|
||||
(rte ?
|
||||
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
|
||||
rte->eref->aliasname) : 0)),
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.148 2006/08/14 23:39:32 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.149 2006/10/04 00:29:56 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -161,7 +161,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
||||
* This is the identical transformation to transformTargetList, except that
|
||||
* the input list elements are bare expressions without ResTarget decoration,
|
||||
* and the output elements are likewise just expressions without TargetEntry
|
||||
* decoration. We use this for ROW() and VALUES() constructs.
|
||||
* decoration. We use this for ROW() and VALUES() constructs.
|
||||
*/
|
||||
List *
|
||||
transformExpressionList(ParseState *pstate, List *exprlist)
|
||||
@ -436,7 +436,7 @@ transformAssignedExpr(ParseState *pstate,
|
||||
colname,
|
||||
format_type_be(attrtype),
|
||||
format_type_be(type_id)),
|
||||
errhint("You will need to rewrite or cast the expression."),
|
||||
errhint("You will need to rewrite or cast the expression."),
|
||||
parser_errposition(pstate, location)));
|
||||
}
|
||||
|
||||
@ -446,7 +446,7 @@ transformAssignedExpr(ParseState *pstate,
|
||||
|
||||
/*
|
||||
* updateTargetListEntry()
|
||||
* This is used in UPDATE statements only. It prepares an UPDATE
|
||||
* This is used in UPDATE statements only. It prepares an UPDATE
|
||||
* TargetEntry for assignment to a column of the target table.
|
||||
* This includes coercing the given value to the target column's type
|
||||
* (if necessary), and dealing with any subfield names or subscripts
|
||||
@ -687,7 +687,7 @@ transformAssignmentIndirection(ParseState *pstate,
|
||||
targetName,
|
||||
format_type_be(targetTypeId),
|
||||
format_type_be(exprType(rhs))),
|
||||
errhint("You will need to rewrite or cast the expression."),
|
||||
errhint("You will need to rewrite or cast the expression."),
|
||||
parser_errposition(pstate, location)));
|
||||
else
|
||||
ereport(ERROR,
|
||||
@ -697,7 +697,7 @@ transformAssignmentIndirection(ParseState *pstate,
|
||||
targetName,
|
||||
format_type_be(targetTypeId),
|
||||
format_type_be(exprType(rhs))),
|
||||
errhint("You will need to rewrite or cast the expression."),
|
||||
errhint("You will need to rewrite or cast the expression."),
|
||||
parser_errposition(pstate, location)));
|
||||
}
|
||||
|
||||
@ -761,9 +761,9 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
|
||||
if (attrno == InvalidAttrNumber)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
||||
errmsg("column \"%s\" of relation \"%s\" does not exist",
|
||||
name,
|
||||
RelationGetRelationName(pstate->p_target_relation)),
|
||||
errmsg("column \"%s\" of relation \"%s\" does not exist",
|
||||
name,
|
||||
RelationGetRelationName(pstate->p_target_relation)),
|
||||
parser_errposition(pstate, col->location)));
|
||||
|
||||
/*
|
||||
@ -825,8 +825,8 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
|
||||
*
|
||||
* (e.g., SELECT * FROM emp, dept)
|
||||
*
|
||||
* Since the grammar only accepts bare '*' at top level of SELECT,
|
||||
* we need not handle the targetlist==false case here.
|
||||
* Since the grammar only accepts bare '*' at top level of SELECT, we
|
||||
* need not handle the targetlist==false case here.
|
||||
*/
|
||||
Assert(targetlist);
|
||||
|
||||
@ -898,7 +898,7 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
|
||||
return expandRelAttrs(pstate, rte, rtindex, sublevels_up);
|
||||
else
|
||||
{
|
||||
List *vars;
|
||||
List *vars;
|
||||
|
||||
expandRTE(rte, rtindex, sublevels_up, false,
|
||||
NULL, &vars);
|
||||
@ -1114,8 +1114,8 @@ expandRecordVariable(ParseState *pstate, Var *var, int levelsup)
|
||||
|
||||
/*
|
||||
* This case should not occur: a column of a table or values list
|
||||
* shouldn't have type RECORD. Fall through and fail
|
||||
* (most likely) at the bottom.
|
||||
* shouldn't have type RECORD. Fall through and fail (most
|
||||
* likely) at the bottom.
|
||||
*/
|
||||
break;
|
||||
case RTE_SUBQUERY:
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.84 2006/09/25 15:17:34 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.85 2006/10/04 00:29:56 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -210,7 +210,7 @@ TypeNameListToString(List *typenames)
|
||||
initStringInfo(&string);
|
||||
foreach(l, typenames)
|
||||
{
|
||||
TypeName *typename = (TypeName *) lfirst(l);
|
||||
TypeName *typename = (TypeName *) lfirst(l);
|
||||
|
||||
Assert(IsA(typename, TypeName));
|
||||
if (l != list_head(typenames))
|
||||
@ -358,7 +358,7 @@ typeTypeRelid(Type typ)
|
||||
|
||||
/*
|
||||
* Given a type structure and a string, returns the internal representation
|
||||
* of that string. The "string" can be NULL to perform conversion of a NULL
|
||||
* of that string. The "string" can be NULL to perform conversion of a NULL
|
||||
* (which might result in failure, if the input function rejects NULLs).
|
||||
*/
|
||||
Datum
|
||||
|
@ -14,7 +14,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parser.c,v 1.67 2006/07/15 03:35:21 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parser.c,v 1.68 2006/10/04 00:29:56 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -64,7 +64,7 @@ raw_parser(const char *str)
|
||||
* Intermediate filter between parser and base lexer (base_yylex in scan.l).
|
||||
*
|
||||
* The filter is needed because in some cases the standard SQL grammar
|
||||
* requires more than one token lookahead. We reduce these cases to one-token
|
||||
* requires more than one token lookahead. We reduce these cases to one-token
|
||||
* lookahead by combining tokens here, in order to keep the grammar LALR(1).
|
||||
*
|
||||
* Using a filter is simpler than trying to recognize multiword tokens
|
||||
@ -91,15 +91,16 @@ filtered_base_yylex(void)
|
||||
switch (cur_token)
|
||||
{
|
||||
case WITH:
|
||||
|
||||
/*
|
||||
* WITH CASCADED, LOCAL, or CHECK must be reduced to one token
|
||||
*
|
||||
* XXX an alternative way is to recognize just WITH_TIME and
|
||||
* put the ugliness into the datetime datatype productions
|
||||
* instead of WITH CHECK OPTION. However that requires promoting
|
||||
* WITH to a fully reserved word. If we ever have to do that
|
||||
* anyway (perhaps for SQL99 recursive queries), come back and
|
||||
* simplify this code.
|
||||
* XXX an alternative way is to recognize just WITH_TIME and put
|
||||
* the ugliness into the datetime datatype productions instead of
|
||||
* WITH CHECK OPTION. However that requires promoting WITH to a
|
||||
* fully reserved word. If we ever have to do that anyway
|
||||
* (perhaps for SQL99 recursive queries), come back and simplify
|
||||
* this code.
|
||||
*/
|
||||
lookahead_token = base_yylex();
|
||||
switch (lookahead_token)
|
||||
|
Reference in New Issue
Block a user