From fd9ff86bd9c4f1a96f3796212212b4099ca275de Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Thu, 9 Mar 2000 05:00:26 +0000 Subject: [PATCH] Trial implementation of ALTER DROP COLUMN. They are #ifdef'd. Add -D_DROP_COLUMN_HACK__ compile option to evaluate it. --- src/backend/commands/command.c | 381 ++++++++++++++++++++++++++++++++- src/backend/commands/copy.c | 44 +++- src/backend/commands/vacuum.c | 6 +- src/backend/optimizer/prep/preptlist.c | 37 +++- src/backend/parser/parse_relation.c | 10 +- src/backend/parser/parse_target.c | 8 +- src/backend/utils/cache/relcache.c | 22 +- src/include/catalog/pg_attribute.h | 16 +- 8 files changed, 514 insertions(+), 10 deletions(-) diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 620c601b17..b75f3840a8 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.69 2000/02/15 18:15:12 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.70 2000/03/09 05:00:23 inoue Exp $ * * NOTES * The PortalExecutorHeapMemory crap needs to be eliminated @@ -43,6 +43,15 @@ #include "utils/syscache.h" #include "utils/temprel.h" #include "commands/trigger.h" +#ifdef _DROP_COLUMN_HACK__ +#include "catalog/pg_index.h" +#include "catalog/pg_relcheck.h" +#include "commands/defrem.h" +#include "commands/comment.h" +#include "access/genam.h" +#include "optimizer/clauses.h" +#include "../parser/parse.h" +#endif /* _DROP_COLUMN_HACK__ */ /* ---------------- * PortalExecutorHeapMemory stuff @@ -668,6 +677,213 @@ drop_default(Oid relid, int16 attnum) } +#ifdef _DROP_COLUMN_HACK__ +/* + * ALTER TABLE DROP COLUMN trial implementation + * + */ + +/* + * system table scan(index scan/sequential scan) + */ +typedef struct SysScanDescData +{ + Relation heap_rel; + Relation irel; + HeapScanDesc scan; + IndexScanDesc iscan; + HeapTupleData tuple; + Buffer buffer; +} SysScanDescData, *SysScanDesc; + +static void * +systable_beginscan(Relation rel, const char *indexRelname, int nkeys, ScanKey entry) +{ + bool hasindex = (rel->rd_rel->relhasindex && !IsIgnoringSystemIndexes()); + SysScanDesc sysscan; + + sysscan = (SysScanDesc) palloc(sizeof(SysScanDescData)); + sysscan->heap_rel = rel; + sysscan->irel = (Relation) NULL; + sysscan->tuple.t_datamcxt = NULL; + sysscan->tuple.t_data = NULL; + sysscan->buffer = InvalidBuffer; + if (hasindex) + { + sysscan->irel = index_openr((char *)indexRelname); + sysscan->iscan = index_beginscan(sysscan->irel, false, nkeys, entry); + } + else + sysscan->scan = heap_beginscan(rel, false, SnapshotNow, nkeys, entry); + return (void *) sysscan; +} +static void +systable_endscan(void *scan) +{ + SysScanDesc sysscan = (SysScanDesc) scan; + + if (sysscan->irel) + { + if (BufferIsValid(sysscan->buffer)) + ReleaseBuffer(sysscan->buffer); + index_endscan(sysscan->iscan); + index_close(sysscan->irel); + } + else + heap_endscan(sysscan->scan); + pfree(scan); +} +static HeapTuple +systable_getnext(void *scan) +{ + SysScanDesc sysscan = (SysScanDesc) scan; + HeapTuple htup = (HeapTuple) NULL; + RetrieveIndexResult indexRes; + + if (sysscan->irel) + { + if (BufferIsValid(sysscan->buffer)) + { + ReleaseBuffer(sysscan->buffer); + sysscan->buffer = InvalidBuffer; + } + while (indexRes = index_getnext(sysscan->iscan, ForwardScanDirection), indexRes != NULL) + { + sysscan->tuple.t_self = indexRes->heap_iptr; + heap_fetch(sysscan->heap_rel, SnapshotNow, &sysscan->tuple, &(sysscan->buffer)); + pfree(indexRes); + if (sysscan->tuple.t_data != NULL) + { + htup = &sysscan->tuple; + break; + } + } + } + else + htup = heap_getnext(sysscan->scan, 0); + return htup; +} + +/* + * find a specified attribute in a node entry + */ +static bool +find_attribute_walker(Node *node, int attnum) +{ + if (node == NULL) + return false; + if (IsA(node, Var)) + { + Var *var = (Var *) node; + if (var->varlevelsup == 0 && var->varno == 1 && + var->varattno == attnum) + return true; + } + return expression_tree_walker(node, find_attribute_walker, (void *)attnum); +} +static bool +find_attribute_in_node(Node *node, int attnum) +{ + return expression_tree_walker(node, find_attribute_walker, (void *)attnum); +} +/* + * Remove/check references for the column + */ +static bool +RemoveColumnReferences(Oid reloid, int attnum, bool checkonly, HeapTuple reltup) +{ + Relation indexRelation, rcrel; + ScanKeyData entry; + HeapScanDesc scan; + void *sysscan; + HeapTuple htup, indexTuple; + Form_pg_index index; + Form_pg_relcheck relcheck; + Form_pg_class pgcform = (Form_pg_class) NULL; + int i; + bool checkok = true; + + + if (!checkonly) + pgcform = (Form_pg_class) GETSTRUCT (reltup); + /* + * Remove/check constraints here + */ + ScanKeyEntryInitialize(&entry, (bits16) 0x0, Anum_pg_relcheck_rcrelid, + (RegProcedure) F_OIDEQ, ObjectIdGetDatum(reloid)); + rcrel = heap_openr(RelCheckRelationName, RowExclusiveLock); + sysscan = systable_beginscan(rcrel, RelCheckIndex,1 ,&entry); + + while (HeapTupleIsValid(htup = systable_getnext(sysscan))) + { + char *ccbin; + Node *node; + + relcheck = (Form_pg_relcheck) GETSTRUCT(htup); + ccbin = textout(&relcheck->rcbin); + if (!ccbin) + continue; + node = stringToNode(ccbin); + pfree(ccbin); + if (find_attribute_in_node(node, attnum)) + { + if (checkonly) + { + checkok = false; + elog(ERROR, "target column is used in a constraint"); + } + else + { + heap_delete(rcrel, &htup->t_self, NULL); + pgcform->relchecks--; + } + } + } + systable_endscan(sysscan); + heap_close(rcrel, NoLock); + + /* + * What to do with triggers/rules/views/procedues ? + */ + + /* + * Remove/check indexes + */ + indexRelation = heap_openr(IndexRelationName, RowExclusiveLock); + ScanKeyEntryInitialize(&entry, 0, Anum_pg_index_indrelid, F_OIDEQ, + ObjectIdGetDatum(reloid)); + scan = heap_beginscan(indexRelation, false, SnapshotNow, 1, &entry); + while (HeapTupleIsValid(indexTuple = heap_getnext(scan, 0))) + { + index = (Form_pg_index) GETSTRUCT(indexTuple); + for (i = 0; i < INDEX_MAX_KEYS; i++) + { + if (index->indkey[i] == InvalidAttrNumber) + break; + else if (index->indkey[i] == attnum) + { + if (checkonly) + { + checkok = false; + elog(ERROR, "target column is used in an index"); + } + else + { + htup = SearchSysCacheTuple(RELOID, + ObjectIdGetDatum(index->indexrelid), + 0, 0, 0); + RemoveIndex(NameStr(((Form_pg_class) GETSTRUCT(htup))->relname)); + } + break; + } + } + } + heap_endscan(scan); + heap_close(indexRelation, NoLock); + + return checkok; +} +#endif /* _DROP_COLUMN_HACK__ */ /* * ALTER TABLE DROP COLUMN @@ -677,7 +893,170 @@ AlterTableDropColumn(const char *relationName, bool inh, const char *colName, int behavior) { +#ifdef _DROP_COLUMN_HACK__ + Relation rel, attrdesc, adrel; + Oid myrelid, attoid; + HeapTuple reltup; + HeapTupleData classtuple; + Buffer buffer; + Form_pg_attribute attribute; + HeapTuple tup; + Relation idescs[Num_pg_attr_indices]; + int attnum; + bool hasindex; + char dropColname[32]; + void *sysscan; + ScanKeyData scankeys[2]; + + if (inh) + elog(ERROR, "ALTER TABLE / DROP COLUMN with inherit option is not supported yet"); + /* + * 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! */ + + /* + * What to do when rel has inheritors ? + */ + if (length(find_all_inheritors(myrelid)) > 1) + elog(ERROR, "ALTER TABLE: cannot drop a column on table that is inherited from"); + + + /* + * lock the pg_class tuple for update + */ + reltup = SearchSysCacheTuple(RELNAME, PointerGetDatum(relationName), + 0, 0, 0); + + if (!HeapTupleIsValid(reltup)) + elog(ERROR, "ALTER TABLE: relation \"%s\" not found", + relationName); + rel = heap_openr(RelationRelationName, RowExclusiveLock); + classtuple.t_self = reltup->t_self; + switch (heap_mark4update(rel, &classtuple, &buffer)) + { + case HeapTupleSelfUpdated: + case HeapTupleMayBeUpdated: + break; + default: + elog(ERROR, "couldn't lock pg_class tuple"); + } + reltup = heap_copytuple(&classtuple); + ReleaseBuffer(buffer); + + /* + * XXX is the following check sufficient? + */ + if (((Form_pg_class) GETSTRUCT(reltup))->relkind != RELKIND_RELATION) + { + elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", + relationName); + } + + attrdesc = heap_openr(AttributeRelationName, RowExclusiveLock); + + /* + * Get the target pg_attribute tuple + */ + tup = SearchSysCacheTupleCopy(ATTNAME, + ObjectIdGetDatum(reltup->t_data->t_oid), + PointerGetDatum(colName), 0, 0); + if (!HeapTupleIsValid(tup)) + elog(ERROR, "ALTER TABLE: column name \"%s\" doesn't exist in table \"%s\"", + colName, relationName); + + attribute = (Form_pg_attribute) GETSTRUCT(tup); + if (attribute->attnum <= 0) + elog(ERROR, "ALTER TABLE: column name \"%s\" was already dropped", colName); + attnum = attribute->attnum; + attoid = tup->t_data->t_oid; + /* + * Check constraints/indices etc here + */ + if (behavior != CASCADE) + { + if (!RemoveColumnReferences(myrelid, attnum, true, NULL)) + elog(ERROR, "the column is referenced"); + } + + /* + * change the target pg_attribute tuple + */ + sprintf(dropColname, "*already Dropped*%d", attnum); + namestrcpy(&(attribute->attname), dropColname); + ATTRIBUTE_DROP_COLUMN(attribute); + + heap_update(attrdesc, &tup->t_self, tup, NULL); + hasindex = (!IsIgnoringSystemIndexes() && RelationGetForm(attrdesc)->relhasindex); + if (hasindex) + { + CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_attr_indices, + attrdesc, tup); + CatalogCloseIndices(Num_pg_attr_indices, idescs); + } + heap_close(attrdesc, NoLock); + heap_freetuple(tup); + + /* delete comments */ + DeleteComments(attoid); + /* delete attrdef */ + adrel = heap_openr(AttrDefaultRelationName, RowExclusiveLock); + ScanKeyEntryInitialize(&scankeys[0], 0x0, Anum_pg_attrdef_adrelid, + F_OIDEQ, ObjectIdGetDatum(myrelid)); + /* Oops pg_attrdef doesn't have (adrelid,adnum) index + ScanKeyEntryInitialize(&scankeys[1], 0x0, Anum_pg_attrdef_adnum, + F_INT2EQ, Int16GetDatum(attnum)); + sysscan = systable_beginscan(adrel, AttrDefaultIndex, 2, scankeys); + */ + sysscan = systable_beginscan(adrel, AttrDefaultIndex, 1, scankeys); + while (HeapTupleIsValid(tup = systable_getnext(sysscan))) + { + if (((Form_pg_attrdef) GETSTRUCT(tup))->adnum == attnum) + { + heap_delete(adrel, &tup->t_self, NULL); + break; + } + } + systable_endscan(sysscan); + heap_close(adrel, NoLock); + /* + * Remove objects which reference this column + */ + if (behavior == CASCADE) + { + Relation ridescs[Num_pg_class_indices]; + + RemoveColumnReferences(myrelid, attnum, false, reltup); + /* update pg_class tuple */ + heap_update(rel, &reltup->t_self, reltup, NULL); + 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); +#else elog(ERROR, "ALTER TABLE / DROP COLUMN is not implemented"); +#endif /* _DROP_COLUMN_HACK__ */ } diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 85a50c1039..a91072522a 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.101 2000/02/13 18:59:50 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.102 2000/03/09 05:00:23 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -394,6 +394,9 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p int32 attr_count, i; +#ifdef _DROP_COLUMN_HACK__ + bool *valid; +#endif /* _DROP_COLUMN_HACK__ */ Form_pg_attribute *attr; FmgrInfo *out_functions; Oid out_func_oid; @@ -425,8 +428,20 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p out_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo)); elements = (Oid *) palloc(attr_count * sizeof(Oid)); typmod = (int32 *) palloc(attr_count * sizeof(int32)); +#ifdef _DROP_COLUMN_HACK__ + valid = (bool *) palloc(attr_count * sizeof(bool)); +#endif /* _DROP_COLUMN_HACK__ */ for (i = 0; i < attr_count; i++) { +#ifdef _DROP_COLUMN_HACK__ + if (COLUMN_IS_DROPPED(attr[i])) + { + valid[i] = false; + continue; + } + else + valid[i] = true; +#endif /* _DROP_COLUMN_HACK__ */ out_func_oid = (Oid) GetOutputFunction(attr[i]->atttypid); fmgr_info(out_func_oid, &out_functions[i]); elements[i] = GetTypeElement(attr[i]->atttypid); @@ -466,6 +481,14 @@ CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null_p value = heap_getattr(tuple, i + 1, tupDesc, &isnull); if (!binary) { +#ifdef _DROP_COLUMN_HACK__ + if (!valid[i]) + { + if (i == attr_count - 1) + CopySendChar('\n', fp); + continue; + } +#endif /* _DROP_COLUMN_HACK__ */ if (!isnull) { string = (char *) (*fmgr_faddr(&out_functions[i])) @@ -692,6 +715,10 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null typmod = (int32 *) palloc(attr_count * sizeof(int32)); for (i = 0; i < attr_count; i++) { +#ifdef _DROP_COLUMN_HACK__ + if (COLUMN_IS_DROPPED(attr[i])) + continue; +#endif /* _DROP_COLUMN_HACK__ */ in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid); fmgr_info(in_func_oid, &in_functions[i]); elements[i] = GetTypeElement(attr[i]->atttypid); @@ -718,6 +745,13 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null { nulls[i] = ' '; index_nulls[i] = ' '; +#ifdef _DROP_COLUMN_HACK__ + if (COLUMN_IS_DROPPED(attr[i])) + { + byval[i] = 'n'; + continue; + } +#endif /* _DROP_COLUMN_HACK__ */ byval[i] = (bool) IsTypeByVal(attr[i]->atttypid); } @@ -750,6 +784,14 @@ CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim, char *null } for (i = 0; i < attr_count && !done; i++) { +#ifdef _DROP_COLUMN_HACK__ + if (COLUMN_IS_DROPPED(attr[i])) + { + values[i] = PointerGetDatum(NULL); + nulls[i] = 'n'; + continue; + } +#endif /* _DROP_COLUMN_HACK__ */ string = CopyReadAttribute(fp, &isnull, delim, &newline, null_print); if (isnull) { diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 3cd9b02651..f86c5bc1e2 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.142 2000/03/08 23:41:00 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.143 2000/03/09 05:00:23 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -2240,6 +2240,10 @@ vc_attrstats(Relation onerel, VRelStats *vacrelstats, HeapTuple tuple) VacAttrStats *stats = &vacattrstats[i]; bool value_hit = true; +#ifdef _DROP_COLUMN_HACK__ + if (COLUMN_IS_DROPPED(stats->attr)) + continue; +#endif /* _DROP_COLUMN_HACK__ */ value = heap_getattr(tuple, stats->attr->attnum, tupDesc, &isnull); diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 8c6c2ceb8d..22ed6f418f 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.34 2000/01/26 05:56:39 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.35 2000/03/09 05:00:24 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -189,10 +189,20 @@ expand_targetlist(List *tlist, int command_type, { case CMD_INSERT: { +#ifdef _DROP_COLUMN_HACK__ + Datum typedefault; +#else Datum typedefault = get_typdefault(atttype); +#endif /* _DROP_COLUMN_HACK__ */ int typlen; Const *temp_const; +#ifdef _DROP_COLUMN_HACK__ + if (COLUMN_IS_DROPPED(att_tup)) + typedefault = PointerGetDatum(NULL); + else + typedefault = get_typdefault(atttype); +#endif /* _DROP_COLUMN_HACK__ */ if (typedefault == PointerGetDatum(NULL)) typlen = 0; else @@ -230,8 +240,25 @@ expand_targetlist(List *tlist, int command_type, { Var *temp_var; +#ifdef _DROP_COLUMN_HACK__ + Node *temp_node = (Node *) NULL; + if (COLUMN_IS_DROPPED(att_tup)) + { + temp_node = (Node *)makeConst(atttype, 0, + PointerGetDatum(NULL), + true, + false, + false, /* not a set */ + false); + } + else +#endif /* _DROP_COLUMN_HACK__ */ temp_var = makeVar(result_relation, attrno, atttype, atttypmod, 0); +#ifdef _DROP_COLUMN_HACK__ + if (!temp_node) + temp_node = (Node *) temp_var; +#endif /* _DROP_COLUMN_HACK__ */ new_tle = makeTargetEntry(makeResdom(attrno, atttype, @@ -239,8 +266,12 @@ expand_targetlist(List *tlist, int command_type, pstrdup(attrname), 0, (Oid) 0, - false), - (Node *) temp_var); + false), +#ifdef _DROP_COLUMN_HACK__ + temp_node); +#else + (Node *) temp_var); +#endif /* _DROP_COLUMN_HACK__ */ break; } default: diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 02a3cd2de0..265642faaf 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.35 2000/02/15 03:37:47 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.36 2000/03/09 05:00:24 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -359,6 +359,10 @@ expandTable(ParseState *pstate, char *refname, bool getaliases) { char *attrname; +#ifdef _DROP_COLUMN_HACK__ + if (COLUMN_IS_DROPPED(rel->rd_att->attrs[varattno])) + continue; +#endif /* _DROP_COLUMN_HACK__ */ attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname)); attr->attrs = lappend(attr->attrs, makeString(attrname)); } @@ -404,6 +408,10 @@ expandAll(ParseState *pstate, char *relname, Attr *ref, int *this_resno) Var *varnode; TargetEntry *te = makeNode(TargetEntry); +#ifdef _DROP_COLUMN_HACK__ + if (COLUMN_IS_DROPPED(rel->rd_att->attrs[varattno])) + continue; +#endif /* _DROP_COLUMN_HACK__ */ attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname)); /* varattno is zero-based, so check that length() is always greater */ diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 9d00e1789e..e815efc963 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.55 2000/02/15 03:37:47 thomas Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.56 2000/03/09 05:00:24 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -355,6 +355,12 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos) { Ident *id = makeNode(Ident); +#ifdef _DROP_COLUMN_HACK__ + if (COLUMN_IS_DROPPED(attr[i])) + { + continue; + } +#endif /* _DROP_COLUMN_HACK__ */ id->name = palloc(NAMEDATALEN); StrNCpy(id->name, NameStr(attr[i]->attname), NAMEDATALEN); id->indirection = NIL; diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 74bcb10c69..11ab6c750f 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.91 2000/02/27 12:02:32 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/relcache.c,v 1.92 2000/03/09 05:00:25 inoue Exp $ * *------------------------------------------------------------------------- */ @@ -568,6 +568,9 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo, AttrDefault *attrdef = NULL; int ndef = 0; int i; +#ifdef _DROP_COLUMN_HACK__ + bool columnDropped; +#endif /* _DROP_COLUMN_HACK__ */ constr->has_not_null = false; @@ -575,12 +578,25 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo, for (i = 1; i <= relation->rd_rel->relnatts; i++) { +#ifdef _DROP_COLUMN_HACK__ + columnDropped = false; +#endif /* _DROP_COLUMN_HACK__ */ atttup = (HeapTuple) AttributeRelidNumIndexScan(attrel, RelationGetRelid(relation), i); if (!HeapTupleIsValid(atttup)) +#ifdef _DROP_COLUMN_HACK__ + { + atttup = (HeapTuple) AttributeRelidNumIndexScan(attrel, + RelationGetRelid(relation), DROPPED_COLUMN_INDEX(i)); + if (!HeapTupleIsValid(atttup)) +#endif /* _DROP_COLUMN_HACK__ */ elog(ERROR, "cannot find attribute %d of relation %s", i, RelationGetRelationName(relation)); +#ifdef _DROP_COLUMN_HACK__ + columnDropped = true; + } +#endif /* _DROP_COLUMN_HACK__ */ attp = (Form_pg_attribute) GETSTRUCT(atttup); relation->rd_att->attrs[i - 1] = @@ -590,6 +606,10 @@ build_tupdesc_ind(RelationBuildDescInfo buildinfo, (char *) attp, ATTRIBUTE_TUPLE_SIZE); +#ifdef _DROP_COLUMN_HACK__ + if (columnDropped) + continue; +#endif /* _DROP_COLUMN_HACK__ */ /* Update if this attribute have a constraint */ if (attp->attnotnull) constr->has_not_null = true; diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index d7a1adb1c6..54f3adc9ee 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_attribute.h,v 1.53 2000/01/26 05:57:57 momjian Exp $ + * $Id: pg_attribute.h,v 1.54 2000/03/09 05:00:26 inoue Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -178,6 +178,20 @@ typedef FormData_pg_attribute *Form_pg_attribute; #define Anum_pg_attribute_atthasdef 15 +#ifdef _DROP_COLUMN_HACK__ +/* + * CONSTANT and MACROS for DROP COLUMN implementation + */ +#define DROP_COLUMN_OFFSET -20 +#define COLUMN_IS_DROPPED(attribute) ((attribute)->attnum <= DROP_COLUMN_OFFSET) +#define DROPPED_COLUMN_INDEX(attidx) (DROP_COLUMN_OFFSET - attidx) +#define ATTRIBUTE_DROP_COLUMN(attribute) \ + Assert((attribute)->attnum > 0); \ + (attribute)->attnum = DROPPED_COLUMN_INDEX((attribute)->attnum); \ + (attribute)->atttypid = (Oid) -1; \ + (attribute)->attnotnull = false; \ + (attribute)->atthasdef = false; +#endif /* _DROP_COLUMN_HACK__ */ /* ---------------- * SCHEMA_ macros for declaring hardcoded tuple descriptors. * these are used in utils/cache/relcache.c -- 2.11.0