Thread: pg_dump versus views and opclasses

pg_dump versus views and opclasses

From
"Brendan Jurd"
Date:
Hey all,

I recently had pg_dump produce a non-restorable dump for one of my
databases.  I can't share the dump itself, but I can describe what
went wrong.

This database had a user-defined composite type in it.  I wanted to be
able to GROUP BY this type, so I added a family of comparison
functions and operators, and created an opclass for btree.  Then I
created a view which grouped on the composite type.  All was well.

Then I tried to create a copy of the database.  Nothing out of the
ordinary, I just did a pg_dump and piped the results into a psql
connecting to a different database name.  The restore failed on
creation of the view; the opclass hadn't been created yet and
therefore the view couldn't figure out how to group on that composite
type.

I had a closer look at the output of pg_dump, and yes indeed, the
opclass and all its operators were listed after the view which needed
them to live.

Then I poked around in the pg_dump source code to get a better feel
for how it orders objects.  That lead me to poke around in pg_depend.
A couple of observations that might be relevant to this case:
* It seems there's no pg_depend entry for
types/functions/operators/opclasses that the view depends on, unless
they are part of the SELECT list.  I don't yet know enough about the
dependency system to understand if this is really a defect (and if so
whether there is a pratical fix for it), but it does seem a bit
limited.  If, for example, you call a user-defined operator in the
WHERE clause of a view, Postgres has no idea about that dependency.
* pg_dump queries the information from pg_depend sorting first by
classid -- the oid of the system catalog the dependent object lives
in, then by the oid of the dependent object.  I ran a similar query in
psql and the results were reminiscent of the order of objects produced
by pg_dump.  pg_opclass and pg_operator have larger oids than
pg_class, and in the absence of dependency information to guide it,
pg_dump output the view (pg_class) first, followed by the opclass.
Coincidence?

Assuming for the moment that I'm on the right track with these
hunches, it seems that pg_dump needs some help.  We could try to make
the dependency information about views more complete, in which case
everything should Just Work in pg_dump.  If that's not practical (and
perhaps even if it is practical) we could also try to give opclasses
and operators a higher default priority in the dump order than views.
This seems logical since a view can depend on an opclass, but an
opclass can't depend on a view.  At least, not directly.

So, am I on to something here, or is it just the ridiculously hot .au
weather talking?

If it would be helpful, I could write up a proper minimal test case to
demonstrate the error.  Let me know.

Cheers,
BJ


Re: pg_dump versus views and opclasses

From
Tom Lane
Date:
"Brendan Jurd" <direvus@gmail.com> writes:
> I recently had pg_dump produce a non-restorable dump for one of my
> databases.  I can't share the dump itself, but I can describe what
> went wrong. ...
>  * It seems there's no pg_depend entry for
> types/functions/operators/opclasses that the view depends on, unless
> they are part of the SELECT list.

What PG version exactly?  We've been moving towards fuller
representation of the semantics in the parse tree over time,
so that's a very relevant question.

FWIW I think this should be pretty much fixed as of CVS HEAD, because
all of the sorting/grouping semantics are now normalized in
SortGroupClauses and find_expr_references() does know about them.
Can you extract a test case from your problem DB so we can verify
nothing got missed?
        regards, tom lane


Re: pg_dump versus views and opclasses

From
"Brendan Jurd"
Date:
On Fri, Jan 16, 2009 at 9:01 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> "Brendan Jurd" <direvus@gmail.com> writes:
>>  * It seems there's no pg_depend entry for
>> types/functions/operators/opclasses that the view depends on, unless
>> they are part of the SELECT list.
>
> What PG version exactly?  We've been moving towards fuller
> representation of the semantics in the parse tree over time,
> so that's a very relevant question.
>

This is all on 8.3.3.

> FWIW I think this should be pretty much fixed as of CVS HEAD, because
> all of the sorting/grouping semantics are now normalized in
> SortGroupClauses and find_expr_references() does know about them.
> Can you extract a test case from your problem DB so we can verify
> nothing got missed?

Okay, I'll work on getting a test case together and try it against
HEAD and 8.3.5 for good measure.  I'll post the results here.

Cheers,
BJ


Re: pg_dump versus views and opclasses

From
Tom Lane
Date:
"Brendan Jurd" <direvus@gmail.com> writes:
> On Fri, Jan 16, 2009 at 9:01 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> "Brendan Jurd" <direvus@gmail.com> writes:
>>> * It seems there's no pg_depend entry for
>>> types/functions/operators/opclasses that the view depends on, unless
>>> they are part of the SELECT list.
>> 
>> What PG version exactly?

> This is all on 8.3.3.

Okay.

Looking at it some more, I notice that the SortGroupClause dependencies
are on the individual operators, which probably isn't good enough: the
operator *classes* have to exist or the parser will complain when trying
to make sense of the view.  So that would be a good thing to change for
8.4 (and it's not too late yet).  However --- it's also the case that
pg_dump should dump all operators *and* operator classes before it gets
to views.  So either you were doing something funny with the dump/reload
or else there's a circular dependency in your DB that pg_dump is
breaking in a bad place.  I look forward to the test case ;-)
        regards, tom lane


Re: pg_dump versus views and opclasses

From
"Brendan Jurd"
Date:
On Fri, Jan 16, 2009 at 10:23 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Looking at it some more, I notice that the SortGroupClause dependencies
> are on the individual operators, which probably isn't good enough: the
> operator *classes* have to exist or the parser will complain when trying
> to make sense of the view.  So that would be a good thing to change for
> 8.4 (and it's not too late yet).

I haven't come up with a stripped-down test case for this yet, but I
do have some further results to report from dumping and restoring my
database into different versions of postgres.

I wanted to check whether the problem was actually reproducible or
some freak occurence in the original database.  So I loaded my dump
(with the opclass created after the view) into a fresh 8.3.5 database.This failed to create the view as expected.  I
thenmanually created
 
the view, which worked fine because the opclass was now present.  I
then ran pg_dump on the new database and got the same results as
before.  The opclass and its operators were listed *after* the view.
So it's not just some kind of one-off weirdness, there really is a
dependency problem somewhere in here.

I'm not doing anything funny with the dump/reload.  The dump is using
the same pg_dump version as the server, with no command line options,
just the name of the database.  The reload is just piping the contents
of the dump file into psql, again the same version as the server and
no special options.

I tried the same experiment on HEAD and found something very
surprising.  The dump was loaded 100% successfully.  Note that this is
the very same dump, and it does indeed create the objects in the wrong
order.  But for some reason, HEAD doesn't seem to have a problem with
that.

This bodes well for anyone wanting to upgrade a database with such a
dependency glitch from 8.3 to 8.4 ... but I'm confused as to why 8.4
doesn't freak out when told to create a view it doesn't actually know
how to execute.  Have the rules for evaluating views changed?

Note also that after creating the database on HEAD, the pg_dump from
HEAD still outputs the objects in the wrong order.

I will continue working on getting a test case together.

Cheers,
BJ


Re: pg_dump versus views and opclasses

From
"Brendan Jurd"
Date:
On Sun, Jan 18, 2009 at 1:41 AM, Brendan Jurd <direvus@gmail.com> wrote:
> ... but I'm confused as to why 8.4
> doesn't freak out when told to create a view it doesn't actually know
> how to execute.  Have the rules for evaluating views changed?
>

Update.  Turns out that 8.4 DOES know how to execute the view.  If you
try to group on a user-defined composite type, 8.4 just goes ahead and
groups it, rather than giving the old "could not identify an ordering
operator" error.

Which renders the whole idea of creating my own opclass for the type
very much bunk.

What sorcery is this?  Does 8.4 add some kind of default ordering
strategy for composite types?

Cheers,
BJ


Re: pg_dump versus views and opclasses

From
Tom Lane
Date:
"Brendan Jurd" <direvus@gmail.com> writes:
> Update.  Turns out that 8.4 DOES know how to execute the view.  If you
> try to group on a user-defined composite type, 8.4 just goes ahead and
> groups it, rather than giving the old "could not identify an ordering
> operator" error.

Is there a hash opclass for the type?  8.4 can group types that have
hash but not btree opclasses, but prior versions insisted on btree.
        regards, tom lane


Re: pg_dump versus views and opclasses

From
"Brendan Jurd"
Date:
On Sun, Jan 18, 2009 at 2:52 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> "Brendan Jurd" <direvus@gmail.com> writes:
>> Update.  Turns out that 8.4 DOES know how to execute the view.  If you
>> try to group on a user-defined composite type, 8.4 just goes ahead and
>> groups it, rather than giving the old "could not identify an ordering
>> operator" error.
>
> Is there a hash opclass for the type?  8.4 can group types that have
> hash but not btree opclasses, but prior versions insisted on btree.

Well I sure didn't create one.  I've only been attempting to create a
btree opclass.  Is there some kind of default hash opclass for
composites?

Cheers,
BJ


Re: pg_dump versus views and opclasses

From
Tom Lane
Date:
"Brendan Jurd" <direvus@gmail.com> writes:
> On Sun, Jan 18, 2009 at 2:52 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Is there a hash opclass for the type?  8.4 can group types that have
>> hash but not btree opclasses, but prior versions insisted on btree.

> Well I sure didn't create one.  I've only been attempting to create a
> btree opclass.  Is there some kind of default hash opclass for
> composites?

No ... but after poking around in the system catalogs I notice there
*is* a default btree opclass for composites, as of 8.4 ...
        regards, tom lane


Re: pg_dump versus views and opclasses

From
"Brendan Jurd"
Date:
On Fri, Jan 16, 2009 at 10:23 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> However --- it's also the case that
> pg_dump should dump all operators *and* operator classes before it gets
> to views.  So either you were doing something funny with the dump/reload
> or else there's a circular dependency in your DB that pg_dump is
> breaking in a bad place.  I look forward to the test case ;-)

Okay, here's the test case.  The attached file
test-view-opclass-deps.sql creates a simple database with a
user-defined composite type "comp", which consists of two integers
called "a" and "b".

It then puts together a simple btree opclass for that that type and
fills a table "stuff" with some generated values for the type.

It then creates a view "group_stuff" which groups on the type.

If you dump out the database, the view will be listed after the type,
but *before* the opclass and all its component operators and
underlying functions.  I've attached a copy of the faulty dump file
for reference.

If you try to load that dump, the view won't be created.

To reproduce the error on 8.3.5:

$ psql -f test-view-opclass-deps.sql postgres
$ psql -c "create database test_view_opclass_deps2;" postgres
$ pg_dump test_view_opclass_deps | psql test_view_opclass_deps2

On HEAD, the dump is still screwy, but in a slightly different way.
It lists the type first, followed by the = and <= operators, then the
table and the view, and finally the remainder of the operators and the
opclass.

If you load the dump into an 8.4 server, the view gets created without
error because 8.4 has a default btree opclass, so the order of objects
in the dump isn't important -- at least not with regard to this
particular scenario.  But I still find it a bit disturbing that the
order of objects in the 8.4 dump is so bizarre.  Why the special
treatment for = and <=?

Cheers,
BJ

Attachment

Re: pg_dump versus views and opclasses

From
Tom Lane
Date:
"Brendan Jurd" <direvus@gmail.com> writes:
> On Fri, Jan 16, 2009 at 10:23 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> However --- it's also the case that
>> pg_dump should dump all operators *and* operator classes before it gets
>> to views.  So either you were doing something funny with the dump/reload
>> or else there's a circular dependency in your DB that pg_dump is
>> breaking in a bad place.  I look forward to the test case ;-)

> Okay, here's the test case.

Interesting --- it works as expected in 8.2.  The problem seems to have
been created by the introduction of arrays over composites in 8.3.
Although those array types don't get dumped separately, they still have
to participate in pg_dump's dependency sort (since they might form part
of dependency arcs).  pg_dump initially sorts them as if they are
ordinary types, which puts them pretty high up in the dependency order,
and then the tables or composite types that they depend on also get
pushed forward in the ordering.  (The topological sort for dependencies
basically causes items to get pushed forward to before anything that
depends on them; nothing ever moves backward.)

I'm surprised nobody noticed before that 8.3 is emitting considerably
different object ordering from 8.2.  In particular this mostly destroys
the intended behavior that operators and operator classes come out
before table definitions.

The right fix seems to be to treat auto-generated array types the same
way pg_dump already treats auto-generated table types, ie, mark them
with a different DumpableObject type code that causes them to sort much
lower in the initial ordering.  Fortunately, this is also a
back-patchable fix, since it's entirely internal to pg_dump.  I've got
some social obligations today but I'll have a patch in a day or so.

I'm thinking that adding operator family info to SortGroupClause in
HEAD might be a good thing too, but it is for a different issue than
this --- it's to prevent you dropping a family that a view has a
semantic dependency on.  However there might be room for a bit of
argument there: if there's both a btree and a hash opfamily then
the view could use either, so preventing you dropping one would be
a bit arbitrary.  In any case it wouldn't stop you doing an ALTER
OPERATOR FAMILY to remove the sort operators from the family, so
maybe there's not much point here.  Thoughts?
        regards, tom lane


Re: pg_dump versus views and opclasses

From
"Brendan Jurd"
Date:
On Sun, Jan 18, 2009 at 5:56 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Interesting --- it works as expected in 8.2.  The problem seems to have
> been created by the introduction of arrays over composites in 8.3.

Congratulations on identifying the source!

Does this also explain the extra-weird output from HEAD, with the <=
and = operators sorting earlier than the view, but the rest of the
operators sorting after it?

> I'm surprised nobody noticed before that 8.3 is emitting considerably
> different object ordering from 8.2.

Well I can't speak for anybody else, but I have noticed changes to the
dump order in the past, but I dismissed it as something that Just
Happens in a major release and got on with my life =).  I've long
since accepted that you can't expect dumps to be directly comparable
over the long term.

Plus, the difference in object ordering only manifests with composite
types, and that's probably something that only a slim portion of users
are actually playing with.

> In particular this mostly destroys
> the intended behavior that operators and operator classes come out
> before table definitions.

Yeah, that seems like a generally sane intention.

> The right fix seems to be to treat auto-generated array types the same
> way pg_dump already treats auto-generated table types, ie, mark them
> with a different DumpableObject type code that causes them to sort much
> lower in the initial ordering.

Sounds good.

> I'm thinking that adding operator family info to SortGroupClause in
> HEAD might be a good thing too, but it is for a different issue than
> this --- it's to prevent you dropping a family that a view has a
> semantic dependency on.  However there might be room for a bit of
> argument there: if there's both a btree and a hash opfamily then
> the view could use either, so preventing you dropping one would be
> a bit arbitrary.

Not to mention that, with the new default btree opclass in 8.4 that I
stumbled across earlier, dropping an opclass that a view uses may not
necessarily murder the view ... it may simply cause it to fall back to
the default opclass.  If falling back to the default opclass was
actually what the user wanted to achieve by dropping the user-defined
opclass, a dependency such as you describe might leave him with no way
to do that.

Worst case scenario is that you drop an opclass which causes a view to
die, and next time you try to run the view you get an intelligible
error message telling you why it doesn't work anymore.  That's
probably not the end of the world.

> In any case it wouldn't stop you doing an ALTER
> OPERATOR FAMILY to remove the sort operators from the family, so
> maybe there's not much point here.  Thoughts?

Honestly, I feel that messing around with operator classes is
something that doesn't happen with any great frequency, and you need
to be careful and hands-on when you're doing it anyway.  I could live
without the dependency.

Cheers,
BJ


Re: pg_dump versus views and opclasses

From
Tom Lane
Date:
"Brendan Jurd" <direvus@gmail.com> writes:
> Does this also explain the extra-weird output from HEAD, with the <=
> and = operators sorting earlier than the view, but the rest of the
> operators sorting after it?

No, that comes from the fact that we have dependencies on those two
operators (but not the whole opclass) in SortGroupClause.  So they
get forced to come out before the view, but the rest do not.
        regards, tom lane


Re: pg_dump versus views and opclasses

From
Tom Lane
Date:
"Brendan Jurd" <direvus@gmail.com> writes:
> On Sun, Jan 18, 2009 at 5:56 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Interesting --- it works as expected in 8.2.  The problem seems to have
>> been created by the introduction of arrays over composites in 8.3.

> Congratulations on identifying the source!

I've applied a patch for this to HEAD and 8.3.

>> I'm thinking that adding operator family info to SortGroupClause in
>> HEAD might be a good thing too, but it is for a different issue than
>> this --- it's to prevent you dropping a family that a view has a
>> semantic dependency on.  However there might be room for a bit of
>> argument there: if there's both a btree and a hash opfamily then
>> the view could use either, so preventing you dropping one would be
>> a bit arbitrary.

> Not to mention that, with the new default btree opclass in 8.4 that I
> stumbled across earlier, dropping an opclass that a view uses may not
> necessarily murder the view ... it may simply cause it to fall back to
> the default opclass.  If falling back to the default opclass was
> actually what the user wanted to achieve by dropping the user-defined
> opclass, a dependency such as you describe might leave him with no way
> to do that.

> Worst case scenario is that you drop an opclass which causes a view to
> die, and next time you try to run the view you get an intelligible
> error message telling you why it doesn't work anymore.  That's
> probably not the end of the world.

True.  I'll leave well enough alone for the moment, unless someone
comes up with additional arguments.
        regards, tom lane


Re: pg_dump versus views and opclasses

From
"Brendan Jurd"
Date:
On Mon, Jan 19, 2009 at 7:47 AM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> I've applied a patch for this to HEAD and 8.3.
>

Cool, thanks Tom.

Just noting that I've tested your fix on both branches, and in both
cases pg_dump's output came out nice, clean and consistent.

Cheers,
BJ