77 *
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.63 2000/01/16 20:04:55 petere Exp $
10+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.64 2000/01/22 14: 20:45 petere Exp $
1111 *
1212 * NOTES
1313 * The PortalExecutorHeapMemory crap needs to be eliminated
3030#include "catalog/pg_attrdef.h"
3131#include "catalog/pg_type.h"
3232#include "commands/command.h"
33+ #include "commands/rename.h"
3334#include "executor/execdefs.h"
3435#include "executor/executor.h"
3536#include "catalog/heap.h"
@@ -299,7 +300,7 @@ AlterTableAddColumn(const char *relationName,
299300Relation idescs [Num_pg_attr_indices ];
300301Relation ridescs [Num_pg_class_indices ];
301302bool hasindex ;
302- List * rawDefaults = NIL ;
303+ // List *rawDefaults = NIL;
303304
304305/*
305306 * permissions checking. this would normally be done in utility.c,
@@ -319,7 +320,7 @@ AlterTableAddColumn(const char *relationName,
319320 * Grab an exclusive lock on the target table, which we will NOT release
320321 * until end of transaction.
321322 */
322- rel = heap_openr (( char * ) relationName ,AccessExclusiveLock );
323+ rel = heap_openr (relationName ,AccessExclusiveLock );
323324myrelid = RelationGetRelid (rel );
324325heap_close (rel ,NoLock );/* close rel but keep lock! */
325326
@@ -519,8 +520,7 @@ AlterTableAlterColumn(const char *relationName,
519520elog (ERROR ,"ALTER TABLE: permission denied" );
520521#endif
521522
522- /* XXX should heap_openr take const char * ? */
523- rel = heap_openr ((char * )relationName ,AccessExclusiveLock );
523+ rel = heap_openr (relationName ,AccessExclusiveLock );
524524myrelid = RelationGetRelid (rel );
525525heap_close (rel ,NoLock );
526526
@@ -626,7 +626,7 @@ AlterTableAlterColumn(const char *relationName,
626626/* keep the system catalog indices current */
627627CatalogOpenIndices (Num_pg_attr_indices ,Name_pg_attr_indices ,irelations );
628628CatalogIndexInsert (irelations ,Num_pg_attr_indices ,attr_rel ,newtuple );
629- CatalogCloseIndices (Num_pg_class_indices ,irelations );
629+ CatalogCloseIndices (Num_pg_attrdef_indices ,irelations );
630630
631631/* get rid of actual default definition */
632632drop_default (myrelid ,attnum );
@@ -672,31 +672,234 @@ drop_default(Oid relid, int16 attnum)
672672
673673/*
674674 * ALTER TABLE DROP COLUMN
675+ *
676+ * Strategy:
677+ * - permission/sanity checks
678+ * - create a new table _ATDC<name> with all attributes minus the desired one
679+ * - copy over all the data
680+ * - make the column defaults point to the new table
681+ * - kill the old table
682+ * - rename the intermediate table back
675683 */
676684void
677685AlterTableDropColumn (const char * relationName ,
678686bool inh ,const char * colName ,
679687int behavior )
680688{
681- elog (NOTICE ,"ALTER TABLE / DROP COLUMN is not implemented" );
689+ Relation oldrel ,newrel ,defrel ;
690+ HeapTuple tuple ;
691+ TupleDesc olddesc ,newdesc ,defdsc ;
692+ int16 dropattnum ,oldnumatts ;
693+ Oid oldrel_oid ,newrel_oid ;
694+ char tmpname [NAMEDATALEN ];
695+ int16 i ;
696+ HeapScanDesc scan ;
697+ ScanKeyData scankey ;
698+
699+ if (!allowSystemTableMods && IsSystemRelationName (relationName ))
700+ elog (ERROR ,"ALTER TABLE: relation \"%s\" is a system catalog" ,
701+ relationName );
702+ #ifndef NO_SECURITY
703+ if (!pg_ownercheck (UserName ,relationName ,RELNAME ))
704+ elog (ERROR ,"ALTER TABLE: permission denied" );
705+ #endif
706+
707+ oldrel = heap_openr (relationName ,AccessExclusiveLock );
708+ if (oldrel -> rd_rel -> relkind != RELKIND_RELATION )
709+ {
710+ heap_close (oldrel ,AccessExclusiveLock );
711+ elog (ERROR ,"ALTER TABLE: relation %s is not a table" ,relationName );
712+ }
713+
714+ oldrel_oid = ObjectIdGetDatum (RelationGetRelid (oldrel ));
715+ oldnumatts = RelationGetNumberOfAttributes (oldrel );
716+
717+ if (oldnumatts == 1 )
718+ {
719+ heap_close (oldrel ,AccessExclusiveLock );
720+ elog (ERROR ,"ALTER TABLE: relation %s only has one column" ,relationName );
721+ }
722+
723+ /* What to do here? */
724+ /*
725+ if (length(find_all_inheritors(RelationGetRelid(oldrel)))>0)
726+ elog(ERROR, "ALTER TABLE: cannot drop a column on table that is inherited from");
727+ */
728+ /*
729+ * get the number of the attribute
730+ */
731+ tuple = SearchSysCacheTuple (ATTNAME ,oldrel_oid ,NameGetDatum (namein (colName )),0 ,0 );
732+ if (!HeapTupleIsValid (tuple ))
733+ {
734+ heap_close (oldrel ,AccessExclusiveLock );
735+ elog (ERROR ,"ALTER TABLE: relation \"%s\" has no column \"%s\"" ,
736+ relationName ,colName );
737+ }
738+
739+ dropattnum = ((Form_pg_attribute )GETSTRUCT (tuple ))-> attnum ;
740+
741+ if (snprintf (tmpname ,NAMEDATALEN ,"_ATDC%s" ,relationName )== -1 )
742+ {
743+ heap_close (oldrel ,AccessExclusiveLock );
744+ elog (ERROR ,"AlterTableDropColumn: relation name too long" );
745+ }
746+
747+ /*
748+ * Build descriptor for new relation
749+ */
750+ olddesc = RelationGetDescr (oldrel );
751+
752+ newdesc = CreateTemplateTupleDesc (oldnumatts - 1 );
753+ for (i = 1 ;i < dropattnum ;i ++ )
754+ {
755+ Form_pg_attribute att = olddesc -> attrs [i - 1 ];
756+ TupleDescInitEntry (newdesc ,i ,nameout (& (att -> attname )),
757+ att -> atttypid ,att -> atttypmod ,
758+ att -> attnelems ,att -> attisset );
759+ /* the above function doesn't take care of these two */
760+ newdesc -> attrs [i - 1 ]-> attnotnull = att -> attnotnull ;
761+ newdesc -> attrs [i - 1 ]-> atthasdef = att -> atthasdef ;
762+ }
763+
764+ for (i = dropattnum ;i <=oldnumatts - 1 ;i ++ )
765+ {
766+ Form_pg_attribute att = olddesc -> attrs [i ];
767+ TupleDescInitEntry (newdesc ,i ,nameout (& (att -> attname )),
768+ att -> atttypid ,att -> atttypmod ,
769+ att -> attnelems ,att -> attisset );
770+ /* the above function doesn't take care of these two */
771+ newdesc -> attrs [i - 1 ]-> attnotnull = att -> attnotnull ;
772+ newdesc -> attrs [i - 1 ]-> atthasdef = att -> atthasdef ;
773+ }
774+
775+ /* Create the new table */
776+ newrel_oid = heap_create_with_catalog (tmpname ,newdesc ,RELKIND_RELATION , false);
777+ if (newrel_oid == InvalidOid )
778+ {
779+ heap_close (oldrel ,AccessExclusiveLock );
780+ elog (ERROR ,"ALTER TABLE: something went wrong" );
781+ }
782+
783+ /* Make the new table visible */
784+ CommandCounterIncrement ();
785+
786+ /*
787+ * Copy over the data
788+ */
789+ newrel = heap_open (newrel_oid ,AccessExclusiveLock );
790+
791+ scan = heap_beginscan (oldrel , false,SnapshotNow ,0 ,NULL );
792+ while (HeapTupleIsValid (tuple = heap_getnext (scan ,0 )))
793+ {
794+ bool isnull ;
795+ Datum * new_record ;
796+ bool * new_record_nulls ;
797+ HeapTuple new_tuple ;
798+
799+ new_record = palloc ((oldnumatts - 1 )* sizeof (* new_record ));
800+ new_record_nulls = palloc ((oldnumatts - 1 )* sizeof (* new_record_nulls ));
801+
802+ for (i = 1 ;i < dropattnum ;i ++ )
803+ {
804+ new_record [i - 1 ]= heap_getattr (tuple ,i ,olddesc ,& isnull );
805+ new_record_nulls [i - 1 ]= isnull ?'n' :' ' ;
806+ }
807+ for (i = dropattnum + 1 ;i <=oldnumatts ;i ++ )
808+ {
809+ new_record [i - 2 ]= heap_getattr (tuple ,i ,olddesc ,& isnull );
810+ new_record_nulls [i - 2 ]= isnull ?'n' :' ' ;
811+ }
812+
813+ new_tuple = heap_formtuple (newdesc ,new_record ,new_record_nulls );
814+ Assert (new_tuple );
815+
816+ if (heap_insert (newrel ,new_tuple )== InvalidOid )
817+ elog (ERROR ,"AlterTableDropColumn: heap_insert failed" );
818+
819+ pfree (new_record );
820+ pfree (new_record_nulls );
821+ }
822+ heap_endscan (scan );
823+
824+ heap_close (newrel ,NoLock );
825+ heap_close (oldrel ,NoLock );
826+
827+ /*
828+ * Move defaults over to the new table
829+ */
830+ defrel = heap_openr (AttrDefaultRelationName ,AccessExclusiveLock );
831+ defdsc = RelationGetDescr (defrel );
832+
833+ /* look for all entries referencing the old table */
834+ ScanKeyEntryInitialize (& scankey ,0x0 ,Anum_pg_attrdef_adrelid ,F_OIDEQ ,
835+ ObjectIdGetDatum (oldrel_oid ));
836+ scan = heap_beginscan (defrel , false,SnapshotNow ,1 ,& scankey );
837+ while (HeapTupleIsValid (tuple = heap_getnext (scan , false)))
838+ {
839+ HeapTuple newtuple ;
840+ int2 attrnum ;
841+ Relation irelations [Num_pg_attrdef_indices ];
842+
843+ attrnum = ((Form_pg_attrdef )GETSTRUCT (tuple ))-> adnum ;
844+
845+ /* remove the entry about the dropped column */
846+ if (attrnum == dropattnum )
847+ {
848+ heap_delete (defrel ,& tuple -> t_self ,NULL );
849+ continue ;
850+ }
851+
852+ newtuple = heap_copytuple (tuple );
853+
854+ if (attrnum > dropattnum )
855+ ((Form_pg_attrdef )GETSTRUCT (newtuple ))-> adnum -- ;
856+
857+ /* make it point to the new table */
858+ ((Form_pg_attrdef )GETSTRUCT (newtuple ))-> adrelid = newrel_oid ;
859+ heap_update (defrel ,& tuple -> t_self ,newtuple ,NULL );
860+
861+ /* keep the system catalog indices current */
862+ CatalogOpenIndices (Num_pg_attrdef_indices ,Name_pg_attrdef_indices ,irelations );
863+ CatalogIndexInsert (irelations ,Num_pg_attrdef_indices ,defrel ,newtuple );
864+ CatalogCloseIndices (Num_pg_attrdef_indices ,irelations );
865+ }
866+ heap_endscan (scan );
867+ heap_close (defrel ,NoLock );
868+
869+ CommandCounterIncrement ();
870+
871+ /* make the old table disappear */
872+ heap_drop_with_catalog (relationName );
873+ CommandCounterIncrement ();
874+
875+ /* set back original name */
876+ TypeRename (tmpname ,relationName );
877+ renamerel (tmpname ,relationName );
682878}
683879
684880
685881
882+ /*
883+ * ALTER TABLE ADD CONSTRAINT
884+ */
686885void
687886AlterTableAddConstraint (const char * relationName ,
688887bool inh ,Node * newConstraint )
689888{
690- elog (NOTICE ,"ALTER TABLE / ADD CONSTRAINT is not implemented" );
889+ elog (ERROR ,"ALTER TABLE / ADD CONSTRAINT is not implemented" );
691890}
692891
693892
694893
695- void AlterTableDropConstraint (const char * relationName ,
696- bool inh ,const char * constrName ,
697- int behavior )
894+ /*
895+ * ALTER TABLE DROP CONSTRAINT
896+ */
897+ void
898+ AlterTableDropConstraint (const char * relationName ,
899+ bool inh ,const char * constrName ,
900+ int behavior )
698901{
699- elog (NOTICE ,"ALTER TABLE / DROP CONSTRAINT is not implemented" );
902+ elog (ERROR ,"ALTER TABLE / DROP CONSTRAINT is not implemented" );
700903}
701904
702905