Index: src/backend/commands/rename.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/rename.c,v retrieving revision 1.61 diff -r1.61 rename.c 21a22 > #include "catalog/pg_trigger.h" 26a28 > #include "commands/trigger.h" /* pg_trigger->tgargs bytea def */ 32a35,36 > #include "utils/builtins.h" > #include "utils/fmgroids.h" 36a41,290 > /* > * update_trigger_tgargs - synchronize tgargs with renamed column. > * This should only be called after we /know/ the column name > * was renamed. > * > * related: CreateTrigger - format of tgargs > * > * What happens here is best said in SQL: > * > * UPDATE pg_trigger SET tgargs = update_tgargs() > * WHERE tgrelid = ${attoid} > * OR tgconstrrelid = ${attoid}; > * > * > * the pseudo-function updated_tgargs()'s description and behavior > * is as follows. > * > * tgargs split on '\0' into an array: > * tgargs[0] = trigger_name > * tgargs[1] = table_1 > * tgargs[2] = table_2 > * tgargs[3] = (brent's a lazy monkey) > * tgargs[4] = column_1 > * tgargs[5] = column_2 > * > * An updated tgargs array will be created, setting > * column_N = ${newattname} where table_N = ${relname} > * > * if( tgargs[1] == relname ) > * tgargs[4] = newattname > * else if( tgargs[2] == relname ) > * tgargs[5] = newattname > * > * This updated tgargs array is then rejoined with '\0' and would > * be returned from the pseudo-function to update the tuple to > * contain the working tgargs. > * > * > * TODO: there are two blocks of identical code. consolidate. > * It's a hassle to make changes twice ;-) Learn to > * program in C -- dbv 20011110 > */ > > static void > update_trigger_tgargs(const char* relname, const char* newattname) > { > Relation rel; > Relation tgrel; > ScanKeyData skey; > HeapScanDesc tgscan; > HeapTuple tuple; > bool isnull; > Datum values[Natts_pg_trigger]; > char nulls[Natts_pg_trigger]; > char replaces[Natts_pg_trigger]; > > rel = heap_openr(relname, AccessExclusiveLock); > > /* update trigger tgargs for this relname */ > tgrel = heap_openr(TriggerRelationName, AccessShareLock); > ScanKeyEntryInitialize(&skey, 0, Anum_pg_trigger_tgrelid, > F_OIDEQ, RelationGetRelid(rel)); > tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey); > while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0))) > { > Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple); > struct varlena* val = (struct varlena *) fastgetattr(tuple, > Anum_pg_trigger_tgargs, > tgrel->rd_att, &isnull); > if(!isnull){ > int i = 0; > char* ap; > int newlen = val->vl_len; > char* argp = (char*)VARDATA(val); > struct varlena* newtgargs; > > int ia; > > char** arga = (char **) > MemoryContextAlloc(CurrentMemoryContext, > pg_trigger->tgnargs * sizeof(char *)); > > /* create an array of the tgargs parts */ > for (i = 0; i < pg_trigger->tgnargs; i++) > { > arga[i] = MemoryContextStrdup(CurrentMemoryContext,argp); > argp += strlen(argp)+1; > } > > /* fix the column names */ > if( strcmp(arga[RI_FK_RELNAME_ARGNO],relname) == 0 ) > { > newlen += ( strlen(newattname) > - strlen(arga[RI_FK_ATTNAME_ARGNO]) ); > pfree(arga[RI_FK_ATTNAME_ARGNO]); > arga[RI_FK_ATTNAME_ARGNO] > = MemoryContextStrdup(CurrentMemoryContext,newattname); > } > else if( strcmp(arga[RI_PK_RELNAME_ARGNO],relname) == 0 ) > { > newlen += (strlen(newattname) > - strlen(arga[RI_PK_ATTNAME_ARGNO]) ); > pfree(arga[RI_PK_ATTNAME_ARGNO]); > arga[RI_PK_ATTNAME_ARGNO] > = MemoryContextStrdup(CurrentMemoryContext,newattname); > } > > /* > * now, reconstruct the byte area > * > * FRAGILE:? I'd feel better /not/ manually creating this varlena. > */ > newtgargs = (struct varlena*)MemoryContextAlloc(CurrentMemoryContext,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); > } > heap_endscan(tgscan); > heap_close(tgrel, AccessShareLock); > > /* update referenced relation trigger tgargs */ > tgrel = heap_openr(TriggerRelationName, AccessShareLock); > ScanKeyEntryInitialize(&skey, 0, Anum_pg_trigger_tgconstrrelid, > F_OIDEQ, RelationGetRelid(rel)); > tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey); > while (HeapTupleIsValid(tuple = heap_getnext(tgscan, 0))) > { > Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple); > struct varlena* val = (struct varlena *) fastgetattr(tuple, > Anum_pg_trigger_tgargs, > tgrel->rd_att, &isnull); > if(!isnull){ > int i = 0; > char* ap; > int newlen = val->vl_len; > char* argp = (char*)VARDATA(val); > struct varlena* newtgargs; > > int ia; > > char** arga = (char **) > MemoryContextAlloc(CurrentMemoryContext, > pg_trigger->tgnargs * sizeof(char *)); > > /* create an array of the tgargs parts */ > for (i = 0; i < pg_trigger->tgnargs; i++) > { > arga[i] = MemoryContextStrdup(CurrentMemoryContext,argp); > argp += strlen(argp)+1; > } > > /* fix the column names */ > if( strcmp(arga[RI_FK_RELNAME_ARGNO],relname) == 0 ) > { > newlen += ( strlen(newattname) > - strlen(arga[RI_FK_ATTNAME_ARGNO]) ); > pfree(arga[RI_FK_ATTNAME_ARGNO]); > arga[RI_FK_ATTNAME_ARGNO] > = MemoryContextStrdup(CurrentMemoryContext,newattname); > } > else if( strcmp(arga[RI_PK_RELNAME_ARGNO],relname) == 0 ) > { > newlen += (strlen(newattname) > - strlen(arga[RI_PK_ATTNAME_ARGNO]) ); > pfree(arga[RI_PK_ATTNAME_ARGNO]); > arga[RI_PK_ATTNAME_ARGNO] > = MemoryContextStrdup(CurrentMemoryContext,newattname); > } > > /* > * now, reconstruct the byte area > * > * FRAGILE:? I'd feel better /not/ manually creating this varlena. > */ > newtgargs = (struct varlena*)MemoryContextAlloc(CurrentMemoryContext,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); > } > heap_endscan(tgscan); > heap_close(tgrel, AccessShareLock); > > heap_close(rel, NoLock); > } 62c316 < Oid relid; --- > Oid relid; 227c481 < --- > 229a484,489 > > /* update the tgargs for for any tuple in pg_trigger that > * refers to this column. > */ > update_trigger_tgargs(relname, newattname); >