aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/command.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/command.c')
-rw-r--r--src/backend/commands/command.c256
1 files changed, 238 insertions, 18 deletions
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index 1874e0e2369..93322d7a7f7 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.62 1999/12/20 10:40:41 wieck Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.63 2000/01/16 20:04:55 petere Exp $
*
* NOTES
* The PortalExecutorHeapMemory crap needs to be eliminated
@@ -23,13 +23,16 @@
#include "postgres.h"
#include "access/heapam.h"
+#include "access/skey.h"
#include "catalog/catalog.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
+#include "catalog/pg_attrdef.h"
#include "catalog/pg_type.h"
#include "commands/command.h"
#include "executor/execdefs.h"
#include "executor/executor.h"
+#include "catalog/heap.h"
#include "miscadmin.h"
#include "optimizer/prep.h"
#include "utils/acl.h"
@@ -37,6 +40,7 @@
#include "utils/syscache.h"
#include "utils/temprel.h"
+
/* ----------------
* PortalExecutorHeapMemory stuff
*
@@ -246,7 +250,8 @@ PerformPortalClose(char *name, CommandDest dest)
}
/* ----------------
- * PerformAddAttribute
+ * AlterTableAddColumn
+ * (formerly known as PerformAddAttribute)
*
* adds an additional attribute to a relation
*
@@ -276,8 +281,7 @@ PerformPortalClose(char *name, CommandDest dest)
* ----------------
*/
void
-PerformAddAttribute(char *relationName,
- char *userName,
+AlterTableAddColumn(const char *relationName,
bool inherits,
ColumnDef *colDef)
{
@@ -295,6 +299,7 @@ PerformAddAttribute(char *relationName,
Relation idescs[Num_pg_attr_indices];
Relation ridescs[Num_pg_class_indices];
bool hasindex;
+ List *rawDefaults = NIL;
/*
* permissions checking. this would normally be done in utility.c,
@@ -303,19 +308,18 @@ PerformAddAttribute(char *relationName,
* normally, only the owner of a class can change its schema.
*/
if (!allowSystemTableMods && IsSystemRelationName(relationName))
- elog(ERROR, "PerformAddAttribute: class \"%s\" is a system catalog",
+ elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog",
relationName);
#ifndef NO_SECURITY
- if (!pg_ownercheck(userName, relationName, RELNAME))
- elog(ERROR, "PerformAddAttribute: you do not own class \"%s\"",
- relationName);
+ if (!pg_ownercheck(UserName, relationName, RELNAME))
+ elog(ERROR, "ALTER TABLE: permission denied");
#endif
/*
* Grab an exclusive lock on the target table, which we will NOT release
* until end of transaction.
*/
- rel = heap_openr(relationName, AccessExclusiveLock);
+ rel = heap_openr((char *)relationName, AccessExclusiveLock);
myrelid = RelationGetRelid(rel);
heap_close(rel, NoLock); /* close rel but keep lock! */
@@ -324,8 +328,10 @@ PerformAddAttribute(char *relationName,
*/
if (colDef->is_not_null)
elog(ERROR, "Can't add a NOT NULL attribute to an existing relation");
+
if (colDef->raw_default || colDef->cooked_default)
- elog(ERROR, "ADD ATTRIBUTE: DEFAULT not yet implemented");
+ elog(ERROR, "Adding columns with defaults is not implemented.");
+
/*
* if the first element in the 'schema' list is a "*" then we are
@@ -358,8 +364,8 @@ PerformAddAttribute(char *relationName,
if (childrelid == myrelid)
continue;
rel = heap_open(childrelid, AccessExclusiveLock);
- PerformAddAttribute(RelationGetRelationName(rel),
- userName, false, colDef);
+ AlterTableAddColumn(RelationGetRelationName(rel),
+ false, colDef);
heap_close(rel, AccessExclusiveLock);
}
}
@@ -372,7 +378,7 @@ PerformAddAttribute(char *relationName,
0, 0, 0);
if (!HeapTupleIsValid(reltup))
- elog(ERROR, "PerformAddAttribute: relation \"%s\" not found",
+ elog(ERROR, "ALTER TABLE: relation \"%s\" not found",
relationName);
/*
@@ -380,14 +386,14 @@ PerformAddAttribute(char *relationName,
*/
if (((Form_pg_class) GETSTRUCT(reltup))->relkind == RELKIND_INDEX)
{
- elog(ERROR, "PerformAddAttribute: index relation \"%s\" not changed",
+ elog(ERROR, "ALTER TABLE: index relation \"%s\" not changed",
relationName);
}
minattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts;
maxatts = minattnum + 1;
if (maxatts > MaxHeapAttributeNumber)
- elog(ERROR, "PerformAddAttribute: relations limited to %d attributes",
+ elog(ERROR, "ALTER TABLE: relations limited to %d columns",
MaxHeapAttributeNumber);
attrdesc = heap_openr(AttributeRelationName, RowExclusiveLock);
@@ -421,7 +427,7 @@ PerformAddAttribute(char *relationName,
0, 0);
if (HeapTupleIsValid(tup))
- elog(ERROR, "PerformAddAttribute: attribute \"%s\" already exists in class \"%s\"",
+ elog(ERROR, "ALTER TABLE: column name \"%s\" already exists in relation \"%s\"",
colDef->colname, relationName);
/*
@@ -444,7 +450,7 @@ PerformAddAttribute(char *relationName,
tform = (Form_pg_type) GETSTRUCT(typeTuple);
if (!HeapTupleIsValid(typeTuple))
- elog(ERROR, "Add: type \"%s\" nonexistent", typename);
+ elog(ERROR, "ALTER TABLE: type \"%s\" does not exist", typename);
namestrcpy(&(attribute->attname), colDef->colname);
attribute->atttypid = typeTuple->t_data->t_oid;
attribute->attlen = tform->typlen;
@@ -483,9 +489,223 @@ PerformAddAttribute(char *relationName,
CatalogCloseIndices(Num_pg_class_indices, ridescs);
heap_freetuple(reltup);
- heap_close(rel, RowExclusiveLock);
+
+ heap_close(rel, NoLock);
+}
+
+
+
+static void drop_default(Oid relid, int16 attnum);
+
+
+/*
+ * ALTER TABLE ALTER COLUMN SET/DROP DEFAULT
+ */
+void
+AlterTableAlterColumn(const char *relationName,
+ bool inh, const char *colName,
+ Node *newDefault)
+{
+ Relation rel;
+ HeapTuple tuple;
+ int16 attnum;
+ Oid myrelid;
+
+ 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
+
+ /* XXX should heap_openr take const char * ? */
+ rel = heap_openr((char *)relationName, AccessExclusiveLock);
+ myrelid = RelationGetRelid(rel);
+ heap_close(rel, NoLock);
+
+ /*
+ * Propagate to children if desired
+ */
+ if (inh)
+ {
+ 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;
+ rel = heap_open(childrelid, AccessExclusiveLock);
+ AlterTableAlterColumn(RelationGetRelationName(rel),
+ false, colName, newDefault);
+ heap_close(rel, AccessExclusiveLock);
+ }
+ }
+
+ /* -= now do the thing on this relation =- */
+
+ /* reopen the business */
+ rel = heap_openr((char *)relationName, AccessExclusiveLock);
+
+ /*
+ * get the number of the attribute
+ */
+ tuple = SearchSysCacheTuple(ATTNAME,
+ ObjectIdGetDatum(myrelid),
+ NameGetDatum(namein((char *)colName)),
+ 0, 0);
+
+ if (!HeapTupleIsValid(tuple))
+ {
+ heap_close(rel, AccessExclusiveLock);
+ elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"",
+ relationName, colName);
+ }
+
+ attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum;
+
+ if (newDefault) /* SET DEFAULT */
+ {
+ List* rawDefaults = NIL;
+ RawColumnDefault *rawEnt;
+
+ /* Get rid of the old one first */
+ drop_default(myrelid, attnum);
+
+ rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault));
+ rawEnt->attnum = attnum;
+ rawEnt->raw_default = newDefault;
+ rawDefaults = lappend(rawDefaults, rawEnt);
+
+ /*
+ * This function is intended for CREATE TABLE,
+ * so it processes a _list_ of defaults, but we just do one.
+ */
+ AddRelationRawConstraints(rel, rawDefaults, NIL);
+ }
+
+ else /* DROP DEFAULT */
+ {
+ Relation attr_rel;
+ ScanKeyData scankeys[3];
+ HeapScanDesc scan;
+ HeapTuple tuple;
+
+ attr_rel = heap_openr(AttributeRelationName, AccessExclusiveLock);
+ ScanKeyEntryInitialize(&scankeys[0], 0x0, Anum_pg_attribute_attrelid, F_OIDEQ,
+ ObjectIdGetDatum(myrelid));
+ ScanKeyEntryInitialize(&scankeys[1], 0x0, Anum_pg_attribute_attnum, F_INT2EQ,
+ Int16GetDatum(attnum));
+ ScanKeyEntryInitialize(&scankeys[2], 0x0, Anum_pg_attribute_atthasdef, F_BOOLEQ,
+ TRUE);
+
+ scan = heap_beginscan(attr_rel, false, SnapshotNow, 3, scankeys);
+ AssertState(scan!=NULL);
+
+ if (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
+ {
+ HeapTuple newtuple;
+ Relation irelations[Num_pg_attr_indices];
+
+ /* update to false */
+ newtuple = heap_copytuple(tuple);
+ ((Form_pg_attribute) GETSTRUCT(newtuple))->atthasdef = FALSE;
+ heap_update(attr_rel, &tuple->t_self, newtuple, NULL);
+
+ /* 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);
+
+ /* get rid of actual default definition */
+ drop_default(myrelid, attnum);
+ }
+ else
+ elog(NOTICE, "ALTER TABLE: there was no default on column \"%s\" of relation \"%s\"",
+ colName, relationName);
+ heap_endscan(scan);
+ heap_close(attr_rel, NoLock);
+ }
+
+ heap_close(rel, NoLock);
+}
+
+
+
+static void
+drop_default(Oid relid, int16 attnum)
+{
+ ScanKeyData scankeys[2];
+ HeapScanDesc scan;
+ Relation attrdef_rel;
+ HeapTuple tuple;
+
+ attrdef_rel = heap_openr(AttrDefaultRelationName, AccessExclusiveLock);
+ ScanKeyEntryInitialize(&scankeys[0], 0x0, Anum_pg_attrdef_adrelid, F_OIDEQ,
+ ObjectIdGetDatum(relid));
+ ScanKeyEntryInitialize(&scankeys[1], 0x0, Anum_pg_attrdef_adnum, F_INT2EQ,
+ Int16GetDatum(attnum));
+
+ scan = heap_beginscan(attrdef_rel, false, SnapshotNow, 2, scankeys);
+ AssertState(scan!=NULL);
+
+ if (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
+ heap_delete(attrdef_rel, &tuple->t_self, NULL);
+
+ heap_endscan(scan);
+
+ heap_close(attrdef_rel, NoLock);
+}
+
+
+
+/*
+ * ALTER TABLE DROP COLUMN
+ */
+void
+AlterTableDropColumn(const char *relationName,
+ bool inh, const char *colName,
+ int behavior)
+{
+ elog(NOTICE, "ALTER TABLE / DROP COLUMN is not implemented");
}
+
+
+void
+AlterTableAddConstraint(const char *relationName,
+ bool inh, Node *newConstraint)
+{
+ elog(NOTICE, "ALTER TABLE / ADD CONSTRAINT is not implemented");
+}
+
+
+
+void AlterTableDropConstraint(const char *relationName,
+ bool inh, const char *constrName,
+ int behavior)
+{
+ elog(NOTICE, "ALTER TABLE / DROP CONSTRAINT is not implemented");
+}
+
+
+
+/*
+ *
+ * LOCK TABLE
+ *
+ */
void
LockTableCommand(LockStmt *lockstmt)
{