1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-22 23:02:54 +03:00
2000-01-22 14:20:56 +00:00

934 lines
26 KiB
C

/*-------------------------------------------------------------------------
*
* command.c
* random postgres portal and utility support code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $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
* by designing a better executor / portal processing memory
* interface.
*
* The PerformAddAttribute() code, like most of the relation
* manipulating code in the commands/ directory, should go
* someplace closer to the lib/catalog code.
*
*-------------------------------------------------------------------------
*/
#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 "commands/rename.h"
#include "executor/execdefs.h"
#include "executor/executor.h"
#include "catalog/heap.h"
#include "miscadmin.h"
#include "optimizer/prep.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
#include "utils/temprel.h"
/* ----------------
* PortalExecutorHeapMemory stuff
*
* This is where the XXXSuperDuperHacky code was. -cim 3/15/90
* ----------------
*/
MemoryContext PortalExecutorHeapMemory = NULL;
/* --------------------------------
* PortalCleanup
* --------------------------------
*/
void
PortalCleanup(Portal portal)
{
MemoryContext context;
/* ----------------
* sanity checks
* ----------------
*/
AssertArg(PortalIsValid(portal));
AssertArg(portal->cleanup == PortalCleanup);
/* ----------------
* set proper portal-executor context before calling ExecMain.
* ----------------
*/
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
/* ----------------
* tell the executor to shutdown the query
* ----------------
*/
ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
/* ----------------
* switch back to previous context
* ----------------
*/
MemoryContextSwitchTo(context);
PortalExecutorHeapMemory = (MemoryContext) NULL;
}
/* --------------------------------
* PerformPortalFetch
* --------------------------------
*/
void
PerformPortalFetch(char *name,
bool forward,
int count,
char *tag,
CommandDest dest)
{
Portal portal;
int feature;
QueryDesc *queryDesc;
MemoryContext context;
Const limcount;
/* ----------------
* sanity checks
* ----------------
*/
if (name == NULL)
{
elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
return;
}
/* ----------------
* Create a const node from the given count value
* ----------------
*/
memset(&limcount, 0, sizeof(limcount));
limcount.type = T_Const;
limcount.consttype = INT4OID;
limcount.constlen = sizeof(int4);
limcount.constvalue = (Datum) count;
limcount.constisnull = FALSE;
limcount.constbyval = TRUE;
limcount.constisset = FALSE;
limcount.constiscast = FALSE;
/* ----------------
* get the portal from the portal name
* ----------------
*/
portal = GetPortalByName(name);
if (!PortalIsValid(portal))
{
elog(NOTICE, "PerformPortalFetch: portal \"%s\" not found",
name);
return;
}
/* ----------------
* switch into the portal context
* ----------------
*/
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
AssertState(context == (MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
/* ----------------
* setup "feature" to tell the executor what direction and
* how many tuples to fetch.
* ----------------
*/
if (forward)
feature = EXEC_FOR;
else
feature = EXEC_BACK;
/* ----------------
* tell the destination to prepare to recieve some tuples
* ----------------
*/
queryDesc = PortalGetQueryDesc(portal);
if (dest == None) /* MOVE */
{
QueryDesc *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc));
memcpy(qdesc, queryDesc, sizeof(QueryDesc));
qdesc->dest = dest;
queryDesc = qdesc;
}
BeginCommand(name,
queryDesc->operation,
portal->attinfo, /* QueryDescGetTypeInfo(queryDesc),
* */
false, /* portal fetches don't end up in
* relations */
false, /* this is a portal fetch, not a "retrieve
* portal" */
tag,
dest);
/* ----------------
* execute the portal fetch operation
* ----------------
*/
PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal);
ExecutorRun(queryDesc, PortalGetState(portal), feature,
(Node *) NULL, (Node *) &limcount);
if (dest == None) /* MOVE */
pfree(queryDesc);
/* ----------------
* Note: the "end-of-command" tag is returned by higher-level
* utility code
*
* Return blank portal for now.
* Otherwise, this named portal will be cleaned.
* Note: portals will only be supported within a BEGIN...END
* block in the near future. Later, someone will fix it to
* do what is possible across transaction boundries.
* ----------------
*/
MemoryContextSwitchTo(
(MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
}
/* --------------------------------
* PerformPortalClose
* --------------------------------
*/
void
PerformPortalClose(char *name, CommandDest dest)
{
Portal portal;
/* ----------------
* sanity checks
* ----------------
*/
if (name == NULL)
{
elog(NOTICE, "PerformPortalClose: blank portal unsupported");
return;
}
/* ----------------
* get the portal from the portal name
* ----------------
*/
portal = GetPortalByName(name);
if (!PortalIsValid(portal))
{
elog(NOTICE, "PerformPortalClose: portal \"%s\" not found",
name);
return;
}
/* ----------------
* Note: PortalCleanup is called as a side-effect
* ----------------
*/
PortalDrop(&portal);
}
/* ----------------
* AlterTableAddColumn
* (formerly known as PerformAddAttribute)
*
* adds an additional attribute to a relation
*
* Adds attribute field(s) to a relation. Each new attribute
* is given attnums in sequential order and is added to the
* ATTRIBUTE relation. If the AMI fails, defunct tuples will
* remain in the ATTRIBUTE relation for later vacuuming.
* Later, there may be some reserved attribute names???
*
* (If needed, can instead use elog to handle exceptions.)
*
* Note:
* Initial idea of ordering the tuple attributes so that all
* the variable length domains occured last was scratched. Doing
* so would not speed access too much (in general) and would create
* many complications in formtuple, amgetattr, and addattribute.
*
* scan attribute catalog for name conflict (within rel)
* scan type catalog for absence of data type (if not arg)
* create attnum magically???
* create attribute tuple
* insert attribute in attribute catalog
* modify reldesc
* create new relation tuple
* insert new relation in relation catalog
* delete original relation from relation catalog
* ----------------
*/
void
AlterTableAddColumn(const char *relationName,
bool inherits,
ColumnDef *colDef)
{
Relation rel,
attrdesc;
Oid myrelid;
HeapTuple reltup;
HeapTuple attributeTuple;
Form_pg_attribute attribute;
FormData_pg_attribute attributeD;
int i;
int minattnum,
maxatts;
HeapTuple tup;
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,
* but this particular routine is recursive.
*
* normally, only the owner of a class can change its schema.
*/
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
/*
* Grab an exclusive lock on the target table, which we will NOT release
* until end of transaction.
*/
rel = heap_openr(relationName, AccessExclusiveLock);
myrelid = RelationGetRelid(rel);
heap_close(rel, NoLock); /* close rel but keep lock! */
/*
* we can't add a not null attribute
*/
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, "Adding columns with defaults is not implemented.");
/*
* if the first element in the 'schema' list is a "*" then we are
* supposed to add this attribute to all classes that inherit from
* 'relationName' (as well as to 'relationName').
*
* any permissions or problems with duplicate attributes will cause the
* whole transaction to abort, which is what we want -- all or
* nothing.
*/
if (colDef != NULL)
{
if (inherits)
{
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);
AlterTableAddColumn(RelationGetRelationName(rel),
false, colDef);
heap_close(rel, AccessExclusiveLock);
}
}
}
rel = heap_openr(RelationRelationName, RowExclusiveLock);
reltup = SearchSysCacheTupleCopy(RELNAME,
PointerGetDatum(relationName),
0, 0, 0);
if (!HeapTupleIsValid(reltup))
elog(ERROR, "ALTER TABLE: relation \"%s\" not found",
relationName);
/*
* XXX is the following check sufficient?
*/
if (((Form_pg_class) GETSTRUCT(reltup))->relkind == RELKIND_INDEX)
{
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, "ALTER TABLE: relations limited to %d columns",
MaxHeapAttributeNumber);
attrdesc = heap_openr(AttributeRelationName, RowExclusiveLock);
/*
* Open all (if any) pg_attribute indices
*/
hasindex = RelationGetForm(attrdesc)->relhasindex;
if (hasindex)
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
attributeD.attrelid = reltup->t_data->t_oid;
attributeTuple = heap_addheader(Natts_pg_attribute,
sizeof attributeD,
(char *) &attributeD);
attribute = (Form_pg_attribute) GETSTRUCT(attributeTuple);
i = 1 + minattnum;
{
HeapTuple typeTuple;
Form_pg_type tform;
char *typename;
int attnelems;
tup = SearchSysCacheTuple(ATTNAME,
ObjectIdGetDatum(reltup->t_data->t_oid),
PointerGetDatum(colDef->colname),
0, 0);
if (HeapTupleIsValid(tup))
elog(ERROR, "ALTER TABLE: column name \"%s\" already exists in relation \"%s\"",
colDef->colname, relationName);
/*
* check to see if it is an array attribute.
*/
typename = colDef->typename->name;
if (colDef->typename->arrayBounds)
{
attnelems = length(colDef->typename->arrayBounds);
typename = makeArrayTypeName(colDef->typename->name);
}
else
attnelems = 0;
typeTuple = SearchSysCacheTuple(TYPENAME,
PointerGetDatum(typename),
0, 0, 0);
tform = (Form_pg_type) GETSTRUCT(typeTuple);
if (!HeapTupleIsValid(typeTuple))
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;
attribute->attdisbursion = 0;
attribute->attcacheoff = -1;
attribute->atttypmod = colDef->typename->typmod;
attribute->attnum = i;
attribute->attbyval = tform->typbyval;
attribute->attnelems = attnelems;
attribute->attisset = (bool) (tform->typtype == 'c');
attribute->attstorage = 'p';
attribute->attalign = tform->typalign;
attribute->attnotnull = false;
attribute->atthasdef = (colDef->raw_default != NULL ||
colDef->cooked_default != NULL);
heap_insert(attrdesc, attributeTuple);
if (hasindex)
CatalogIndexInsert(idescs,
Num_pg_attr_indices,
attrdesc,
attributeTuple);
}
if (hasindex)
CatalogCloseIndices(Num_pg_attr_indices, idescs);
heap_close(attrdesc, RowExclusiveLock);
((Form_pg_class) GETSTRUCT(reltup))->relnatts = maxatts;
heap_update(rel, &reltup->t_self, reltup, NULL);
/* keep catalog indices current */
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
CatalogIndexInsert(ridescs, Num_pg_class_indices, rel, reltup);
CatalogCloseIndices(Num_pg_class_indices, ridescs);
heap_freetuple(reltup);
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
rel = heap_openr(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_attrdef_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
*
* 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)
{
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(ERROR, "ALTER TABLE / ADD CONSTRAINT is not implemented");
}
/*
* ALTER TABLE DROP CONSTRAINT
*/
void
AlterTableDropConstraint(const char *relationName,
bool inh, const char *constrName,
int behavior)
{
elog(ERROR, "ALTER TABLE / DROP CONSTRAINT is not implemented");
}
/*
*
* LOCK TABLE
*
*/
void
LockTableCommand(LockStmt *lockstmt)
{
Relation rel;
int aclresult;
rel = heap_openr(lockstmt->relname, NoLock);
if (! RelationIsValid(rel))
elog(ERROR, "Relation '%s' does not exist", lockstmt->relname);
if (lockstmt->mode == AccessShareLock)
aclresult = pg_aclcheck(lockstmt->relname, GetPgUserName(), ACL_RD);
else
aclresult = pg_aclcheck(lockstmt->relname, GetPgUserName(), ACL_WR);
if (aclresult != ACLCHECK_OK)
elog(ERROR, "LOCK TABLE: permission denied");
LockRelation(rel, lockstmt->mode);
heap_close(rel, NoLock); /* close rel, keep lock */
}