parse_relation.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,944 行 · 第 1/4 页
C
1,944 行
* column aliases is reasonable. */ maxattrs = RelationGetNumberOfAttributes(rel); if (maxattrs < numaliases) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("table \"%s\" has %d columns available but %d columns specified", RelationGetRelationName(rel), maxattrs, numaliases))); /* fill in alias columns using actual column names */ for (varattno = numaliases; varattno < maxattrs; varattno++) { char *attrname; attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname)); eref->colnames = lappend(eref->colnames, makeString(attrname)); } /* * Drop the rel refcount, but keep the access lock till end of * transaction so that the table can't be deleted or have its * schema modified underneath us. */ relation_close(rel, NoLock); } else if (functyptype == 'b' || functyptype == 'd') { /* * Must be a base data type, i.e. scalar. Just add one alias * column named for the function. */ if (numaliases > 1) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("too many column aliases specified for function %s", funcname))); if (numaliases == 0) eref->colnames = makeList1(makeString(eref->aliasname)); } else if (functyptype == 'p' && funcrettype == RECORDOID) { List *col; /* Use the column definition list to form the alias list */ eref->colnames = NIL; foreach(col, coldeflist) { ColumnDef *n = lfirst(col); char *attrname; attrname = pstrdup(n->colname); eref->colnames = lappend(eref->colnames, makeString(attrname)); } } else ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("function \"%s\" in FROM has unsupported return type", funcname))); /*---------- * Flags: * - this RTE should be expanded to include descendant tables, * - this RTE is in the FROM clause, * - this RTE should be checked for read/write access rights. *---------- */ rte->inh = false; /* never true for functions */ rte->inFromCl = inFromCl; rte->checkForRead = true; rte->checkForWrite = false; rte->checkAsUser = InvalidOid; /* * Add completed RTE to pstate's range table list, but not to join * list nor namespace --- caller must do that if appropriate. */ if (pstate != NULL) pstate->p_rtable = lappend(pstate->p_rtable, rte); return rte;}/* * Add an entry for a join to the pstate's range table (p_rtable). * * This is much like addRangeTableEntry() except that it makes a join RTE. */RangeTblEntry *addRangeTableEntryForJoin(ParseState *pstate, List *colnames, JoinType jointype, List *aliasvars, Alias *alias, bool inFromCl){ RangeTblEntry *rte = makeNode(RangeTblEntry); Alias *eref; int numaliases; rte->rtekind = RTE_JOIN; rte->relid = InvalidOid; rte->subquery = NULL; rte->jointype = jointype; rte->joinaliasvars = aliasvars; rte->alias = alias; eref = alias ? (Alias *) copyObject(alias) : makeAlias("unnamed_join", NIL); numaliases = length(eref->colnames); /* fill in any unspecified alias columns */ if (numaliases < length(colnames)) { while (numaliases-- > 0) colnames = lnext(colnames); eref->colnames = nconc(eref->colnames, colnames); } rte->eref = eref; /*---------- * Flags: * - this RTE should be expanded to include descendant tables, * - this RTE is in the FROM clause, * - this RTE should be checked for read/write access rights. * * Joins are never checked for access rights. *---------- */ rte->inh = false; /* never true for joins */ rte->inFromCl = inFromCl; rte->checkForRead = false; rte->checkForWrite = false; rte->checkAsUser = InvalidOid; /* * Add completed RTE to pstate's range table list, but not to join * list nor namespace --- caller must do that if appropriate. */ if (pstate != NULL) pstate->p_rtable = lappend(pstate->p_rtable, rte); return rte;}/* * Has the specified refname been selected FOR UPDATE? */static boolisForUpdate(ParseState *pstate, char *refname){ /* Outer loop to check parent query levels as well as this one */ while (pstate != NULL) { if (pstate->p_forUpdate != NIL) { if (lfirst(pstate->p_forUpdate) == NULL) { /* all tables used in query */ return true; } else { /* just the named tables */ List *l; foreach(l, pstate->p_forUpdate) { char *rname = strVal(lfirst(l)); if (strcmp(refname, rname) == 0) return true; } } } pstate = pstate->parentParseState; } return false;}/* * Add the given RTE as a top-level entry in the pstate's join list * and/or name space list. (We assume caller has checked for any * namespace conflict.) */voidaddRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToNameSpace){ int rtindex = RTERangeTablePosn(pstate, rte, NULL); RangeTblRef *rtr = makeNode(RangeTblRef); rtr->rtindex = rtindex; if (addToJoinList) pstate->p_joinlist = lappend(pstate->p_joinlist, rtr); if (addToNameSpace) pstate->p_namespace = lappend(pstate->p_namespace, rtr);}/* * Add a POSTQUEL-style implicit RTE. * * We assume caller has already checked that there is no RTE or join with * a conflicting name. */RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation){ RangeTblEntry *rte; rte = addRangeTableEntry(pstate, relation, NULL, false, false); addRTEtoQuery(pstate, rte, true, true); warnAutoRange(pstate, relation); return rte;}/* expandRTE() * * Given a rangetable entry, create lists of its column names (aliases if * provided, else real names) and Vars for each column. Only user columns * are considered, since this is primarily used to expand '*' and determine * the contents of JOIN tables. * * If only one of the two kinds of output list is needed, pass NULL for the * output pointer for the unwanted one. */voidexpandRTE(ParseState *pstate, RangeTblEntry *rte, List **colnames, List **colvars){ int rtindex, sublevels_up, varattno; if (colnames) *colnames = NIL; if (colvars) *colvars = NIL; /* Need the RT index of the entry for creating Vars */ rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up); switch (rte->rtekind) { case RTE_RELATION: { /* Ordinary relation RTE */ Relation rel; int maxattrs; int numaliases; rel = heap_open(rte->relid, AccessShareLock); maxattrs = RelationGetNumberOfAttributes(rel); numaliases = length(rte->eref->colnames); for (varattno = 0; varattno < maxattrs; varattno++) { Form_pg_attribute attr = rel->rd_att->attrs[varattno]; if (attr->attisdropped) continue; if (colnames) { char *label; if (varattno < numaliases) label = strVal(nth(varattno, rte->eref->colnames)); else label = NameStr(attr->attname); *colnames = lappend(*colnames, makeString(pstrdup(label))); } if (colvars) { Var *varnode; varnode = makeVar(rtindex, attr->attnum, attr->atttypid, attr->atttypmod, sublevels_up); *colvars = lappend(*colvars, varnode); } } heap_close(rel, AccessShareLock); } break; case RTE_SUBQUERY: { /* Subquery RTE */ List *aliasp = rte->eref->colnames; List *tlistitem; varattno = 0; foreach(tlistitem, rte->subquery->targetList) { TargetEntry *te = (TargetEntry *) lfirst(tlistitem); if (te->resdom->resjunk) continue; varattno++; Assert(varattno == te->resdom->resno); if (colnames) { /* Assume there is one alias per target item */ char *label = strVal(lfirst(aliasp)); *colnames = lappend(*colnames, makeString(pstrdup(label))); aliasp = lnext(aliasp); } if (colvars) { Var *varnode; varnode = makeVar(rtindex, varattno, te->resdom->restype, te->resdom->restypmod, sublevels_up); *colvars = lappend(*colvars, varnode); } } } break; case RTE_FUNCTION: { /* Function RTE */ Oid funcrettype = exprType(rte->funcexpr); char functyptype = get_typtype(funcrettype); List *coldeflist = rte->coldeflist; if (functyptype == 'c') { /* * Composite data type, i.e. a table's row type Same * as ordinary relation RTE */ Oid funcrelid = typeidTypeRelid(funcrettype); Relation rel; int maxattrs; int numaliases; if (!OidIsValid(funcrelid)) /* shouldn't happen */ elog(ERROR, "invalid typrelid for complex type %u", funcrettype); rel = relation_open(funcrelid, AccessShareLock); maxattrs = RelationGetNumberOfAttributes(rel); numaliases = length(rte->eref->colnames); for (varattno = 0; varattno < maxattrs; varattno++) { Form_pg_attribute attr = rel->rd_att->attrs[varattno]; if (attr->attisdropped) continue; if (colnames) { char *label; if (varattno < numaliases) label = strVal(nth(varattno, rte->eref->colnames)); else label = NameStr(attr->attname); *colnames = lappend(*colnames, makeString(pstrdup(label))); } if (colvars) { Var *varnode; varnode = makeVar(rtindex, attr->attnum, attr->atttypid, attr->atttypmod, sublevels_up); *colvars = lappend(*colvars, varnode); } } relation_close(rel, AccessShareLock); } else if (functyptype == 'b' || functyptype == 'd') { /* * Must be a base data type, i.e. scalar */ if (colnames) *colnames = lappend(*colnames, lfirst(rte->eref->colnames)); if (colvars) { Var *varnode; varnode = makeVar(rtindex, 1, funcrettype, -1, sublevels_up); *colvars = lappend(*colvars, varnode); } } else if (functyptype == 'p' && funcrettype == RECORDOID) { List *col; int attnum = 0; foreach(col, coldeflist) { ColumnDef *colDef = lfirst(col); attnum++; if (colnames) { char *attrname; attrname = pstrdup(colDef->colname); *colnames = lappend(*colnames, makeString(attrname)); } if (colvars) { Var *varnode; Oid atttypid; atttypid = typenameTypeId(colDef->typename); varnode = makeVar(rtindex, attnum, atttypid, -1, sublevels_up); *colvars = lappend(*colvars, varnode); } } } else ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("function in FROM has unsupported return type"))); } break; case RTE_JOIN: { /* Join RTE */ List *aliasp = rte->eref->colnames; List *aliasvars = rte->joinaliasvars; varattno = 0; while (aliasp) { Assert(aliasvars); varattno++; if (colnames) { char *label = strVal(lfirst(aliasp)); *colnames = lappend(*colnames, makeString(pstrdup(label))); } if (colvars) { Node *aliasvar = (Node *) lfirst(aliasvars); Var *varnode; varnode = makeVar(rtindex, varattno, exprType(aliasvar), exprTypmod(aliasvar), sublevels_up); *colvars = lappend(*colvars, varnode); } aliasp = lnext(aliasp);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?