In connection with bug #3403
I've come to the conclusion that we really shouldn't do *any* processing
of utility commands at parse analysis time; they should be left as
raw-grammar output trees until execution.
The key reason for this is that any processing we do that is dependent
on database state might be obsolete by the time of execution, and we
don't have any infrastructure for taking locks or otherwise checking the
up-to-dateness of a utility command tree. The time delay involved could
be significant in the case of a command that is put into the plan cache
(eg, a statement in a plpgsql function), so this isn't an academic
concern. I had already foreseen this and delayed the processing of
several utility commands (eg, CREATE INDEX, CREATE RULE) until runtime
as part of the plan-cache patch; but I left CREATE TABLE and ALTER TABLE
alone, mistakenly thinking that their parse analysis work was purely
syntactic transformations and so could be done without reference to the
database state. As noted in the discussion of bug #3403, this is wrong
with respect to the processing of SERIAL-column sequences. And there's
also the matter of CREATE TABLE ... LIKE, for which the CVS-HEAD code
* Change the LIKE <subtable> portion of a CREATE TABLE statement into
* column definitions which recreate the user defined column portions of
* Note: because we do this at parse analysis time, any change in the
* referenced table between parse analysis and execution won't be reflected
* into the new table. Is this OK?
So I'm thinking we should complete the break-up and delay the processing
done by transformCreateStmt and transformAlterTableStmt until execution
of the utility command begins. In the case of ALTER TABLE we should
take out an exclusive lock on the target table before we even start to
do any of transformAlterTableStmt's work.
I had originally thought that parser/analyze.c was too intertwined to
try to break up, but upon looking more closely I find that there is
actually almost complete separation between the handling of plannable
commands and utility commands. I would like to refactor analyze.c
into two files to reflect this new understanding of when things happen:
analyze.c: keeps parse_analyze, transformStmt, and the handling of
SELECT/INSERT/UPDATE/DELETE commands, as well as EXPLAIN and DECLARE
CURSOR, which are special cases but more nearly related to plannable
commands than not.
a new file named something like parse_utilcmd.c: transformCreateStmt,
transformAlterTableStmt, transformCreateSchemaStmt, transformIndexStmt,
transformRuleStmt, and subsidiary routines. These functions would now
be called at the beginning of execution of the respective utility
commands, and not from parse_analyze() at all.
It looks like only release_pstate_resources() and makeFromExpr() are
used in common by these two files; both of them arguably belong
somewhere else anyway (parse_node.c and makefuncs.c respectively).
Also we might need to export transformStmt() from analyze.c; the
utility-command routines currently call that directly, and I'm undecided
whether they can or should go through parse_analyze() instead.
With this refactoring, there will not be any use of the
extras_before/extras_after mechanism within analyze.c, and I'm sorely
tempted to just rip it out, redeclaring parse_analyze() and friends
to return a single Query node instead of a List. Can anyone foresee
a reason we might still need to return multiple Query nodes from a
single plannable statement? (Note: "rule expansion" isn't a reason,
that happens later.)
regards, tom lane
---------------------------(end of broadcast)---------------------------
TIP 5: don't forget to increase your free space map settings