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