📄 parse_target.c
字号:
errmsg("SELECT * with no tables specified is not valid"))); foreach(l, pstate->p_varnamespace) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); int rtindex = RTERangeTablePosn(pstate, rte, NULL); target = list_concat(target, expandRelAttrs(pstate, rte, rtindex, 0)); } return target;}/* * ExpandIndirectionStar() * Turns foo.* (in the target list) into a list of targetlist entries. * * This handles the case where '*' appears as the last item in A_Indirection. */static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind){ Node *expr; TupleDesc tupleDesc; int numAttrs; int i; List *te_list = NIL; /* Strip off the '*' to create a reference to the rowtype object */ ind = copyObject(ind); ind->indirection = list_truncate(ind->indirection, list_length(ind->indirection) - 1); /* And transform that */ expr = transformExpr(pstate, (Node *) ind); /* * Verify it's a composite type, and get the tupdesc. We use * get_expr_result_type() because that can handle references to functions * returning anonymous record types. If that fails, use * lookup_rowtype_tupdesc(), which will almost certainly fail as well, but * it will give an appropriate error message. * * If it's a Var of type RECORD, we have to work even harder: we have to * find what the Var refers to, and pass that to get_expr_result_type. * That task is handled by expandRecordVariable(). */ if (IsA(expr, Var) && ((Var *) expr)->vartype == RECORDOID) tupleDesc = expandRecordVariable(pstate, (Var *) expr, 0); else if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE) tupleDesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(exprType(expr), exprTypmod(expr))); Assert(tupleDesc); /* Generate a list of references to the individual fields */ numAttrs = tupleDesc->natts; for (i = 0; i < numAttrs; i++) { Form_pg_attribute att = tupleDesc->attrs[i]; Node *fieldnode; TargetEntry *te; if (att->attisdropped) continue; /* * If we got a whole-row Var from the rowtype reference, we can expand * the fields as simple Vars. Otherwise we must generate multiple * copies of the rowtype reference and do FieldSelects. */ if (IsA(expr, Var) && ((Var *) expr)->varattno == InvalidAttrNumber) { Var *var = (Var *) expr; fieldnode = (Node *) makeVar(var->varno, i + 1, att->atttypid, att->atttypmod, var->varlevelsup); } else { FieldSelect *fselect = makeNode(FieldSelect); fselect->arg = (Expr *) copyObject(expr); fselect->fieldnum = i + 1; fselect->resulttype = att->atttypid; fselect->resulttypmod = att->atttypmod; fieldnode = (Node *) fselect; } te = makeTargetEntry((Expr *) fieldnode, (AttrNumber) pstate->p_next_resno++, pstrdup(NameStr(att->attname)), false); te_list = lappend(te_list, te); } return te_list;}/* * expandRecordVariable * Get the tuple descriptor for a Var of type RECORD, if possible. * * Since no actual table or view column is allowed to have type RECORD, such * a Var must refer to a JOIN or FUNCTION RTE or to a subquery output. We * drill down to find the ultimate defining expression and attempt to infer * the tupdesc from it. We ereport if we can't determine the tupdesc. * * levelsup is an extra offset to interpret the Var's varlevelsup correctly. */TupleDescexpandRecordVariable(ParseState *pstate, Var *var, int levelsup){ TupleDesc tupleDesc; int netlevelsup; RangeTblEntry *rte; AttrNumber attnum; Node *expr; /* Check my caller didn't mess up */ Assert(IsA(var, Var)); Assert(var->vartype == RECORDOID); netlevelsup = var->varlevelsup + levelsup; rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup); attnum = var->varattno; if (attnum == InvalidAttrNumber) { /* Whole-row reference to an RTE, so expand the known fields */ List *names, *vars; ListCell *lname, *lvar; int i; expandRTE(rte, var->varno, 0, false, &names, &vars); tupleDesc = CreateTemplateTupleDesc(list_length(vars), false); i = 1; forboth(lname, names, lvar, vars) { char *label = strVal(lfirst(lname)); Node *varnode = (Node *) lfirst(lvar); TupleDescInitEntry(tupleDesc, i, label, exprType(varnode), exprTypmod(varnode), 0); i++; } Assert(lname == NULL && lvar == NULL); /* lists same length? */ return tupleDesc; } expr = (Node *) var; /* default if we can't drill down */ switch (rte->rtekind) { case RTE_RELATION: case RTE_SPECIAL: /* * This case should not occur: a column of a table shouldn't have * type RECORD. Fall through and fail (most likely) at the * bottom. */ break; case RTE_SUBQUERY: { /* Subselect-in-FROM: examine sub-select's output expr */ TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList, attnum); if (ste == NULL || ste->resjunk) elog(ERROR, "subquery %s does not have attribute %d", rte->eref->aliasname, attnum); expr = (Node *) ste->expr; if (IsA(expr, Var)) { /* * Recurse into the sub-select to see what its Var refers * to. We have to build an additional level of ParseState * to keep in step with varlevelsup in the subselect. */ ParseState mypstate; MemSet(&mypstate, 0, sizeof(mypstate)); mypstate.parentParseState = pstate; mypstate.p_rtable = rte->subquery->rtable; /* don't bother filling the rest of the fake pstate */ return expandRecordVariable(&mypstate, (Var *) expr, 0); } /* else fall through to inspect the expression */ } break; case RTE_JOIN: /* Join RTE --- recursively inspect the alias variable */ Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars)); expr = (Node *) list_nth(rte->joinaliasvars, attnum - 1); if (IsA(expr, Var)) return expandRecordVariable(pstate, (Var *) expr, netlevelsup); /* else fall through to inspect the expression */ break; case RTE_FUNCTION: /* * We couldn't get here unless a function is declared with one of * its result columns as RECORD, which is not allowed. */ break; } /* * We now have an expression we can't expand any more, so see if * get_expr_result_type() can do anything with it. If not, pass to * lookup_rowtype_tupdesc() which will probably fail, but will give an * appropriate error message while failing. */ if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE) tupleDesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(exprType(expr), exprTypmod(expr))); return tupleDesc;}/* * FigureColname - * if the name of the resulting column is not specified in the target * list, we have to guess a suitable name. The SQL spec provides some * guidance, but not much... * * Note that the argument is the *untransformed* parse tree for the target * item. This is a shade easier to work with than the transformed tree. */char *FigureColname(Node *node){ char *name = NULL; FigureColnameInternal(node, &name); if (name != NULL) return name; /* default result if we can't guess anything */ return "?column?";}static intFigureColnameInternal(Node *node, char **name){ int strength = 0; if (node == NULL) return strength; switch (nodeTag(node)) { case T_ColumnRef: { char *fname = NULL; ListCell *l; /* find last field name, if any, ignoring "*" */ foreach(l, ((ColumnRef *) node)->fields) { Node *i = lfirst(l); if (strcmp(strVal(i), "*") != 0) fname = strVal(i); } if (fname) { *name = fname; return 2; } } break; case T_A_Indirection: { A_Indirection *ind = (A_Indirection *) node; char *fname = NULL; ListCell *l; /* find last field name, if any, ignoring "*" */ foreach(l, ind->indirection) { Node *i = lfirst(l); if (IsA(i, String) && strcmp(strVal(i), "*") != 0) fname = strVal(i); } if (fname) { *name = fname; return 2; } return FigureColnameInternal(ind->arg, name); } break; case T_FuncCall: *name = strVal(llast(((FuncCall *) node)->funcname)); return 2; case T_A_Expr: /* make nullif() act like a regular function */ if (((A_Expr *) node)->kind == AEXPR_NULLIF) { *name = "nullif"; return 2; } break; case T_A_Const: if (((A_Const *) node)->typename != NULL) { *name = strVal(llast(((A_Const *) node)->typename->names)); return 1; } break; case T_TypeCast: strength = FigureColnameInternal(((TypeCast *) node)->arg, name); if (strength <= 1) { if (((TypeCast *) node)->typename != NULL) { *name = strVal(llast(((TypeCast *) node)->typename->names)); return 1; } } break; case T_CaseExpr: strength = FigureColnameInternal((Node *) ((CaseExpr *) node)->defresult, name); if (strength <= 1) { *name = "case"; return 1; } break; case T_ArrayExpr: /* make ARRAY[] act like a function */ *name = "array"; return 2; case T_RowExpr: /* make ROW() act like a function */ *name = "row"; return 2; case T_CoalesceExpr: /* make coalesce() act like a regular function */ *name = "coalesce"; return 2; case T_MinMaxExpr: /* make greatest/least act like a regular function */ switch (((MinMaxExpr *) node)->op) { case IS_GREATEST: *name = "greatest"; return 2; case IS_LEAST: *name = "least"; return 2; } break; default: break; } return strength;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -