tablecmds.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,338 行 · 第 1/5 页
C
2,338 行
recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL); /* * Mark the parent as having subclasses. */ setRelhassubclassInRelation(parentOid, true); seqNumber += 1; } heap_close(relation, RowExclusiveLock);}/* * Look for an existing schema entry with the given name. * * Returns the index (starting with 1) if attribute already exists in schema, * 0 if it doesn't. */static intfindAttrByName(const char *attributeName, List *schema){ List *s; int i = 0; foreach(s, schema) { ColumnDef *def = lfirst(s); ++i; if (strcmp(attributeName, def->colname) == 0) return i; } return 0;}/* * Update a relation's pg_class.relhassubclass entry to the given value */static voidsetRelhassubclassInRelation(Oid relationId, bool relhassubclass){ Relation relationRelation; HeapTuple tuple; Form_pg_class classtuple; /* * Fetch a modifiable copy of the tuple, modify it, update pg_class. * * If the tuple already has the right relhassubclass setting, we * don't need to update it, but we still need to issue an SI inval * message. */ relationRelation = heap_openr(RelationRelationName, RowExclusiveLock); tuple = SearchSysCacheCopy(RELOID, ObjectIdGetDatum(relationId), 0, 0, 0); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for relation %u", relationId); classtuple = (Form_pg_class) GETSTRUCT(tuple); if (classtuple->relhassubclass != relhassubclass) { classtuple->relhassubclass = relhassubclass; simple_heap_update(relationRelation, &tuple->t_self, tuple); /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relationRelation, tuple); } else { /* no need to change tuple, but force relcache rebuild anyway */ CacheInvalidateRelcache(relationId); } heap_freetuple(tuple); heap_close(relationRelation, RowExclusiveLock);}/* * renameatt - changes the name of a attribute in a relation * * Attname attribute is changed in attribute catalog. * No record of the previous attname is kept (correct?). * * get proper relrelation from relation catalog (if not arg) * scan attribute catalog * for name conflict (within rel) * for original attribute (if not arg) * modify attname in attribute tuple * insert modified attribute in attribute catalog * delete original attribute from attribute catalog */voidrenameatt(Oid myrelid, const char *oldattname, const char *newattname, bool recurse, bool recursing){ Relation targetrelation; Relation attrelation; HeapTuple atttup; Form_pg_attribute attform; int attnum; List *indexoidlist; List *indexoidscan; /* * Grab an exclusive lock on the target table, which we will NOT * release until end of transaction. */ targetrelation = relation_open(myrelid, AccessExclusiveLock); /* * permissions checking. this would normally be done in utility.c, * but this particular routine is recursive. * * normally, only the owner of a class can change its schema. */ if (!pg_class_ownercheck(myrelid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, RelationGetRelationName(targetrelation)); if (!allowSystemTableMods && IsSystemRelation(targetrelation)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied: \"%s\" is a system catalog", RelationGetRelationName(targetrelation)))); /* * if the 'recurse' flag is set then we are supposed to rename this * attribute in all classes that inherit from 'relname' (as well as in * 'relname'). * * any permissions or problems with duplicate attributes will cause the * whole transaction to abort, which is what we want -- all or * nothing. */ if (recurse) { List *child, *children; /* this routine is actually in the planner */ children = find_all_inheritors(myrelid); /* * find_all_inheritors does the recursive search of the * inheritance hierarchy, so all we have to do is process all of * the relids in the list that it returns. */ foreach(child, children) { Oid childrelid = lfirsto(child); if (childrelid == myrelid) continue; /* note we need not recurse again! */ renameatt(childrelid, oldattname, newattname, false, true); } } else { /* * If we are told not to recurse, there had better not be any * child tables; else the rename would put them out of step. */ if (!recursing && find_inheritance_children(myrelid) != NIL) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("inherited column \"%s\" must be renamed in child tables too", oldattname))); } attrelation = heap_openr(AttributeRelationName, RowExclusiveLock); atttup = SearchSysCacheCopyAttName(myrelid, oldattname); if (!HeapTupleIsValid(atttup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" does not exist", oldattname))); attform = (Form_pg_attribute) GETSTRUCT(atttup); attnum = attform->attnum; if (attnum < 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot rename system column \"%s\"", oldattname))); /* * if the attribute is inherited, forbid the renaming, unless we are * already inside a recursive rename. */ if (attform->attinhcount > 0 && !recursing) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("cannot rename inherited column \"%s\"", oldattname))); /* should not already exist */ /* this test is deliberately not attisdropped-aware */ if (SearchSysCacheExists(ATTNAME, ObjectIdGetDatum(myrelid), PointerGetDatum(newattname), 0, 0)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("column \"%s\" of relation \"%s\" already exists", newattname, RelationGetRelationName(targetrelation)))); namestrcpy(&(attform->attname), newattname); simple_heap_update(attrelation, &atttup->t_self, atttup); /* keep system catalog indexes current */ CatalogUpdateIndexes(attrelation, atttup); heap_freetuple(atttup); /* * Update column names of indexes that refer to the column being * renamed. */ indexoidlist = RelationGetIndexList(targetrelation); foreach(indexoidscan, indexoidlist) { Oid indexoid = lfirsto(indexoidscan); HeapTuple indextup; Form_pg_index indexform; int i; /* * Scan through index columns to see if there's any simple index * entries for this attribute. We ignore expressional entries. */ indextup = SearchSysCache(INDEXRELID, ObjectIdGetDatum(indexoid), 0, 0, 0); if (!HeapTupleIsValid(indextup)) elog(ERROR, "cache lookup failed for index %u", indexoid); indexform = (Form_pg_index) GETSTRUCT(indextup); for (i = 0; i < indexform->indnatts; i++) { if (attnum != indexform->indkey[i]) continue; /* * Found one, rename it. */ atttup = SearchSysCacheCopy(ATTNUM, ObjectIdGetDatum(indexoid), Int16GetDatum(i + 1), 0, 0); if (!HeapTupleIsValid(atttup)) continue; /* should we raise an error? */ /* * Update the (copied) attribute tuple. */ namestrcpy(&(((Form_pg_attribute) GETSTRUCT(atttup))->attname), newattname); simple_heap_update(attrelation, &atttup->t_self, atttup); /* keep system catalog indexes current */ CatalogUpdateIndexes(attrelation, atttup); heap_freetuple(atttup); } ReleaseSysCache(indextup); } freeList(indexoidlist); heap_close(attrelation, RowExclusiveLock); /* * Update att name in any RI triggers associated with the relation. */ if (targetrelation->rd_rel->reltriggers > 0) { /* update tgargs column reference where att is primary key */ update_ri_trigger_args(RelationGetRelid(targetrelation), oldattname, newattname, false, false); /* update tgargs column reference where att is foreign key */ update_ri_trigger_args(RelationGetRelid(targetrelation), oldattname, newattname, true, false); } relation_close(targetrelation, NoLock); /* close rel but keep * lock! */}/* * renamerel - change the name of a relation * * XXX - When renaming sequences, we don't bother to modify the * sequence name that is stored within the sequence itself * (this would cause problems with MVCC). In the future, * the sequence name should probably be removed from the * sequence, AFAIK there's no need for it to be there. */voidrenamerel(Oid myrelid, const char *newrelname){ Relation targetrelation; Relation relrelation; /* for RELATION relation */ HeapTuple reltup; Oid namespaceId; char *oldrelname; char relkind; bool relhastriggers; /* * Grab an exclusive lock on the target table or index, which we will * NOT release until end of transaction. */ targetrelation = relation_open(myrelid, AccessExclusiveLock); oldrelname = pstrdup(RelationGetRelationName(targetrelation)); namespaceId = RelationGetNamespace(targetrelation); if (!allowSystemTableMods && IsSystemRelation(targetrelation)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied: \"%s\" is a system catalog", RelationGetRelationName(targetrelation)))); relkind = targetrelation->rd_rel->relkind; relhastriggers = (targetrelation->rd_rel->reltriggers > 0); /* * Find relation's pg_class tuple, and make sure newrelname isn't in * use. */ relrelation = heap_openr(RelationRelationName, RowExclusiveLock); reltup = SearchSysCacheCopy(RELOID, PointerGetDatum(myrelid), 0, 0, 0); if (!HeapTupleIsValid(reltup)) /* shouldn't happen */ elog(ERROR, "cache lookup failed for relation %u", myrelid); if (get_relname_relid(newrelname, namespaceId) != InvalidOid) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_TABLE), errmsg("relation \"%s\" already exists", newrelname))); /* * Update pg_class tuple with new relname. (Scribbling on reltup is * OK because it's a copy...) */ namestrcpy(&(((Form_pg_class) GETSTRUCT(reltup))->relname), newrelname); simple_heap_update(relrelation, &reltup->t_self, reltup); /* keep the system catalog indexes current */ CatalogUpdateIndexes(relrelation, reltup); heap_freetuple(reltup); heap_close(relrelation, RowExclusiveLock); /* * Also rename the associated type, if any. */ if (relkind != RELKIND_INDEX) TypeRename(oldrelname, namespaceId, newrelname); /* * Update rel name in any RI triggers associated with the relation. */ if (relhastriggers) { /* update tgargs where relname is primary key */ update_ri_trigger_args(myrelid, oldrelname, newrelname, false, true); /* update tgargs where relname is foreign key */ update_ri_trigger_args(myrelid, oldrelname, newrelname, true, true); } /* * Close rel, but keep exclusive lock! */ relation_close(targetrelation, NoLock);}/* * Given a trigger function OID, determine whether it is an RI trigger, * and if so whether it is attached to PK or FK relation. * * XXX this probably doesn't belong here; should be exported by * ri_triggers.c */static intri_trigger_type(Oid tgfoid){ switch (tgfoid) { case F_RI_FKEY_CASCADE_DEL: case F_RI_FKEY_CASCADE_UPD: case F_RI_FKEY_RESTRICT_DEL: case F_RI_FKEY_RESTRICT_UPD: case F_RI_FKEY_SETNULL_DEL: case F_RI_FKEY_SETNULL_UPD: case F_RI_FKEY_SETDEFAULT_DEL: case F_RI_FKEY_SETDEFAULT_UPD: case F_RI_FKEY_NOACTION_DEL: case F_RI_FKEY_NOACTION_UPD: return RI_TRIGGER_PK; case F_RI_FKEY_CHECK_INS: case F_RI_FKEY_CHECK_UPD: return RI_TRIGGER_FK; } return RI_TRIGGER_NONE;}/* * Scan pg_trigger for RI triggers that are on the specified relation * (if fk_scan is false) or have it as the tgconstrrel (if fk_scan * is true). Update RI trigger args fields matching oldname to contain * newname instead. If update_relname is true, examine the relname * fields; otherwise examine the attname fields. */static voidupdate_ri_trigger_args(Oid relid, const char *oldname, const char *newname, bool fk_scan, bool update_relname){ Relation tgrel; ScanKeyData skey[1]; SysScanDesc trigscan; HeapTuple tuple; Datum values[Natts_pg_trigger]; char nulls[Natts_pg_trigger]; char replaces[Natts_pg_trigger]; tgrel = heap_openr(TriggerRelationName, RowExclusiveLock); if (fk_scan) { ScanKeyEntryInitialize(&skey[0], 0x0, Anum_pg_trigger_tgconstrrelid, F_OIDEQ, ObjectIdGetDatum(relid)); trigscan = systable_beginscan(tgrel, TriggerConstrRelidIndex, true, SnapshotNow, 1, skey); } else
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?