diff options
Diffstat (limited to 'src/backend/commands/command.c')
-rw-r--r-- | src/backend/commands/command.c | 227 |
1 files changed, 215 insertions, 12 deletions
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 93322d7a7f7..5c29dd692ac 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.63 2000/01/16 20:04:55 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.64 2000/01/22 14:20:45 petere Exp $ * * NOTES * The PortalExecutorHeapMemory crap needs to be eliminated @@ -30,6 +30,7 @@ #include "catalog/pg_attrdef.h" #include "catalog/pg_type.h" #include "commands/command.h" +#include "commands/rename.h" #include "executor/execdefs.h" #include "executor/executor.h" #include "catalog/heap.h" @@ -299,7 +300,7 @@ AlterTableAddColumn(const char *relationName, Relation idescs[Num_pg_attr_indices]; Relation ridescs[Num_pg_class_indices]; bool hasindex; - List *rawDefaults = NIL; +// List *rawDefaults = NIL; /* * permissions checking. this would normally be done in utility.c, @@ -319,7 +320,7 @@ AlterTableAddColumn(const char *relationName, * Grab an exclusive lock on the target table, which we will NOT release * until end of transaction. */ - rel = heap_openr((char *)relationName, AccessExclusiveLock); + rel = heap_openr(relationName, AccessExclusiveLock); myrelid = RelationGetRelid(rel); heap_close(rel, NoLock); /* close rel but keep lock! */ @@ -519,8 +520,7 @@ AlterTableAlterColumn(const char *relationName, elog(ERROR, "ALTER TABLE: permission denied"); #endif - /* XXX should heap_openr take const char * ? */ - rel = heap_openr((char *)relationName, AccessExclusiveLock); + rel = heap_openr(relationName, AccessExclusiveLock); myrelid = RelationGetRelid(rel); heap_close(rel, NoLock); @@ -626,7 +626,7 @@ AlterTableAlterColumn(const char *relationName, /* keep the system catalog indices current */ CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, irelations); CatalogIndexInsert(irelations, Num_pg_attr_indices, attr_rel, newtuple); - CatalogCloseIndices(Num_pg_class_indices, irelations); + CatalogCloseIndices(Num_pg_attrdef_indices, irelations); /* get rid of actual default definition */ drop_default(myrelid, attnum); @@ -672,31 +672,234 @@ drop_default(Oid relid, int16 attnum) /* * ALTER TABLE DROP COLUMN + * + * Strategy: + * - permission/sanity checks + * - create a new table _ATDC<name> with all attributes minus the desired one + * - copy over all the data + * - make the column defaults point to the new table + * - kill the old table + * - rename the intermediate table back */ void AlterTableDropColumn(const char *relationName, bool inh, const char *colName, int behavior) { - elog(NOTICE, "ALTER TABLE / DROP COLUMN is not implemented"); + Relation oldrel, newrel, defrel; + HeapTuple tuple; + TupleDesc olddesc, newdesc, defdsc; + int16 dropattnum, oldnumatts; + Oid oldrel_oid, newrel_oid; + char tmpname[NAMEDATALEN]; + int16 i; + HeapScanDesc scan; + ScanKeyData scankey; + + if (!allowSystemTableMods && IsSystemRelationName(relationName)) + elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", + relationName); +#ifndef NO_SECURITY + if (!pg_ownercheck(UserName, relationName, RELNAME)) + elog(ERROR, "ALTER TABLE: permission denied"); +#endif + + oldrel = heap_openr(relationName, AccessExclusiveLock); + if (oldrel->rd_rel->relkind != RELKIND_RELATION) + { + heap_close(oldrel, AccessExclusiveLock); + elog(ERROR, "ALTER TABLE: relation %s is not a table", relationName); + } + + oldrel_oid = ObjectIdGetDatum(RelationGetRelid(oldrel)); + oldnumatts = RelationGetNumberOfAttributes(oldrel); + + if (oldnumatts==1) + { + heap_close(oldrel, AccessExclusiveLock); + elog(ERROR, "ALTER TABLE: relation %s only has one column", relationName); + } + +/* What to do here? */ +/* + if (length(find_all_inheritors(RelationGetRelid(oldrel)))>0) + elog(ERROR, "ALTER TABLE: cannot drop a column on table that is inherited from"); +*/ + /* + * get the number of the attribute + */ + tuple = SearchSysCacheTuple(ATTNAME, oldrel_oid, NameGetDatum(namein(colName)), 0, 0); + if (!HeapTupleIsValid(tuple)) + { + heap_close(oldrel, AccessExclusiveLock); + elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"", + relationName, colName); + } + + dropattnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum; + + if (snprintf(tmpname, NAMEDATALEN, "_ATDC%s", relationName)==-1) + { + heap_close(oldrel, AccessExclusiveLock); + elog(ERROR, "AlterTableDropColumn: relation name too long"); + } + + /* + * Build descriptor for new relation + */ + olddesc = RelationGetDescr(oldrel); + + newdesc = CreateTemplateTupleDesc(oldnumatts-1); + for(i = 1; i < dropattnum; i++) + { + Form_pg_attribute att = olddesc->attrs[i-1]; + TupleDescInitEntry(newdesc, i, nameout(&(att->attname)), + att->atttypid, att->atttypmod, + att->attnelems, att->attisset); + /* the above function doesn't take care of these two */ + newdesc->attrs[i-1]->attnotnull = att->attnotnull; + newdesc->attrs[i-1]->atthasdef = att->atthasdef; + } + + for(i = dropattnum; i <= oldnumatts-1; i++) + { + Form_pg_attribute att = olddesc->attrs[i]; + TupleDescInitEntry(newdesc, i, nameout(&(att->attname)), + att->atttypid, att->atttypmod, + att->attnelems, att->attisset); + /* the above function doesn't take care of these two */ + newdesc->attrs[i-1]->attnotnull = att->attnotnull; + newdesc->attrs[i-1]->atthasdef = att->atthasdef; + } + + /* Create the new table */ + newrel_oid = heap_create_with_catalog(tmpname, newdesc, RELKIND_RELATION, false); + if (newrel_oid == InvalidOid) + { + heap_close(oldrel, AccessExclusiveLock); + elog(ERROR, "ALTER TABLE: something went wrong"); + } + + /* Make the new table visible */ + CommandCounterIncrement(); + + /* + * Copy over the data + */ + newrel = heap_open(newrel_oid, AccessExclusiveLock); + + scan = heap_beginscan(oldrel, false, SnapshotNow, 0, NULL); + while (HeapTupleIsValid(tuple = heap_getnext(scan, 0))) + { + bool isnull; + Datum *new_record; + bool *new_record_nulls; + HeapTuple new_tuple; + + new_record = palloc((oldnumatts-1) * sizeof(*new_record)); + new_record_nulls = palloc((oldnumatts-1) * sizeof(*new_record_nulls)); + + for(i = 1; i < dropattnum; i++) + { + new_record[i-1] = heap_getattr(tuple, i, olddesc, &isnull); + new_record_nulls[i-1] = isnull ? 'n' : ' '; + } + for(i = dropattnum+1; i <= oldnumatts; i++) + { + new_record[i-2] = heap_getattr(tuple, i, olddesc, &isnull); + new_record_nulls[i-2] = isnull ? 'n' : ' '; + } + + new_tuple = heap_formtuple(newdesc, new_record, new_record_nulls); + Assert(new_tuple); + + if (heap_insert(newrel, new_tuple) == InvalidOid) + elog(ERROR, "AlterTableDropColumn: heap_insert failed"); + + pfree(new_record); + pfree(new_record_nulls); + } + heap_endscan(scan); + + heap_close(newrel, NoLock); + heap_close(oldrel, NoLock); + + /* + * Move defaults over to the new table + */ + defrel = heap_openr(AttrDefaultRelationName, AccessExclusiveLock); + defdsc = RelationGetDescr(defrel); + + /* look for all entries referencing the old table */ + ScanKeyEntryInitialize(&scankey, 0x0, Anum_pg_attrdef_adrelid, F_OIDEQ, + ObjectIdGetDatum(oldrel_oid)); + scan = heap_beginscan(defrel, false, SnapshotNow, 1, &scankey); + while(HeapTupleIsValid(tuple = heap_getnext(scan, false))) + { + HeapTuple newtuple; + int2 attrnum; + Relation irelations[Num_pg_attrdef_indices]; + + attrnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum; + + /* remove the entry about the dropped column */ + if (attrnum == dropattnum) + { + heap_delete(defrel, &tuple->t_self, NULL); + continue; + } + + newtuple = heap_copytuple(tuple); + + if (attrnum > dropattnum) + ((Form_pg_attrdef) GETSTRUCT(newtuple))->adnum--; + + /* make it point to the new table */ + ((Form_pg_attrdef) GETSTRUCT(newtuple))->adrelid = newrel_oid; + heap_update(defrel, &tuple->t_self, newtuple, NULL); + + /* keep the system catalog indices current */ + CatalogOpenIndices(Num_pg_attrdef_indices, Name_pg_attrdef_indices, irelations); + CatalogIndexInsert(irelations, Num_pg_attrdef_indices, defrel, newtuple); + CatalogCloseIndices(Num_pg_attrdef_indices, irelations); + } + heap_endscan(scan); + heap_close(defrel, NoLock); + + CommandCounterIncrement(); + + /* make the old table disappear */ + heap_drop_with_catalog(relationName); + CommandCounterIncrement(); + + /* set back original name */ + TypeRename(tmpname, relationName); + renamerel(tmpname, relationName); } +/* + * ALTER TABLE ADD CONSTRAINT + */ void AlterTableAddConstraint(const char *relationName, bool inh, Node *newConstraint) { - elog(NOTICE, "ALTER TABLE / ADD CONSTRAINT is not implemented"); + elog(ERROR, "ALTER TABLE / ADD CONSTRAINT is not implemented"); } -void AlterTableDropConstraint(const char *relationName, - bool inh, const char *constrName, - int behavior) +/* + * ALTER TABLE DROP CONSTRAINT + */ +void +AlterTableDropConstraint(const char *relationName, + bool inh, const char *constrName, + int behavior) { - elog(NOTICE, "ALTER TABLE / DROP CONSTRAINT is not implemented"); + elog(ERROR, "ALTER TABLE / DROP CONSTRAINT is not implemented"); } |