Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitf14fdad

Browse files
committed
Make ALTER TABLE RENAME update foreign-key trigger arguments correctly.
Brent Verner, with review and kibitzing from Tom Lane.
1 parent8bfc437 commitf14fdad

File tree

3 files changed

+304
-13
lines changed

3 files changed

+304
-13
lines changed

‎src/backend/commands/rename.c

Lines changed: 283 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,33 +8,51 @@
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+
#defineRI_TRIGGER_PK 1/* is a trigger on the PK relation */
45+
#defineRI_TRIGGER_FK 2/* is a trigger on the FK relation */
46+
#defineRI_TRIGGER_NONE 0/* is not an RI trigger function */
47+
48+
staticintri_trigger_type(Oidtgfoid);
49+
staticvoidupdate_ri_trigger_args(Oidrelid,
50+
constchar*oldname,
51+
constchar*newname,
52+
boolfk_scan,
53+
boolupdate_relname);
54+
55+
3856
/*
3957
*renameatt- changes the name of a attribute in a relation
4058
*
@@ -226,6 +244,22 @@ renameatt(char *relname,
226244
freeList(indexoidlist);
227245

228246
heap_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+
229263
heap_close(targetrelation,NoLock);/* close rel but keep lock! */
230264
}
231265

@@ -240,6 +274,7 @@ renamerel(const char *oldrelname, const char *newrelname)
240274
HeapTuplereltup;
241275
Oidreloid;
242276
charrelkind;
277+
boolrelhastriggers;
243278
Relationirelations[Num_pg_class_indices];
244279

245280
if (!allowSystemTableMods&&IsSystemRelationName(oldrelname))
@@ -265,6 +300,7 @@ renamerel(const char *oldrelname, const char *newrelname)
265300

266301
reloid=RelationGetRelid(targetrelation);
267302
relkind=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)
331367
newrulename=MakeRetrieveViewRuleName(newrelname);
332368
RenameRewriteRule(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+
staticint
395+
ri_trigger_type(Oidtgfoid)
396+
{
397+
switch (tgfoid)
398+
{
399+
caseF_RI_FKEY_CASCADE_DEL:
400+
caseF_RI_FKEY_CASCADE_UPD:
401+
caseF_RI_FKEY_RESTRICT_DEL:
402+
caseF_RI_FKEY_RESTRICT_UPD:
403+
caseF_RI_FKEY_SETNULL_DEL:
404+
caseF_RI_FKEY_SETNULL_UPD:
405+
caseF_RI_FKEY_SETDEFAULT_DEL:
406+
caseF_RI_FKEY_SETDEFAULT_UPD:
407+
caseF_RI_FKEY_NOACTION_DEL:
408+
caseF_RI_FKEY_NOACTION_UPD:
409+
returnRI_TRIGGER_PK;
410+
411+
caseF_RI_FKEY_CHECK_INS:
412+
caseF_RI_FKEY_CHECK_UPD:
413+
returnRI_TRIGGER_FK;
414+
}
415+
416+
returnRI_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+
staticvoid
427+
update_ri_trigger_args(Oidrelid,
428+
constchar*oldname,
429+
constchar*newname,
430+
boolfk_scan,
431+
boolupdate_relname)
432+
{
433+
Relationtgrel;
434+
Relationirel;
435+
ScanKeyDataskey[1];
436+
IndexScanDescidxtgscan;
437+
RetrieveIndexResultidxres;
438+
Datumvalues[Natts_pg_trigger];
439+
charnulls[Natts_pg_trigger];
440+
charreplaces[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+
HeapTupleDatatupledata;
457+
Bufferbuffer;
458+
HeapTupletuple;
459+
Form_pg_triggerpg_trigger;
460+
bytea*val;
461+
bytea*newtgargs;
462+
boolisnull;
463+
inttg_type;
464+
boolexamine_pk;
465+
boolchanged;
466+
inttgnargs;
467+
inti;
468+
intnewlen;
469+
constchar*arga[RI_MAX_ARGUMENTS];
470+
constchar*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= (constchar*)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+
Relationirelations[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
}

‎src/backend/utils/adt/ri_triggers.c

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
* Portions Copyright (c) 2000-2001, PostgreSQL Global Development Group
1919
* Copyright 1999 Jan Wieck
2020
*
21-
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.29 2001/10/25 05:49:45 momjian Exp $
21+
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ri_triggers.c,v 1.30 2001/11/12 00:46:36 tgl Exp $
2222
*
2323
* ----------
2424
*/
@@ -43,16 +43,6 @@
4343
* Local definitions
4444
* ----------
4545
*/
46-
#defineRI_CONSTRAINT_NAME_ARGNO0
47-
#defineRI_FK_RELNAME_ARGNO1
48-
#defineRI_PK_RELNAME_ARGNO2
49-
#defineRI_MATCH_TYPE_ARGNO3
50-
#defineRI_FIRST_ATTNAME_ARGNO4
51-
52-
#defineRI_MAX_NUMKEYS16
53-
#defineRI_MAX_ARGUMENTS(RI_FIRST_ATTNAME_ARGNO + (RI_MAX_NUMKEYS * 2))
54-
#defineRI_KEYPAIR_FK_IDX0
55-
#defineRI_KEYPAIR_PK_IDX1
5646

5747
#defineRI_INIT_QUERYHASHSIZE128
5848
#defineRI_INIT_OPREQHASHSIZE128

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp