*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.260 2004/02/15 21:01:39 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.261 2004/03/23 19:35:16 tgl Exp $
*
*
* INTERFACE ROUTINES
static void
AddNewAttributeTuples(Oid new_rel_oid,
TupleDesc tupdesc,
- char relkind)
+ char relkind,
+ bool oidislocal,
+ int oidinhcount)
{
Form_pg_attribute *dpp;
int i;
false,
ATTRIBUTE_TUPLE_SIZE,
(void *) *dpp);
+ attStruct = (Form_pg_attribute) GETSTRUCT(tup);
/* Fill in the correct relation OID in the copied tuple */
- attStruct = (Form_pg_attribute) GETSTRUCT(tup);
attStruct->attrelid = new_rel_oid;
+ /* Fill in correct inheritance info for the OID column */
+ if (attStruct->attnum == ObjectIdAttributeNumber)
+ {
+ attStruct->attislocal = oidislocal;
+ attStruct->attinhcount = oidinhcount;
+ }
+
/*
* Unneeded since they should be OK in the constant data
* anyway
TupleDesc tupdesc,
char relkind,
bool shared_relation,
+ bool oidislocal,
+ int oidinhcount,
OnCommitAction oncommit,
bool allow_system_table_mods)
{
* now add tuples to pg_attribute for the attributes in our new
* relation.
*/
- AddNewAttributeTuples(new_rel_oid, new_rel_desc->rd_att, relkind);
+ AddNewAttributeTuples(new_rel_oid, new_rel_desc->rd_att, relkind,
+ oidislocal, oidinhcount);
/*
* make a dependency link to force the relation to be deleted if its
attnum, relid);
attStruct = (Form_pg_attribute) GETSTRUCT(tuple);
- /* Mark the attribute as dropped */
- attStruct->attisdropped = true;
+ if (attnum < 0)
+ {
+ /* System attribute (probably OID) ... just delete the row */
- /*
- * Set the type OID to invalid. A dropped attribute's type link
- * cannot be relied on (once the attribute is dropped, the type might
- * be too). Fortunately we do not need the type row --- the only
- * really essential information is the type's typlen and typalign,
- * which are preserved in the attribute's attlen and attalign. We set
- * atttypid to zero here as a means of catching code that incorrectly
- * expects it to be valid.
- */
- attStruct->atttypid = InvalidOid;
+ simple_heap_delete(attr_rel, &tuple->t_self);
+ }
+ else
+ {
+ /* Dropping user attributes is lots harder */
- /* Remove any NOT NULL constraint the column may have */
- attStruct->attnotnull = false;
+ /* Mark the attribute as dropped */
+ attStruct->attisdropped = true;
- /* We don't want to keep stats for it anymore */
- attStruct->attstattarget = 0;
+ /*
+ * Set the type OID to invalid. A dropped attribute's type link
+ * cannot be relied on (once the attribute is dropped, the type might
+ * be too). Fortunately we do not need the type row --- the only
+ * really essential information is the type's typlen and typalign,
+ * which are preserved in the attribute's attlen and attalign. We set
+ * atttypid to zero here as a means of catching code that incorrectly
+ * expects it to be valid.
+ */
+ attStruct->atttypid = InvalidOid;
- /* Change the column name to something that isn't likely to conflict */
- snprintf(newattname, sizeof(newattname),
- "........pg.dropped.%d........", attnum);
- namestrcpy(&(attStruct->attname), newattname);
+ /* Remove any NOT NULL constraint the column may have */
+ attStruct->attnotnull = false;
- simple_heap_update(attr_rel, &tuple->t_self, tuple);
+ /* We don't want to keep stats for it anymore */
+ attStruct->attstattarget = 0;
- /* keep the system catalog indexes current */
- CatalogUpdateIndexes(attr_rel, tuple);
+ /* Change the column name to something that isn't likely to conflict */
+ snprintf(newattname, sizeof(newattname),
+ "........pg.dropped.%d........", attnum);
+ namestrcpy(&(attStruct->attname), newattname);
+
+ simple_heap_update(attr_rel, &tuple->t_self, tuple);
+
+ /* keep the system catalog indexes current */
+ CatalogUpdateIndexes(attr_rel, tuple);
+ }
/*
* Because updating the pg_attribute row will trigger a relcache flush
heap_close(attr_rel, RowExclusiveLock);
- RemoveStatistics(rel, attnum);
+ if (attnum > 0)
+ RemoveStatistics(rel, attnum);
relation_close(rel, NoLock);
}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.100 2004/03/13 22:09:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.101 2004/03/23 19:35:16 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static List *MergeAttributes(List *schema, List *supers, bool istemp,
- List **supOids, List **supconstr, bool *supHasOids);
+ List **supOids, List **supconstr, int *supOidCount);
static bool change_varattnos_of_a_node(Node *node, const AttrNumber *newattno);
static void StoreCatalogInheritance(Oid relationId, List *supers);
static int findAttrByName(const char *attributeName, List *schema);
TupleDesc descriptor;
List *inheritOids;
List *old_constraints;
- bool parentHasOids;
+ bool localHasOids;
+ int parentOidCount;
List *rawDefaults;
List *listptr;
int i;
*/
schema = MergeAttributes(schema, stmt->inhRelations,
stmt->relation->istemp,
- &inheritOids, &old_constraints, &parentHasOids);
+ &inheritOids, &old_constraints, &parentOidCount);
/*
* Create a relation descriptor from the relation schema and create
*/
descriptor = BuildDescForRelation(schema);
- if (parentHasOids)
- descriptor->tdhasoid = true;
- else
- descriptor->tdhasoid = interpretOidsOption(stmt->hasoids);
+ localHasOids = interpretOidsOption(stmt->hasoids);
+ descriptor->tdhasoid = (localHasOids || parentOidCount > 0);
if (old_constraints != NIL)
{
descriptor,
relkind,
false,
+ localHasOids,
+ parentOidCount,
stmt->oncommit,
allowSystemTableMods);
* '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.
- * 'supHasOids' is set TRUE if any parent has OIDs, else it is set FALSE.
+ * 'supOidCount' is set to the number of parents that have OID columns.
*
* Return value:
* Completed schema list.
*/
static List *
MergeAttributes(List *schema, List *supers, bool istemp,
- List **supOids, List **supconstr, bool *supHasOids)
+ List **supOids, List **supconstr, int *supOidCount)
{
List *entry;
List *inhSchema = NIL;
List *parentOids = NIL;
List *constraints = NIL;
- bool parentHasOids = false;
+ int parentsWithOids = 0;
bool have_bogus_defaults = false;
char *bogus_marker = "Bogus!"; /* marks conflicting
* defaults */
parentOids = lappendo(parentOids, RelationGetRelid(relation));
- parentHasOids |= relation->rd_rel->relhasoids;
+ if (relation->rd_rel->relhasoids)
+ parentsWithOids++;
tupleDesc = RelationGetDescr(relation);
constr = tupleDesc->constr;
*supOids = parentOids;
*supconstr = constraints;
- *supHasOids = parentHasOids;
+ *supOidCount = parentsWithOids;
return schema;
}
}
/*
- * ALTER TABLE SET {WITHOUT} OIDS
+ * ALTER TABLE SET WITH/WITHOUT OIDS
*/
void
-AlterTableAlterOids(Oid myrelid, bool recurse, bool setOid)
+AlterTableAlterOids(Oid myrelid, bool setOid, bool recurse,
+ DropBehavior behavior)
{
Relation rel;
- Relation class_rel;
- HeapTuple tuple;
- Form_pg_class tuple_class;
rel = heap_open(myrelid, AccessExclusiveLock);
- 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(myrelid, 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))));
-
- /*
- * Propagate to children if desired
- */
- 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 = lfirsti(child);
-
- if (childrelid == myrelid)
- continue;
-
- AlterTableAlterOids(childrelid, false, setOid);
- }
- }
-
- /* Do the thing on this relation */
- class_rel = heap_openr(RelationRelationName, RowExclusiveLock);
-
- tuple = SearchSysCacheCopy(RELOID,
- ObjectIdGetDatum(myrelid),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for relation %u", myrelid);
- tuple_class = (Form_pg_class) GETSTRUCT(tuple);
-
/*
* check to see if we actually need to change anything
*/
- if (tuple_class->relhasoids == setOid)
+ if (rel->rd_rel->relhasoids == setOid)
{
- heap_close(class_rel, RowExclusiveLock);
heap_close(rel, NoLock); /* close rel, but keep lock! */
return;
}
- tuple_class->relhasoids = setOid;
- simple_heap_update(class_rel, &tuple->t_self, tuple);
-
- /* Keep the catalog indexes up to date */
- CatalogUpdateIndexes(class_rel, tuple);
-
if (setOid)
{
/*
- * TODO: Generate the now required OID pg_attribute entry
+ * TODO: Generate the now required OID pg_attribute entry, and
+ * modify physical rows to have OIDs.
*/
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
}
else
{
- HeapTuple atttup;
- Relation attrel;
-
- /* Add / Remove the oid record from pg_attribute */
- attrel = heap_open(RelOid_pg_attribute, RowExclusiveLock);
-
- /*
- * Oids are being removed from the relation, so we need to remove
- * the oid pg_attribute record relating.
- */
- atttup = SearchSysCache(ATTNUM,
- ObjectIdGetDatum(myrelid),
- Int16GetDatum(ObjectIdAttributeNumber),
- 0, 0);
- if (!HeapTupleIsValid(atttup))
- elog(ERROR, "cache lookup failed for attribute %d of relation %u",
- ObjectIdAttributeNumber, myrelid);
-
- simple_heap_delete(attrel, &atttup->t_self);
-
- ReleaseSysCache(atttup);
+ heap_close(rel, NoLock); /* close rel, but keep lock! */
- heap_close(attrel, RowExclusiveLock);
+ AlterTableDropColumn(myrelid, recurse, false, "oid", behavior);
}
-
- heap_close(class_rel, RowExclusiveLock);
-
- heap_close(rel, NoLock); /* close rel, but keep lock! */
}
/*
{
Relation rel;
AttrNumber attnum;
- TupleDesc tupleDesc;
+ HeapTuple tuple;
+ Form_pg_attribute targetatt;
ObjectAddress object;
rel = heap_open(myrelid, AccessExclusiveLock);
/*
* get the number of the attribute
*/
- attnum = get_attnum(myrelid, colName);
- if (attnum == InvalidAttrNumber)
+ tuple = SearchSysCacheAttName(myrelid, colName);
+ if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
- errmsg("column \"%s\" of relation \"%s\" does not exist",
- colName, RelationGetRelationName(rel))));
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
+ colName, RelationGetRelationName(rel))));
+ targetatt = (Form_pg_attribute) GETSTRUCT(tuple);
- /* Can't drop a system attribute */
- /* XXX perhaps someday allow dropping OID? */
- if (attnum < 0)
+ attnum = targetatt->attnum;
+
+ /* Can't drop a system attribute, except OID */
+ if (attnum <= 0 && attnum != ObjectIdAttributeNumber)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot drop system column \"%s\"",
colName)));
/* Don't drop inherited columns */
- tupleDesc = RelationGetDescr(rel);
- if (tupleDesc->attrs[attnum - 1]->attinhcount > 0 && !recursing)
+ if (targetatt->attinhcount > 0 && !recursing)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("cannot drop inherited column \"%s\"",
colName)));
+ ReleaseSysCache(tuple);
+
/*
* If we are asked to drop ONLY in this table (no recursion), we need
* to mark the inheritors' attribute as locally defined rather than
{
Oid childrelid = lfirsto(child);
Relation childrel;
- HeapTuple tuple;
Form_pg_attribute childatt;
childrel = heap_open(childrelid, AccessExclusiveLock);
{
Oid childrelid = lfirsto(child);
Relation childrel;
- HeapTuple tuple;
Form_pg_attribute childatt;
if (childrelid == myrelid)
}
/*
- * Perform the actual deletion
+ * Perform the actual column deletion
*/
object.classId = RelOid_pg_class;
object.objectId = myrelid;
performDeletion(&object, behavior);
+ /*
+ * If we dropped the OID column, must adjust pg_class.relhasoids
+ */
+ if (attnum == ObjectIdAttributeNumber)
+ {
+ Relation class_rel;
+ Form_pg_class tuple_class;
+
+ class_rel = heap_openr(RelationRelationName, RowExclusiveLock);
+
+ tuple = SearchSysCacheCopy(RELOID,
+ ObjectIdGetDatum(myrelid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", myrelid);
+ tuple_class = (Form_pg_class) GETSTRUCT(tuple);
+
+ tuple_class->relhasoids = false;
+ simple_heap_update(class_rel, &tuple->t_self, tuple);
+
+ /* Keep the catalog indexes up to date */
+ CatalogUpdateIndexes(class_rel, tuple);
+
+ heap_close(class_rel, RowExclusiveLock);
+ }
+
heap_close(rel, NoLock); /* close rel, but keep lock! */
}
tupdesc,
RELKIND_TOASTVALUE,
shared_relation,
+ true,
+ 0,
ONCOMMIT_NOOP,
true);