Truncate Triggers

Started by Simon Riggsabout 18 years ago36 messageshackers
Jump to latest
#1Simon Riggs
simon@2ndQuadrant.com

(for 8.4 ...)
I'd like to introduce triggers that fire when we issue a truncate:

CREATE TRIGGER name [BEFORE | AFTER ] TRUNCATE ON table
FOR EACH STATEMENT EXECUTE PROCEDURE function (arguments);

The truncate trigger would fire separately from a statement-level DELETE
statement, to allow us to distinguish those two events. There would be
nothing to stop both triggers executing the same function however, if
desired.

COPY already provides a model for how a utility command can execute
triggers. tablecmds.c would invoke ExecBSTruncateTriggers() and
ExecASTruncateTriggers(), both of which would live in triggers.c

There doesn't seem much too difficult about the implementation or
behaviour, but I want to make sure we have the discussion at least, to
see if anybody has concerns or additional requirements.

Notes: As the syntax shows, these would be statement-level triggers
(only). Requesting row level triggers will cause an error. [As Chris
Browne explained, if people really want, they can use these facilities
to create a Before Statement trigger that executes a DELETE, which then
fires row level calls.]

I also plan to add a TRUNCATE privilege, though that will be a separate
patch in a later post. That will widen the use case of TRUNCATE, which
should be OK to do once we've covered the replication concerns.

--
Simon Riggs
2ndQuadrant http://www.2ndQuadrant.com

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: Simon Riggs (#1)
Re: Truncate Triggers

Simon Riggs <simon@2ndquadrant.com> writes:

Notes: As the syntax shows, these would be statement-level triggers
(only). Requesting row level triggers will cause an error. [As Chris
Browne explained, if people really want, they can use these facilities
to create a Before Statement trigger that executes a DELETE, which then
fires row level calls.]

Is there a way for a BS trigger to return a flag "skip the statement",
as there is for BR?

I also plan to add a TRUNCATE privilege, though that will be a separate
patch in a later post. That will widen the use case of TRUNCATE, which
should be OK to do once we've covered the replication concerns.

Considering it's not MVCC-safe, do we *want* to widen the use case?

There are way too many table privilege bits already; to add more you
need something a lot stronger than a "might be nice" argument.

regards, tom lane

#3Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Simon Riggs (#1)
Re: Truncate Triggers

On Fri, Jan 25, 2008 at 11:40:19AM +0000, Simon Riggs wrote:

(for 8.4 ...)
I'd like to introduce triggers that fire when we issue a truncate:

Rather than focusing exclusively on TRUNCATE, how about "triggers" that
fire whenever any kind of DDL operation is performed? (Ok, truncate is
more DML than DDL, but still).

The reason I put triggers in quotes is because I'm not suggesting that
we actually put triggers on the catalog tables, since we all know that's
hard/impossible. Instead this would have to tie into command processing,
similar to what you're proposing for truncate.
--
Decibel!, aka Jim C. Nasby, Database Architect decibel@decibel.org
Give your computer some brain candy! www.distributed.net Team #1828

#4Simon Riggs
simon@2ndQuadrant.com
In reply to: Tom Lane (#2)
Re: Truncate Triggers

On Fri, 2008-01-25 at 10:44 -0500, Tom Lane wrote:

Simon Riggs <simon@2ndquadrant.com> writes:

Notes: As the syntax shows, these would be statement-level triggers
(only). Requesting row level triggers will cause an error. [As Chris
Browne explained, if people really want, they can use these facilities
to create a Before Statement trigger that executes a DELETE, which then
fires row level calls.]

Is there a way for a BS trigger to return a flag "skip the statement",
as there is for BR?

We can alter the API for triggers to do that. Or are you thinking of
having the Truncate Trigger API be different?

I also plan to add a TRUNCATE privilege, though that will be a separate
patch in a later post. That will widen the use case of TRUNCATE, which
should be OK to do once we've covered the replication concerns.

Considering it's not MVCC-safe, do we *want* to widen the use case?

There are way too many table privilege bits already; to add more you
need something a lot stronger than a "might be nice" argument.

People use TRUNCATE whatever we say. If you force people to be table
owners or superusers you merely restrict their security options.

If you want to prevent wider use then perhaps a better explanation of
what "MVCC-safe" means in the docs would do that. Most people don't
understand that phrase, or its implications.

--
Simon Riggs
2ndQuadrant http://www.2ndQuadrant.com

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: Simon Riggs (#4)
Re: Truncate Triggers

Simon Riggs <simon@2ndquadrant.com> writes:

On Fri, 2008-01-25 at 10:44 -0500, Tom Lane wrote:

There are way too many table privilege bits already; to add more you
need something a lot stronger than a "might be nice" argument.

People use TRUNCATE whatever we say. If you force people to be table
owners or superusers you merely restrict their security options.

By that argument you could justify a separate privilege bit for anything
at all, eg, each sub-variant of ALTER TABLE. Please present an actual
argument why TRUNCATE should get its own bit.

regards, tom lane

#6Stephen Frost
sfrost@snowman.net
In reply to: Tom Lane (#5)
Re: Truncate Triggers

* Tom Lane (tgl@sss.pgh.pa.us) wrote:

Simon Riggs <simon@2ndquadrant.com> writes:

On Fri, 2008-01-25 at 10:44 -0500, Tom Lane wrote:

There are way too many table privilege bits already; to add more you
need something a lot stronger than a "might be nice" argument.

People use TRUNCATE whatever we say. If you force people to be table
owners or superusers you merely restrict their security options.

By that argument you could justify a separate privilege bit for anything
at all, eg, each sub-variant of ALTER TABLE. Please present an actual
argument why TRUNCATE should get its own bit.

I've done this already, and continue to feel that TRUNCATE should have
its own bit. There are many cases where you want a user to be able to
truncate a table but not alter its structure. TRUNCATE is not a
DDL-type statement, those can and should be reserved to the owner.

Thanks,

Stephen

#7Simon Riggs
simon@2ndQuadrant.com
In reply to: Tom Lane (#5)
Re: Truncate Triggers

On Fri, 2008-01-25 at 14:00 -0500, Tom Lane wrote:

Simon Riggs <simon@2ndquadrant.com> writes:

On Fri, 2008-01-25 at 10:44 -0500, Tom Lane wrote:

There are way too many table privilege bits already; to add more you
need something a lot stronger than a "might be nice" argument.

People use TRUNCATE whatever we say. If you force people to be table
owners or superusers you merely restrict their security options.

By that argument you could justify a separate privilege bit for anything
at all, eg, each sub-variant of ALTER TABLE.

I already made the argument that TRUNCATE is not similar to DDL in its
effects or usage.
http://archives.postgresql.org/pgsql-sql/2008-01/msg00093.php

Please present an actual
argument why TRUNCATE should get its own bit.

Claiming my argument doesn't exist is itself a fairly weak defence...

I only mentioned this for completeness, since its on the TODO list. You
should probably go through the TODO and remove the items you disagree
with. I didn't put it there, nor did I originally propose it. I do think
it has merit; I came up against exactly that issue earlier this month.

Perhaps we should be implementing "extended privileges" by using one
additional bit to mean "has extended privilege list". We presumably want
to implement column level privileges, plus you raise interesting
thoughts about fine grained security access controls for certain
operations, so an extension mechanism seems like the way to go.

--
Simon Riggs
2ndQuadrant http://www.2ndQuadrant.com

#8Bruce Momjian
bruce@momjian.us
In reply to: Simon Riggs (#7)
Re: Truncate Triggers

"Simon Riggs" <simon@2ndquadrant.com> writes:

On Fri, 2008-01-25 at 14:00 -0500, Tom Lane wrote:

Simon Riggs <simon@2ndquadrant.com> writes:

On Fri, 2008-01-25 at 10:44 -0500, Tom Lane wrote:

There are way too many table privilege bits already; to add more you
need something a lot stronger than a "might be nice" argument.

People use TRUNCATE whatever we say. If you force people to be table
owners or superusers you merely restrict their security options.

By that argument you could justify a separate privilege bit for anything
at all, eg, each sub-variant of ALTER TABLE.

I already made the argument that TRUNCATE is not similar to DDL in its
effects or usage.
http://archives.postgresql.org/pgsql-sql/2008-01/msg00093.php

Please present an actual
argument why TRUNCATE should get its own bit.

Claiming my argument doesn't exist is itself a fairly weak defence...

Uhm, your argument seems to consist of:

| 1. Commands that alter the rows in the table
| e.g. UPDATE, DELETE, INSERT + TRUNCATE is clearly part of this group

I don't think saying "clearly" constitutes an argument.

The fact is that TRUNCATE is a big of a screw case. It can be seen either way.
A lot of users use it as a "cheaper form of delete" which would make it DML.
Except the whole reason it's cheaper is precisely because of the way it works
which is by being a closer analogy to a DROP and CREATE sequence of DDL.

This two-faced personality is just why we're facing this problem. It looks to
users like DML but it under the hood it behaves just like DDL.

I think there are two strategies here. Either we paper over the DDLishness by
making it look as much as possible like DML. It'll never be perfect but we'll
be as friendly as we can for users. That might just make the DDLishness pop up
at all the more surprising moments and be all that much harder to explain
though.

Or we can just declare it DDL and put a warning in the documentation that
while it may sound like it's DML it is in fact better thought of as a shortcut
for doing DROP and CREATE and should be used as such.

On the other hand perhaps it would be nice to have per-statement DDL triggers
in general. So you could, for example, update a data dictionary automatically
for simple cases like DROP TABLE.

Per-statement DDL triggers might also provide a more extensible way to enforce
unusual security policies. "Nobody's allowed to do any DDL except during a
maintenance window" for example.

--
Gregory Stark
EnterpriseDB http://www.enterprisedb.com
Ask me about EnterpriseDB's 24x7 Postgres support!

#9Brendan Jurd
direvus@gmail.com
In reply to: Bruce Momjian (#8)
Re: Truncate Triggers

On Jan 26, 2008 8:14 AM, Gregory Stark <stark@enterprisedb.com> wrote:

This two-faced personality is just why we're facing this problem. It looks to
users like DML but it under the hood it behaves just like DDL.

Agreed that it looks like DML. Speaking as a user, I came away from
the documentation thinking that "TRUNCATE foo;" was just a quicker (to
type as well as to run) alternative to "DELETE * FROM foo;". Plus it
has the handy quality of being able to empty multiple tables in the
one command.

I think there are two strategies here. Either we paper over the DDLishness by
making it look as much as possible like DML. It'll never be perfect but we'll
be as friendly as we can for users. That might just make the DDLishness pop up
at all the more surprising moments and be all that much harder to explain
though.

Or we can just declare it DDL and put a warning in the documentation that
while it may sound like it's DML it is in fact better thought of as a shortcut
for doing DROP and CREATE and should be used as such.

It's my humble opinion that the analogy to DROP + CREATE does need to
be made more clear.

Cheers
BJ

#10Stephen Frost
sfrost@snowman.net
In reply to: Simon Riggs (#7)
Re: Truncate Triggers

* Simon Riggs (simon@2ndquadrant.com) wrote:

Perhaps we should be implementing "extended privileges" by using one
additional bit to mean "has extended privilege list". We presumably want
to implement column level privileges, plus you raise interesting
thoughts about fine grained security access controls for certain
operations, so an extension mechanism seems like the way to go.

I disagree and feel that my now rather ancient proposal is still better-
split the "permission" bits and the "grantable" bits into two seperate
32bit integers. That has the advantage of doubleing the number of
available bits while also splitting up the frequently used bits
("permission" bits) from the much, much, much less frequently used bits
("grantable" bits).

Of course, the last time this went around the argument was that we
shouldn't add alot of extra code until we actually needed to, while at
the same time we shouldn't use up the few remaining bits we have. The
fact that this makes for an impossible situation seems to have been
lost.

Thanks,

Stephen

#11Robert Treat
xzilla@users.sourceforge.net
In reply to: Simon Riggs (#1)
Re: Truncate Triggers

On Friday 25 January 2008 06:40, Simon Riggs wrote:

Notes: As the syntax shows, these would be statement-level triggers
(only). Requesting row level triggers will cause an error. [As Chris
Browne explained, if people really want, they can use these facilities
to create a Before Statement trigger that executes a DELETE, which then
fires row level calls.]

This seems to completly hand-wave away the idea of implementing row level
visibility in statement level triggers, something I am hoping to see
implemented somewhere down the line. Am I missing something?

--
Robert Treat
Build A Brighter LAMP :: Linux Apache {middleware} PostgreSQL

#12Bruce Momjian
bruce@momjian.us
In reply to: Robert Treat (#11)
Re: Truncate Triggers

"Robert Treat" <xzilla@users.sourceforge.net> writes:

the idea of implementing row level visibility in statement level triggers

Huh?

--
Gregory Stark
EnterpriseDB http://www.enterprisedb.com
Ask me about EnterpriseDB's On-Demand Production Tuning

#13Andreas Pflug
pgadmin@pse-consulting.de
In reply to: Robert Treat (#11)
Re: Truncate Triggers

Robert Treat wrote:

On Friday 25 January 2008 06:40, Simon Riggs wrote:

Notes: As the syntax shows, these would be statement-level triggers
(only). Requesting row level triggers will cause an error. [As Chris
Browne explained, if people really want, they can use these facilities
to create a Before Statement trigger that executes a DELETE, which then
fires row level calls.]

This seems to completly hand-wave away the idea of implementing row level
visibility in statement level triggers, something I am hoping to see
implemented somewhere down the line. Am I missing something?

The rowset (not row) associated with the statement level trigger would
be the whole table in case of a TRUNCATE trigger, so in this (corner)
case it's not too helpful.

Regards,
Andreas

#14Martijn van Oosterhout
kleptog@svana.org
In reply to: Bruce Momjian (#12)
Re: Truncate Triggers

On Sat, Jan 26, 2008 at 04:33:53PM +0000, Gregory Stark wrote:

"Robert Treat" <xzilla@users.sourceforge.net> writes:

the idea of implementing row level visibility in statement level triggers

Huh?

I think he means that statement level triggers can see the rows that
got affected, presumably by NEW representing a tuplestore. How that
would work for BEFORE STATEMENT triggers I don't know.

Have a nice day,
--
Martijn van Oosterhout <kleptog@svana.org> http://svana.org/kleptog/

Show quoted text

Those who make peaceful revolution impossible will make violent revolution inevitable.
-- John F Kennedy

#15Tom Lane
tgl@sss.pgh.pa.us
In reply to: Robert Treat (#11)
Re: Truncate Triggers

Robert Treat <xzilla@users.sourceforge.net> writes:

This seems to completly hand-wave away the idea of implementing row level
visibility in statement level triggers, something I am hoping to see
implemented somewhere down the line. Am I missing something?

That was discussed already --- we agreed that TRUNCATE triggers would
simply omit that functionality, when and if it's implemented for other
trigger types.

regards, tom lane

#16Tom Lane
tgl@sss.pgh.pa.us
In reply to: Stephen Frost (#10)
Re: Truncate Triggers

Stephen Frost <sfrost@snowman.net> writes:

Of course, the last time this went around the argument was that we
shouldn't add alot of extra code until we actually needed to, while at
the same time we shouldn't use up the few remaining bits we have. The
fact that this makes for an impossible situation seems to have been
lost.

No, it hasn't been forgotten at all. Whenever we have to cross that
bridge, we'll do so. The questions being asked here are about whether
an adequate case has been made for adding *user-visible* complexity,
not about nitty little details of internal representation.

There are also some compatibility concerns involved. If we add
grantable privileges for TRUNCATE and/or DDL operations, then GRANT ALL
ON TABLE suddenly conveys a whole lot more privilege than it did before.
This could lead to unpleasant surprises in security-sensitive
operations. One could also put forward the argument that it's a direct
violation of the SQL spec, which after all does specify exactly what
privileges ALL is supposed to grant.

regards, tom lane

#17Stephen Frost
sfrost@snowman.net
In reply to: Tom Lane (#16)
Re: Truncate Triggers

* Tom Lane (tgl@sss.pgh.pa.us) wrote:

There are also some compatibility concerns involved. If we add
grantable privileges for TRUNCATE and/or DDL operations, then GRANT ALL
ON TABLE suddenly conveys a whole lot more privilege than it did before.
This could lead to unpleasant surprises in security-sensitive
operations. One could also put forward the argument that it's a direct
violation of the SQL spec, which after all does specify exactly what
privileges ALL is supposed to grant.

iirc, the suggestion was to exclude the non-SQL-spec things from 'GRANT
ALL' to avoid just that issue. Having to grant TRUNCATE and/or DDL
operation permissions explicitly would be reasonable. This might create
a disconnect with what 'revoke all' does, since that should really
remove all of the perms, but I feel that's reasonable. A 'Default
secure' approach.

Thanks,

Stephen

#18Tom Lane
tgl@sss.pgh.pa.us
In reply to: Stephen Frost (#17)
Re: Truncate Triggers

Stephen Frost <sfrost@snowman.net> writes:

iirc, the suggestion was to exclude the non-SQL-spec things from 'GRANT
ALL' to avoid just that issue. Having to grant TRUNCATE and/or DDL
operation permissions explicitly would be reasonable. This might create
a disconnect with what 'revoke all' does, since that should really
remove all of the perms, but I feel that's reasonable. A 'Default
secure' approach.

More like "default impossibly confusing" :-(. "GRANT ALL" doesn't mean
grant all privileges? How the heck are you going to explain/justify
that to a newbie?

regards, tom lane

#19Simon Riggs
simon@2ndQuadrant.com
In reply to: Robert Treat (#11)
Re: Truncate Triggers

On Sat, 2008-01-26 at 11:19 -0500, Robert Treat wrote:

On Friday 25 January 2008 06:40, Simon Riggs wrote:

Notes: As the syntax shows, these would be statement-level triggers
(only). Requesting row level triggers will cause an error. [As Chris
Browne explained, if people really want, they can use these facilities
to create a Before Statement trigger that executes a DELETE, which then
fires row level calls.]

This seems to completly hand-wave away the idea of implementing row level
visibility in statement level triggers, something I am hoping to see
implemented somewhere down the line. Am I missing something?

Not sure why you say that.

We have a choice:
i) TRUNCATE never has access to rows
ii) TRUNCATE can have access, in which case it acts like a DELETE

Forcing ii) in all cases would effectively negate truncate triggers, so
we must have some way of providing both alternatives as options.

As Chris explained, if we allow a BEFORE STATEMENT trigger on TRUNCATE
to issue a DELETE instead, then we are OK to just allow i) and yet
retain the ability to access rows for those that want it. There may be
another of way of doing this also, but I'll leave that possibility to
whoever tries to implement the feature you mention in the future.

--
Simon Riggs
2ndQuadrant http://www.2ndQuadrant.com

#20Stephen Frost
sfrost@snowman.net
In reply to: Tom Lane (#18)
Re: Truncate Triggers

* Tom Lane (tgl@sss.pgh.pa.us) wrote:

Stephen Frost <sfrost@snowman.net> writes:

iirc, the suggestion was to exclude the non-SQL-spec things from 'GRANT
ALL' to avoid just that issue. Having to grant TRUNCATE and/or DDL
operation permissions explicitly would be reasonable. This might create
a disconnect with what 'revoke all' does, since that should really
remove all of the perms, but I feel that's reasonable. A 'Default
secure' approach.

More like "default impossibly confusing" :-(. "GRANT ALL" doesn't mean
grant all privileges? How the heck are you going to explain/justify
that to a newbie?

"grant all" *already* doesn't mean grant all privileges. This isn't
really a change from that. Additionally, there's lots of places where
we follow the SQL spec because that's the right thing to do even though
it's not always the most intuitive thing to do. I certainly don't feel
this is 'impossibly confusing' any more than 'grant all' doesn't mean
you can truncate or alter the table today.

Thanks,

Stephen

#21Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Jim Nasby (#3)
#22Simon Riggs
simon@2ndQuadrant.com
In reply to: Tom Lane (#2)
#23Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Alvaro Herrera (#21)
#24Simon Riggs
simon@2ndQuadrant.com
In reply to: Jim Nasby (#23)
#25Bruce Momjian
bruce@momjian.us
In reply to: Jim Nasby (#23)
#26Hannu Krosing
hannu@tm.ee
In reply to: Bruce Momjian (#25)
#27Simon Riggs
simon@2ndQuadrant.com
In reply to: Bruce Momjian (#25)
#28Jim Nasby
Jim.Nasby@BlueTreble.com
In reply to: Simon Riggs (#27)
#29David Fetter
david@fetter.org
In reply to: Bruce Momjian (#25)
#30Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Fetter (#29)
#31David Fetter
david@fetter.org
In reply to: Tom Lane (#30)
#32Chris Browne
cbbrowne@acm.org
In reply to: David Fetter (#31)
#33David Fetter
david@fetter.org
In reply to: Chris Browne (#32)
#34Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Fetter (#33)
#35Simon Riggs
simon@2ndQuadrant.com
In reply to: Tom Lane (#34)
#36Greg Sabino Mullane
greg@turnstep.com
In reply to: Simon Riggs (#35)