Thread: ALTER TABLE RENAME fix

ALTER TABLE RENAME fix

From
Brent Verner
Date:
These patches fix the problem where an

  ALTER TABLE <table> RENAME <oldcolumn> TO <newcolumn>

did not update the RI_ triggers if the oldcolumn was referenced in
a RI constraint. The net effect of these patches is that the following
sql now works.

  create table parent (id int UNIQUE);
  create table child (id int references parent(id) on update cascade);
  alter table parent rename id to hello;
  insert into parent values(1);
  insert into child values(1);


The first patch (pgsql-1.diff) moves the defines for the RI_ function
args to an include, instead of just being local definitions.  It also
changes the name of one of the defines and adds another define so that
all function args in the pg_trigger.tgargs bytea are #defined.

The second patch (pgsql-2.diff) adds a function update_trigger_tgargs().
See comments in the file for explanation.  This code could /really/ use
a sanity check by someone with more C-foo than I have, to make sure I'm
not doing anything blatantly wrong.  Also, I'm directly creating a
varlena type, which I'm a bit uncomfortable with, so if there is a
utility to create these (without creating a char* for use with
byteain()), I'd appreciate you pointing me towards that, and I'll
resubmit a better patch.

I have not exhaustively tested this code, but everything I've thrown
at it does the right thing, and no regression failures are caused.

I'll work on regression tests after some sleep ;-)

cheers.
  brent

--
"Develop your talent, man, and leave the world something. Records are
really gifts from people. To think that an artist would love you enough
to share his music with anyone is a beautiful thing."  -- Duane Allman

Attachment

Re: ALTER TABLE RENAME fix

From
Tom Lane
Date:
Brent Verner <brent@rcfile.org> writes:
> These patches fix the problem where an
>   ALTER TABLE <table> RENAME <oldcolumn> TO <newcolumn>
> did not update the RI_ triggers if the oldcolumn was referenced in
> a RI constraint.

This seems wrong on its face: the code unconditionally updates the
attname part of a trigger's tgargs without checking whether the trigger
actually refers to the attribute being renamed.  Don't you need to have
a comparison against the old attname in there somewhere?

Another problem is that you're assuming that *all* triggers are RI
triggers.  You need to check the trigger function before assuming that
the tgargs are of a form you can parse.  There's at least one place in
the existing code that makes such a check already, but I forget where.

Also, I would think that you need to look not only at triggers on the
relation containing the att being renamed, but also at triggers on the
rels that are the other side of the FK relationships.  Those triggers
also contain references to the attname, no?

A performance issue here is that scanning all of pg_trigger could be
kind of slow in a database with lots and lots of triggers.  You should
be doing an indexscan using pg_trigger_tgrelid_index.  Actually, given
the previous comment, probably more than one indexscan.  My inclination
would be to accumulate the distinct tgconstrrelid values seen on
triggers that are found to refer to the renamed att during the first
indexscan on the original rel's relid, and then do additional indexscans
looking at those relids (probably there won't be many).

One stylistic quibble: the direct references to CurrentMemoryContext
are verbose and unnecessary.  Use palloc() and pstrdup().

            regards, tom lane

Re: ALTER TABLE RENAME fix

From
Brent Verner
Date:
On 10 Nov 2001 at 14:21 (-0500), Tom Lane wrote:
| Brent Verner <brent@rcfile.org> writes:
| > These patches fix the problem where an
| >   ALTER TABLE <table> RENAME <oldcolumn> TO <newcolumn>
| > did not update the RI_ triggers if the oldcolumn was referenced in
| > a RI constraint.
|
| This seems wrong on its face: the code unconditionally updates the
| attname part of a trigger's tgargs without checking whether the trigger
| actually refers to the attribute being renamed.  Don't you need to have
| a comparison against the old attname in there somewhere?

agreed.

| Another problem is that you're assuming that *all* triggers are RI
| triggers.  You need to check the trigger function before assuming that
| the tgargs are of a form you can parse.  There's at least one place in
| the existing code that makes such a check already, but I forget where.

Yes, I thought about this as I was going to sleep. I believe I can just
check that tgisconstraint='t' in the tuple.  I'll make sure this test
is sane.

| Also, I would think that you need to look not only at triggers on the
| relation containing the att being renamed, but also at triggers on the
| rels that are the other side of the FK relationships.  Those triggers
| also contain references to the attname, no?

Either this is already being done, or I do not understand what you mean.
The code currently will inspect all tuples where tgrelid or tgconstrrelid
is the altered relname's oid.  If relname appears as tgargs[1] or tgargs[2],
the attname tgargs[4] or tgargs[5] is updated appropriately.

| A performance issue here is that scanning all of pg_trigger could be
| kind of slow in a database with lots and lots of triggers.  You should
| be doing an indexscan using pg_trigger_tgrelid_index.  Actually, given
| the previous comment, probably more than one indexscan.  My inclination
| would be to accumulate the distinct tgconstrrelid values seen on
| triggers that are found to refer to the renamed att during the first
| indexscan on the original rel's relid, and then do additional indexscans
| looking at those relids (probably there won't be many).

I'll look into this after I get the rest of the code working correctly.

| One stylistic quibble: the direct references to CurrentMemoryContext
| are verbose and unnecessary.  Use palloc() and pstrdup().

gotcha.


Thank you,
  Brent

--
"Develop your talent, man, and leave the world something. Records are
really gifts from people. To think that an artist would love you enough
to share his music with anyone is a beautiful thing."  -- Duane Allman

Re: ALTER TABLE RENAME fix

From
Tom Lane
Date:
Brent Verner <brent@rcfile.org> writes:
> | Another problem is that you're assuming that *all* triggers are RI
> | triggers.  You need to check the trigger function before assuming that
> | the tgargs are of a form you can parse.  There's at least one place in
> | the existing code that makes such a check already, but I forget where.

> Yes, I thought about this as I was going to sleep. I believe I can just
> check that tgisconstraint='t' in the tuple.  I'll make sure this test
> is sane.

The code I was recalling is in trigger.c, and what it does is to test
the tgfoid to see if it's one of the RI_FKEY functions:

                /*
                 * We are interested in RI_FKEY triggers only.
                 */
                switch (trigger->tgfoid)
                {
                    case F_RI_FKEY_NOACTION_UPD:
                    case F_RI_FKEY_CASCADE_UPD:
                    case F_RI_FKEY_RESTRICT_UPD:
                    case F_RI_FKEY_SETNULL_UPD:
                    case F_RI_FKEY_SETDEFAULT_UPD:
                        is_ri_trigger = true;
                        break;

                    default:
                        is_ri_trigger = false;
                        break;
                }

I'd suggest sticking with that approach.  (It'd probably be a good idea
to break this chunk of knowledge out into a function, along the lines of
bool is_ri_trigger_function(func_oid), rather than duplicating it in two
different modules.)

> | Also, I would think that you need to look not only at triggers on the
> | relation containing the att being renamed, but also at triggers on the
> | rels that are the other side of the FK relationships.  Those triggers
> | also contain references to the attname, no?

> Either this is already being done, or I do not understand what you mean.
> The code currently will inspect all tuples where tgrelid or tgconstrrelid
> is the altered relname's oid.  If relname appears as tgargs[1] or tgargs[2],
> the attname tgargs[4] or tgargs[5] is updated appropriately.

But your patch has

>   tgrel = heap_openr(TriggerRelationName, AccessShareLock);
>   ScanKeyEntryInitialize(&skey, 0, Anum_pg_trigger_tgrelid,
>                      F_OIDEQ, RelationGetRelid(rel));
>   tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey);

The scankey tells the scan subroutines to only return tuples matching
the scan key, ie, only tuples with tgrelid = OID of the relation.
So even though you're plowing through all the tuples of pg_trigger,
only those attached to the target rel will be examined.


Oh, one other thing: patches should be submitted in "diff -c" format.
Plain diff format is considered too risky to apply, since it fails
silently if the line numbers are at all different between what you've
been working with and the file the committer is trying to apply the
patch to.  A context diff provides a little bit of protection.

            regards, tom lane

Re: ALTER TABLE RENAME fix

From
Brent Verner
Date:
On 10 Nov 2001 at 19:08 (-0500), Tom Lane wrote:
| Brent Verner <brent@rcfile.org> writes:
| > | Another problem is that you're assuming that *all* triggers are RI
| > | triggers.  You need to check the trigger function before assuming that
| > | the tgargs are of a form you can parse.  There's at least one place in
| > | the existing code that makes such a check already, but I forget where.
|
| > Yes, I thought about this as I was going to sleep. I believe I can just
| > check that tgisconstraint='t' in the tuple.  I'll make sure this test
| > is sane.
|
| The code I was recalling is in trigger.c, and what it does is to test
| the tgfoid to see if it's one of the RI_FKEY functions:
 [snip]
| I'd suggest sticking with that approach.  (It'd probably be a good idea
| to break this chunk of knowledge out into a function, along the lines of
| bool is_ri_trigger_function(func_oid), rather than duplicating it in two
| different modules.)

Thanks for this tip.  I'll make that code a function.

| > | Also, I would think that you need to look not only at triggers on the
| > | relation containing the att being renamed, but also at triggers on the
| > | rels that are the other side of the FK relationships.  Those triggers
| > | also contain references to the attname, no?
|
| > Either this is already being done, or I do not understand what you mean.
| > The code currently will inspect all tuples where tgrelid or tgconstrrelid
| > is the altered relname's oid.  If relname appears as tgargs[1] or tgargs[2],
| > the attname tgargs[4] or tgargs[5] is updated appropriately.
|
| But your patch has
|
| >   tgrel = heap_openr(TriggerRelationName, AccessShareLock);
| >   ScanKeyEntryInitialize(&skey, 0, Anum_pg_trigger_tgrelid,
| >                      F_OIDEQ, RelationGetRelid(rel));
| >   tgscan = heap_beginscan(tgrel, 0, SnapshotNow, 1, &skey);
|
| The scankey tells the scan subroutines to only return tuples matching
| the scan key, ie, only tuples with tgrelid = OID of the relation.
| So even though you're plowing through all the tuples of pg_trigger,
| only those attached to the target rel will be examined.

Yes, but I'm doing two separate scans for relname's OID; tgrelid and
tgconstrrelid.  The second scan returns tuples where tgrelid is the
OID of the other relname in the constraint.  Is there a way to do
this in one scan?

| Oh, one other thing: patches should be submitted in "diff -c" format.

gotcha.


Thanks,
  Brent

--
"Develop your talent, man, and leave the world something. Records are
really gifts from people. To think that an artist would love you enough
to share his music with anyone is a beautiful thing."  -- Duane Allman

Re: ALTER TABLE RENAME fix

From
Tom Lane
Date:
Brent Verner <brent@rcfile.org> writes:
> Yes, but I'm doing two separate scans for relname's OID; tgrelid and
> tgconstrrelid.

Oh!  Duh ... I managed to miss that completely.  You're right, the
scan for tgconstrrelid should catch the "other half" triggers that
I was worried you'd miss.  The code is kinda misleadingly structured,
since it looks at both RI_FK_RELNAME_ARGNO and RI_PK_RELNAME_ARGNO in
each loop, which is really wrong: ISTM you should be examining only one
of those, depending on whether you found the trigger by tgrelid or
tgconstrrelid, and it shouldn't be necessary to look at the stored
relname at all should it?

> The second scan returns tuples where tgrelid is the
> OID of the other relname in the constraint.  Is there a way to do
> this in one scan?

I don't think so, but it seems like you could avoid the duplicated code
by having a subroutine that's invoked twice with two different parameter
sets.

Each of the scans could be indexscans (but using two different indexes,
viz pg_trigger_tgconstrrelid_index and pg_trigger_tgrelid_index), so
it should still be plenty fast enough.

            regards, tom lane

Re: ALTER TABLE RENAME fix

From
Brent Verner
Date:
On 10 Nov 2001 at 19:35 (-0500), Tom Lane wrote:
| Brent Verner <brent@rcfile.org> writes:
| > Yes, but I'm doing two separate scans for relname's OID; tgrelid and
| > tgconstrrelid.
|
| Oh!  Duh ... I managed to miss that completely.  You're right, the
| scan for tgconstrrelid should catch the "other half" triggers that
| I was worried you'd miss.  The code is kinda misleadingly structured,
| since it looks at both RI_FK_RELNAME_ARGNO and RI_PK_RELNAME_ARGNO in
| each loop, which is really wrong: ISTM you should be examining only one
| of those, depending on whether you found the trigger by tgrelid or
| tgconstrrelid, and it shouldn't be necessary to look at the stored
| relname at all should it?

<light bulb over head>

no doubt, very badly/misleadingly written.  There is no reason for
me to reconstruct the new tgargs for each tuple at all.  I just need
to do the check against PK_RELNAME and FK_RELNAME for the first tuple
that needs updating, since the tgargs is the /same/ for all calls to
this trigger... but we have to check both PK_RELNAME and FK_RELNAME,
since we don't know which side of the constraint this relname is on.
The following pseudo-code describes all I need to do.

newtgargs = NULL;
while(tuple = scan(tgrelid==relname.oid)){
  if( is_ri_trigger(tuple) ){
    if( newtgargs == NULL ){
      get_newtgargs(tuple,newtgargs);
    }
    update_tgargs(tuple,newtgargs);
  }
}
while(tuple = scan(tgconstrrelid==relname.oid)){
  if( is_ri_trigger(tuple) ){
    update_tgargs(tuple,newtgargs);
  }
}

| > The second scan returns tuples where tgrelid is the
| > OID of the other relname in the constraint.  Is there a way to do
| > this in one scan?
|
| I don't think so, but it seems like you could avoid the duplicated code
| by having a subroutine that's invoked twice with two different parameter
| sets.

Yeah, I started to do this anyway, since making the same change in two
places was just painful ;-)

| Each of the scans could be indexscans (but using two different indexes,
| viz pg_trigger_tgconstrrelid_index and pg_trigger_tgrelid_index), so
| it should still be plenty fast enough.

I'll make it so.

Thanks,
  Brent

--
"Develop your talent, man, and leave the world something. Records are
really gifts from people. To think that an artist would love you enough
to share his music with anyone is a beautiful thing."  -- Duane Allman

Re: ALTER TABLE RENAME fix

From
Tom Lane
Date:
Brent Verner <brent@rcfile.org> writes:
> ... but we have to check both PK_RELNAME and FK_RELNAME,
> since we don't know which side of the constraint this relname is on.

But we do, because we know whether we're scanning by tgrelid or
tgconstrrelid.  This is not merely an efficiency hack, I believe it's
*necessary* to ensure correct functioning.  Think about (a) FK
constraints against a different rel that happens to have an att of the
same name as the one being renamed; (b) an FK constraint against the
*same* rel (quite legal).

Another thing in the back of my mind is that I think ALTER RENAME TABLE
has the same problem as ALTER RENAME COLUMN: the relnames in RI triggers
need to be fixed, and aren't getting fixed.  It seems to me that this
scan subroutine could be the workhorse for solving both problems, if
it's defined to do string substitution in a particular field of the
RI trigger args.  The scan subr should be something like

update_ri_trigger_args (Oid relid,
            bool scan_by_constrrelid,
            int tgargs_item_num,
            const char *oldname,
            const char *newname)

with the semantics that it examines all RI triggers with tgrelid=relid
if scan_by_constrrelid is FALSE, or all RI triggers with tgconstrrelid
= relid if scan_by_constrrelid is TRUE.  If the field numbered
tgargs_item_num contains the string oldname, replace it with newname;
else do nothing to that trigger.

Now, ALTER RENAME COLUMN does this:

update_ri_trigger_args(relid, false, RI_PK_ATTNAME_ARGNO,
               oldattname, newattname);
update_ri_trigger_args(relid, true, RI_FK_ATTNAME_ARGNO,
               oldattname, newattname);

and ALTER RENAME TABLE does this:

update_ri_trigger_args(relid, false, RI_PK_RELNAME_ARGNO,
               oldrelname, newrelname);
update_ri_trigger_args(relid, true, RI_FK_RELNAME_ARGNO,
               oldrelname, newrelname);

I might have the FK and PK roles backwards, but it seems like this
should work.

BTW, you probably need a CommandCounterIncrement between the two scans
in each case.  Otherwise the second scan doesn't see the tuples already
updated by the first, which is deadly if there are any self-referential
triggers.

            regards, tom lane

Re: ALTER TABLE RENAME fix

From
Brent Verner
Date:
On 10 Nov 2001 at 20:26 (-0500), Brent Verner wrote:

| <light bulb over head>

<sound of light bulb busting>

| no doubt, very badly/misleadingly written.  There is no reason for
| me to reconstruct the new tgargs for each tuple at all.  I just need
| to do the check against PK_RELNAME and FK_RELNAME for the first tuple
| that needs updating, since the tgargs is the /same/ for all calls to
| this trigger... but we have to check both PK_RELNAME and FK_RELNAME,
| since we don't know which side of the constraint this relname is on.
| The following pseudo-code describes all I need to do.

disregard this idea. It will not do the right thing with multiple
constraints.

  brent

--
"Develop your talent, man, and leave the world something. Records are
really gifts from people. To think that an artist would love you enough
to share his music with anyone is a beautiful thing."  -- Duane Allman

Re: ALTER TABLE RENAME fix

From
Brent Verner
Date:
On 10 Nov 2001 at 20:41 (-0500), Tom Lane wrote:
| Brent Verner <brent@rcfile.org> writes:
| > ... but we have to check both PK_RELNAME and FK_RELNAME,
| > since we don't know which side of the constraint this relname is on.
|
| But we do, because we know whether we're scanning by tgrelid or
| tgconstrrelid.

My brain is not stretching far enough to see this.  Yes, we know
what we are scanning on, but that stilll doesn't tell us which
side of the FK/PK relation this relname is on.

  CREATE TABLE p_rel (id int UNIQUE);
  CREATE TABLE f_rel (id int REFERENCES p_rel(id) ON UPDATE CASCADE);

p_rel.id is our PK
f_rel.id is our FK

scan on tgrelid==p_rel.oid  : 2 tuples.
scan on tgconstrrelid==p_rel.oid : 1 tuple.

scan on tgrelid==f_rel.oid  : 1 tuple.
scan on tgconstrrelid==f_rel.oid : 2 tuples.

AFAICS, given a relname, the only way we can know if it is the PK or
FK is the number of tuples a known scan returns.  What am I missing
here?

| Another thing in the back of my mind is that I think ALTER RENAME TABLE
| has the same problem as ALTER RENAME COLUMN: the relnames in RI triggers
| need to be fixed, and aren't getting fixed.  It seems to me that this
| scan subroutine could be the workhorse for solving both problems, if
| it's defined to do string substitution in a particular field of the
| RI trigger args.  The scan subr should be something like
|
| update_ri_trigger_args (Oid relid,
|             bool scan_by_constrrelid,
|             int tgargs_item_num,
|             const char *oldname,
|             const char *newname)

I wasn't aware of the related ALTER RENAME TABLE problem.  This is
certainly an appropriate solution.  I'll work to do what you suggest.

| BTW, you probably need a CommandCounterIncrement between the two scans
| in each case.  Otherwise the second scan doesn't see the tuples already
| updated by the first, which is deadly if there are any self-referential
| triggers.

cool. Thanks for alerting me of this danger -- I had no idea.

thanks.
  b

--
"Develop your talent, man, and leave the world something. Records are
really gifts from people. To think that an artist would love you enough
to share his music with anyone is a beautiful thing."  -- Duane Allman

Re: ALTER TABLE RENAME fix

From
Tom Lane
Date:
Brent Verner <brent@rcfile.org> writes:
> | But we do, because we know whether we're scanning by tgrelid or
> | tgconstrrelid.

> My brain is not stretching far enough to see this.  Yes, we know
> what we are scanning on, but that stilll doesn't tell us which
> side of the FK/PK relation this relname is on.

Doesn't it?  Maybe I'm the one who's confused.  The RI trigger functions
certainly know which field is which without any searching.

I did:

regression=# CREATE TABLE p_rel (p_id int UNIQUE);
NOTICE:  CREATE TABLE / UNIQUE will create implicit index 'p_rel_p_id_key' for table 'p_rel'
CREATE
regression=# CREATE TABLE f_rel (f_id int REFERENCES p_rel(p_id) ON UPDATE CASCADE);
NOTICE:  CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
CREATE
regression=# select tgfoid::regproc,tgargs from pg_trigger where tgrelid =
regression-# (select oid from pg_class where relname = 'p_rel');
        tgfoid        |                             tgargs
----------------------+----------------------------------------------------------------
 RI_FKey_noaction_del | <unnamed>\000f_rel\000p_rel\000UNSPECIFIED\000f_id\000p_id\000
 RI_FKey_cascade_upd  | <unnamed>\000f_rel\000p_rel\000UNSPECIFIED\000f_id\000p_id\000
(2 rows)

regression=# select tgfoid::regproc,tgargs from pg_trigger where tgconstrrelid =
regression-# (select oid from pg_class where relname = 'p_rel');
      tgfoid       |                             tgargs
-------------------+----------------------------------------------------------------
 RI_FKey_check_ins | <unnamed>\000f_rel\000p_rel\000UNSPECIFIED\000f_id\000p_id\000
(1 row)

regression=# select tgfoid::regproc,tgargs from pg_trigger where tgrelid =
regression-# (select oid from pg_class where relname = 'f_rel');
      tgfoid       |                             tgargs
-------------------+----------------------------------------------------------------
 RI_FKey_check_ins | <unnamed>\000f_rel\000p_rel\000UNSPECIFIED\000f_id\000p_id\000
(1 row)

regression=# select tgfoid::regproc,tgargs from pg_trigger where tgconstrrelid =
regression-# (select oid from pg_class where relname = 'f_rel');
        tgfoid        |                             tgargs
----------------------+----------------------------------------------------------------
 RI_FKey_noaction_del | <unnamed>\000f_rel\000p_rel\000UNSPECIFIED\000f_id\000p_id\000
 RI_FKey_cascade_upd  | <unnamed>\000f_rel\000p_rel\000UNSPECIFIED\000f_id\000p_id\000
(2 rows)

Hmm, so the same tgargs vector is passed to all the triggers regardless
of which side of the relationship they're on, and it's up to the trigger
itself to know which relname/attname applies to its own table.

I think what this means is that a boolean "is_ri_trigger" classification
isn't good enough.  You need to make the knowledge function have a
three-way return: not an RI trigger, RI trigger for PK relation, or
RI trigger for FK relation.  Then the scan subroutine has to take two
item-number parameters, one telling it which tgarg item to look at for a
PK relation and a different one to look at for an FK relation.

Or maybe some slightly different structure would be cleaner.  But the
point is that you have to be able to decide which item to look at
by some means that doesn't involve checking the relname item.  Else it
doesn't work for self-referential RI constraints (same relname on
both sides).

> AFAICS, given a relname, the only way we can know if it is the PK or
> FK is the number of tuples a known scan returns.

The number of tuples is an implementation artifact and might change;
I don't think we should trust that.  (For example, RI_FKey_noaction_del
and RI_FKey_cascade_upd could theoretically be merged into a single
trigger that pays attention to the event it was called for.)

            regards, tom lane

Re: ALTER TABLE RENAME fix

From
Tom Lane
Date:
Brent Verner <brent@rcfile.org> writes:
> exactly. which is why we've gotta inspecy the relname to determine
> which of the attnames to modify.

My point is that inspecting the tgfoid is safer, because it
unambiguously tells you what you are looking at.  The relname is
inherently ambiguous because it could be the same on both sides.
Also, depending on the relname is highly fragile if you're trying
to handle the RENAME TABLE case --- did you already update (one
side of) this trigger, or not?

> right.  I was not proposing that as any bit of info to use, just an
> example that there is no useful way (in a pg_trigger scan) to know
> if the relname is a PK or FK rel.

There is: the tgfoid, which is indirectly the same way that the trigger
functions themselves know what to do.

            regards, tom lane

Re: ALTER TABLE RENAME fix

From
Brent Verner
Date:
On 10 Nov 2001 at 21:41 (-0500), Tom Lane wrote:
| Brent Verner <brent@rcfile.org> writes:
| > | But we do, because we know whether we're scanning by tgrelid or
| > | tgconstrrelid.
|
| > My brain is not stretching far enough to see this.  Yes, we know
| > what we are scanning on, but that stilll doesn't tell us which
| > side of the FK/PK relation this relname is on.
|
| Doesn't it?  Maybe I'm the one who's confused.  The RI trigger functions
| certainly know which field is which without any searching.
 [snip]
| Hmm, so the same tgargs vector is passed to all the triggers regardless
| of which side of the relationship they're on, and it's up to the trigger
| itself to know which relname/attname applies to its own table.

exactly. which is why we've gotta inspecy the relname to determine
which of the attnames to modify.

| I think what this means is that a boolean "is_ri_trigger" classification
| isn't good enough.  You need to make the knowledge function have a
| three-way return: not an RI trigger, RI trigger for PK relation, or
| RI trigger for FK relation.  Then the scan subroutine has to take two
| item-number parameters, one telling it which tgarg item to look at for a
| PK relation and a different one to look at for an FK relation.

I'm not sure why this is necessary.

  A scan on tgrelid==relname.oid returns an RI trigger.
  A scan on tgconstrrelid==relname.oid returns an RI trigger.

We must update these tuples.  We can't know if the relname being
modified is the PK or FK, and it really doesn't matter, because
its name or attname must be updated to refer to the new name.  This
is why I'm checking relname in either the PK or FK position for
each tuple.  Is there a case where updating these tuples tgargs
to contain the new relname|attname would break things?  If not, I
believe my 'update all references to the oldname' behavior is
acceptable, and even correct :)

| Or maybe some slightly different structure would be cleaner.  But the
| point is that you have to be able to decide which item to look at
| by some means that doesn't involve checking the relname item.  Else it
| doesn't work for self-referential RI constraints (same relname on
| both sides).

do you have a bit of sql in mind so that I might test this
self-referential RI constraint?

| > AFAICS, given a relname, the only way we can know if it is the PK or
| > FK is the number of tuples a known scan returns.
|
| The number of tuples is an implementation artifact and might change;
| I don't think we should trust that.  (For example, RI_FKey_noaction_del
| and RI_FKey_cascade_upd could theoretically be merged into a single
| trigger that pays attention to the event it was called for.)

right.  I was not proposing that as any bit of info to use, just an
example that there is no useful way (in a pg_trigger scan) to know
if the relname is a PK or FK rel.

cheers.
  brent

--
"Develop your talent, man, and leave the world something. Records are
really gifts from people. To think that an artist would love you enough
to share his music with anyone is a beautiful thing."  -- Duane Allman

Re: ALTER TABLE RENAME fix

From
Brent Verner
Date:
On 10 Nov 2001 at 22:42 (-0500), Tom Lane wrote:
| Brent Verner <brent@rcfile.org> writes:
| > exactly. which is why we've gotta inspecy the relname to determine
| > which of the attnames to modify.
|
| My point is that inspecting the tgfoid is safer, because it
| unambiguously tells you what you are looking at.  The relname is
| inherently ambiguous because it could be the same on both sides.

gotcha!  I'm digging further into how the F_RI_FKEY_* defines
relate to this case.

thanks.
  brent

--
"Develop your talent, man, and leave the world something. Records are
really gifts from people. To think that an artist would love you enough
to share his music with anyone is a beautiful thing."  -- Duane Allman

Re: ALTER TABLE RENAME fix

From
Brent Verner
Date:
On 10 Nov 2001 at 23:25 (-0500), Brent Verner wrote:
| On 10 Nov 2001 at 22:42 (-0500), Tom Lane wrote:
| | Brent Verner <brent@rcfile.org> writes:
| | > exactly. which is why we've gotta inspecy the relname to determine
| | > which of the attnames to modify.
| |
| | My point is that inspecting the tgfoid is safer, because it
| | unambiguously tells you what you are looking at.  The relname is
| | inherently ambiguous because it could be the same on both sides.
|
| gotcha!  I'm digging further into how the F_RI_FKEY_* defines
| relate to this case.

Ok, I'm sending an updated patch that does not use relname at all, and
uses an indexscan (getting the Buffer Leak message was fun ;-).

cheers.
  brent

--
"Develop your talent, man, and leave the world something. Records are
really gifts from people. To think that an artist would love you enough
to share his music with anyone is a beautiful thing."  -- Duane Allman

Re: ALTER TABLE RENAME fix

From
Peter Eisentraut
Date:
Brent Verner writes:

> These patches fix the problem where an
>
>   ALTER TABLE <table> RENAME <oldcolumn> TO <newcolumn>
>
> did not update the RI_ triggers if the oldcolumn was referenced in
> a RI constraint.

Instead of trying to fix this, how about making the RI triggers not use
the column names in the first place.  (Instead they should use the oid of
the table and the attnums.)

--
Peter Eisentraut   peter_e@gmx.net


Re: ALTER TABLE RENAME fix

From
Tom Lane
Date:
Peter Eisentraut <peter_e@gmx.net> writes:
> Instead of trying to fix this, how about making the RI triggers not use
> the column names in the first place.  (Instead they should use the oid of
> the table and the attnums.)

That would probably be a better answer in the long run, but since it
implies initdb for everyone with an RI trigger, I'm disinclined to
attack it that way during beta.

            regards, tom lane

Re: ALTER TABLE RENAME fix

From
Bruce Momjian
Date:
> Peter Eisentraut <peter_e@gmx.net> writes:
> > Instead of trying to fix this, how about making the RI triggers not use
> > the column names in the first place.  (Instead they should use the oid of
> > the table and the attnums.)
>
> That would probably be a better answer in the long run, but since it
> implies initdb for everyone with an RI trigger, I'm disinclined to
> attack it that way during beta.

If that is the proper answer, maybe we should just leave it and fix it
properly in 7.3.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: ALTER TABLE RENAME fix

From
Brent Verner
Date:
On 12 Nov 2001 at 18:28 (+0100), Peter Eisentraut wrote:
| Brent Verner writes:
|
| > These patches fix the problem where an
| >
| >   ALTER TABLE <table> RENAME <oldcolumn> TO <newcolumn>
| >
| > did not update the RI_ triggers if the oldcolumn was referenced in
| > a RI constraint.
|
| Instead of trying to fix this, how about making the RI triggers not use
| the column names in the first place.  (Instead they should use the oid of
| the table and the attnums.)

I agree with you.  Two things led me toward the current approach
(modifying tgargs)
  1) it would require fewer changes to get correct behavior, which
     was important as late in beta as I started and
  2) I had /some/ idea of how to get it done ;-)

I'll begin to look at what would be required to do it the right
way for 7.3.

cheers.
  brent

--
"Develop your talent, man, and leave the world something. Records are
really gifts from people. To think that an artist would love you enough
to share his music with anyone is a beautiful thing."  -- Duane Allman

Re: ALTER TABLE RENAME fix

From
Bruce Momjian
Date:
> On 12 Nov 2001 at 18:28 (+0100), Peter Eisentraut wrote:
> | Brent Verner writes:
> |
> | > These patches fix the problem where an
> | >
> | >   ALTER TABLE <table> RENAME <oldcolumn> TO <newcolumn>
> | >
> | > did not update the RI_ triggers if the oldcolumn was referenced in
> | > a RI constraint.
> |
> | Instead of trying to fix this, how about making the RI triggers not use
> | the column names in the first place.  (Instead they should use the oid of
> | the table and the attnums.)
>
> I agree with you.  Two things led me toward the current approach
> (modifying tgargs)
>   1) it would require fewer changes to get correct behavior, which
>      was important as late in beta as I started and
>   2) I had /some/ idea of how to get it done ;-)
>
> I'll begin to look at what would be required to do it the right
> way for 7.3.

Added to TODO:

    * Make triggers refer to columns by oid, not name

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: ALTER TABLE RENAME fix

From
Stephan Szabo
Date:
On Mon, 12 Nov 2001, Brent Verner wrote:

> On 12 Nov 2001 at 18:28 (+0100), Peter Eisentraut wrote:
> | Brent Verner writes:
> |
> | > These patches fix the problem where an
> | >
> | >   ALTER TABLE <table> RENAME <oldcolumn> TO <newcolumn>
> | >
> | > did not update the RI_ triggers if the oldcolumn was referenced in
> | > a RI constraint.
> |
> | Instead of trying to fix this, how about making the RI triggers not use
> | the column names in the first place.  (Instead they should use the oid of
> | the table and the attnums.)
>
> I agree with you.  Two things led me toward the current approach
> (modifying tgargs)
>   1) it would require fewer changes to get correct behavior, which
>      was important as late in beta as I started and
>   2) I had /some/ idea of how to get it done ;-)
>
> I'll begin to look at what would be required to do it the right
> way for 7.3.

The biggest pain involved is deal with old dumps that have a create
constraint trigger with the names which would either mean we'd need
to support both for a version or have it massage the data on the
create constraint trigger if the function being specified is one of
the ri functions since I don't think its preferable to force one to
use the new dump to upgrade.


Re: ALTER TABLE RENAME fix

From
Hiroshi Inoue
Date:
Bruce Momjian wrote:
>
> > On 12 Nov 2001 at 18:28 (+0100), Peter Eisentraut wrote:
> > | Brent Verner writes:
> > |
> > | > These patches fix the problem where an
> > | >
> > | >   ALTER TABLE <table> RENAME <oldcolumn> TO <newcolumn>
> > | >
> > | > did not update the RI_ triggers if the oldcolumn was referenced in
> > | > a RI constraint.
> > |
> > | Instead of trying to fix this, how about making the RI triggers not use
> > | the column names in the first place.  (Instead they should use the oid of
> > | the table and the attnums.)
> >
> > I agree with you.  Two things led me toward the current approach
> > (modifying tgargs)
> >   1) it would require fewer changes to get correct behavior, which
> >      was important as late in beta as I started and
> >   2) I had /some/ idea of how to get it done ;-)
> >
> > I'll begin to look at what would be required to do it the right
> > way for 7.3.
>
> Added to TODO:
>
>         * Make triggers refer to columns by oid, not name

What OIDs could we use to point columns ?

Is it really a good idea to use IDs or numbers in the first place ?
We know now reference by IDs aren't necessarily good, don't we ?
It's not preferable to optimize only *rename*. IMHO this should be
considered as a part of total object-dependency mechanism.

regards,
Hiroshi Inoue

Re: ALTER TABLE RENAME fix

From
Bruce Momjian
Date:
> What OIDs could we use to point columns ?
>
> Is it really a good idea to use IDs or numbers in the first place ?
> We know now reference by IDs aren't necessarily good, don't we ?
> It's not preferable to optimize only *rename*. IMHO this should be
> considered as a part of total object-dependency mechanism.

Sorry, I should have said attribute numbers, not oid, since _Tom_
removed OID's from pg_attribute.  :-)

Good question.  Several people thought attno was the way to go and it
seemed more natural because almost everything else goes by attno and not
name.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

Re: ALTER TABLE RENAME fix

From
Tom Lane
Date:
Bruce Momjian <pgman@candle.pha.pa.us> writes:
> Good question.  Several people thought attno was the way to go and it
> seemed more natural because almost everything else goes by attno and not
> name.

Since the primary key for pg_attribute is reloid+attnum, it would seem
that that's an appropriate representation for RI trigger links too.

But Hiroshi's got a point: we have a whole set of issues with tracking
object dependencies, and it probably makes sense to think about how we
are going to deal with those issues before we fool around with changing
the representation of RI triggers.

            regards, tom lane