Thread: Triggers on system tables

Triggers on system tables

From
Gavin Sherry
Date:
Hi all,

I've been thinking about triggers on system tables. The motivation for
this is to allow for better interaction between the system and interfaces.
For example, interfaces could store database meta data (list of tables)
and have the cache invalidated by a trigger on pg_class (calling a
function which NOTIFYs an event, etc).

There have been a few discussions about triggers on system tables in
the past and the problems with such triggers seem to be:

1) system table modificications do not (should not) go through the
executor, where the existing trigger code works out of.

2) If we're not in the executor, there might be some state based problems
which mean that triggers cannot be run.

3) We can't (shouldn't?) hand system table data off to user land trigger
functions for manipulation

I've looked into these three problems. To solve (1) means we just have to
interface to the trigger system within low-level DDL routines. I've rigged
up a test trigger on pg_class and fired it from within
heap_create_with_catalog() and came across no problems. That's not that
say that problems don't exist, but I think any state problems can be
solved.

I think (3) is important. I think we can solve a host of problems by
looking at triggers on system tables differently. Neil has suggested
adding triggers on DDL commands as opposed to system tables. For example:

CREATE TRIGGER foo AFTER CREATE TABLE FOR EACH STATEMENT  ...

Now, because a DDL command may touch several system tables, the trigger is
not (from a user point of view) on a table as such (in reality, the
trigger would be on pg_class for this example). For this reason, we only
allow statement level triggers. This resolves the conceptual problem of
passing catalog data onto user functions as well as some potential state
problems, I think.

There'll be a few other issues. The first one that comes to mind is system
table cache invalidation inside the create/drop trigger routines if a
trigger is (effectively) being created on a system table.

Ideas, criticism?

Gavin



Re: Triggers on system tables

From
Gavin Sherry
Date:
On Thu, 12 Feb 2004, Gavin Sherry wrote:

> Hi all,
>
> I've been thinking about triggers on system tables. The motivation for
> this is to allow for better interaction between the system and interfaces.
> For example, interfaces could store database meta data (list of tables)
> and have the cache invalidated by a trigger on pg_class (calling a
> function which NOTIFYs an event, etc).
>
> There have been a few discussions about triggers on system tables in
> the past and the problems with such triggers seem to be:
>
> 1) system table modificications do not (should not) go through the
> executor, where the existing trigger code works out of.
>
> 2) If we're not in the executor, there might be some state based problems
> which mean that triggers cannot be run.
>
> 3) We can't (shouldn't?) hand system table data off to user land trigger
> functions for manipulation
>
> I've looked into these three problems. To solve (1) means we just have to
> interface to the trigger system within low-level DDL routines. I've rigged
> up a test trigger on pg_class and fired it from within
> heap_create_with_catalog() and came across no problems. That's not that
> say that problems don't exist, but I think any state problems can be
> solved.
>
> I think (3) is important. I think we can solve a host of problems by
> looking at triggers on system tables differently. Neil has suggested
> adding triggers on DDL commands as opposed to system tables. For example:
>
> CREATE TRIGGER foo AFTER CREATE TABLE FOR EACH STATEMENT  ...
>
> Now, because a DDL command may touch several system tables, the trigger is
> not (from a user point of view) on a table as such (in reality, the
> trigger would be on pg_class for this example). For this reason, we only
> allow statement level triggers. This resolves the conceptual problem of
> passing catalog data onto user functions as well as some potential state
> problems, I think.
>
> There'll be a few other issues. The first one that comes to mind is system
> table cache invalidation inside the create/drop trigger routines if a
> trigger is (effectively) being created on a system table.

I meant to add, doing it this way will give us the flexibility to avoiding
having to support system table triggers on every system table. This way,
we can just support { CREATE|ALTER|DROP } TABLE and, say, { CREATE | DROP
} TYPE if other DDLs present significant issues.

It is, of course, reasonable to want the feature supported on all DDL
commands.

>
> Ideas, criticism?
>

Gavin


Re: Triggers on system tables

From
Tom Lane
Date:
Gavin Sherry <swm@linuxworld.com.au> writes:
> There have been a few discussions about triggers on system tables in
> the past and the problems with such triggers seem to be:

I think the killer problem is that we couldn't allow triggers on system
tables to do very much.  By definition, the database is in an inconsistent
state if we are in the middle of updating system tables.  We can't allow
arbitrary bits of SQL to run then.

It might be feasible to allow AFTER triggers on system tables, since
those don't actually fire until end of statement, at which point things
are hopefully consistent again.  I don't even want to think about
allowing BEFORE triggers.
        regards, tom lane


Re: Triggers on system tables

From
Gavin Sherry
Date:
On Wed, 11 Feb 2004, Tom Lane wrote:

> Gavin Sherry <swm@linuxworld.com.au> writes:
> > There have been a few discussions about triggers on system tables in
> > the past and the problems with such triggers seem to be:
>
> I think the killer problem is that we couldn't allow triggers on system
> tables to do very much.  By definition, the database is in an inconsistent
> state if we are in the middle of updating system tables.  We can't allow
> arbitrary bits of SQL to run then.
>
> It might be feasible to allow AFTER triggers on system tables, since
> those don't actually fire until end of statement, at which point things
> are hopefully consistent again.  I don't even want to think about
> allowing BEFORE triggers.

Actually, all my tests (CREATE TABLE case) have been for
AFTER triggers as I didn't want to look at BEFORE cases either.

If the trigger is executed after all system catalog/index updates, plus
CommandCounterIncrement(), we should be consistent, right?

My idea is to provide a generic interface which is called inside
ProcessUtility() after all other functions are called for the particular
node we're handling. The nodetag itself will be passed to this generic
function, the function will map nodetag to the relevant underlying system
table, get the TriggerDesc for the relation and pass it and the relation
data onto the trigger system. CREATE will call insert triggers, ALTER will
call update triggers, DROP will call delete.

If this sounds good, I think we can deal with AFTER ... STATEMENT
level triggers without having to worry about constructing state.

Thanks,

Gavin


Re: Triggers on system tables

From
Rod Taylor
Date:
On Wed, 2004-02-11 at 22:30, Tom Lane wrote:
> Gavin Sherry <swm@linuxworld.com.au> writes:
> > There have been a few discussions about triggers on system tables in
> > the past and the problems with such triggers seem to be:
> 
> I think the killer problem is that we couldn't allow triggers on system
> tables to do very much.  By definition, the database is in an inconsistent
> state if we are in the middle of updating system tables.  We can't allow
> arbitrary bits of SQL to run then.

Yes, the internal calls from one command to another make this tricky --
but the return Tag is set very early for the statement. Could the Before
trigger for system commands (CREATE, ALTER, etc.) not be kicked of in
the same area as the tag is set?




Re: Triggers on system tables

From
Tom Lane
Date:
Gavin Sherry <swm@linuxworld.com.au> writes:
> My idea is to provide a generic interface which is called inside
> ProcessUtility() after all other functions are called for the particular
> node we're handling. The nodetag itself will be passed to this generic
> function, the function will map nodetag to the relevant underlying system
> table, get the TriggerDesc for the relation and pass it and the relation
> data onto the trigger system. CREATE will call insert triggers, ALTER will
> call update triggers, DROP will call delete.

I didn't actually much care for the "abstract event" aspect of your
proposal.  I think that that presupposes too much about what people
will want to do with such triggers.  Plus you still have to define
what data will be supplied to the trigger.  I think it's fine to make
these things be real triggers that get real row values.  We just have
to pay attention to calling them at a safe time.

One "state problem" that needs to be thought about is that many of the
system functions are implemented in a way that involves multiple steps
of updates on a single row.  (In contrast, an ordinary UPDATE command
can't change a row more than once.)  The intermediate states of these
rows are probably good examples of the sort of inconsistent data we
don't want to expose --- not only because they are inconsistent, but
because the exact intermediate states are implementation details that
are highly likely to change across versions.  Can we collapse such
events together so that the user triggers see only the initial and final
states, and not the intermediate states?
        regards, tom lane


Re: Triggers on system tables

From
Tom Lane
Date:
Rod Taylor <pg@rbt.ca> writes:
> Yes, the internal calls from one command to another make this tricky --
> but the return Tag is set very early for the statement. Could the Before
> trigger for system commands (CREATE, ALTER, etc.) not be kicked of in
> the same area as the tag is set?

At that point there wouldn't be a "new row" available to pass to the
trigger.  I'm unsure what such a trigger could usefully do.
        regards, tom lane


Re: Triggers on system tables

From
Gavin Sherry
Date:
On Wed, 11 Feb 2004, Tom Lane wrote:

> Gavin Sherry <swm@linuxworld.com.au> writes:
> > My idea is to provide a generic interface which is called inside
> > ProcessUtility() after all other functions are called for the particular
> > node we're handling. The nodetag itself will be passed to this generic
> > function, the function will map nodetag to the relevant underlying system
> > table, get the TriggerDesc for the relation and pass it and the relation
> > data onto the trigger system. CREATE will call insert triggers, ALTER will
> > call update triggers, DROP will call delete.
>
> I didn't actually much care for the "abstract event" aspect of your
> proposal.  I think that that presupposes too much about what people
> will want to do with such triggers.  Plus you still have to define
> what data will be supplied to the trigger.  I think it's fine to make
> these things be real triggers that get real row values.  We just have
> to pay attention to calling them at a safe time.

Okay then.

>
> One "state problem" that needs to be thought about is that many of the
> system functions are implemented in a way that involves multiple steps
> of updates on a single row.  (In contrast, an ordinary UPDATE command

Yeah. That's what I liked about restricting it to CREATE TABLE, etc. We
know when the state is consistent.

> can't change a row more than once.)  The intermediate states of these
> rows are probably good examples of the sort of inconsistent data we
> don't want to expose --- not only because they are inconsistent, but
> because the exact intermediate states are implementation details that
> are highly likely to change across versions.  Can we collapse such
> events together so that the user triggers see only the initial and final
> states, and not the intermediate states?

Do you have an example at hand of a system function which will face this
problem so that I can see what is involved?

Thanks,

Gavin



Re: Triggers on system tables

From
Tom Lane
Date:
Gavin Sherry <swm@linuxworld.com.au> writes:
> Do you have an example at hand of a system function which will face this
> problem so that I can see what is involved?

Mmm ... try CREATE TABLE with foreign keys.  IIRC the basic table is
created and then we do ALTER TABLE ADD FOREIGN KEY.
        regards, tom lane


Re: Triggers on system tables

From
Gavin Sherry
Date:
On Thu, 12 Feb 2004, Tom Lane wrote:

> Gavin Sherry <swm@linuxworld.com.au> writes:
> > Do you have an example at hand of a system function which will face this
> > problem so that I can see what is involved?
>
> Mmm ... try CREATE TABLE with foreign keys.  IIRC the basic table is
> created and then we do ALTER TABLE ADD FOREIGN KEY.

Ahh, of course. I misunderstood you. I was taking system 'function'
literally. CREATE TABLE by itself is bad enough. We do ALTER TABLE ADD
TOAST outside of DefineRelation().

Gavin


Re: Triggers on system tables

From
Bruce Momjian
Date:
Added to TODO:
* Allow AFTER triggers on system tables


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

Gavin Sherry wrote:
> On Thu, 12 Feb 2004, Tom Lane wrote:
> 
> > Gavin Sherry <swm@linuxworld.com.au> writes:
> > > Do you have an example at hand of a system function which will face this
> > > problem so that I can see what is involved?
> >
> > Mmm ... try CREATE TABLE with foreign keys.  IIRC the basic table is
> > created and then we do ALTER TABLE ADD FOREIGN KEY.
> 
> Ahh, of course. I misunderstood you. I was taking system 'function'
> literally. CREATE TABLE by itself is bad enough. We do ALTER TABLE ADD
> TOAST outside of DefineRelation().
> 
> Gavin
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 1: subscribe and unsubscribe commands go to majordomo@postgresql.org
> 

--  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,
Pennsylvania19073