Index: src/backend/commands/rename.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/rename.c,v retrieving revision 1.61 diff -c -r1.61 rename.c *** src/backend/commands/rename.c 2001/11/05 17:46:24 1.61 --- src/backend/commands/rename.c 2001/11/11 09:06:23 *************** *** 16,40 **** --- 16,282 ---- #include + #include "access/genam.h" #include "access/heapam.h" + #include "access/itup.h" #include "catalog/catname.h" #include "catalog/pg_index.h" + #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" #include "catalog/heap.h" #include "catalog/indexing.h" #include "catalog/catalog.h" #include "commands/rename.h" + #include "commands/trigger.h" /* pg_trigger->tgargs bytea def */ #include "miscadmin.h" #include "storage/smgr.h" #include "optimizer/prep.h" #include "rewrite/rewriteDefine.h" #include "rewrite/rewriteSupport.h" #include "utils/acl.h" + #include "utils/builtins.h" + #include "utils/fmgroids.h" #include "utils/relcache.h" #include "utils/syscache.h" #include "utils/temprel.h" + #define RI_TRIGGER_PK 1 + #define RI_TRIGGER_FK 2 + #define RI_TRIGGER_NONE 0 + + static int + ri_trigger_type(int tgfoid){ + switch (tgfoid) + { + case F_RI_FKEY_CASCADE_DEL: + case F_RI_FKEY_CASCADE_UPD: + case F_RI_FKEY_RESTRICT_DEL: + case F_RI_FKEY_RESTRICT_UPD: + case F_RI_FKEY_SETNULL_DEL: + case F_RI_FKEY_SETNULL_UPD: + case F_RI_FKEY_SETDEFAULT_DEL: + case F_RI_FKEY_SETDEFAULT_UPD: + case F_RI_FKEY_NOACTION_DEL: + case F_RI_FKEY_NOACTION_UPD: + return RI_TRIGGER_PK; + break; + + case F_RI_FKEY_CHECK_INS: + case F_RI_FKEY_CHECK_UPD: + return RI_TRIGGER_FK; + break; + + default: + return RI_TRIGGER_NONE; + break; + } + } + + static void + update_ri_trigger_args(Oid relid, + const char* oldname, + const char* newname, + bool fk_scan, + bool update_relname){ + Relation tgrel; + Relation irel = (Relation)NULL; + ScanKeyData skey; + HeapScanDesc tgscan = (HeapScanDesc)NULL; + IndexScanDesc idxtgscan = (IndexScanDesc)NULL; + RetrieveIndexResult idxres; + HeapTuple tuple; + bool isnull; + Datum values[Natts_pg_trigger]; + char nulls[Natts_pg_trigger]; + char replaces[Natts_pg_trigger]; + bool use_index; + int fk_update_argno = RI_FK_ATTNAME_ARGNO; + int pk_update_argno = RI_PK_ATTNAME_ARGNO; + char* scan_index_fk = TriggerConstrRelidIndex; + char* scan_index_pk = TriggerRelidIndex; + char* scan_idx; + + if( fk_scan ){ + scan_idx = scan_index_fk; + } + else{ + scan_idx = scan_index_pk; + } + + if( update_relname ) + { + pk_update_argno = RI_PK_RELNAME_ARGNO; + fk_update_argno = RI_FK_RELNAME_ARGNO; + } + + tgrel = heap_openr(TriggerRelationName, AccessShareLock); + use_index = (tgrel->rd_rel->relhasindex && !IsIgnoringSystemIndexes()); + ScanKeyEntryInitialize(&skey, + 0, + 1, + F_OIDEQ, + relid); + irel = index_openr(scan_idx); + idxtgscan = index_beginscan(irel, false, 1, &skey); + + while((idxres = index_getnext(idxtgscan, ForwardScanDirection))) + { + HeapTupleData tupledata; + Buffer buffer; + Form_pg_trigger pg_trigger; + struct varlena* val; + int tg_type; + + tupledata.t_self = idxres->heap_iptr; + heap_fetch(tgrel, SnapshotNow, &tupledata, &buffer, idxtgscan); + tuple = heap_copytuple(&tupledata); + ReleaseBuffer(buffer); + pfree(idxres); + if (!tupledata.t_data){ + continue; + } + pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple); + val = (struct varlena *) fastgetattr(tuple, + Anum_pg_trigger_tgargs, + tgrel->rd_att, &isnull); + + tg_type = ri_trigger_type(pg_trigger->tgfoid); + + if( !isnull && tg_type ) + { + int i = 0; + char* ap; + int newlen = val->vl_len; + char* argp = (char*)VARDATA(val); + struct varlena* newtgargs; + int ia; + int update_key; + + char** arga = (char **)palloc(pg_trigger->tgnargs * sizeof(char *)); + + /* create an array of the tgargs parts */ + for (i = 0; i < pg_trigger->tgnargs; i++) + { + arga[i] = pstrdup(argp); + argp += strlen(argp)+1; + } + + if( tg_type == RI_TRIGGER_PK ){ + /* trigger for a relation having the primary key */ + if( relid == pg_trigger->tgrelid ){ + /* relation is the one the triggger is attached to. the + * column being renamed is in the pk_update_argno + */ + update_key = pk_update_argno; + } + else{ + update_key = fk_update_argno; + } + } + else{ + /* trigger for a relation having the referencing a primary key */ + if( relid == pg_trigger->tgrelid ){ + /* relation has trigger referencing a primary key. the + * column being renamed is in the fk_update_argno + */ + update_key = fk_update_argno; + } + else{ + update_key = pk_update_argno; + } + } + + /* for self referential fk/pk, tgrelid == tgconstrrelid, so + * our previous rules are broken, infact ... + */ + if( pg_trigger->tgconstrrelid == pg_trigger->tgrelid ) + { + /* update either the fk_update_argno or pk_update_argno + * if it matches oldname + */ + if( strcmp(oldname,arga[fk_update_argno]) == 0 ){ + newlen += ( strlen(newname) + - strlen(arga[fk_update_argno]) ); + pfree( arga[fk_update_argno] ); + arga[fk_update_argno] = pstrdup(newname); + } + if( strcmp(oldname,arga[pk_update_argno]) == 0 ){ + newlen += ( strlen(newname) + - strlen(arga[pk_update_argno]) ); + pfree( arga[pk_update_argno] ); + arga[pk_update_argno] = pstrdup(newname); + } + } + else if( strcmp(oldname,arga[update_key]) == 0 ) + { + newlen += ( strlen(newname) + - strlen(arga[update_key]) ); + pfree( arga[update_key] ); + arga[update_key] = pstrdup(newname); + } + else{ + /* nothing else to do ? */ + } + + + /* + * now, reconstruct the byte area + * + * FRAGILE:? I'd feel better /not/ manually creating this varlena. + */ + newtgargs = (struct varlena*)palloc(sizeof(struct varlena*) + newlen); + newtgargs->vl_len = newlen; + memset(newtgargs->vl_dat,0x00,newlen); + ap = newtgargs->vl_dat; + for (i = 0; i < pg_trigger->tgnargs; i++) + { + char* sp = arga[i]; + while( (*ap++ = *sp++) ); + } + + for (ia = 0; ia < Natts_pg_trigger; ++ia) + { + values[ia] = (Datum) 0; + replaces[ia] = ' '; + nulls[ia] = ' '; + } + values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(newtgargs); + replaces[Anum_pg_trigger_tgargs - 1] = 'r'; + + tuple = heap_modifytuple(tuple,tgrel,values,nulls,replaces); + simple_heap_update(tgrel,&tuple->t_self,tuple); + + /* synchronize trigger indexes for updated tuple */ + { + Relation irelations[Num_pg_attr_indices]; + CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, irelations); + CatalogIndexInsert(irelations, Num_pg_trigger_indices, tgrel, tuple); + CatalogCloseIndices(Num_pg_trigger_indices, irelations); + } + + /* free up our scratch memory... */ + for (i = 0; i < pg_trigger->tgnargs; i++) + pfree(arga[i]); + pfree(arga); + pfree(newtgargs); + } + + heap_freetuple(tuple); + } + + if( use_index ){ + index_endscan(idxtgscan); + index_close(irel); + } + else + heap_endscan(tgscan); + + heap_close(tgrel, AccessShareLock); + + CommandCounterIncrement(); + } + /* * renameatt - changes the name of a attribute in a relation * *************** *** 59,65 **** Relation attrelation; HeapTuple reltup, atttup; ! Oid relid; List *indexoidlist; List *indexoidscan; --- 301,307 ---- Relation attrelation; HeapTuple reltup, atttup; ! Oid relid; List *indexoidlist; List *indexoidscan; *************** *** 226,232 **** freeList(indexoidlist); heap_close(attrelation, RowExclusiveLock); ! heap_close(targetrelation, NoLock); /* close rel but keep lock! */ } /* --- 468,483 ---- freeList(indexoidlist); heap_close(attrelation, RowExclusiveLock); ! ! /* update tgargs column reference where relname is primary key */ ! update_ri_trigger_args(RelationGetRelid(targetrelation), ! oldattname, newattname, false, false); ! /* update tgargs column reference where relname is the forein key */ ! update_ri_trigger_args(RelationGetRelid(targetrelation), ! oldattname, newattname, ! true, false); ! ! heap_close(targetrelation, NoLock); /* close rel but keep lock! */ } /* *************** *** 265,270 **** --- 516,530 ---- reloid = RelationGetRelid(targetrelation); relkind = targetrelation->rd_rel->relkind; + + /* update tgargs where relname is primary key */ + update_ri_trigger_args(RelationGetRelid(targetrelation), + oldrelname, newrelname, + false, true); + /* update tgargs where relname is the forein key */ + update_ri_trigger_args(RelationGetRelid(targetrelation), + oldrelname, newrelname, + true, true); /* * Close rel, but keep exclusive lock!