tablecmds.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,338 行 · 第 1/5 页
C
2,338 行
* the column will not have a default. * (3) If conflicting defaults are inherited from different parents * (and not overridden by the child), an error is raised. * (4) Otherwise the inherited default is used. * Rule (3) is new in Postgres 7.1; in earlier releases you got a * rather arbitrary choice of which parent default to use. *---------- */static List *MergeAttributes(List *schema, List *supers, bool istemp, List **supOids, List **supconstr, bool *supHasOids){ List *entry; List *inhSchema = NIL; List *parentOids = NIL; List *constraints = NIL; bool parentHasOids = false; bool have_bogus_defaults = false; char *bogus_marker = "Bogus!"; /* marks conflicting * defaults */ int child_attno; /* * Check for duplicate names in the explicit list of attributes. * * Although we might consider merging such entries in the same way that * we handle name conflicts for inherited attributes, it seems to make * more sense to assume such conflicts are errors. */ foreach(entry, schema) { ColumnDef *coldef = lfirst(entry); List *rest; foreach(rest, lnext(entry)) { ColumnDef *restdef = lfirst(rest); if (strcmp(coldef->colname, restdef->colname) == 0) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("column \"%s\" duplicated", coldef->colname))); } } /* * Scan the parents left-to-right, and merge their attributes to form * a list of inherited attributes (inhSchema). Also check to see if * we need to inherit an OID column. */ child_attno = 0; foreach(entry, supers) { RangeVar *parent = (RangeVar *) lfirst(entry); Relation relation; TupleDesc tupleDesc; TupleConstr *constr; AttrNumber *newattno; AttrNumber parent_attno; relation = heap_openrv(parent, AccessShareLock); if (relation->rd_rel->relkind != RELKIND_RELATION) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("inherited relation \"%s\" is not a table", parent->relname))); /* Permanent rels cannot inherit from temporary ones */ if (!istemp && isTempNamespace(RelationGetNamespace(relation))) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot inherit from temporary relation \"%s\"", parent->relname))); /* * We should have an UNDER permission flag for this, but for now, * demand that creator of a child table own the parent. */ if (!pg_class_ownercheck(RelationGetRelid(relation), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, RelationGetRelationName(relation)); /* * Reject duplications in the list of parents. */ if (oidMember(RelationGetRelid(relation), parentOids)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_TABLE), errmsg("inherited relation \"%s\" duplicated", parent->relname))); parentOids = lappendo(parentOids, RelationGetRelid(relation)); parentHasOids |= relation->rd_rel->relhasoids; tupleDesc = RelationGetDescr(relation); constr = tupleDesc->constr; /* * newattno[] will contain the child-table attribute numbers for * the attributes of this parent table. (They are not the same * for parents after the first one, nor if we have dropped * columns.) +1 is to prevent error if parent has zero columns. */ newattno = (AttrNumber *) palloc((tupleDesc->natts + 1) * sizeof(AttrNumber)); for (parent_attno = 1; parent_attno <= tupleDesc->natts; parent_attno++) { Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1]; char *attributeName = NameStr(attribute->attname); int exist_attno; ColumnDef *def; TypeName *typename; /* * Ignore dropped columns in the parent. */ if (attribute->attisdropped) { /* * change_varattnos_of_a_node asserts that this is greater * than zero, so if anything tries to use it, we should * find out. */ newattno[parent_attno - 1] = 0; continue; } /* * Does it conflict with some previously inherited column? */ exist_attno = findAttrByName(attributeName, inhSchema); if (exist_attno > 0) { /* * Yes, try to merge the two column definitions. They must * have the same type and typmod. */ ereport(NOTICE, (errmsg("merging multiple inherited definitions of column \"%s\"", attributeName))); def = (ColumnDef *) nth(exist_attno - 1, inhSchema); if (typenameTypeId(def->typename) != attribute->atttypid || def->typename->typmod != attribute->atttypmod) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("inherited column \"%s\" has a type conflict", attributeName), errdetail("%s versus %s", TypeNameToString(def->typename), format_type_be(attribute->atttypid)))); def->inhcount++; /* Merge of NOT NULL constraints = OR 'em together */ def->is_not_null |= attribute->attnotnull; /* Default and other constraints are handled below */ newattno[parent_attno - 1] = exist_attno; } else { /* * No, create a new inherited column */ def = makeNode(ColumnDef); def->colname = pstrdup(attributeName); typename = makeNode(TypeName); typename->typeid = attribute->atttypid; typename->typmod = attribute->atttypmod; def->typename = typename; def->inhcount = 1; def->is_local = false; def->is_not_null = attribute->attnotnull; def->raw_default = NULL; def->cooked_default = NULL; def->constraints = NIL; def->support = NULL; inhSchema = lappend(inhSchema, def); newattno[parent_attno - 1] = ++child_attno; } /* * Copy default if any */ if (attribute->atthasdef) { char *this_default = NULL; AttrDefault *attrdef; int i; /* Find default in constraint structure */ Assert(constr != NULL); attrdef = constr->defval; for (i = 0; i < constr->num_defval; i++) { if (attrdef[i].adnum == parent_attno) { this_default = attrdef[i].adbin; break; } } Assert(this_default != NULL); /* * If default expr could contain any vars, we'd need to * fix 'em, but it can't; so default is ready to apply to * child. * * If we already had a default from some prior parent, check * to see if they are the same. If so, no problem; if * not, mark the column as having a bogus default. Below, * we will complain if the bogus default isn't overridden * by the child schema. */ Assert(def->raw_default == NULL); if (def->cooked_default == NULL) def->cooked_default = pstrdup(this_default); else if (strcmp(def->cooked_default, this_default) != 0) { def->cooked_default = bogus_marker; have_bogus_defaults = true; } } } /* * Now copy the constraints of this parent, adjusting attnos using * the completed newattno[] map */ if (constr && constr->num_check > 0) { ConstrCheck *check = constr->check; int i; for (i = 0; i < constr->num_check; i++) { Constraint *cdef = makeNode(Constraint); Node *expr; cdef->contype = CONSTR_CHECK; /* * Do not inherit generated constraint names, since they * might conflict across multiple inheritance parents. * (But conflicts between user-assigned names will cause * an error.) */ if (ConstraintNameIsGenerated(check[i].ccname)) cdef->name = NULL; else cdef->name = pstrdup(check[i].ccname); cdef->raw_expr = NULL; /* adjust varattnos of ccbin here */ expr = stringToNode(check[i].ccbin); change_varattnos_of_a_node(expr, newattno); cdef->cooked_expr = nodeToString(expr); constraints = lappend(constraints, cdef); } } pfree(newattno); /* * Close the parent rel, but keep our AccessShareLock on it until * xact commit. That will prevent someone else from deleting or * ALTERing the parent before the child is committed. */ heap_close(relation, NoLock); } /* * If we had no inherited attributes, the result schema is just the * explicitly declared columns. Otherwise, we need to merge the * declared columns into the inherited schema list. */ if (inhSchema != NIL) { foreach(entry, schema) { ColumnDef *newdef = lfirst(entry); char *attributeName = newdef->colname; int exist_attno; /* * Does it conflict with some previously inherited column? */ exist_attno = findAttrByName(attributeName, inhSchema); if (exist_attno > 0) { ColumnDef *def; /* * Yes, try to merge the two column definitions. They must * have the same type and typmod. */ ereport(NOTICE, (errmsg("merging column \"%s\" with inherited definition", attributeName))); def = (ColumnDef *) nth(exist_attno - 1, inhSchema); if (typenameTypeId(def->typename) != typenameTypeId(newdef->typename) || def->typename->typmod != newdef->typename->typmod) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("column \"%s\" has a type conflict", attributeName), errdetail("%s versus %s", TypeNameToString(def->typename), TypeNameToString(newdef->typename)))); /* Mark the column as locally defined */ def->is_local = true; /* Merge of NOT NULL constraints = OR 'em together */ def->is_not_null |= newdef->is_not_null; /* If new def has a default, override previous default */ if (newdef->raw_default != NULL) { def->raw_default = newdef->raw_default; def->cooked_default = newdef->cooked_default; } } else { /* * No, attach new column to result schema */ inhSchema = lappend(inhSchema, newdef); } } schema = inhSchema; } /* * If we found any conflicting parent default values, check to make * sure they were overridden by the child. */ if (have_bogus_defaults) { foreach(entry, schema) { ColumnDef *def = lfirst(entry); if (def->cooked_default == bogus_marker) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_DEFINITION), errmsg("column \"%s\" inherits conflicting default values", def->colname), errhint("To resolve the conflict, specify a default explicitly."))); } } *supOids = parentOids; *supconstr = constraints; *supHasOids = parentHasOids; return schema;}/* * complementary static functions for MergeAttributes(). * * Varattnos of pg_constraint.conbin must be rewritten when subclasses inherit * constraints from parent classes, since the inherited attributes could * be given different column numbers in multiple-inheritance cases. * * Note that the passed node tree is modified in place! */static boolchange_varattnos_walker(Node *node, const AttrNumber *newattno){ if (node == NULL) return false; if (IsA(node, Var)) { Var *var = (Var *) node; if (var->varlevelsup == 0 && var->varno == 1 && var->varattno > 0) { /* * ??? the following may be a problem when the node is * multiply referenced though stringToNode() doesn't create * such a node currently. */ Assert(newattno[var->varattno - 1] > 0); var->varattno = newattno[var->varattno - 1]; } return false; } return expression_tree_walker(node, change_varattnos_walker, (void *) newattno);}static boolchange_varattnos_of_a_node(Node *node, const AttrNumber *newattno){ return change_varattnos_walker(node, newattno);}/* * StoreCatalogInheritance * Updates the system catalogs with proper inheritance information. * * supers is a list of the OIDs of the new relation's direct ancestors. */static voidStoreCatalogInheritance(Oid relationId, List *supers){ Relation relation; TupleDesc desc; int16 seqNumber; List *entry; HeapTuple tuple; /* * sanity checks */ AssertArg(OidIsValid(relationId)); if (supers == NIL) return; /* * Store INHERITS information in pg_inherits using direct ancestors * only. Also enter dependencies on the direct ancestors, and make sure * they are marked with relhassubclass = true. * * (Once upon a time, both direct and indirect ancestors were found here * and then entered into pg_ipl. Since that catalog doesn't exist anymore, * there's no need to look for indirect ancestors.) */ relation = heap_openr(InheritsRelationName, RowExclusiveLock); desc = RelationGetDescr(relation); seqNumber = 1; foreach(entry, supers) { Oid parentOid = lfirsto(entry); Datum datum[Natts_pg_inherits]; char nullarr[Natts_pg_inherits]; ObjectAddress childobject, parentobject; datum[0] = ObjectIdGetDatum(relationId); /* inhrel */ datum[1] = ObjectIdGetDatum(parentOid); /* inhparent */ datum[2] = Int16GetDatum(seqNumber); /* inhseqno */ nullarr[0] = ' '; nullarr[1] = ' '; nullarr[2] = ' '; tuple = heap_formtuple(desc, datum, nullarr); simple_heap_insert(relation, tuple); CatalogUpdateIndexes(relation, tuple); heap_freetuple(tuple); /* * Store a dependency too */ parentobject.classId = RelOid_pg_class; parentobject.objectId = parentOid; parentobject.objectSubId = 0; childobject.classId = RelOid_pg_class; childobject.objectId = relationId; childobject.objectSubId = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?