Thread: attislocal value changed with dump

attislocal value changed with dump

From
elein
Date:
The problem is that after a dump and reload of
a table hierarchy there are different values in
pg_attribute.attislocal.

A quick grep shows few references to attislocal.
But I cannot say for sure it is unused since it is
documented.  However, I'm looking at a db diff
tool and there it does matter.

This is the setup:

I've got an inheritance hierarchy, answer_values
with a bunch of answer_[type] tables inheriting
from it.

tiny=# \d answer_values
                            Table "public.answer_values"
 Column |  Type   |                            Modifiers
--------+---------+-----------------------------------------------------------------
 orid   | integer | not null
 qid    | integer | not null
 avid   | integer | not null default nextval('public.answer_values_avid_seq'::text)
 atype  | text    |
 ncols  | integer |
Indexes:
    "answer_values_pkey" PRIMARY KEY, btree (orid, qid, avid)

tiny=# \d answer_text
                         Table "public.answer_text"
 Column |  Type   |                        Modifiers
--------+---------+----------------------------------------------------------
 orid   | integer | not null
 qid    | integer | not null
 avid   | integer | not null default nextval('answer_values_avid_seq'::text)
 atype  | text    |
 ncols  | integer |
 avalue | text    |
Indexes:
    "answer_text_pk" UNIQUE, btree (avid)
Inherits: answer_values


* In 8.0.4,
* created a clean db (tiny) and loaded the SQL to define the hierarchy.
* pg_dump tiny > tiny.dat
* createdb tiny2
* psql < tiny.dat

After this, looking at the 'avid' attribute in the
pg_attribute table all of tables loaded in the second
db have 't' for attislocal.  This is different from
the original definition.


tiny=# select r.relname, attname, attislocal, attinhcount from pg_attribute a join pg_class r ON (a.attrelid = r.oid)
whereattname = 'avid' order by relname; 
       relname        | attname | attislocal | attinhcount
----------------------+---------+------------+-------------
 answer_addr          | avid    | f          |           1
 answer_addr_pk       | avid    | t          |           0
 answer_bool_pk       | avid    | t          |           0
 answer_boolean       | avid    | f          |           1
 answer_date          | avid    | f          |           1
 answer_date_pk       | avid    | t          |           0
 answer_date_range    | avid    | f          |           1
 answer_dater_pk      | avid    | t          |           0
 answer_float         | avid    | f          |           1
 answer_flt_pk        | avid    | t          |           0
 answer_num_pk        | avid    | t          |           0
 answer_numeric       | avid    | f          |           1
 answer_numeric_range | avid    | f          |           1
 answer_numr_pk       | avid    | t          |           0
 answer_text          | avid    | f          |           1
 answer_text_pk       | avid    | t          |           0
 answer_values        | avid    | t          |           0
 answer_values_pkey   | avid    | t          |           0
 av_v                 | avid    | t          |           0
(19 rows)

tiny2=# select r.relname, attname, attislocal, attinhcount from pg_attribute a join pg_class r ON (a.attrelid = r.oid)
whereattname = 'avid' order by relname; 
       relname        | attname | attislocal | attinhcount
----------------------+---------+------------+-------------
 answer_addr          | avid    | t          |           1
 answer_addr_pk       | avid    | t          |           0
 answer_bool_pk       | avid    | t          |           0
 answer_boolean       | avid    | t          |           1
 answer_date          | avid    | t          |           1
 answer_date_pk       | avid    | t          |           0
 answer_date_range    | avid    | t          |           1
 answer_dater_pk      | avid    | t          |           0
 answer_float         | avid    | t          |           1
 answer_flt_pk        | avid    | t          |           0
 answer_num_pk        | avid    | t          |           0
 answer_numeric       | avid    | t          |           1
 answer_numeric_range | avid    | t          |           1
 answer_numr_pk       | avid    | t          |           0
 answer_text          | avid    | t          |           1
 answer_text_pk       | avid    | t          |           0
 answer_values        | avid    | t          |           0
 answer_values_pkey   | avid    | t          |           0
 av_v                 | avid    | t          |           0
(19 rows)


----- End forwarded message -----

Re: attislocal value changed with dump

From
Alvaro Herrera
Date:
Hi Elein,

elein wrote:

> The problem is that after a dump and reload of
> a table hierarchy there are different values in
> pg_attribute.attislocal.
>
> A quick grep shows few references to attislocal.
> But I cannot say for sure it is unused since it is
> documented.  However, I'm looking at a db diff
> tool and there it does matter.

It's not unused, though it's not a hot spot (it's only used to prevent
you from dropping an inherited column).  I can't reproduce your problem
here though -- the dump comes out just like the tables I produced.  Care
to provide the original SQL script?

--
Alvaro Herrera                                http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.

Re: attislocal value changed with the dump

From
elein
Date:
This is the repro with the sql file below.

createdb bug1
psql bug1 < qna.sql
pg_dump bug1 > bug1.sql
createdb bug2
psql bug2 < bug1.sql

psql bug1
=# select r.relname, attname, attislocal, attinhcount from pg_attribute a join pg_class r ON (a.attrelid = r.oid) where
attname= 'avid' order by relname; 
...output omitted...
=# \c bug2
=# select r.relname, attname, attislocal, attinhcount from pg_attribute a join pg_class r ON (a.attrelid = r.oid) where
attname= 'avid' order by relname; 
...output omitted but shows all columns as local...


I'm running 8.0.4 by the way.

The problem may be with the addition of
default values and indexes on the inherited
columns.  It may assume that because we
are altering the column and/or adding an
index on the inherited columns then the
column is local.

--elein

---- =====
--
-- == CLEAN UP ==
--
drop table askers cascade;
drop table answerers cascade;
drop table questions cascade;
drop table asker_questions cascade;
drop table answer_values cascade;
drop table answer_numeric cascade;
drop table answer_date cascade;
drop table answer_boolean cascade;
drop table answer_float cascade;
drop table answer_text cascade;
drop table answer_date_2 cascade;
drop table answer_numeric_2 cascade;
drop table answers cascade;
drop table atypes cascade;

--
-- == TABLES ==
--
create table askers (
    fid    SERIAL PRIMARY KEY,
    fname    text
);

create table answerers (
    orid    SERIAL PRIMARY KEY,
    orname    text
);

create table atypes (
    atype    text ,
    ncols    smallint,
    PRIMARY KEY (atype, ncols)
);

create table questions (
    qid        SERIAL PRIMARY KEY,
    question    text,
    atype        text,
    ncols        integer,
    FOREIGN KEY (atype, ncols) references atypes (atype, ncols)
);


create table asker_questions (
    fid    integer REFERENCES askers (fid),
    qid    integer REFERENCES questions (qid),
    fset    text,
    PRIMARY KEY (fid, qid, fset)
);

create table answer_values (
    orid    integer REFERENCES answerers (orid),
    qid    integer REFERENCES questions (qid),
    avid    SERIAL,
    atype    text,
    ncols    integer,
    PRIMARY KEY (orid, qid, avid),
    FOREIGN KEY (atype, ncols) references atypes (atype,ncols)
);

--
-- == CHILDREN ANSWER TABLES ==
--
create table answer_numeric (
    avalue    numeric
) inherits (answer_values) ;
alter table answer_numeric alter column avid  set default nextval('answer_values_avid_seq');
create unique index answer_num_pk on answer_numeric (avid);

create table answer_date (
    avalue    date
) inherits (answer_values) ;
alter table answer_date alter column avid  set default nextval('answer_values_avid_seq');
create unique index answer_date_pk on answer_date (avid);

create table answer_boolean (
    avalue    boolean
) inherits (answer_values) ;
alter table answer_boolean alter column avid  set default nextval('answer_values_avid_seq');
create unique index answer_bool_pk on answer_boolean (avid);

create table answer_float (
    avalue    float
) inherits (answer_values) ;
alter table answer_float alter column avid  set default nextval('answer_values_avid_seq');
create unique index answer_flt_pk on answer_float (avid);

create table answer_text (
    avalue    text
) inherits (answer_values) ;
alter table answer_text alter column avid  set default nextval('answer_values_avid_seq');
create unique index answer_text_pk on answer_text (avid);

create table answer_date_2 (
    astart    date,
    aend    date
) inherits (answer_values) ;
alter table answer_date_2 alter column avid  set default nextval('answer_values_avid_seq');
create unique index answer_dater_pk on answer_date_2 (avid);

create table answer_numeric_2 (
    astart    numeric,
    aend    numeric
) inherits (answer_values) ;
create unique index answer_numr_pk on answer_numeric_2 (avid);
alter table answer_numeric_2 alter column avid  set default nextval('answer_values_avid_seq');

create table answer_addr (
    addr    text,
    city    text,
    state    char(2),
    zip    text
) inherits (answer_values) ;
alter table answer_addr alter column avid  set default nextval('answer_values_avid_seq');
create unique index answer_addr_pk on answer_addr (avid);

Re: attislocal value changed with the dump

From
Tom Lane
Date:
elein <elein@varlena.com> writes:
> This is the repro with the sql file below.

FWIW, this seems to work as expected with 8.1.  Don't have time to try
it with 8.0 right now, but it may be an already-solved issue ...

            regards, tom lane

Re: attislocal value changed with the dump

From
Tom Lane
Date:
elein <elein@varlena.com> writes:
> This is the repro with the sql file below.

I looked into this, and the answer is you're doing it to yourself;
you shouldn't be explicitly re-specifying the defaults for the child
columns.

> create table answer_numeric (
>     avalue    numeric
> ) inherits (answer_values) ;
> alter table answer_numeric alter column avid  set default nextval('answer_values_avid_seq');

It's unnecessary to have that "alter column set default" command,
because avid will have inherited the default expression from the parent
anyway.  The reason that setting it changes pg_dump's output is that
what you are setting is not quite right: the actual default expression
in the parent is
    nextval('public.answer_values_avid_seq')
Since that's different, pg_dump concludes that the child's default is
non-inherited and emits a redefinition of the column.

The reason I didn't see the same behavior in CVS tip is that now that
we use regclass literals for nextval() arguments, the changed default
still lists out the same way as the parent's default, and so pg_dump
thinks it's an inherited default.

It strikes me that there is still a risk here, which is that because
listing of regclass values is search-path-sensitive, pg_dump could
come to the wrong conclusion about the inheritance of a default when
the child is in a different schema than the parent.  We could probably
fix that by comparing adbin strings instead of the reverse-compiled
expressions to decide if a child default matches its parent or not.

Alternatively, maybe we should add explicit inheritance information
to pg_attrdef.  There's already a proposal to do that for constraints...

            regards, tom lane

Re: attislocal value changed with the dump

From
Bruce Momjian
Date:
Is there a TODO here?

---------------------------------------------------------------------------

Tom Lane wrote:
> elein <elein@varlena.com> writes:
> > This is the repro with the sql file below.
>
> I looked into this, and the answer is you're doing it to yourself;
> you shouldn't be explicitly re-specifying the defaults for the child
> columns.
>
> > create table answer_numeric (
> >     avalue    numeric
> > ) inherits (answer_values) ;
> > alter table answer_numeric alter column avid  set default nextval('answer_values_avid_seq');
>
> It's unnecessary to have that "alter column set default" command,
> because avid will have inherited the default expression from the parent
> anyway.  The reason that setting it changes pg_dump's output is that
> what you are setting is not quite right: the actual default expression
> in the parent is
>     nextval('public.answer_values_avid_seq')
> Since that's different, pg_dump concludes that the child's default is
> non-inherited and emits a redefinition of the column.
>
> The reason I didn't see the same behavior in CVS tip is that now that
> we use regclass literals for nextval() arguments, the changed default
> still lists out the same way as the parent's default, and so pg_dump
> thinks it's an inherited default.
>
> It strikes me that there is still a risk here, which is that because
> listing of regclass values is search-path-sensitive, pg_dump could
> come to the wrong conclusion about the inheritance of a default when
> the child is in a different schema than the parent.  We could probably
> fix that by comparing adbin strings instead of the reverse-compiled
> expressions to decide if a child default matches its parent or not.
>
> Alternatively, maybe we should add explicit inheritance information
> to pg_attrdef.  There's already a proposal to do that for constraints...
>
>             regards, tom lane
>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: In versions below 8.0, the planner will ignore your desire to
>        choose an index scan if your joining column's datatypes do not
>        match
>

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073