/* *Supportforfuzzilymatchingcolumns. * *Thisisforbuildingdiagnosticmessages,wheremultipleornon-exact *matchingattributesareofinterest. * *"distance"isthecurrentbestfuzzy-matchdistanceifrfirstisn'tNULL, *otherwiseitisthemaximumacceptabledistanceplus1. * *rfirst/firstrecordtheclosestnon-exactmatchsofar,anddistance *isitsdistancefromthetargetname.Ifwehavefoundasecondnon-exact *matchofexactlythesamedistance,rsecond/secondrecordthat.(If *wefindthreeofthesamedistance,weconcludethat"distance"isnot *atightenoughboundforausefulhintandclearrfirst/rsecondagain. *Onlyifwelaterfindsomethingcloserwillwere-populaterfirst.) * *rexact1/exact1recordthelocationofthefirstexactly-matchingcolumn, *ifany.Ifwefindmultipleexactmatchesthenrexact2/exact2record *anotherone(wedon'tespeciallycarewhich).Currently,theseget *populatedindependentlyofthefuzzy-matchfields.
*/ typedefstruct
{ int distance; /* Current or limit distance */
RangeTblEntry *rfirst; /* RTE of closest non-exact match, or NULL */
AttrNumber first; /* Col index in rfirst */
RangeTblEntry *rsecond; /* RTE of another non-exact match w/same dist */
AttrNumber second; /* Col index in rsecond */
RangeTblEntry *rexact1; /* RTE of first exact match, or NULL */
AttrNumber exact1; /* Col index in rexact1 */
RangeTblEntry *rexact2; /* RTE of second exact match, or NULL */
AttrNumber exact2; /* Col index in rexact2 */
} FuzzyAttrMatchState;
#define MAX_FUZZY_DISTANCE 3
static ParseNamespaceItem *scanNameSpaceForRefname(ParseState *pstate, constchar *refname, int location); static ParseNamespaceItem *scanNameSpaceForRelid(ParseState *pstate, Oid relid, int location); staticvoid check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem, int location); staticint scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
Alias *eref, constchar *colname, int location, int fuzzy_rte_penalty,
FuzzyAttrMatchState *fuzzystate); staticvoid markRTEForSelectPriv(ParseState *pstate, int rtindex, AttrNumber col); staticvoid expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
VarReturningType returning_type, int location, bool include_dropped,
List **colnames, List **colvars); staticvoid expandTupleDesc(TupleDesc tupdesc, Alias *eref, int count, int offset, int rtindex, int sublevels_up,
VarReturningType returning_type, int location, bool include_dropped,
List **colnames, List **colvars); staticint specialAttNum(constchar *attname); staticbool rte_visible_if_lateral(ParseState *pstate, RangeTblEntry *rte); staticbool rte_visible_if_qualified(ParseState *pstate, RangeTblEntry *rte); staticbool isQueryUsingTempRelation_walker(Node *node, void *context);
/* Ignore columns-only items */ if (!nsitem->p_rel_visible) continue; /* If not inside LATERAL, ignore lateral-only items */ if (nsitem->p_lateral_only && !pstate->p_lateral_active) continue; /* Ignore OLD/NEW namespace items that can appear in RETURNING */ if (nsitem->p_returning_type != VAR_RETURNING_DEFAULT) continue;
/* yes, the test for alias == NULL should be there... */ if (rte->rtekind == RTE_RELATION &&
rte->relid == relid &&
rte->alias == NULL)
{ if (result)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_ALIAS),
errmsg("table reference %u is ambiguous",
relid),
parser_errposition(pstate, location)));
check_lateral_ref_ok(pstate, nsitem, location);
result = nsitem;
}
} return result;
}
/* *Searchthequery'sCTEnamespaceforaCTEmatchingthegivenunqualified *refname.ReturntheCTE(anditslevelsupcount)ifamatch,orNULL *ifnomatch.Weneednotworryaboutmultiplematches,sinceparse_cte.c *rejectsWITHlistscontainingduplicateCTEnames.
*/
CommonTableExpr *
scanNameSpaceForCTE(ParseState *pstate, constchar *refname,
Index *ctelevelsup)
{
Index levelsup;
if (!cte && !isenr)
relId = RangeVarGetRelid(relation, NoLock, true);
/* Now look for RTEs matching either the relation/CTE/ENR or the alias */ for (levelsup = 0;
pstate != NULL;
pstate = pstate->parentParseState, levelsup++)
{
ListCell *l;
if (!nsitem2->p_rel_visible) continue; if (strcmp(aliasname2, aliasname1) != 0) continue; /* definitely no conflict */ if (rte1->rtekind == RTE_RELATION && rte1->alias == NULL &&
rte2->rtekind == RTE_RELATION && rte2->alias == NULL &&
rte1->relid != rte2->relid) continue; /* no conflict per SQL rule */
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_ALIAS),
errmsg("table name \"%s\" specified more than once",
aliasname1)));
}
}
}
/* *ComplainifanamespaceitemiscurrentlydisallowedasaLATERALreference. *ThisenforcesbothSQL:2008'sratheroddideaofwhattodowithaLATERAL *referencetothewrongsideofanouterjoin,andourownprohibitionon *referencingthetargettableofanUPDATEorDELETEasalateralreference *inaFROM/USINGclause. * *Note:thepstateshouldbethesamequerylevelthensitemwasfoundin. * *Conveniencesubroutinetoavoidmultiplecopiesofaratheruglyereport.
*/ staticvoid
check_lateral_ref_ok(ParseState *pstate, ParseNamespaceItem *nsitem, int location)
{ if (nsitem->p_lateral_only && !nsitem->p_lateral_ok)
{ /* SQL:2008 demands this be an error, not an invisible item */
RangeTblEntry *rte = nsitem->p_rte; char *refname = nsitem->p_names->aliasname;
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
refname),
(pstate->p_target_nsitem != NULL &&
rte == pstate->p_target_nsitem->p_rte) ?
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
refname) :
errdetail("The combining JOIN type must be INNER or LEFT for a LATERAL reference."),
parser_errposition(pstate, location)));
}
}
/* *GivenanRTindexandnestingdepth,findthecorresponding *ParseNamespaceItem(theremustbeone).
*/
ParseNamespaceItem *
GetNSItemByRangeTablePosn(ParseState *pstate, int varno, int sublevels_up)
{
ListCell *lc;
if (attnum == InvalidAttrNumber) return NULL; /* Return NULL if no match */
/* In constraint check, no system column is allowed except tableOid */ if (pstate->p_expr_kind == EXPR_KIND_CHECK_CONSTRAINT &&
attnum < InvalidAttrNumber && attnum != TableOidAttributeNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("system column \"%s\" reference in check constraint is invalid",
colname),
parser_errposition(pstate, location)));
/* *Ingeneratedcolumn,nosystemcolumnisallowedexcepttableOid. *(Requiredforstoredgenerated,butwealsodoitforvirtualgenerated *fornowforconsistency.)
*/ if (pstate->p_expr_kind == EXPR_KIND_GENERATED_COLUMN &&
attnum < InvalidAttrNumber && attnum != TableOidAttributeNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("cannot use system column \"%s\" in column generation expression",
colname),
parser_errposition(pstate, location)));
/* *InaMERGEWHENcondition,nosystemcolumnisallowedexcepttableOid
*/ if (pstate->p_expr_kind == EXPR_KIND_MERGE_WHEN &&
attnum < InvalidAttrNumber && attnum != TableOidAttributeNumber)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("cannot use system column \"%s\" in MERGE WHEN condition",
colname),
parser_errposition(pstate, location)));
/* Found a valid match, so build a Var */ if (attnum > InvalidAttrNumber)
{ /* Get attribute data from the ParseNamespaceColumn array */
ParseNamespaceColumn *nscol = &nsitem->p_nscolumns[attnum - 1];
/* Complain if dropped column. See notes in scanRTEForColumn. */ if (nscol->p_varno == 0)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
colname,
nsitem->p_names->aliasname)));
var = makeVar(nscol->p_varno,
nscol->p_varattno,
nscol->p_vartype,
nscol->p_vartypmod,
nscol->p_varcollid,
sublevels_up); /* makeVar doesn't offer parameters for these, so set them by hand: */
var->varnosyn = nscol->p_varnosyn;
var->varattnosyn = nscol->p_varattnosyn;
} else
{ /* System column, so use predetermined type data */ const FormData_pg_attribute *sysatt;
attnum++; if (strcmp(attcolname, colname) == 0)
{ if (result)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_COLUMN),
errmsg("column reference \"%s\" is ambiguous",
colname),
parser_errposition(pstate, location)));
result = attnum;
}
/* Update fuzzy match state, if provided. */ if (fuzzystate != NULL)
updateFuzzyAttrMatchState(fuzzy_rte_penalty, fuzzystate,
rte, attcolname, colname, attnum);
}
/* *Ifwehaveauniquematch,returnit.Notethatthisallowsauser *aliastooverrideasystemcolumnname(suchasOID)withouterror.
*/ if (result) return result;
/* *IftheRTErepresentsarealrelation,considersystemcolumnnames. *Compositesareonlyusedforpseudo-relationslikeONCONFLICT's *excluded.
*/ if (rte->rtekind == RTE_RELATION &&
rte->relkind != RELKIND_COMPOSITE_TYPE)
{ /* quick check to see if name could be a system column */
attnum = specialAttNum(colname); if (attnum != InvalidAttrNumber)
{ /* now check to see if column actually is defined */ if (SearchSysCacheExists2(ATTNUM,
ObjectIdGetDatum(rte->relid),
Int16GetDatum(attnum)))
result = attnum;
}
}
if (rte->rtekind == RTE_RELATION)
{
RTEPermissionInfo *perminfo;
/* Make sure the rel as a whole is marked for SELECT access */
perminfo = getRTEPermissionInfo(pstate->p_rteperminfos, rte);
perminfo->requiredPerms |= ACL_SELECT; /* Must offset the attnum to fit in a bitmapset */
perminfo->selectedCols =
bms_add_member(perminfo->selectedCols,
col - FirstLowInvalidHeapAttributeNumber);
} elseif (rte->rtekind == RTE_JOIN)
{ if (col == InvalidAttrNumber)
{ /* *Awhole-rowreferencetoajoinhastobetreatedaswhole-row *referencestothetwoinputs.
*/
JoinExpr *j;
if (rtindex > 0 && rtindex <= list_length(pstate->p_joinexprs))
j = list_nth_node(JoinExpr, pstate->p_joinexprs, rtindex - 1); else
j = NULL; if (j == NULL)
elog(ERROR, "could not find JoinExpr for whole-row reference");
/* Note: we can't see FromExpr here */ if (IsA(j->larg, RangeTblRef))
{ int varno = ((RangeTblRef *) j->larg)->rtindex;
if (attr->attisdropped)
{ /* Always insert an empty string for a dropped column */
attrname = makeString(pstrdup("")); if (aliaslc)
alias->colnames = lappend(alias->colnames, attrname);
numdropped++;
} elseif (aliaslc)
{ /* Use the next user-supplied alias */
attrname = lfirst_node(String, aliaslc);
aliaslc = lnext(aliaslist, aliaslc);
alias->colnames = lappend(alias->colnames, attrname);
} else
{
attrname = makeString(pstrdup(NameStr(attr->attname))); /* we're done with the alias if any */
}
/* Too many user-supplied aliases? */ if (aliaslc)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("table \"%s\" has %d columns available but %d columns specified",
eref->aliasname, maxattrs - numdropped, numaliases)));
}
setup_parser_errposition_callback(&pcbstate, pstate, relation->location);
rel = table_openrv_extended(relation, lockmode, true); if (rel == NULL)
{ if (relation->schemaname)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation \"%s.%s\" does not exist",
relation->schemaname, relation->relname))); else
{ /* *Anunqualifiednamemighthavebeenmeantasareferenceto *somenot-yet-in-scopeCTE.Thebare"doesnotexist"message *hasprovenremarkablyunhelpfulforfiguringoutsuchproblems, *sowetakepainstoofferaspecifichint.
*/ if (isFutureCTE(pstate, relation->relname))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation \"%s\" does not exist",
relation->relname),
errdetail("There is a WITH item named \"%s\", but it cannot be referenced from this part of the query.",
relation->relname),
errhint("Use WITH RECURSIVE, or re-order the WITH items to remove forward references."))); else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation \"%s\" does not exist",
relation->relname)));
}
}
cancel_parser_errposition_callback(&pcbstate); return rel;
}
/* fill in any unspecified alias columns, and extract column type info */
coltypes = coltypmods = colcollations = NIL;
varattno = 0;
foreach(tlistitem, subquery->targetList)
{
TargetEntry *te = (TargetEntry *) lfirst(tlistitem);
if (te->resjunk) continue;
varattno++;
Assert(varattno == te->resno); if (varattno > numaliases)
{ char *attrname;
/* *AcoldeflistisrequiredifthefunctionreturnsRECORDandhasn't *gotapredeterminedrecordtype,andisprohibitedotherwise.This *canbeabitconfusing,soweexpendsomeeffortondeliveringa *relevanterrormessage.
*/ if (coldeflist != NIL)
{ switch (functypclass)
{ case TYPEFUNC_RECORD: /* ok */ break; case TYPEFUNC_COMPOSITE: case TYPEFUNC_COMPOSITE_DOMAIN:
/* *Ifthefunction'srawresulttypeisRECORD,wemust *haveresolveditusingitsOUTparameters.Otherwise, *itmusthaveanamedcompositetype.
*/ if (exprType(funcexpr) == RECORDOID)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("a column definition list is redundant for a function with OUT parameters"),
parser_errposition(pstate,
exprLocation((Node *) coldeflist)))); else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("a column definition list is redundant for a function returning a named composite type"),
parser_errposition(pstate,
exprLocation((Node *) coldeflist)))); break; default:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("a column definition list is only allowed for functions returning \"record\""),
parser_errposition(pstate,
exprLocation((Node *) coldeflist)))); break;
}
} else
{ if (functypclass == TYPEFUNC_RECORD)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("a column definition list is required for functions returning \"record\""),
parser_errposition(pstate, exprLocation(funcexpr))));
}
if (functypclass == TYPEFUNC_COMPOSITE ||
functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
{ /* Composite data type, e.g. a table's row type */
Assert(tupdesc);
} elseif (functypclass == TYPEFUNC_SCALAR)
{ /* Base data type, i.e. scalar */
tupdesc = CreateTemplateTupleDesc(1);
TupleDescInitEntry(tupdesc,
(AttrNumber) 1,
chooseScalarFunctionAlias(funcexpr, funcname,
alias, nfuncs),
funcrettype,
exprTypmod(funcexpr), 0);
TupleDescInitEntryCollation(tupdesc,
(AttrNumber) 1,
exprCollation(funcexpr));
} elseif (functypclass == TYPEFUNC_RECORD)
{
ListCell *col;
/* *Usethecolumndefinitionlisttoconstructatupdescandfill *intheRangeTblFunction'slists.Limitnumberofcolumnsto *MaxHeapAttributeNumber,becauseCheckAttributeNamesTypeswill.
*/ if (list_length(coldeflist) > MaxHeapAttributeNumber)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_COLUMNS),
errmsg("column definition lists can have at most %d entries",
MaxHeapAttributeNumber),
parser_errposition(pstate,
exprLocation((Node *) coldeflist))));
tupdesc = CreateTemplateTupleDesc(list_length(coldeflist));
i = 1;
foreach(col, coldeflist)
{
ColumnDef *n = (ColumnDef *) lfirst(col); char *attrname;
Oid attrtype;
int32 attrtypmod;
Oid attrcollation;
/* *Ensurethatthecoldeflistdefinesalegalsetofnames(no *duplicates,butweneedn'tworryaboutsystemcolumnnames)and *datatypes.Althoughwemostlycan'tallowpseudo-types,it *seemssafetoallowRECORDandRECORD[],sincevalueswithin *thosetypeclassesareself-identifyingatruntime,andthe *coldeflistdoesn'trepresentanythingthatwillbevisibleto *othersessions.
*/
CheckAttributeNamesTypes(tupdesc, RELKIND_COMPOSITE_TYPE,
CHKATYPE_ANYRECORD);
} else
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("function \"%s\" in FROM has unsupported return type %s",
funcname, format_type_be(funcrettype)),
parser_errposition(pstate, exprLocation(funcexpr))));
/* Finish off the RangeTblFunction and add it to the RTE's list */
rtfunc->funccolcount = tupdesc->natts;
rte->functions = lappend(rte->functions, rtfunc);
/* Save the tupdesc for use below */
functupdescs[funcno] = tupdesc;
totalatts += tupdesc->natts;
funcno++;
}
/* *Ifthere'smorethanonefunction,orwewantanordinalitycolumn,we *havetoproduceamergedtupdesc.
*/ if (nfuncs > 1 || rangefunc->ordinality)
{ if (rangefunc->ordinality)
totalatts++;
/* Disallow more columns than will fit in a tuple */ if (totalatts > MaxTupleAttributeNumber)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_COLUMNS),
errmsg("functions in FROM can return at most %d columns",
MaxTupleAttributeNumber),
parser_errposition(pstate,
exprLocation((Node *) funcexprs))));
/* Merge the tuple descs of each function into a composite one */
tupdesc = CreateTemplateTupleDesc(totalatts);
natts = 0; for (i = 0; i < nfuncs; i++)
{ for (j = 1; j <= functupdescs[i]->natts; j++)
TupleDescCopyEntry(tupdesc, ++natts, functupdescs[i], j);
}
/* Add the ordinality column if needed */ if (rangefunc->ordinality)
{
TupleDescInitEntry(tupdesc,
(AttrNumber) ++natts, "ordinality",
INT8OID,
-1, 0); /* no need to set collation */
}
Assert(natts == totalatts);
} else
{ /* We can just use the single function's tupdesc as-is */
tupdesc = functupdescs[0];
}
/* Use the tupdesc while assigning column aliases for the RTE */
buildRelationAliases(tupdesc, alias, eref);
/* *Addanentryforatablefunctiontothepstate'srangetable(p_rtable). *Then,constructandreturnaParseNamespaceItemforthenewRTE. * *ThisismuchlikeaddRangeTableEntry()exceptthatitmakesatablefuncRTE.
*/
ParseNamespaceItem *
addRangeTableEntryForTableFunc(ParseState *pstate,
TableFunc *tf,
Alias *alias, bool lateral, bool inFromCl)
{
RangeTblEntry *rte = makeNode(RangeTblEntry); char *refname;
Alias *eref; int numaliases;
Assert(pstate != NULL);
/* Disallow more columns than will fit in a tuple */ if (list_length(tf->colnames) > MaxTupleAttributeNumber)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_COLUMNS),
errmsg("functions in FROM can return at most %d columns",
MaxTupleAttributeNumber),
parser_errposition(pstate,
exprLocation((Node *) tf))));
Assert(list_length(tf->coltypes) == list_length(tf->colnames));
Assert(list_length(tf->coltypmods) == list_length(tf->colnames));
Assert(list_length(tf->colcollations) == list_length(tf->colnames));
/* fill in any unspecified alias columns */ if (numaliases < list_length(tf->colnames))
eref->colnames = list_concat(eref->colnames,
list_copy_tail(tf->colnames, numaliases));
if (numaliases > list_length(tf->colnames))
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("%s function has %d columns available but %d columns specified",
tf->functype == TFT_XMLTABLE ? "XMLTABLE" : "JSON_TABLE",
list_length(tf->colnames), numaliases)));
/* *AddanentryforaVALUESlisttothepstate'srangetable(p_rtable). *Then,constructandreturnaParseNamespaceItemforthenewRTE. * *ThisismuchlikeaddRangeTableEntry()exceptthatitmakesavaluesRTE.
*/
ParseNamespaceItem *
addRangeTableEntryForValues(ParseState *pstate,
List *exprs,
List *coltypes,
List *coltypmods,
List *colcollations,
Alias *alias, bool lateral, bool inFromCl)
{
RangeTblEntry *rte = makeNode(RangeTblEntry); char *refname = alias ? alias->aliasname : pstrdup("*VALUES*");
Alias *eref; int numaliases; int numcolumns;
eref = alias ? copyObject(alias) : makeAlias(refname, NIL);
/* fill in any unspecified alias columns */
numcolumns = list_length((List *) linitial(exprs));
numaliases = list_length(eref->colnames); while (numaliases < numcolumns)
{ char attrname[64];
numaliases++;
snprintf(attrname, sizeof(attrname), "column%d", numaliases);
eref->colnames = lappend(eref->colnames,
makeString(pstrdup(attrname)));
} if (numcolumns < numaliases)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("VALUES lists \"%s\" have %d columns available but %d columns specified",
refname, numcolumns, numaliases)));
/* *Addanentryforajointothepstate'srangetable(p_rtable). *Then,constructandreturnaParseNamespaceItemforthenewRTE. * *ThisismuchlikeaddRangeTableEntry()exceptthatitmakesajoinRTE. *Also,it'smoreconvenientforthecallertoconstructthe *ParseNamespaceColumnarray,sowepassthatin.
*/
ParseNamespaceItem *
addRangeTableEntryForJoin(ParseState *pstate,
List *colnames,
ParseNamespaceColumn *nscolumns,
JoinType jointype, int nummergedcols,
List *aliasvars,
List *leftcols,
List *rightcols,
Alias *join_using_alias,
Alias *alias, bool inFromCl)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
Alias *eref; int numaliases;
ParseNamespaceItem *nsitem;
Assert(pstate != NULL);
/* *Failifjoinhastoomanycolumns---wemustbeabletoreferenceany *ofthecolumnswithanAttrNumber.
*/ if (list_length(aliasvars) > MaxAttrNumber)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("joins can have at most %d columns",
MaxAttrNumber)));
/* fill in any unspecified alias columns */ if (numaliases < list_length(colnames))
eref->colnames = list_concat(eref->colnames,
list_copy_tail(colnames, numaliases));
if (numaliases > list_length(colnames))
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("join expression \"%s\" has %d columns available but %d columns specified",
eref->aliasname, list_length(colnames), numaliases)));
/* Self-reference if and only if CTE's parse analysis isn't completed */
rte->self_reference = !IsA(cte->ctequery, Query);
Assert(cte->cterecursive || !rte->self_reference); /* Bump the CTE's refcount if this isn't a self-reference */ if (!rte->self_reference)
cte->cterefcount++;
if (ctequery->commandType != CMD_SELECT &&
ctequery->returningList == NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("WITH query \"%s\" does not have a RETURNING clause",
cte->ctename),
parser_errposition(pstate, rv->location)));
}
/* fill in any unspecified alias columns */
varattno = 0;
foreach(lc, cte->ctecolnames)
{
varattno++; if (varattno > numaliases)
eref->colnames = lappend(eref->colnames, lfirst(lc));
} if (varattno < numaliases)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("table \"%s\" has %d columns available but %d columns specified",
refname, varattno, numaliases)));
/* If it has a coldeflist, it returns RECORD */ if (rtfunc->funccolnames != NIL)
functypclass = TYPEFUNC_RECORD; else
functypclass = get_expr_result_type(rtfunc->funcexpr,
&funcrettype,
&tupdesc);
if (functypclass == TYPEFUNC_COMPOSITE ||
functypclass == TYPEFUNC_COMPOSITE_DOMAIN)
{ /* Composite data type, e.g. a table's row type */
Assert(tupdesc);
expandTupleDesc(tupdesc, rte->eref,
rtfunc->funccolcount, atts_done,
rtindex, sublevels_up,
returning_type, location,
include_dropped, colnames, colvars);
} elseif (functypclass == TYPEFUNC_SCALAR)
{ /* Base data type, i.e. scalar */ if (colnames)
*colnames = lappend(*colnames,
list_nth(rte->eref->colnames,
atts_done));
*colvars = lappend(*colvars, varnode);
} elseif (include_dropped)
{ /* *Itdoesn'treallymatterwhattypetheConst *claimstobe.
*/
*colvars = lappend(*colvars,
makeNullConst(INT4OID, -1,
InvalidOid));
}
}
}
} break; case RTE_RESULT: case RTE_GROUP: /* These expose no columns, so nothing to do */ break; default:
elog(ERROR, "unrecognized RTE kind: %d", (int) rte->rtekind);
}
}
/* *expandRelation--expandRTEsubroutine
*/ staticvoid
expandRelation(Oid relid, Alias *eref, int rtindex, int sublevels_up,
VarReturningType returning_type, int location, bool include_dropped,
List **colnames, List **colvars)
{
Relation rel;
/* Get the tupledesc and turn it over to expandTupleDesc */
rel = relation_open(relid, AccessShareLock);
expandTupleDesc(rel->rd_att, eref, rel->rd_att->natts, 0,
rtindex, sublevels_up, returning_type,
location, include_dropped,
colnames, colvars);
relation_close(rel, AccessShareLock);
}
/* *expandTupleDesc--expandRTEsubroutine * *Generatenamesand/orVarsforthefirst"count"attributesofthetupdesc, *andappendthemtocolnames/colvars."offset"isaddedtothevarattno *thateachVarwouldotherwisehave,andwealsoskipthefirst"offset" *entriesineref->colnames.(Theseprovisionsallowuseofthiscodefor *anindividualcomposite-returningfunctioninanRTE_FUNCTIONRTE.)
*/ staticvoid
expandTupleDesc(TupleDesc tupdesc, Alias *eref, int count, int offset, int rtindex, int sublevels_up,
VarReturningType returning_type, int location, bool include_dropped,
List **colnames, List **colvars)
{
ListCell *aliascell; int varattno;
if (attr->attisdropped)
{ if (include_dropped)
{ if (colnames)
*colnames = lappend(*colnames, makeString(pstrdup(""))); if (colvars)
{ /* *can'tuseatttypidhere,butitdoesn'treallymatter *whattypetheConstclaimstobe.
*/
*colvars = lappend(*colvars,
makeNullConst(INT4OID, -1, InvalidOid));
}
} if (aliascell)
aliascell = lnext(eref->colnames, aliascell); continue;
}
if (colnames)
{ char *label;
if (aliascell)
{
label = strVal(lfirst(aliascell));
aliascell = lnext(eref->colnames, aliascell);
} else
{ /* If we run out of aliases, use the underlying name */
label = NameStr(attr->attname);
}
*colnames = lappend(*colnames, makeString(pstrdup(label)));
}
tp = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(rte->relid),
Int16GetDatum(attnum)); if (!HeapTupleIsValid(tp)) /* shouldn't happen */
elog(ERROR, "cache lookup failed for attribute %d of relation %u",
attnum, rte->relid);
att_tup = (Form_pg_attribute) GETSTRUCT(tp);
result = att_tup->attisdropped;
ReleaseSysCache(tp);
} break; case RTE_SUBQUERY: case RTE_TABLEFUNC: case RTE_VALUES: case RTE_CTE: case RTE_GROUP:
/* *Subselect,TableFunctions,Values,CTE,GROUPRTEsneverhave *droppedcolumns
*/
result = false; break; case RTE_NAMEDTUPLESTORE:
{ /* Check dropped-ness by testing for valid coltype */ if (attnum <= 0 ||
attnum > list_length(rte->coltypes))
elog(ERROR, "invalid varattno %d", attnum);
result = !OidIsValid((list_nth_oid(rte->coltypes, attnum - 1)));
} break; case RTE_JOIN:
{ /* *AjoinRTEwouldnothavedroppedcolumnswhenconstructed, *butoneinastoredrulemightcontaincolumnsthatwere *droppedfromtheunderlyingtables,ifsaidcolumnsare *nowhereexplicitlyreferencedintherule.Thiswillbe *signaledtousbyanullpointerinthejoinaliasvarslist.
*/
Var *aliasvar;
/* If it has a coldeflist, it returns RECORD */ if (rtfunc->funccolnames != NIL) returnfalse; /* can't have any dropped columns */
tupdesc = get_expr_result_tupdesc(rtfunc->funcexpr, true); if (tupdesc)
{ /* Composite data type, e.g. a table's row type */
Form_pg_attribute att_tup;
/* *givenattributeid,returncollationofthatattribute * *Thisshouldonlybeusediftherelationisalreadytable_open()'ed.
*/
Oid
attnumCollationId(Relation rd, int attid)
{ if (attid <= 0)
{ /* All system attributes are of noncollatable types. */ return InvalidOid;
} if (attid > rd->rd_att->natts)
elog(ERROR, "invalid attribute number %d", attid); return TupleDescAttr(rd->rd_att, attid - 1)->attcollation;
}
/* If it looks like the user forgot to use an alias, hint about that */ if (badAlias)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
relation->relname),
errhint("Perhaps you meant to reference the table alias \"%s\".",
badAlias),
parser_errposition(pstate, relation->location))); /* Hint about case where we found an (inaccessible) exact match */ elseif (rte)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
relation->relname),
errdetail("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
rte->eref->aliasname),
rte_visible_if_lateral(pstate, rte) ?
errhint("To reference that table, you must mark this subquery with LATERAL.") : 0,
parser_errposition(pstate, relation->location))); /* Else, we have nothing to offer but the bald statement of error */ else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("missing FROM-clause entry for table \"%s\"",
relation->relname),
parser_errposition(pstate, relation->location)));
}
/* *Searchtheentirertablelookingforpossiblematches.Ifwefindone, *emitahintaboutit.
*/
state = searchRangeTableForCol(pstate, relname, colname, location);
/* *Ifthereareexactmatch(es),theymustbeinaccessibleforsome *reason.
*/ if (state->rexact1)
{ /* *Wedon'ttrytoohardwhenthere'smultipleinaccessibleexact *matches,butatleastbesurethatwedon'tmisleadinglysuggest *thatthere'sonlyone.
*/ if (state->rexact2)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
relname ?
errmsg("column %s.%s does not exist", relname, colname) :
errmsg("column \"%s\" does not exist", colname),
errdetail("There are columns named \"%s\", but they are in tables that cannot be referenced from this part of the query.",
colname),
!relname ? errhint("Try using a table-qualified name.") : 0,
parser_errposition(pstate, location))); /* Single exact match, so try to determine why it's inaccessible. */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
relname ?
errmsg("column %s.%s does not exist", relname, colname) :
errmsg("column \"%s\" does not exist", colname),
errdetail("There is a column named \"%s\" in table \"%s\", but it cannot be referenced from this part of the query.",
colname, state->rexact1->eref->aliasname),
rte_visible_if_lateral(pstate, state->rexact1) ?
errhint("To reference that column, you must mark this subquery with LATERAL.") :
(!relname && rte_visible_if_qualified(pstate, state->rexact1)) ?
errhint("To reference that column, you must use a table-qualified name.") : 0,
parser_errposition(pstate, location)));
}
if (!state->rsecond)
{ /* If we found no match at all, we have little to report */ if (!state->rfirst)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
relname ?
errmsg("column %s.%s does not exist", relname, colname) :
errmsg("column \"%s\" does not exist", colname),
parser_errposition(pstate, location))); /* Handle case where we have a single alternative spelling to offer */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
relname ?
errmsg("column %s.%s does not exist", relname, colname) :
errmsg("column \"%s\" does not exist", colname),
errhint("Perhaps you meant to reference the column \"%s.%s\".",
state->rfirst->eref->aliasname,
strVal(list_nth(state->rfirst->eref->colnames,
state->first - 1))),
parser_errposition(pstate, location)));
} else
{ /* Handle case where there are two equally useful column hints */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
relname ?
errmsg("column %s.%s does not exist", relname, colname) :
errmsg("column \"%s\" does not exist", colname),
errhint("Perhaps you meant to reference the column \"%s.%s\" or the column \"%s.%s\".",
state->rfirst->eref->aliasname,
strVal(list_nth(state->rfirst->eref->colnames,
state->first - 1)),
state->rsecond->eref->aliasname,
strVal(list_nth(state->rsecond->eref->colnames,
state->second - 1))),
parser_errposition(pstate, location)));
}
}
/* Nope, so make one and add to the list. */
perminfo = makeNode(RTEPermissionInfo);
perminfo->relid = rte->relid;
perminfo->inh = rte->inh; /* Other information is set by fetching the node as and where needed. */
*rteperminfos = lappend(*rteperminfos, perminfo);
/* Note its index (1-based!) */
rte->perminfoindex = list_length(*rteperminfos);
if (rte->perminfoindex == 0 ||
rte->perminfoindex > list_length(rteperminfos))
elog(ERROR, "invalid perminfoindex %u in RTE with relid %u",
rte->perminfoindex, rte->relid);
perminfo = list_nth_node(RTEPermissionInfo, rteperminfos,
rte->perminfoindex - 1); if (perminfo->relid != rte->relid)
elog(ERROR, "permission info at index %u (with relid=%u) does not match provided RTE (with relid=%u)",
rte->perminfoindex, perminfo->relid, rte->relid);
return perminfo;
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.149 Sekunden
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.