I was able to reproduce the problem complained of here
http://archives.postgresql.org/pgsql-bugs/2007-11/msg00322.php
with this function:

create or replace function foo() returns int as $$
declare r int;
begin
  drop table if exists temptable cascade;
  create temp table temptable as select * from generate_series(1,4) f1;
  create temp view vv as select * from temptable;
--  perform 2+2;
  for r in select * from vv loop
    raise notice '%', r;
  end loop;
  return 0;
end$$ language plpgsql;

regression=# select foo();
NOTICE:  table "temptable" does not exist, skipping
CONTEXT:  SQL statement "drop table if exists temptable cascade"
PL/pgSQL function "foo" line 3 at SQL statement
NOTICE:  1
NOTICE:  2
NOTICE:  3
NOTICE:  4
 foo 
-----
   0
(1 row)

regression=# select foo();
NOTICE:  drop cascades to rule _RETURN on view vv
CONTEXT:  SQL statement "drop table if exists temptable cascade"
PL/pgSQL function "foo" line 3 at SQL statement
NOTICE:  drop cascades to view vv
CONTEXT:  SQL statement "drop table if exists temptable cascade"
PL/pgSQL function "foo" line 3 at SQL statement
ERROR:  could not open relation 1663/121218/145930: No such file or directory
CONTEXT:  PL/pgSQL function "foo" line 7 at FOR over SELECT rows


The problem goes away if there's any SQL action between the CREATE VIEW
and the FOR command, eg if you uncomment the PERFORM shown above.
What is happening is that the last step of CREATE VIEW, namely
DefineViewRules(), isn't visible at the time we try to re-validate
the cached plan for the FOR command, because no CommandCounterIncrement
has happened between.  So the plan gets regenerated as a simple seqscan
of the view relation, which of course fails for lack of any underlying
storage.

This is not CREATE VIEW's fault, since no utility command expects that
it should do a final CommandCounterIncrement (henceforth CCI)
internally; CCI calls are supposed to be done between commands by system
control logic when needed.  Moreover inserting a CCI at the end of
DefineView would only fix this particular manifestation, and not other
cases of DDL immediately before re-use of a plan.

One fairly simple answer is to insert a CCI call at the start of
RevalidateCachedPlan.  I dislike that solution, at least by itself,
on two grounds:

* A patch of that form would approximately double the number of CCI
calls involved in executing a plpgsql function; which quite aside from
any performance cost would halve the distance to the
2^32-commands-per-transaction horizon.  We've already heard from people
who ran into that limit, so I don't want to bring it closer.

* This would result in executing CCI calls even during stable/immutable
PL functions.  I'm not sure that would have any bad semantic side-effects,
but I'm not convinced it wouldn't, either.  And it also gives back
whatever command count limit savings we bought when we fixed things
so that stable/immutable functions don't call CCI.

I've also thought about rearranging the current conventions for where to
call CCI.  This particular form of the problem would go away if SPI
command execution did CCI after, instead of before, each non-read-only
command.  Or perhaps safer, before each such command and after the last
one.  I'm a bit worried though about whether that leaves any code paths
in which we're still missing a needed CCI.

An idea we could use in combination with either of the above is to make
command ID assignment "lazy" in a similar sense to what we did for XID
assignment recently; that is, fix things so that CCI is a no-op if
no database change actually happened since the last one.  This would
greatly reduce the command-limit disadvantages of having a scheme that
executes "unnecessary" CCI's.

Comments, better ideas?

                        regards, tom lane

---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

Reply via email to