📄 tablecmds.c
字号:
localHasOids, parentOidCount, stmt->oncommit, allowSystemTableMods); StoreCatalogInheritance(relationId, inheritOids); /* * We must bump the command counter to make the newly-created relation * tuple visible for opening. */ CommandCounterIncrement(); /* * Open the new relation and acquire exclusive lock on it. This isn't * really necessary for locking out other backends (since they can't see * the new rel anyway until we commit), but it keeps the lock manager from * complaining about deadlock risks. */ rel = relation_open(relationId, AccessExclusiveLock); /* * Now add any newly specified column default values and CHECK constraints * to the new relation. These are passed to us in the form of raw * parsetrees; we need to transform them to executable expression trees * before they can be added. The most convenient way to do that is to * apply the parser's transformExpr routine, but transformExpr doesn't * work unless we have a pre-existing relation. So, the transformation has * to be postponed to this final step of CREATE TABLE. * * Another task that's conveniently done at this step is to add dependency * links between columns and supporting relations (such as SERIAL * sequences). * * First, scan schema to find new column defaults. */ rawDefaults = NIL; attnum = 0; foreach(listptr, schema) { ColumnDef *colDef = lfirst(listptr); attnum++; if (colDef->raw_default != NULL) { RawColumnDefault *rawEnt; Assert(colDef->cooked_default == NULL); rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault)); rawEnt->attnum = attnum; rawEnt->raw_default = colDef->raw_default; rawDefaults = lappend(rawDefaults, rawEnt); } /* Create dependency for supporting relation for this column */ if (colDef->support != NULL) add_column_support_dependency(relationId, attnum, colDef->support); } /* * Parse and add the defaults/constraints, if any. */ if (rawDefaults || stmt->constraints) AddRelationRawConstraints(rel, rawDefaults, stmt->constraints); /* * Clean up. We keep lock on new relation (although it shouldn't be * visible to anyone else anyway, until commit). */ relation_close(rel, NoLock); return relationId;}/* * RemoveRelation * Deletes a relation. */voidRemoveRelation(const RangeVar *relation, DropBehavior behavior){ Oid relOid; ObjectAddress object; relOid = RangeVarGetRelid(relation, false); object.classId = RelationRelationId; object.objectId = relOid; object.objectSubId = 0; performDeletion(&object, behavior);}/* * ExecuteTruncate * Executes a TRUNCATE command. * * This is a multi-relation truncate. It first opens and grabs exclusive * locks on all relations involved, checking permissions and otherwise * verifying that the relation is OK for truncation. When they are all * open, it checks foreign key references on them, namely that FK references * are all internal to the group that's being truncated. Finally all * relations are truncated and reindexed. */voidExecuteTruncate(List *relations){ List *rels = NIL; ListCell *cell; foreach(cell, relations) { RangeVar *rv = lfirst(cell); Relation rel; /* Grab exclusive lock in preparation for truncate */ rel = heap_openrv(rv, AccessExclusiveLock); /* Only allow truncate on regular tables */ if (rel->rd_rel->relkind != RELKIND_RELATION) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table", RelationGetRelationName(rel)))); /* Permissions checks */ if (!pg_class_ownercheck(RelationGetRelid(rel), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, RelationGetRelationName(rel)); if (!allowSystemTableMods && IsSystemRelation(rel)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied: \"%s\" is a system catalog", RelationGetRelationName(rel)))); /* * We can never allow truncation of shared or nailed-in-cache * relations, because we can't support changing their relfilenode * values. */ if (rel->rd_rel->relisshared || rel->rd_isnailed) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot truncate system relation \"%s\"", RelationGetRelationName(rel)))); /* * Don't allow truncate on temp tables of other backends ... their * local buffer manager is not going to cope. */ if (isOtherTempNamespace(RelationGetNamespace(rel))) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot truncate temporary tables of other sessions"))); /* Save it into the list of rels to truncate */ rels = lappend(rels, rel); } /* * Check foreign key references. */ heap_truncate_check_FKs(rels, false); /* * OK, truncate each table. */ foreach(cell, rels) { Relation rel = lfirst(cell); Oid heap_relid; Oid toast_relid; /* * Create a new empty storage file for the relation, and assign it as * the relfilenode value. The old storage file is scheduled for * deletion at commit. */ setNewRelfilenode(rel); heap_relid = RelationGetRelid(rel); toast_relid = rel->rd_rel->reltoastrelid; heap_close(rel, NoLock); /* * The same for the toast table, if any. */ if (OidIsValid(toast_relid)) { rel = relation_open(toast_relid, AccessExclusiveLock); setNewRelfilenode(rel); heap_close(rel, NoLock); } /* * Reconstruct the indexes to match, and we're done. */ reindex_relation(heap_relid, true); }}/*---------- * MergeAttributes * Returns new schema given initial schema and superclasses. * * Input arguments: * 'schema' is the column/attribute definition for the table. (It's a list * of ColumnDef's.) It is destructively changed. * 'supers' is a list of names (as RangeVar nodes) of parent relations. * 'istemp' is TRUE if we are creating a temp relation. * * Output arguments: * 'supOids' receives a list of the OIDs of the parent relations. * 'supconstr' receives a list of constraints belonging to the parents, * updated as necessary to be valid for the child. * 'supOidCount' is set to the number of parents that have OID columns. * * Return value: * Completed schema list. * * Notes: * The order in which the attributes are inherited is very important. * Intuitively, the inherited attributes should come first. If a table * inherits from multiple parents, the order of those attributes are * according to the order of the parents specified in CREATE TABLE. * * Here's an example: * * create table person (name text, age int4, location point); * create table emp (salary int4, manager text) inherits(person); * create table student (gpa float8) inherits (person); * create table stud_emp (percent int4) inherits (emp, student); * * The order of the attributes of stud_emp is: * * person {1:name, 2:age, 3:location} * / \ * {6:gpa} student emp {4:salary, 5:manager} * \ / * stud_emp {7:percent} * * If the same attribute name appears multiple times, then it appears * in the result table in the proper location for its first appearance. * * Constraints (including NOT NULL constraints) for the child table * are the union of all relevant constraints, from both the child schema * and parent tables. * * The default value for a child column is defined as: * (1) If the child schema specifies a default, that value is used. * (2) If neither the child nor any parent specifies a default, then * 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, int *supOidCount){ ListCell *entry; List *inhSchema = NIL; List *parentOids = NIL; List *constraints = NIL; int parentsWithOids = 0; bool have_bogus_defaults = false; char *bogus_marker = "Bogus!"; /* marks conflicting defaults */ int child_attno; /* * Check for and reject tables with too many columns. We perform this * check relatively early for two reasons: (a) we don't run the risk of * overflowing an AttrNumber in subsequent code (b) an O(n^2) algorithm is * okay if we're processing <= 1600 columns, but could take minutes to * execute if the user attempts to create a table with hundreds of * thousands of columns. * * Note that we also need to check that any we do not exceed this figure * after including columns from inherited relations. */ if (list_length(schema) > MaxHeapAttributeNumber) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_COLUMNS), errmsg("tables can have at most %d columns", MaxHeapAttributeNumber))); /* * 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); ListCell *rest; for_each_cell(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 (list_member_oid(parentOids, RelationGetRelid(relation))) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_TABLE), errmsg("inherited relation \"%s\" duplicated", parent->relname))); parentOids = lappend_oid(parentOids, RelationGetRelid(relation)); if (relation->rd_rel->relhasoids) parentsWithOids++; 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.) */ newattno = (AttrNumber *) palloc(tupleDesc->natts * 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 *) list_nth(inhSchema, exist_attno - 1); 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 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -