|
|
|
@ -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"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|