88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.61 2001/11/05 17 :46:24 momjian Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.62 2001/11/12 00 :46:36 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
1515#include "postgres.h"
1616
1717#include <errno.h>
1818
19+ #include "access/genam.h"
1920#include "access/heapam.h"
21+ #include "access/itup.h"
2022#include "catalog/catname.h"
2123#include "catalog/pg_index.h"
24+ #include "catalog/pg_trigger.h"
2225#include "catalog/pg_type.h"
2326#include "catalog/heap.h"
2427#include "catalog/indexing.h"
2528#include "catalog/catalog.h"
2629#include "commands/rename.h"
30+ #include "commands/trigger.h"
2731#include "miscadmin.h"
2832#include "storage/smgr.h"
2933#include "optimizer/prep.h"
3034#include "rewrite/rewriteDefine.h"
3135#include "rewrite/rewriteSupport.h"
3236#include "utils/acl.h"
37+ #include "utils/builtins.h"
38+ #include "utils/fmgroids.h"
3339#include "utils/relcache.h"
3440#include "utils/syscache.h"
3541#include "utils/temprel.h"
3642
3743
44+ #define RI_TRIGGER_PK 1/* is a trigger on the PK relation */
45+ #define RI_TRIGGER_FK 2/* is a trigger on the FK relation */
46+ #define RI_TRIGGER_NONE 0/* is not an RI trigger function */
47+
48+ static int ri_trigger_type (Oid tgfoid );
49+ static void update_ri_trigger_args (Oid relid ,
50+ const char * oldname ,
51+ const char * newname ,
52+ bool fk_scan ,
53+ bool update_relname );
54+
55+
3856/*
3957 *renameatt- changes the name of a attribute in a relation
4058 *
@@ -226,6 +244,22 @@ renameatt(char *relname,
226244freeList (indexoidlist );
227245
228246heap_close (attrelation ,RowExclusiveLock );
247+
248+ /*
249+ * Update att name in any RI triggers associated with the relation.
250+ */
251+ if (targetrelation -> rd_rel -> reltriggers > 0 )
252+ {
253+ /* update tgargs column reference where att is primary key */
254+ update_ri_trigger_args (RelationGetRelid (targetrelation ),
255+ oldattname ,newattname ,
256+ false, false);
257+ /* update tgargs column reference where att is foreign key */
258+ update_ri_trigger_args (RelationGetRelid (targetrelation ),
259+ oldattname ,newattname ,
260+ true, false);
261+ }
262+
229263heap_close (targetrelation ,NoLock );/* close rel but keep lock! */
230264}
231265
@@ -240,6 +274,7 @@ renamerel(const char *oldrelname, const char *newrelname)
240274HeapTuple reltup ;
241275Oid reloid ;
242276char relkind ;
277+ bool relhastriggers ;
243278Relation irelations [Num_pg_class_indices ];
244279
245280if (!allowSystemTableMods && IsSystemRelationName (oldrelname ))
@@ -265,6 +300,7 @@ renamerel(const char *oldrelname, const char *newrelname)
265300
266301reloid = RelationGetRelid (targetrelation );
267302relkind = targetrelation -> rd_rel -> relkind ;
303+ relhastriggers = (targetrelation -> rd_rel -> reltriggers > 0 );
268304
269305/*
270306 * Close rel, but keep exclusive lock!
@@ -331,4 +367,250 @@ renamerel(const char *oldrelname, const char *newrelname)
331367newrulename = MakeRetrieveViewRuleName (newrelname );
332368RenameRewriteRule (oldrulename ,newrulename );
333369}
370+
371+ /*
372+ * Update rel name in any RI triggers associated with the relation.
373+ */
374+ if (relhastriggers )
375+ {
376+ /* update tgargs where relname is primary key */
377+ update_ri_trigger_args (reloid ,
378+ oldrelname ,newrelname ,
379+ false, true);
380+ /* update tgargs where relname is foreign key */
381+ update_ri_trigger_args (reloid ,
382+ oldrelname ,newrelname ,
383+ true, true);
384+ }
385+ }
386+
387+ /*
388+ * Given a trigger function OID, determine whether it is an RI trigger,
389+ * and if so whether it is attached to PK or FK relation.
390+ *
391+ * XXX this probably doesn't belong here; should be exported by
392+ * ri_triggers.c
393+ */
394+ static int
395+ ri_trigger_type (Oid tgfoid )
396+ {
397+ switch (tgfoid )
398+ {
399+ case F_RI_FKEY_CASCADE_DEL :
400+ case F_RI_FKEY_CASCADE_UPD :
401+ case F_RI_FKEY_RESTRICT_DEL :
402+ case F_RI_FKEY_RESTRICT_UPD :
403+ case F_RI_FKEY_SETNULL_DEL :
404+ case F_RI_FKEY_SETNULL_UPD :
405+ case F_RI_FKEY_SETDEFAULT_DEL :
406+ case F_RI_FKEY_SETDEFAULT_UPD :
407+ case F_RI_FKEY_NOACTION_DEL :
408+ case F_RI_FKEY_NOACTION_UPD :
409+ return RI_TRIGGER_PK ;
410+
411+ case F_RI_FKEY_CHECK_INS :
412+ case F_RI_FKEY_CHECK_UPD :
413+ return RI_TRIGGER_FK ;
414+ }
415+
416+ return RI_TRIGGER_NONE ;
417+ }
418+
419+ /*
420+ * Scan pg_trigger for RI triggers that are on the specified relation
421+ * (if fk_scan is false) or have it as the tgconstrrel (if fk_scan
422+ * is true). Update RI trigger args fields matching oldname to contain
423+ * newname instead. If update_relname is true, examine the relname
424+ * fields; otherwise examine the attname fields.
425+ */
426+ static void
427+ update_ri_trigger_args (Oid relid ,
428+ const char * oldname ,
429+ const char * newname ,
430+ bool fk_scan ,
431+ bool update_relname )
432+ {
433+ Relation tgrel ;
434+ Relation irel ;
435+ ScanKeyData skey [1 ];
436+ IndexScanDesc idxtgscan ;
437+ RetrieveIndexResult idxres ;
438+ Datum values [Natts_pg_trigger ];
439+ char nulls [Natts_pg_trigger ];
440+ char replaces [Natts_pg_trigger ];
441+
442+ tgrel = heap_openr (TriggerRelationName ,RowExclusiveLock );
443+ if (fk_scan )
444+ irel = index_openr (TriggerConstrRelidIndex );
445+ else
446+ irel = index_openr (TriggerRelidIndex );
447+
448+ ScanKeyEntryInitialize (& skey [0 ],0x0 ,
449+ 1 ,/* always column 1 of index */
450+ F_OIDEQ ,
451+ ObjectIdGetDatum (relid ));
452+ idxtgscan = index_beginscan (irel , false,1 ,skey );
453+
454+ while ((idxres = index_getnext (idxtgscan ,ForwardScanDirection ))!= NULL )
455+ {
456+ HeapTupleData tupledata ;
457+ Buffer buffer ;
458+ HeapTuple tuple ;
459+ Form_pg_trigger pg_trigger ;
460+ bytea * val ;
461+ bytea * newtgargs ;
462+ bool isnull ;
463+ int tg_type ;
464+ bool examine_pk ;
465+ bool changed ;
466+ int tgnargs ;
467+ int i ;
468+ int newlen ;
469+ const char * arga [RI_MAX_ARGUMENTS ];
470+ const char * argp ;
471+
472+ tupledata .t_self = idxres -> heap_iptr ;
473+ heap_fetch (tgrel ,SnapshotNow ,& tupledata ,& buffer ,idxtgscan );
474+ pfree (idxres );
475+ if (!tupledata .t_data )
476+ continue ;
477+ tuple = & tupledata ;
478+ pg_trigger = (Form_pg_trigger )GETSTRUCT (tuple );
479+ tg_type = ri_trigger_type (pg_trigger -> tgfoid );
480+ if (tg_type == RI_TRIGGER_NONE )
481+ {
482+ /* Not an RI trigger, forget it */
483+ ReleaseBuffer (buffer );
484+ continue ;
485+ }
486+
487+ /*
488+ * It is an RI trigger, so parse the tgargs bytea.
489+ *
490+ * NB: we assume the field will never be compressed or moved
491+ * out of line; so does trigger.c ...
492+ */
493+ tgnargs = pg_trigger -> tgnargs ;
494+ val = (bytea * )fastgetattr (tuple ,
495+ Anum_pg_trigger_tgargs ,
496+ tgrel -> rd_att ,& isnull );
497+ if (isnull || tgnargs < RI_FIRST_ATTNAME_ARGNO ||
498+ tgnargs > RI_MAX_ARGUMENTS )
499+ {
500+ /* This probably shouldn't happen, but ignore busted triggers */
501+ ReleaseBuffer (buffer );
502+ continue ;
503+ }
504+ argp = (const char * )VARDATA (val );
505+ for (i = 0 ;i < tgnargs ;i ++ )
506+ {
507+ arga [i ]= argp ;
508+ argp += strlen (argp )+ 1 ;
509+ }
510+
511+ /*
512+ * Figure out which item(s) to look at. If the trigger is
513+ * primary-key type and attached to my rel, I should look at
514+ * the PK fields; if it is foreign-key type and attached to my
515+ * rel, I should look at the FK fields. But the opposite rule
516+ * holds when examining triggers found by tgconstrrel search.
517+ */
518+ examine_pk = (tg_type == RI_TRIGGER_PK )== (!fk_scan );
519+
520+ changed = false;
521+ if (update_relname )
522+ {
523+ /* Change the relname if needed */
524+ i = examine_pk ?RI_PK_RELNAME_ARGNO :RI_FK_RELNAME_ARGNO ;
525+ if (strcmp (arga [i ],oldname )== 0 )
526+ {
527+ arga [i ]= newname ;
528+ changed = true;
529+ }
530+ }
531+ else
532+ {
533+ /* Change attname(s) if needed */
534+ i = examine_pk ?RI_FIRST_ATTNAME_ARGNO + RI_KEYPAIR_PK_IDX :
535+ RI_FIRST_ATTNAME_ARGNO + RI_KEYPAIR_FK_IDX ;
536+ for (;i < tgnargs ;i += 2 )
537+ {
538+ if (strcmp (arga [i ],oldname )== 0 )
539+ {
540+ arga [i ]= newname ;
541+ changed = true;
542+ }
543+ }
544+ }
545+
546+ if (!changed )
547+ {
548+ /* Don't need to update this tuple */
549+ ReleaseBuffer (buffer );
550+ continue ;
551+ }
552+
553+ /*
554+ * Construct modified tgargs bytea.
555+ */
556+ newlen = VARHDRSZ ;
557+ for (i = 0 ;i < tgnargs ;i ++ )
558+ newlen += strlen (arga [i ])+ 1 ;
559+ newtgargs = (bytea * )palloc (newlen );
560+ VARATT_SIZEP (newtgargs )= newlen ;
561+ newlen = VARHDRSZ ;
562+ for (i = 0 ;i < tgnargs ;i ++ )
563+ {
564+ strcpy (((char * )newtgargs )+ newlen ,arga [i ]);
565+ newlen += strlen (arga [i ])+ 1 ;
566+ }
567+
568+ /*
569+ * Build modified tuple.
570+ */
571+ for (i = 0 ;i < Natts_pg_trigger ;i ++ )
572+ {
573+ values [i ]= (Datum )0 ;
574+ replaces [i ]= ' ' ;
575+ nulls [i ]= ' ' ;
576+ }
577+ values [Anum_pg_trigger_tgargs - 1 ]= PointerGetDatum (newtgargs );
578+ replaces [Anum_pg_trigger_tgargs - 1 ]= 'r' ;
579+
580+ tuple = heap_modifytuple (tuple ,tgrel ,values ,nulls ,replaces );
581+
582+ /*
583+ * Now we can release hold on original tuple.
584+ */
585+ ReleaseBuffer (buffer );
586+
587+ /*
588+ * Update pg_trigger and its indexes
589+ */
590+ simple_heap_update (tgrel ,& tuple -> t_self ,tuple );
591+
592+ {
593+ Relation irelations [Num_pg_attr_indices ];
594+
595+ CatalogOpenIndices (Num_pg_trigger_indices ,Name_pg_trigger_indices ,irelations );
596+ CatalogIndexInsert (irelations ,Num_pg_trigger_indices ,tgrel ,tuple );
597+ CatalogCloseIndices (Num_pg_trigger_indices ,irelations );
598+ }
599+
600+ /* free up our scratch memory */
601+ pfree (newtgargs );
602+ heap_freetuple (tuple );
603+ }
604+
605+ index_endscan (idxtgscan );
606+ index_close (irel );
607+
608+ heap_close (tgrel ,RowExclusiveLock );
609+
610+ /*
611+ * Increment cmd counter to make updates visible; this is needed
612+ * in case the same tuple has to be updated again by next pass
613+ * (can happen in case of a self-referential FK relationship).
614+ */
615+ CommandCounterIncrement ();
334616}