📄 parse_target.c
字号:
while (ilist != NIL) { A_Indices *ind = lfirst(ilist); ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST); ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST); ilist = lnext(ilist); } } res->name = colname; return MakeTargetEntryExpr(pstate, res->name, expr, res->indirection, false); }}/* * MakeTargetEntryAttr() * Make a TargetEntry from a complex node. */static TargetEntry *MakeTargetEntryAttr(ParseState *pstate, ResTarget *res){ Oid type_id; int32 type_mod; Attr *att = (Attr *) res->val; Node *result; char *attrname; char *resname; Resdom *resnode; int resdomno; List *attrs = att->attrs; TargetEntry *tent; attrname = strVal(lfirst(att->attrs)); /* * Target item is fully specified: ie. relation.attribute */ result = ParseNestedFuncOrColumn(pstate, att, &pstate->p_last_resno, EXPR_COLUMN_FIRST); handleTargetColname(pstate, &res->name, att->relname, attrname); if (att->indirection != NIL) { List *ilist = att->indirection; while (ilist != NIL) { A_Indices *ind = lfirst(ilist); ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST); ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST); ilist = lnext(ilist); } result = (Node *) make_array_ref(result, att->indirection); } type_id = exprType(result); if (nodeTag(result) == T_Var) type_mod = ((Var *) result)->vartypmod; else type_mod = -1; /* move to last entry */ while (lnext(attrs) != NIL) attrs = lnext(attrs); resname = (res->name) ? res->name : strVal(lfirst(attrs)); if (pstate->p_is_insert || pstate->p_is_update) { Relation rd; /* * insert or update query -- insert, update work only on one * relation, so multiple occurence of same resdomno is bogus */ rd = pstate->p_target_relation; Assert(rd != NULL); resdomno = attnameAttNum(rd, res->name); } else resdomno = pstate->p_last_resno++; resnode = makeResdom((AttrNumber) resdomno, (Oid) type_id, type_mod, resname, (Index) 0, (Oid) 0, false); tent = makeNode(TargetEntry); tent->resdom = resnode; tent->expr = result; return tent;}/* transformTargetList() * Turns a list of ResTarget's into a list of TargetEntry's. */List *transformTargetList(ParseState *pstate, List *targetlist){ List *p_target = NIL; List *tail_p_target = NIL; while (targetlist != NIL) { ResTarget *res = (ResTarget *) lfirst(targetlist); TargetEntry *tent = NULL; switch (nodeTag(res->val)) { case T_Ident: { char *identname; identname = ((Ident *) res->val)->name; tent = MakeTargetEntryIdent(pstate, (Node *) res->val, &res->name, NULL, identname, false); break; } case T_ParamNo: case T_FuncCall: case T_A_Const: case T_A_Expr: { tent = MakeTargetEntryComplex(pstate, res); break; } case T_CaseExpr: { tent = MakeTargetEntryCase(pstate, res); break; } case T_Attr: { bool expand_star = false; char *attrname; Attr *att = (Attr *) res->val; /* * Target item is a single '*', expand all tables (eg. * SELECT * FROM emp) */ if (att->relname != NULL && !strcmp(att->relname, "*")) { if (tail_p_target == NIL) p_target = tail_p_target = ExpandAllTables(pstate); else lnext(tail_p_target) = ExpandAllTables(pstate); expand_star = true; } else { /* * Target item is relation.*, expand the table * (eg. SELECT emp.*, dname FROM emp, dept) */ attrname = strVal(lfirst(att->attrs)); if (att->attrs != NIL && !strcmp(attrname, "*")) { /* * tail_p_target is the target list we're * building in the while loop. Make sure we * fix it after appending more nodes. */ if (tail_p_target == NIL) p_target = tail_p_target = expandAll(pstate, att->relname, att->relname, &pstate->p_last_resno); else lnext(tail_p_target) = expandAll(pstate, att->relname, att->relname, &pstate->p_last_resno); expand_star = true; } } if (expand_star) { while (lnext(tail_p_target) != NIL) /* make sure we point to the last target entry */ tail_p_target = lnext(tail_p_target); /* * skip rest of while loop */ targetlist = lnext(targetlist); continue; } else { tent = MakeTargetEntryAttr(pstate, res); break; } } default: /* internal error */ elog(ERROR, "Unable to transform targetlist (internal error)"); break; } if (p_target == NIL) p_target = tail_p_target = lcons(tent, NIL); else { lnext(tail_p_target) = lcons(tent, NIL); tail_p_target = lnext(tail_p_target); } targetlist = lnext(targetlist); } return p_target;} /* transformTargetList() */Node *CoerceTargetExpr(ParseState *pstate, Node *expr, Oid type_id, Oid attrtype){ if (can_coerce_type(1, &type_id, &attrtype)) expr = coerce_type(pstate, expr, type_id, attrtype, -1);#ifndef DISABLE_STRING_HACKS /* * string hacks to get transparent conversions w/o explicit * conversions */ else if ((attrtype == BPCHAROID) || (attrtype == VARCHAROID)) { Oid text_id = TEXTOID; if (type_id == TEXTOID) { } else if (can_coerce_type(1, &type_id, &text_id)) expr = coerce_type(pstate, expr, type_id, text_id, -1); else expr = NULL; }#endif else expr = NULL; return expr;} /* CoerceTargetExpr() *//* SizeTargetExpr() * Apparently going to a fixed-length string? * Then explicitly size for storage... */static Node *SizeTargetExpr(ParseState *pstate, Node *expr, Oid attrtype, int32 attrtypmod){ int i; HeapTuple ftup; char *funcname; Oid oid_array[MAXFARGS]; FuncCall *func; A_Const *cons; funcname = typeidTypeName(attrtype); oid_array[0] = attrtype; oid_array[1] = INT4OID; for (i = 2; i < MAXFARGS; i++) oid_array[i] = InvalidOid; /* attempt to find with arguments exactly as specified... */ ftup = SearchSysCacheTuple(PRONAME, PointerGetDatum(funcname), Int32GetDatum(2), PointerGetDatum(oid_array), 0); if (HeapTupleIsValid(ftup)) { func = makeNode(FuncCall); func->funcname = funcname; cons = makeNode(A_Const); cons->val.type = T_Integer; cons->val.val.ival = attrtypmod; func->args = lappend(lcons(expr, NIL), cons); expr = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST); } return expr;} /* SizeTargetExpr() *//* * makeTargetNames - * generate a list of column names if not supplied or * test supplied column names to make sure they are in target table * (used exclusively for inserts) */List *makeTargetNames(ParseState *pstate, List *cols){ List *tl = NULL; /* Generate ResTarget if not supplied */ if (cols == NIL) { int numcol; int i; Form_pg_attribute *attr = pstate->p_target_relation->rd_att->attrs; numcol = pstate->p_target_relation->rd_rel->relnatts; for (i = 0; i < numcol; i++) { Ident *id = makeNode(Ident); id->name = palloc(NAMEDATALEN); StrNCpy(id->name, attr[i]->attname.data, NAMEDATALEN); id->indirection = NIL; id->isRel = false; if (tl == NIL) cols = tl = lcons(id, NIL); else { lnext(tl) = lcons(id, NIL); tl = lnext(tl); } } } else { foreach(tl, cols) { List *nxt; char *name = ((Ident *) lfirst(tl))->name; /* elog on failure */ attnameAttNum(pstate->p_target_relation, name); foreach(nxt, lnext(tl)) if (!strcmp(name, ((Ident *) lfirst(nxt))->name)) elog(ERROR, "Attribute '%s' should be specified only once", name); } } return cols;}/* * ExpandAllTables - * turns '*' (in the target list) into a list of attributes * (of all relations in the range table) */static List *ExpandAllTables(ParseState *pstate){ List *target = NIL; List *legit_rtable = NIL; List *rt, *rtable; rtable = pstate->p_rtable; if (pstate->p_is_rule) { /* * skip first two entries, "*new*" and "*current*" */ rtable = lnext(lnext(pstate->p_rtable)); } /* SELECT *; */ if (rtable == NULL) elog(ERROR, "Wildcard with no tables specified."); /* * go through the range table and make a list of range table entries * which we will expand. */ foreach(rt, rtable) { RangeTblEntry *rte = lfirst(rt); /* * we only expand those specify in the from clause. (This will * also prevent us from using the wrong table in inserts: eg. * tenk2 in "insert into tenk2 select * from tenk1;") */ if (!rte->inFromCl) continue; legit_rtable = lappend(legit_rtable, rte); } foreach(rt, legit_rtable) { RangeTblEntry *rte = lfirst(rt); List *temp = target; if (temp == NIL) target = expandAll(pstate, rte->relname, rte->refname, &pstate->p_last_resno); else { while (temp != NIL && lnext(temp) != NIL) temp = lnext(temp); lnext(temp) = expandAll(pstate, rte->relname, rte->refname, &pstate->p_last_resno); } } return target;}/* * FigureColname - * if the name of the resulting column is not specified in the target * list, we have to guess. * */static char *FigureColname(Node *expr, Node *resval){ switch (nodeTag(expr)) { case T_Aggref: return (char *) ((Aggref *) expr)->aggname; case T_Expr: if (((Expr *) expr)->opType == FUNC_EXPR) { if (nodeTag(resval) == T_FuncCall) return ((FuncCall *) resval)->funcname; } break; case T_CaseExpr: { char *name; name = FigureColname(((CaseExpr *) expr)->defresult, resval); if (!strcmp(name, "?column?")) name = "case"; return name; } break; default: break; } return "?column?";}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -