parse_target.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 672 行 · 第 1/2 页
C
672 行
* If the expression is a DEFAULT placeholder, insert the attribute's * type/typmod into it so that exprType will report the right things. * (We expect that the eventually substituted default expression will * in fact have this type and typmod.) Also, reject trying to update * an array element with DEFAULT, since there can't be any default for * individual elements of a column. */ if (tle->expr && IsA(tle->expr, SetToDefault)) { SetToDefault *def = (SetToDefault *) tle->expr; def->typeId = attrtype; def->typeMod = attrtypmod; if (indirection) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot set an array element to DEFAULT"))); } /* Now we can use exprType() safely. */ type_id = exprType((Node *) tle->expr); /* * If there are subscripts on the target column, prepare an array * assignment expression. This will generate an array value that the * source value has been inserted into, which can then be placed in * the new tuple constructed by INSERT or UPDATE. Note that * transformArraySubscripts takes care of type coercion. */ if (indirection) { Node *arrayBase; ArrayRef *aref; if (pstate->p_is_insert) { /* * The command is INSERT INTO table (arraycol[subscripts]) ... * so there is not really a source array value to work with. * Let the executor do something reasonable, if it can. Notice * that we force transformArraySubscripts to treat the * subscripting op as an array-slice op below, so the source * data will have been coerced to the array type. */ arrayBase = NULL; /* signal there is no source array */ } else { /* * Build a Var for the array to be updated. */ arrayBase = (Node *) make_var(pstate, pstate->p_target_rangetblentry, attrno); } aref = transformArraySubscripts(pstate, arrayBase, attrtype, attrtypmod, indirection, pstate->p_is_insert, (Node *) tle->expr); tle->expr = (Expr *) aref; } else { /* * For normal non-subscripted target column, do type checking and * coercion. But accept InvalidOid, which indicates the source is * a NULL constant. (XXX is that still true?) */ if (type_id != InvalidOid) { tle->expr = (Expr *) coerce_to_target_type(pstate, (Node *) tle->expr, type_id, attrtype, attrtypmod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST); if (tle->expr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("column \"%s\" is of type %s" " but expression is of type %s", colname, format_type_be(attrtype), format_type_be(type_id)), errhint("You will need to rewrite or cast the expression."))); } } /* * The result of the target expression should now match the * destination column's type. */ resnode->restype = attrtype; resnode->restypmod = attrtypmod; /* * Set the resno to identify the target column --- the rewriter and * planner depend on this. We also set the resname to identify the * target column, but this is only for debugging purposes; it should * not be relied on. (In particular, it might be out of date in a * stored rule.) */ resnode->resno = (AttrNumber) attrno; resnode->resname = colname;}/* * checkInsertTargets - * generate a list of INSERT column targets if not supplied, or * test supplied column names to make sure they are in target table. * Also return an integer list of the columns' attribute numbers. */List *checkInsertTargets(ParseState *pstate, List *cols, List **attrnos){ *attrnos = NIL; if (cols == NIL) { /* * Generate default column list for INSERT. */ Form_pg_attribute *attr = pstate->p_target_relation->rd_att->attrs; int numcol = pstate->p_target_relation->rd_rel->relnatts; int i; for (i = 0; i < numcol; i++) { ResTarget *col; if (attr[i]->attisdropped) continue; col = makeNode(ResTarget); col->name = pstrdup(NameStr(attr[i]->attname)); col->indirection = NIL; col->val = NULL; cols = lappend(cols, col); *attrnos = lappendi(*attrnos, i + 1); } } else { /* * Do initial validation of user-supplied INSERT column list. */ List *tl; foreach(tl, cols) { char *name = ((ResTarget *) lfirst(tl))->name; int attrno; /* Lookup column name, ereport on failure */ attrno = attnameAttNum(pstate->p_target_relation, name, false); /* Check for duplicates */ if (intMember(attrno, *attrnos)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("column \"%s\" specified more than once", name))); *attrnos = lappendi(*attrnos, attrno); } } return cols;}/* ExpandAllTables() * Turns '*' (in the target list) into a list of targetlist entries. * * tlist entries are generated for each relation appearing at the top level * of the query's namespace, except for RTEs marked not inFromCl. (These * may include NEW/OLD pseudo-entries, implicit RTEs, etc.) */static List *ExpandAllTables(ParseState *pstate){ List *target = NIL; bool found_table = false; List *ns; foreach(ns, pstate->p_namespace) { Node *n = (Node *) lfirst(ns); RangeTblEntry *rte; if (IsA(n, RangeTblRef)) rte = rt_fetch(((RangeTblRef *) n)->rtindex, pstate->p_rtable); else if (IsA(n, JoinExpr)) rte = rt_fetch(((JoinExpr *) n)->rtindex, pstate->p_rtable); else { elog(ERROR, "unrecognized node type: %d", (int) nodeTag(n)); rte = NULL; /* keep compiler quiet */ } /* * Ignore added-on relations that were not listed in the FROM * clause. */ if (!rte->inFromCl) continue; found_table = true; target = nconc(target, expandRelAttrs(pstate, rte)); } /* Check for SELECT *; */ if (!found_table) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("SELECT * with no tables specified is not valid"))); return target;}/* * 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. */static 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 *cname = strVal(llast(((ColumnRef *) node)->fields)); if (strcmp(cname, "*") != 0) { *name = cname; return 2; } } break; case T_ExprFieldSelect: { ExprFieldSelect *efs = (ExprFieldSelect *) node; if (efs->fields) { char *fname = strVal(llast(efs->fields)); if (strcmp(fname, "*") != 0) { *name = fname; return 2; } } return FigureColnameInternal(efs->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_CoalesceExpr: /* make coalesce() act like a regular function */ *name = "coalesce"; return 2; default: break; } return strength;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?