BUG #16909: On update (not insert) the attisdropped flag is set for tables which are recreated with the same col

Started by PG Bug reporting formabout 5 years ago4 messagesbugs
Jump to latest
#1PG Bug reporting form
noreply@postgresql.org

The following bug has been logged on the website:

Bug reference: 16909
Logged by: Grumpylittleted
Email address: grumpylittleted@googlemail.com
PostgreSQL version: 13.2
Operating system: Linux 5.8.0-44-generic #50~20.04.1-Ubuntu S
Description:

/*

BUG:

Using 13.2
On update (not insert) the attisdropped flag is set for tables which are
recreated with the same column names as the original but where preceding
columns have been dropped

METHOD:
Create a table t with more than two columns: x, y, z
Drop that table
Create a table t with a subset of the columns with the same name as the
previous table: here we remove y
Insert a new row: there are two attributes (correct), neither of which
have the attisdropped flag set (correct) (so bug not apparent with
inserts)
Update the row: there are two attributes (correct), the first attribute
has the attisdropped flag unset (correct) BUT the second attribute has the
attisdropped flag set (incorrect)

make
sudo cp ./f.so `pg_config --pkglibdir`

SQL:

create or replace function f() returns trigger as './f.so','f' language c
strict;

drop table if exists t cascade;
create table t(x int, y int, z int);

drop table t cascade;
create table t(x int, z int);
create trigger tf before insert or update on t for each row execute
procedure f();
insert into t values(4,5); -- attr num=1 attisdropped=0
update t set x=2;

*/

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include "postgres.h"
#include "fmgr.h"
#include "executor/spi.h"
#include "commands/trigger.h"
#include "utils/rel.h"
#include "utils/fmgrprotos.h"

PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1( f );
Datum f( PG_FUNCTION_ARGS ) {

TriggerData *trigdata = ( TriggerData * ) fcinfo->context;
const TupleDesc tupdesc = trigdata->tg_relation->rd_att;
HeapTuple tuple = TRIGGER_FIRED_BY_UPDATE( trigdata->tg_event ) ?
trigdata->tg_newtuple : trigdata->tg_trigtuple;

for( int i = 1; i <= tupdesc->natts; i++ ) {
elog( INFO, "attr num=%d attisdropped=%d", i, TupleDescAttr( tupdesc, i
)->attisdropped );
}

return PointerGetDatum( tuple );

}

#2Hamid Akhtar
hamid.akhtar@gmail.com
In reply to: PG Bug reporting form (#1)
Re: BUG #16909: On update (not insert) the attisdropped flag is set for tables which are recreated with the same col

Can you please share the complete output?

Seems like a false alarm per my testing.

On Tue, Mar 2, 2021 at 3:58 PM PG Bug reporting form <noreply@postgresql.org>
wrote:

Show quoted text

The following bug has been logged on the website:

Bug reference: 16909
Logged by: Grumpylittleted
Email address: grumpylittleted@googlemail.com
PostgreSQL version: 13.2
Operating system: Linux 5.8.0-44-generic #50~20.04.1-Ubuntu S
Description:

/*

BUG:

Using 13.2
On update (not insert) the attisdropped flag is set for tables which are
recreated with the same column names as the original but where preceding
columns have been dropped

METHOD:
Create a table t with more than two columns: x, y, z
Drop that table
Create a table t with a subset of the columns with the same name as the
previous table: here we remove y
Insert a new row: there are two attributes (correct), neither of which
have the attisdropped flag set (correct) (so bug not apparent with
inserts)
Update the row: there are two attributes (correct), the first attribute
has the attisdropped flag unset (correct) BUT the second attribute has the
attisdropped flag set (incorrect)

make
sudo cp ./f.so `pg_config --pkglibdir`

SQL:

create or replace function f() returns trigger as './f.so','f' language c
strict;

drop table if exists t cascade;
create table t(x int, y int, z int);

drop table t cascade;
create table t(x int, z int);
create trigger tf before insert or update on t for each row execute
procedure f();
insert into t values(4,5); -- attr num=1 attisdropped=0
update t set x=2;

*/

#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include "postgres.h"
#include "fmgr.h"
#include "executor/spi.h"
#include "commands/trigger.h"
#include "utils/rel.h"
#include "utils/fmgrprotos.h"

PG_MODULE_MAGIC;
PG_FUNCTION_INFO_V1( f );
Datum f( PG_FUNCTION_ARGS ) {

TriggerData *trigdata = ( TriggerData * ) fcinfo->context;
const TupleDesc tupdesc = trigdata->tg_relation->rd_att;
HeapTuple tuple = TRIGGER_FIRED_BY_UPDATE( trigdata->tg_event ) ?
trigdata->tg_newtuple : trigdata->tg_trigtuple;

for( int i = 1; i <= tupdesc->natts; i++ ) {
elog( INFO, "attr num=%d attisdropped=%d", i, TupleDescAttr( tupdesc, i
)->attisdropped );
}

return PointerGetDatum( tuple );

}

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: PG Bug reporting form (#1)
Re: BUG #16909: On update (not insert) the attisdropped flag is set for tables which are recreated with the same col

PG Bug reporting form <noreply@postgresql.org> writes:

On update (not insert) the attisdropped flag is set for tables which are
recreated with the same column names as the original but where preceding
columns have been dropped

I think this is just faulty C code.

for( int i = 1; i <= tupdesc->natts; i++ ) {
elog( INFO, "attr num=%d attisdropped=%d", i, TupleDescAttr( tupdesc, i
)->attisdropped );
}

The index argument of TupleDescAttr needs to run from 0 to natts-1.
As coded, this is fetching off the end of the array and getting garbage.

The mistake might've been more obvious if you'd tried to print any
non-boolean fields of the tupledesc.

regards, tom lane

#4Grumpy LittleTed
grumpylittleted@gmail.com
In reply to: Tom Lane (#3)
Re: BUG #16909: On update (not insert) the attisdropped flag is set for tables which are recreated with the same col

Thanks Tom, that explains it.

I had seen the use of attisdropped elsewhere, thought I'd better check it
and assumed that the TupleDescAttr was 1 based, like the SPI functions,
rather than 0 based. I have now gone into the code and it does indeed have
a comment /* attrs[N] is the description of Attribute Number N+1 */

It also explains why Hamid got different results. Sorry to raise a false
alarm.

On Tue, 2 Mar 2021 at 15:40, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Show quoted text

PG Bug reporting form <noreply@postgresql.org> writes:

On update (not insert) the attisdropped flag is set for tables which

are

recreated with the same column names as the original but where preceding
columns have been dropped

I think this is just faulty C code.

for( int i = 1; i <= tupdesc->natts; i++ ) {
elog( INFO, "attr num=%d attisdropped=%d", i, TupleDescAttr(

tupdesc, i

)->attisdropped );
}

The index argument of TupleDescAttr needs to run from 0 to natts-1.
As coded, this is fetching off the end of the array and getting garbage.

The mistake might've been more obvious if you'd tried to print any
non-boolean fields of the tupledesc.

regards, tom lane