📄 parse_target.c
字号:
* needed. * * targetName is the name of the field or subfield we're assigning to, and * targetIsArray is true if we're subscripting it. These are just for * error reporting. * * targetTypeId and targetTypMod indicate the datatype of the object to * be assigned to (initially the target column, later some subobject). * * indirection is the sublist remaining to process. When it's NULL, we're * done recursing and can just coerce and return the RHS. * * rhs is the already-transformed value to be assigned; note it has not been * coerced to any particular type. */static Node *transformAssignmentIndirection(ParseState *pstate, Node *basenode, const char *targetName, bool targetIsArray, Oid targetTypeId, int32 targetTypMod, ListCell *indirection, Node *rhs){ Node *result; List *subscripts = NIL; bool isSlice = false; ListCell *i; if (indirection && !basenode) { /* Set up a substitution. We reuse CaseTestExpr for this. */ CaseTestExpr *ctest = makeNode(CaseTestExpr); ctest->typeId = targetTypeId; ctest->typeMod = targetTypMod; basenode = (Node *) ctest; } /* * We have to split any field-selection operations apart from * subscripting. Adjacent A_Indices nodes have to be treated as a single * multidimensional subscript operation. */ for_each_cell(i, indirection) { Node *n = lfirst(i); if (IsA(n, A_Indices)) { subscripts = lappend(subscripts, n); if (((A_Indices *) n)->lidx != NULL) isSlice = true; } else { FieldStore *fstore; Oid typrelid; AttrNumber attnum; Oid fieldTypeId; int32 fieldTypMod; Assert(IsA(n, String)); /* process subscripts before this field selection */ if (subscripts) { Oid elementTypeId = transformArrayType(targetTypeId); Oid typeNeeded = isSlice ? targetTypeId : elementTypeId; /* recurse to create appropriate RHS for array assign */ rhs = transformAssignmentIndirection(pstate, NULL, targetName, true, typeNeeded, targetTypMod, i, rhs); /* process subscripts */ return (Node *) transformArraySubscripts(pstate, basenode, targetTypeId, elementTypeId, targetTypMod, subscripts, rhs); } /* No subscripts, so can process field selection here */ typrelid = typeidTypeRelid(targetTypeId); if (!typrelid) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("cannot assign to field \"%s\" of column \"%s\" because its type %s is not a composite type", strVal(n), targetName, format_type_be(targetTypeId)))); attnum = get_attnum(typrelid, strVal(n)); if (attnum == InvalidAttrNumber) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("cannot assign to field \"%s\" of column \"%s\" because there is no such column in data type %s", strVal(n), targetName, format_type_be(targetTypeId)))); if (attnum < 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("cannot assign to system column \"%s\"", strVal(n)))); get_atttypetypmod(typrelid, attnum, &fieldTypeId, &fieldTypMod); /* recurse to create appropriate RHS for field assign */ rhs = transformAssignmentIndirection(pstate, NULL, strVal(n), false, fieldTypeId, fieldTypMod, lnext(i), rhs); /* and build a FieldStore node */ fstore = makeNode(FieldStore); fstore->arg = (Expr *) basenode; fstore->newvals = list_make1(rhs); fstore->fieldnums = list_make1_int(attnum); fstore->resulttype = targetTypeId; return (Node *) fstore; } } /* process trailing subscripts, if any */ if (subscripts) { Oid elementTypeId = transformArrayType(targetTypeId); Oid typeNeeded = isSlice ? targetTypeId : elementTypeId; /* recurse to create appropriate RHS for array assign */ rhs = transformAssignmentIndirection(pstate, NULL, targetName, true, typeNeeded, targetTypMod, NULL, rhs); /* process subscripts */ return (Node *) transformArraySubscripts(pstate, basenode, targetTypeId, elementTypeId, targetTypMod, subscripts, rhs); } /* base case: just coerce RHS to match target type ID */ result = coerce_to_target_type(pstate, rhs, exprType(rhs), targetTypeId, targetTypMod, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST); if (result == NULL) { if (targetIsArray) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("array assignment to \"%s\" requires type %s" " but expression is of type %s", targetName, format_type_be(targetTypeId), format_type_be(exprType(rhs))), errhint("You will need to rewrite or cast the expression."))); else ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("subfield \"%s\" is of type %s" " but expression is of type %s", targetName, format_type_be(targetTypeId), format_type_be(exprType(rhs))), errhint("You will need to rewrite or cast the expression."))); } return result;}/* * 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 = lappend_int(*attrnos, i + 1); } } else { /* * Do initial validation of user-supplied INSERT column list. */ Bitmapset *wholecols = NULL; Bitmapset *partialcols = NULL; ListCell *tl; foreach(tl, cols) { ResTarget *col = (ResTarget *) lfirst(tl); char *name = col->name; int attrno; /* Lookup column name, ereport on failure */ attrno = attnameAttNum(pstate->p_target_relation, name, false); /* * Check for duplicates, but only of whole columns --- we allow * INSERT INTO foo (col.subcol1, col.subcol2) */ if (col->indirection == NIL) { /* whole column; must not have any other assignment */ if (bms_is_member(attrno, wholecols) || bms_is_member(attrno, partialcols)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("column \"%s\" specified more than once", name))); wholecols = bms_add_member(wholecols, attrno); } else { /* partial column; must not have any whole assignment */ if (bms_is_member(attrno, wholecols)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("column \"%s\" specified more than once", name))); partialcols = bms_add_member(partialcols, attrno); } *attrnos = lappend_int(*attrnos, attrno); } } return cols;}/* * ExpandColumnRefStar() * Turns foo.* (in the target list) into a list of targetlist entries. * * This handles the case where '*' appears as the last or only name in a * ColumnRef. */static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref){ List *fields = cref->fields; int numnames = list_length(fields); if (numnames == 1) { /* * Target item is a bare '*', expand all tables * * (e.g., SELECT * FROM emp, dept) */ return ExpandAllTables(pstate); } else { /* * Target item is relation.*, expand that table * * (e.g., SELECT emp.*, dname FROM emp, dept) */ char *schemaname; char *relname; RangeTblEntry *rte; int sublevels_up; int rtindex; switch (numnames) { case 2: schemaname = NULL; relname = strVal(linitial(fields)); break; case 3: schemaname = strVal(linitial(fields)); relname = strVal(lsecond(fields)); break; case 4: { char *name1 = strVal(linitial(fields)); /* * We check the catalog name and then ignore it. */ if (strcmp(name1, get_database_name(MyDatabaseId)) != 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cross-database references are not implemented: %s", NameListToString(fields)))); schemaname = strVal(lsecond(fields)); relname = strVal(lthird(fields)); break; } default: ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("improper qualified name (too many dotted names): %s", NameListToString(fields)))); schemaname = NULL; /* keep compiler quiet */ relname = NULL; break; } rte = refnameRangeTblEntry(pstate, schemaname, relname, &sublevels_up); if (rte == NULL) rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname)); rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up); return expandRelAttrs(pstate, rte, rtindex, sublevels_up); }}/* * ExpandAllTables() * Turns '*' (in the target list) into a list of targetlist entries. * * tlist entries are generated for each relation appearing in the query's * varnamespace. We do not consider relnamespace because that would include * input tables of aliasless JOINs, NEW/OLD pseudo-entries, implicit RTEs, * etc. */static List *ExpandAllTables(ParseState *pstate){ List *target = NIL; ListCell *l; /* Check for SELECT *; */ if (!pstate->p_varnamespace) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -