#include "parser/parse_node.h"

Go to the source code of this file.
Functions | |
| void | transformFromClause (ParseState *pstate, List *frmList) |
| int | setTargetTable (ParseState *pstate, RangeVar *relation, bool inh, bool alsoSource, AclMode requiredPerms) |
| bool | interpretInhOption (InhOption inhOpt) |
| bool | interpretOidsOption (List *defList, bool allowOids) |
| Node * | transformWhereClause (ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName) |
| Node * | transformLimitClause (ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName) |
| List * | transformGroupClause (ParseState *pstate, List *grouplist, List **targetlist, List *sortClause, ParseExprKind exprKind, bool useSQL99) |
| List * | transformSortClause (ParseState *pstate, List *orderlist, List **targetlist, ParseExprKind exprKind, bool resolveUnknown, bool useSQL99) |
| List * | transformWindowDefinitions (ParseState *pstate, List *windowdefs, List **targetlist) |
| List * | transformDistinctClause (ParseState *pstate, List **targetlist, List *sortClause, bool is_agg) |
| List * | transformDistinctOnClause (ParseState *pstate, List *distinctlist, List **targetlist, List *sortClause) |
| Index | assignSortGroupRef (TargetEntry *tle, List *tlist) |
| bool | targetIsInSortList (TargetEntry *tle, Oid sortop, List *sortList) |
| Index assignSortGroupRef | ( | TargetEntry * | tle, | |
| List * | tlist | |||
| ) |
Definition at line 2226 of file parse_clause.c.
References lfirst, and TargetEntry::ressortgroupref.
Referenced by addTargetToGroupList(), addTargetToSortList(), build_minmax_path(), create_unique_plan(), and transformDistinctOnClause().
{
Index maxRef;
ListCell *l;
if (tle->ressortgroupref) /* already has one? */
return tle->ressortgroupref;
/* easiest way to pick an unused refnumber: max used + 1 */
maxRef = 0;
foreach(l, tlist)
{
Index ref = ((TargetEntry *) lfirst(l))->ressortgroupref;
if (ref > maxRef)
maxRef = ref;
}
tle->ressortgroupref = maxRef + 1;
return tle->ressortgroupref;
}
Definition at line 226 of file parse_clause.c.
References elog, ERROR, INH_DEFAULT, INH_NO, INH_YES, and SQL_inheritance.
Referenced by AlterTable(), ExecuteTruncate(), LockTableCommand(), renameatt(), RenameConstraint(), transformDeleteStmt(), transformTableEntry(), and transformUpdateStmt().
{
switch (inhOpt)
{
case INH_NO:
return false;
case INH_YES:
return true;
case INH_DEFAULT:
return SQL_inheritance;
}
elog(ERROR, "bogus InhOption value: %d", inhOpt);
return false; /* keep compiler quiet */
}
Definition at line 252 of file parse_clause.c.
References default_with_oids, defGetBoolean(), DefElem::defname, DefElem::defnamespace, ereport, errcode(), errmsg(), ERROR, lfirst, NULL, and pg_strcasecmp().
Referenced by DefineRelation(), GetIntoRelEFlags(), and transformCreateStmt().
{
ListCell *cell;
/* Scan list to see if OIDS was included */
foreach(cell, defList)
{
DefElem *def = (DefElem *) lfirst(cell);
if (def->defnamespace == NULL &&
pg_strcasecmp(def->defname, "oids") == 0)
{
if (!allowOids)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unrecognized parameter \"%s\"",
def->defname)));
return defGetBoolean(def);
}
}
/* Force no-OIDS result if caller disallows OIDS. */
if (!allowOids)
return false;
/* OIDS option was not specified, so use default. */
return default_with_oids;
}
| int setTargetTable | ( | ParseState * | pstate, | |
| RangeVar * | relation, | |||
| bool | inh, | |||
| bool | alsoSource, | |||
| AclMode | requiredPerms | |||
| ) |
Definition at line 166 of file parse_clause.c.
References addRangeTableEntryForRelation(), addRTEtoQuery(), RangeVar::alias, Assert, heap_close, list_length(), NoLock, NULL, ParseState::p_rtable, ParseState::p_target_rangetblentry, ParseState::p_target_relation, parserOpenTable(), RangeTblEntry::requiredPerms, RowExclusiveLock, and rt_fetch.
Referenced by transformDeleteStmt(), transformInsertStmt(), and transformUpdateStmt().
{
RangeTblEntry *rte;
int rtindex;
/* Close old target; this could only happen for multi-action rules */
if (pstate->p_target_relation != NULL)
heap_close(pstate->p_target_relation, NoLock);
/*
* Open target rel and grab suitable lock (which we will hold till end of
* transaction).
*
* free_parsestate() will eventually do the corresponding heap_close(),
* but *not* release the lock.
*/
pstate->p_target_relation = parserOpenTable(pstate, relation,
RowExclusiveLock);
/*
* Now build an RTE.
*/
rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation,
relation->alias, inh, false);
pstate->p_target_rangetblentry = rte;
/* assume new rte is at end */
rtindex = list_length(pstate->p_rtable);
Assert(rte == rt_fetch(rtindex, pstate->p_rtable));
/*
* Override addRangeTableEntry's default ACL_SELECT permissions check, and
* instead mark target table as requiring exactly the specified
* permissions.
*
* If we find an explicit reference to the rel later during parse
* analysis, we will add the ACL_SELECT bit back again; see
* markVarForSelectPriv and its callers.
*/
rte->requiredPerms = requiredPerms;
/*
* If UPDATE/DELETE, add table to joinlist and namespace.
*/
if (alsoSource)
addRTEtoQuery(pstate, rte, true, true, true);
return rtindex;
}
| bool targetIsInSortList | ( | TargetEntry * | tle, | |
| Oid | sortop, | |||
| List * | sortList | |||
| ) |
Definition at line 2267 of file parse_clause.c.
References get_commutator(), InvalidOid, lfirst, TargetEntry::ressortgroupref, SortGroupClause::sortop, and SortGroupClause::tleSortGroupRef.
Referenced by addTargetToGroupList(), addTargetToSortList(), examine_simple_variable(), qual_is_pushdown_safe(), transformDistinctOnClause(), and transformGroupClause().
{
Index ref = tle->ressortgroupref;
ListCell *l;
/* no need to scan list if tle has no marker */
if (ref == 0)
return false;
foreach(l, sortList)
{
SortGroupClause *scl = (SortGroupClause *) lfirst(l);
if (scl->tleSortGroupRef == ref &&
(sortop == InvalidOid ||
sortop == scl->sortop ||
sortop == get_commutator(scl->sortop)))
return true;
}
return false;
}
| List* transformDistinctClause | ( | ParseState * | pstate, | |
| List ** | targetlist, | |||
| List * | sortClause, | |||
| bool | is_agg | |||
| ) |
Definition at line 1819 of file parse_clause.c.
References addTargetToGroupList(), copyObject(), ereport, errcode(), errmsg(), ERROR, TargetEntry::expr, exprLocation(), get_sortgroupclause_tle(), lappend(), lfirst, parser_errposition(), and TargetEntry::resjunk.
Referenced by transformAggregateCall(), and transformSelectStmt().
{
List *result = NIL;
ListCell *slitem;
ListCell *tlitem;
/*
* The distinctClause should consist of all ORDER BY items followed by all
* other non-resjunk targetlist items. There must not be any resjunk
* ORDER BY items --- that would imply that we are sorting by a value that
* isn't necessarily unique within a DISTINCT group, so the results
* wouldn't be well-defined. This construction ensures we follow the rule
* that sortClause and distinctClause match; in fact the sortClause will
* always be a prefix of distinctClause.
*
* Note a corner case: the same TLE could be in the ORDER BY list multiple
* times with different sortops. We have to include it in the
* distinctClause the same way to preserve the prefix property. The net
* effect will be that the TLE value will be made unique according to both
* sortops.
*/
foreach(slitem, sortClause)
{
SortGroupClause *scl = (SortGroupClause *) lfirst(slitem);
TargetEntry *tle = get_sortgroupclause_tle(scl, *targetlist);
if (tle->resjunk)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
is_agg ?
errmsg("in an aggregate with DISTINCT, ORDER BY expressions must appear in argument 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));
}
/*
* Now add any remaining non-resjunk tlist items, using default sort/group
* semantics for their data types.
*/
foreach(tlitem, *targetlist)
{
TargetEntry *tle = (TargetEntry *) lfirst(tlitem);
if (tle->resjunk)
continue; /* ignore junk */
result = addTargetToGroupList(pstate, tle,
result, *targetlist,
exprLocation((Node *) tle->expr),
true);
}
return result;
}
| List* transformDistinctOnClause | ( | ParseState * | pstate, | |
| List * | distinctlist, | |||
| List ** | targetlist, | |||
| List * | sortClause | |||
| ) |
Definition at line 1890 of file parse_clause.c.
References addTargetToGroupList(), assignSortGroupRef(), copyObject(), ereport, errcode(), errmsg(), ERROR, EXPR_KIND_DISTINCT_ON, exprLocation(), findTargetlistEntrySQL92(), forboth, get_matching_location(), get_sortgroupref_tle(), InvalidOid, lappend(), lappend_int(), lfirst, lfirst_int, list_member_int(), parser_errposition(), targetIsInSortList(), and SortGroupClause::tleSortGroupRef.
Referenced by transformSelectStmt().
{
List *result = NIL;
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 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(lc, distinctlist)
{
Node *dexpr = (Node *) lfirst(lc);
int sortgroupref;
TargetEntry *tle;
tle = findTargetlistEntrySQL92(pstate, dexpr, targetlist,
EXPR_KIND_DISTINCT_ON);
sortgroupref = assignSortGroupRef(tle, *targetlist);
sortgrouprefs = lappend_int(sortgrouprefs, sortgroupref);
}
/*
* If the user writes both DISTINCT ON and ORDER BY, adopt the sorting
* semantics from ORDER BY items that match DISTINCT ON items, and also
* adopt their column sort order. We insist that the distinctClause and
* sortClause match, so throw error if we find the need to add any more
* distinctClause items after we've skipped an ORDER BY item that wasn't
* in DISTINCT ON.
*/
skipped_sortitem = false;
foreach(lc, sortClause)
{
SortGroupClause *scl = (SortGroupClause *) lfirst(lc);
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"),
parser_errposition(pstate,
get_matching_location(scl->tleSortGroupRef,
sortgrouprefs,
distinctlist))));
else
result = lappend(result, copyObject(scl));
}
else
skipped_sortitem = true;
}
/*
* Now add any remaining DISTINCT ON items, using default sort/group
* semantics for their data types. (Note: this is pretty questionable; if
* the ORDER BY list doesn't include all the DISTINCT ON items and more
* besides, you certainly aren't using DISTINCT ON in the intended way,
* and you probably aren't going to get consistent results. It might be
* better to throw an error or warning here. But historically we've
* allowed it, so keep doing so.)
*/
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))
continue; /* already in list (with some semantics) */
if (skipped_sortitem)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
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;
}
| void transformFromClause | ( | ParseState * | pstate, | |
| List * | frmList | |||
| ) |
Definition at line 100 of file parse_clause.c.
References checkNameSpaceConflicts(), lappend(), lfirst, list_concat(), ParseState::p_joinlist, ParseState::p_namespace, setNamespaceLateralState(), and transformFromClauseItem().
Referenced by transformDeleteStmt(), transformSelectStmt(), and transformUpdateStmt().
{
ListCell *fl;
/*
* The grammar will have produced a list of RangeVars, RangeSubselects,
* RangeFunctions, and/or JoinExprs. Transform each one (possibly adding
* entries to the rtable), check for duplicate refnames, and then add it
* to the joinlist and namespace.
*
* Note we must process the items left-to-right for proper handling of
* LATERAL references.
*/
foreach(fl, frmList)
{
Node *n = lfirst(fl);
RangeTblEntry *rte;
int rtindex;
List *namespace;
n = transformFromClauseItem(pstate, n,
&rte,
&rtindex,
&namespace);
checkNameSpaceConflicts(pstate, pstate->p_namespace, namespace);
/* Mark the new namespace items as visible only to LATERAL */
setNamespaceLateralState(namespace, true, true);
pstate->p_joinlist = lappend(pstate->p_joinlist, n);
pstate->p_namespace = list_concat(pstate->p_namespace, namespace);
}
/*
* We're done parsing the FROM list, so make all namespace items
* unconditionally visible. Note that this will also reset lateral_only
* for any namespace items that were already present when we were called;
* but those should have been that way already.
*/
setNamespaceLateralState(pstate->p_namespace, false, true);
}
| List* transformGroupClause | ( | ParseState * | pstate, | |
| List * | grouplist, | |||
| List ** | targetlist, | |||
| List * | sortClause, | |||
| ParseExprKind | exprKind, | |||
| bool | useSQL99 | |||
| ) |
Definition at line 1557 of file parse_clause.c.
References addTargetToGroupList(), copyObject(), exprLocation(), findTargetlistEntrySQL92(), findTargetlistEntrySQL99(), InvalidOid, lappend(), lfirst, TargetEntry::ressortgroupref, targetIsInSortList(), and SortGroupClause::tleSortGroupRef.
Referenced by transformSelectStmt(), and transformWindowDefinitions().
{
List *result = NIL;
ListCell *gl;
foreach(gl, grouplist)
{
Node *gexpr = (Node *) lfirst(gl);
TargetEntry *tle;
bool found = false;
if (useSQL99)
tle = findTargetlistEntrySQL99(pstate, gexpr,
targetlist, exprKind);
else
tle = findTargetlistEntrySQL92(pstate, gexpr,
targetlist, exprKind);
/* Eliminate duplicates (GROUP BY x, x) */
if (targetIsInSortList(tle, InvalidOid, result))
continue;
/*
* If the GROUP BY tlist entry also appears in ORDER BY, copy operator
* info from the (first) matching ORDER BY item. This means that if
* you write something like "GROUP BY foo ORDER BY foo USING <<<", the
* GROUP BY operation silently takes on the equality semantics implied
* by the ORDER BY. There are two reasons to do this: it improves the
* odds that we can implement both GROUP BY and ORDER BY with a single
* sort step, and it allows the user to choose the equality semantics
* used by GROUP BY, should she be working with a datatype that has
* more than one equality operator.
*/
if (tle->ressortgroupref > 0)
{
ListCell *sl;
foreach(sl, sortClause)
{
SortGroupClause *sc = (SortGroupClause *) lfirst(sl);
if (sc->tleSortGroupRef == tle->ressortgroupref)
{
result = lappend(result, copyObject(sc));
found = true;
break;
}
}
}
/*
* If no match in ORDER BY, just add it to the result using default
* sort/group semantics.
*/
if (!found)
result = addTargetToGroupList(pstate, tle,
result, *targetlist,
exprLocation(gexpr),
true);
}
return result;
}
| Node* transformLimitClause | ( | ParseState * | pstate, | |
| Node * | clause, | |||
| ParseExprKind | exprKind, | |||
| const char * | constructName | |||
| ) |
Definition at line 1218 of file parse_clause.c.
References checkExprIsVarFree(), coerce_to_specific_type(), INT8OID, NULL, and transformExpr().
Referenced by transformSelectStmt(), transformSetOperationStmt(), and transformValuesClause().
{
Node *qual;
if (clause == NULL)
return NULL;
qual = transformExpr(pstate, clause, exprKind);
qual = coerce_to_specific_type(pstate, qual, INT8OID, constructName);
/* LIMIT can't refer to any variables of the current query */
checkExprIsVarFree(pstate, qual, constructName);
return qual;
}
| List* transformSortClause | ( | ParseState * | pstate, | |
| List * | orderlist, | |||
| List ** | targetlist, | |||
| ParseExprKind | exprKind, | |||
| bool | resolveUnknown, | |||
| bool | useSQL99 | |||
| ) |
Definition at line 1634 of file parse_clause.c.
References addTargetToSortList(), findTargetlistEntrySQL92(), findTargetlistEntrySQL99(), lfirst, and SortBy::node.
Referenced by transformAggregateCall(), transformSelectStmt(), transformSetOperationStmt(), transformValuesClause(), and transformWindowDefinitions().
{
List *sortlist = NIL;
ListCell *olitem;
foreach(olitem, orderlist)
{
SortBy *sortby = (SortBy *) lfirst(olitem);
TargetEntry *tle;
if (useSQL99)
tle = findTargetlistEntrySQL99(pstate, sortby->node,
targetlist, exprKind);
else
tle = findTargetlistEntrySQL92(pstate, sortby->node,
targetlist, exprKind);
sortlist = addTargetToSortList(pstate, tle,
sortlist, *targetlist, sortby,
resolveUnknown);
}
return sortlist;
}
| Node* transformWhereClause | ( | ParseState * | pstate, | |
| Node * | clause, | |||
| ParseExprKind | exprKind, | |||
| const char * | constructName | |||
| ) |
Definition at line 1191 of file parse_clause.c.
References coerce_to_boolean(), NULL, and transformExpr().
Referenced by CreateTrigger(), transformDeleteStmt(), transformIndexStmt(), transformJoinOnClause(), transformRuleStmt(), transformSelectStmt(), and transformUpdateStmt().
{
Node *qual;
if (clause == NULL)
return NULL;
qual = transformExpr(pstate, clause, exprKind);
qual = coerce_to_boolean(pstate, qual, constructName);
return qual;
}
| List* transformWindowDefinitions | ( | ParseState * | pstate, | |
| List * | windowdefs, | |||
| List ** | targetlist | |||
| ) |
Definition at line 1669 of file parse_clause.c.
References WindowClause::copiedOrder, copyObject(), WindowDef::endOffset, WindowClause::endOffset, ereport, errcode(), errmsg(), ERROR, EXPR_KIND_WINDOW_ORDER, EXPR_KIND_WINDOW_PARTITION, findWindowClause(), FRAMEOPTION_DEFAULTS, WindowDef::frameOptions, WindowClause::frameOptions, lappend(), lfirst, WindowDef::location, makeNode, WindowClause::name, WindowDef::name, NULL, WindowClause::orderClause, WindowDef::orderClause, parser_errposition(), WindowClause::partitionClause, WindowDef::partitionClause, WindowClause::refname, WindowDef::refname, WindowDef::startOffset, WindowClause::startOffset, transformFrameOffset(), transformGroupClause(), transformSortClause(), and WindowClause::winref.
Referenced by transformSelectStmt().
{
List *result = NIL;
Index winref = 0;
ListCell *lc;
foreach(lc, windowdefs)
{
WindowDef *windef = (WindowDef *) lfirst(lc);
WindowClause *refwc = NULL;
List *partitionClause;
List *orderClause;
WindowClause *wc;
winref++;
/*
* Check for duplicate window names.
*/
if (windef->name &&
findWindowClause(result, windef->name) != NULL)
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("window \"%s\" is already defined", windef->name),
parser_errposition(pstate, windef->location)));
/*
* If it references a previous window, look that up.
*/
if (windef->refname)
{
refwc = findWindowClause(result, windef->refname);
if (refwc == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("window \"%s\" does not exist",
windef->refname),
parser_errposition(pstate, windef->location)));
}
/*
* Transform PARTITION and ORDER specs, if any. These are treated
* almost exactly like top-level GROUP BY and ORDER BY clauses,
* including the special handling of nondefault operator semantics.
*/
orderClause = transformSortClause(pstate,
windef->orderClause,
targetlist,
EXPR_KIND_WINDOW_ORDER,
true /* fix unknowns */ ,
true /* force SQL99 rules */ );
partitionClause = transformGroupClause(pstate,
windef->partitionClause,
targetlist,
orderClause,
EXPR_KIND_WINDOW_PARTITION,
true /* force SQL99 rules */ );
/*
* And prepare the new WindowClause.
*/
wc = makeNode(WindowClause);
wc->name = windef->name;
wc->refname = windef->refname;
/*
* Per spec, a windowdef that references a previous one copies the
* previous partition clause (and mustn't specify its own). It can
* specify its own ordering clause. but only if the previous one had
* none. It always specifies its own frame clause, and the previous
* one must not have a frame clause. (Yeah, it's bizarre that each of
* these cases works differently, but SQL:2008 says so; see 7.11
* <window clause> syntax rule 10 and general rule 1.)
*/
if (refwc)
{
if (partitionClause)
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("cannot override PARTITION BY clause of window \"%s\"",
windef->refname),
parser_errposition(pstate, windef->location)));
wc->partitionClause = copyObject(refwc->partitionClause);
}
else
wc->partitionClause = partitionClause;
if (refwc)
{
if (orderClause && refwc->orderClause)
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("cannot override ORDER BY clause of window \"%s\"",
windef->refname),
parser_errposition(pstate, windef->location)));
if (orderClause)
{
wc->orderClause = orderClause;
wc->copiedOrder = false;
}
else
{
wc->orderClause = copyObject(refwc->orderClause);
wc->copiedOrder = true;
}
}
else
{
wc->orderClause = orderClause;
wc->copiedOrder = false;
}
if (refwc && refwc->frameOptions != FRAMEOPTION_DEFAULTS)
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("cannot override frame clause of window \"%s\"",
windef->refname),
parser_errposition(pstate, windef->location)));
wc->frameOptions = windef->frameOptions;
/* Process frame offset expressions */
wc->startOffset = transformFrameOffset(pstate, wc->frameOptions,
windef->startOffset);
wc->endOffset = transformFrameOffset(pstate, wc->frameOptions,
windef->endOffset);
wc->winref = winref;
result = lappend(result, wc);
}
return result;
}
1.7.1