2012-07-18 16:16:16 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* event_trigger.c
|
|
|
|
* PostgreSQL EVENT TRIGGER support code.
|
|
|
|
*
|
2017-01-03 19:48:53 +01:00
|
|
|
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
|
2012-07-18 16:16:16 +02:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
|
|
|
* src/backend/commands/event_trigger.c
|
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.h"
|
2012-07-20 17:38:47 +02:00
|
|
|
#include "access/xact.h"
|
2012-07-18 16:16:16 +02:00
|
|
|
#include "catalog/dependency.h"
|
|
|
|
#include "catalog/indexing.h"
|
|
|
|
#include "catalog/objectaccess.h"
|
|
|
|
#include "catalog/pg_event_trigger.h"
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
#include "catalog/pg_namespace.h"
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
#include "catalog/pg_opclass.h"
|
|
|
|
#include "catalog/pg_opfamily.h"
|
2012-07-18 16:16:16 +02:00
|
|
|
#include "catalog/pg_proc.h"
|
|
|
|
#include "catalog/pg_trigger.h"
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
#include "catalog/pg_ts_config.h"
|
2012-07-18 16:16:16 +02:00
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "commands/dbcommands.h"
|
|
|
|
#include "commands/event_trigger.h"
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
#include "commands/extension.h"
|
2012-07-18 16:16:16 +02:00
|
|
|
#include "commands/trigger.h"
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
#include "funcapi.h"
|
2012-07-18 16:16:16 +02:00
|
|
|
#include "parser/parse_func.h"
|
|
|
|
#include "pgstat.h"
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
#include "lib/ilist.h"
|
2012-07-18 16:16:16 +02:00
|
|
|
#include "miscadmin.h"
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
#include "tcop/deparse_utility.h"
|
2012-07-18 16:16:16 +02:00
|
|
|
#include "utils/acl.h"
|
|
|
|
#include "utils/builtins.h"
|
2012-07-20 17:38:47 +02:00
|
|
|
#include "utils/evtcache.h"
|
2012-07-18 16:16:16 +02:00
|
|
|
#include "utils/fmgroids.h"
|
|
|
|
#include "utils/lsyscache.h"
|
|
|
|
#include "utils/memutils.h"
|
|
|
|
#include "utils/rel.h"
|
|
|
|
#include "utils/tqual.h"
|
|
|
|
#include "utils/syscache.h"
|
|
|
|
#include "tcop/utility.h"
|
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
typedef struct EventTriggerQueryState
|
|
|
|
{
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
/* memory context for this state's objects */
|
|
|
|
MemoryContext cxt;
|
|
|
|
|
2014-12-07 16:55:28 +01:00
|
|
|
/* sql_drop */
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
slist_head SQLDropList;
|
|
|
|
bool in_sql_drop;
|
2014-12-07 16:55:28 +01:00
|
|
|
|
|
|
|
/* table_rewrite */
|
2015-05-24 03:35:49 +02:00
|
|
|
Oid table_rewrite_oid; /* InvalidOid, or set for
|
|
|
|
* table_rewrite event */
|
2014-12-07 16:55:28 +01:00
|
|
|
int table_rewrite_reason; /* AT_REWRITE reason */
|
|
|
|
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
/* Support for command collection */
|
|
|
|
bool commandCollectionInhibited;
|
|
|
|
CollectedCommand *currentCommand;
|
2015-05-24 03:35:49 +02:00
|
|
|
List *commandList; /* list of CollectedCommand; see
|
|
|
|
* deparse_utility.h */
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
struct EventTriggerQueryState *previous;
|
|
|
|
} EventTriggerQueryState;
|
|
|
|
|
2014-02-09 03:21:46 +01:00
|
|
|
static EventTriggerQueryState *currentEventTriggerState = NULL;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
2012-07-18 16:16:16 +02:00
|
|
|
typedef struct
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
const char *obtypename;
|
|
|
|
bool supported;
|
2012-07-18 16:16:16 +02:00
|
|
|
} event_trigger_support_data;
|
|
|
|
|
2012-07-20 17:38:47 +02:00
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
EVENT_TRIGGER_COMMAND_TAG_OK,
|
|
|
|
EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED,
|
|
|
|
EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED
|
|
|
|
} event_trigger_command_tag_check_result;
|
|
|
|
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
/* XXX merge this with ObjectTypeMap? */
|
2012-07-18 16:16:16 +02:00
|
|
|
static event_trigger_support_data event_trigger_support[] = {
|
2016-03-24 03:01:35 +01:00
|
|
|
{"ACCESS METHOD", true},
|
2013-05-29 22:58:43 +02:00
|
|
|
{"AGGREGATE", true},
|
|
|
|
{"CAST", true},
|
|
|
|
{"CONSTRAINT", true},
|
|
|
|
{"COLLATION", true},
|
|
|
|
{"CONVERSION", true},
|
|
|
|
{"DATABASE", false},
|
|
|
|
{"DOMAIN", true},
|
|
|
|
{"EXTENSION", true},
|
|
|
|
{"EVENT TRIGGER", false},
|
|
|
|
{"FOREIGN DATA WRAPPER", true},
|
|
|
|
{"FOREIGN TABLE", true},
|
|
|
|
{"FUNCTION", true},
|
|
|
|
{"INDEX", true},
|
|
|
|
{"LANGUAGE", true},
|
|
|
|
{"MATERIALIZED VIEW", true},
|
|
|
|
{"OPERATOR", true},
|
|
|
|
{"OPERATOR CLASS", true},
|
|
|
|
{"OPERATOR FAMILY", true},
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
{"POLICY", true},
|
2017-01-19 18:00:00 +01:00
|
|
|
{"PUBLICATION", true},
|
2013-05-29 22:58:43 +02:00
|
|
|
{"ROLE", false},
|
|
|
|
{"RULE", true},
|
|
|
|
{"SCHEMA", true},
|
|
|
|
{"SEQUENCE", true},
|
|
|
|
{"SERVER", true},
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
{"STATISTICS", true},
|
2017-01-19 18:00:00 +01:00
|
|
|
{"SUBSCRIPTION", true},
|
2013-05-29 22:58:43 +02:00
|
|
|
{"TABLE", true},
|
|
|
|
{"TABLESPACE", false},
|
2015-04-26 16:33:14 +02:00
|
|
|
{"TRANSFORM", true},
|
2013-05-29 22:58:43 +02:00
|
|
|
{"TRIGGER", true},
|
|
|
|
{"TEXT SEARCH CONFIGURATION", true},
|
|
|
|
{"TEXT SEARCH DICTIONARY", true},
|
|
|
|
{"TEXT SEARCH PARSER", true},
|
|
|
|
{"TEXT SEARCH TEMPLATE", true},
|
|
|
|
{"TYPE", true},
|
|
|
|
{"USER MAPPING", true},
|
|
|
|
{"VIEW", true},
|
|
|
|
{NULL, false}
|
2012-07-18 16:16:16 +02:00
|
|
|
};
|
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/* Support for dropped objects */
|
|
|
|
typedef struct SQLDropObject
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
ObjectAddress address;
|
|
|
|
const char *schemaname;
|
|
|
|
const char *objname;
|
|
|
|
const char *objidentity;
|
|
|
|
const char *objecttype;
|
2014-12-30 21:41:46 +01:00
|
|
|
List *addrnames;
|
|
|
|
List *addrargs;
|
2014-12-19 19:00:45 +01:00
|
|
|
bool original;
|
|
|
|
bool normal;
|
2015-04-06 16:40:55 +02:00
|
|
|
bool istemp;
|
2013-05-29 22:58:43 +02:00
|
|
|
slist_node next;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
} SQLDropObject;
|
|
|
|
|
2012-07-18 16:16:16 +02:00
|
|
|
static void AlterEventTriggerOwner_internal(Relation rel,
|
2013-05-29 22:58:43 +02:00
|
|
|
HeapTuple tup,
|
|
|
|
Oid newOwnerId);
|
2012-07-20 17:38:47 +02:00
|
|
|
static event_trigger_command_tag_check_result check_ddl_tag(const char *tag);
|
2014-12-07 16:55:28 +01:00
|
|
|
static event_trigger_command_tag_check_result check_table_rewrite_ddl_tag(
|
2015-05-24 03:35:49 +02:00
|
|
|
const char *tag);
|
2012-07-18 16:16:16 +02:00
|
|
|
static void error_duplicate_filter_variable(const char *defname);
|
|
|
|
static Datum filter_list_to_array(List *filterlist);
|
2012-12-29 13:55:37 +01:00
|
|
|
static Oid insert_event_trigger_tuple(char *trigname, char *eventname,
|
2013-05-29 22:58:43 +02:00
|
|
|
Oid evtOwner, Oid funcoid, List *tags);
|
2012-07-18 16:16:16 +02:00
|
|
|
static void validate_ddl_tags(const char *filtervar, List *taglist);
|
2014-12-07 16:55:28 +01:00
|
|
|
static void validate_table_rewrite_tags(const char *filtervar, List *taglist);
|
2012-07-20 17:38:47 +02:00
|
|
|
static void EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata);
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
static const char *stringify_grantobjtype(GrantObjectType objtype);
|
|
|
|
static const char *stringify_adefprivs_objtype(GrantObjectType objtype);
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Create an event trigger.
|
|
|
|
*/
|
2012-12-29 13:55:37 +01:00
|
|
|
Oid
|
2012-07-18 16:16:16 +02:00
|
|
|
CreateEventTrigger(CreateEventTrigStmt *stmt)
|
|
|
|
{
|
|
|
|
HeapTuple tuple;
|
|
|
|
Oid funcoid;
|
|
|
|
Oid funcrettype;
|
2015-06-27 23:47:39 +02:00
|
|
|
Oid fargtypes[1]; /* dummy */
|
2012-07-18 16:16:16 +02:00
|
|
|
Oid evtowner = GetUserId();
|
|
|
|
ListCell *lc;
|
|
|
|
List *tags = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* It would be nice to allow database owners or even regular users to do
|
|
|
|
* this, but there are obvious privilege escalation risks which would have
|
|
|
|
* to somehow be plugged first.
|
|
|
|
*/
|
|
|
|
if (!superuser())
|
|
|
|
ereport(ERROR,
|
2013-05-29 22:58:43 +02:00
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
|
|
|
errmsg("permission denied to create event trigger \"%s\"",
|
|
|
|
stmt->trigname),
|
|
|
|
errhint("Must be superuser to create an event trigger.")));
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
/* Validate event name. */
|
2013-01-22 00:00:24 +01:00
|
|
|
if (strcmp(stmt->eventname, "ddl_command_start") != 0 &&
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
strcmp(stmt->eventname, "ddl_command_end") != 0 &&
|
2014-12-07 16:55:28 +01:00
|
|
|
strcmp(stmt->eventname, "sql_drop") != 0 &&
|
|
|
|
strcmp(stmt->eventname, "table_rewrite") != 0)
|
2012-07-18 16:16:16 +02:00
|
|
|
ereport(ERROR,
|
2013-05-29 22:58:43 +02:00
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("unrecognized event name \"%s\"",
|
|
|
|
stmt->eventname)));
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
/* Validate filter conditions. */
|
2013-05-29 22:58:43 +02:00
|
|
|
foreach(lc, stmt->whenclause)
|
2012-07-18 16:16:16 +02:00
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
DefElem *def = (DefElem *) lfirst(lc);
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
if (strcmp(def->defname, "tag") == 0)
|
|
|
|
{
|
|
|
|
if (tags != NULL)
|
|
|
|
error_duplicate_filter_variable(def->defname);
|
|
|
|
tags = (List *) def->arg;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
2013-05-29 22:58:43 +02:00
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("unrecognized filter variable \"%s\"", def->defname)));
|
2012-07-18 16:16:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Validate tag list, if any. */
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
if ((strcmp(stmt->eventname, "ddl_command_start") == 0 ||
|
|
|
|
strcmp(stmt->eventname, "ddl_command_end") == 0 ||
|
|
|
|
strcmp(stmt->eventname, "sql_drop") == 0)
|
|
|
|
&& tags != NULL)
|
2012-07-18 16:16:16 +02:00
|
|
|
validate_ddl_tags("tag", tags);
|
2014-12-07 16:55:28 +01:00
|
|
|
else if (strcmp(stmt->eventname, "table_rewrite") == 0
|
|
|
|
&& tags != NULL)
|
|
|
|
validate_table_rewrite_tags("tag", tags);
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Give user a nice error message if an event trigger of the same name
|
|
|
|
* already exists.
|
|
|
|
*/
|
|
|
|
tuple = SearchSysCache1(EVENTTRIGGERNAME, CStringGetDatum(stmt->trigname));
|
|
|
|
if (HeapTupleIsValid(tuple))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
errmsg("event trigger \"%s\" already exists",
|
2013-05-29 22:58:43 +02:00
|
|
|
stmt->trigname)));
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
/* Find and validate the trigger function. */
|
2015-06-27 23:47:39 +02:00
|
|
|
funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false);
|
2012-07-18 16:16:16 +02:00
|
|
|
funcrettype = get_func_rettype(funcoid);
|
|
|
|
if (funcrettype != EVTTRIGGEROID)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
2016-04-01 18:35:48 +02:00
|
|
|
errmsg("function %s must return type %s",
|
2016-03-28 19:12:00 +02:00
|
|
|
NameListToString(stmt->funcname), "event_trigger")));
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
/* Insert catalog entries. */
|
2012-12-29 13:55:37 +01:00
|
|
|
return insert_event_trigger_tuple(stmt->trigname, stmt->eventname,
|
|
|
|
evtowner, funcoid, tags);
|
2012-07-18 16:16:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Validate DDL command tags.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
validate_ddl_tags(const char *filtervar, List *taglist)
|
|
|
|
{
|
|
|
|
ListCell *lc;
|
|
|
|
|
2013-05-29 22:58:43 +02:00
|
|
|
foreach(lc, taglist)
|
2012-07-18 16:16:16 +02:00
|
|
|
{
|
|
|
|
const char *tag = strVal(lfirst(lc));
|
2012-07-20 17:38:47 +02:00
|
|
|
event_trigger_command_tag_check_result result;
|
2012-07-18 16:16:16 +02:00
|
|
|
|
2012-07-20 17:38:47 +02:00
|
|
|
result = check_ddl_tag(tag);
|
|
|
|
if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("filter value \"%s\" not recognized for filter variable \"%s\"",
|
2013-05-29 22:58:43 +02:00
|
|
|
tag, filtervar)));
|
2012-07-20 17:38:47 +02:00
|
|
|
if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED)
|
2012-07-18 16:16:16 +02:00
|
|
|
ereport(ERROR,
|
2013-05-29 22:58:43 +02:00
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
/* translator: %s represents an SQL statement name */
|
|
|
|
errmsg("event triggers are not supported for %s",
|
|
|
|
tag)));
|
2012-07-18 16:16:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-20 17:38:47 +02:00
|
|
|
static event_trigger_command_tag_check_result
|
|
|
|
check_ddl_tag(const char *tag)
|
|
|
|
{
|
|
|
|
const char *obtypename;
|
2013-05-29 22:58:43 +02:00
|
|
|
event_trigger_support_data *etsd;
|
2012-07-20 17:38:47 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle some idiosyncratic special cases.
|
|
|
|
*/
|
|
|
|
if (pg_strcasecmp(tag, "CREATE TABLE AS") == 0 ||
|
|
|
|
pg_strcasecmp(tag, "SELECT INTO") == 0 ||
|
2013-03-04 01:23:31 +01:00
|
|
|
pg_strcasecmp(tag, "REFRESH MATERIALIZED VIEW") == 0 ||
|
2012-07-20 17:38:47 +02:00
|
|
|
pg_strcasecmp(tag, "ALTER DEFAULT PRIVILEGES") == 0 ||
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
pg_strcasecmp(tag, "ALTER LARGE OBJECT") == 0 ||
|
2015-02-23 18:22:42 +01:00
|
|
|
pg_strcasecmp(tag, "COMMENT") == 0 ||
|
|
|
|
pg_strcasecmp(tag, "GRANT") == 0 ||
|
|
|
|
pg_strcasecmp(tag, "REVOKE") == 0 ||
|
2014-07-10 21:01:31 +02:00
|
|
|
pg_strcasecmp(tag, "DROP OWNED") == 0 ||
|
2015-02-23 18:22:42 +01:00
|
|
|
pg_strcasecmp(tag, "IMPORT FOREIGN SCHEMA") == 0 ||
|
|
|
|
pg_strcasecmp(tag, "SECURITY LABEL") == 0)
|
2012-07-20 17:38:47 +02:00
|
|
|
return EVENT_TRIGGER_COMMAND_TAG_OK;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Otherwise, command should be CREATE, ALTER, or DROP.
|
|
|
|
*/
|
|
|
|
if (pg_strncasecmp(tag, "CREATE ", 7) == 0)
|
|
|
|
obtypename = tag + 7;
|
|
|
|
else if (pg_strncasecmp(tag, "ALTER ", 6) == 0)
|
|
|
|
obtypename = tag + 6;
|
|
|
|
else if (pg_strncasecmp(tag, "DROP ", 5) == 0)
|
|
|
|
obtypename = tag + 5;
|
|
|
|
else
|
|
|
|
return EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ...and the object type should be something recognizable.
|
|
|
|
*/
|
|
|
|
for (etsd = event_trigger_support; etsd->obtypename != NULL; etsd++)
|
|
|
|
if (pg_strcasecmp(etsd->obtypename, obtypename) == 0)
|
|
|
|
break;
|
|
|
|
if (etsd->obtypename == NULL)
|
|
|
|
return EVENT_TRIGGER_COMMAND_TAG_NOT_RECOGNIZED;
|
|
|
|
if (!etsd->supported)
|
|
|
|
return EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED;
|
|
|
|
return EVENT_TRIGGER_COMMAND_TAG_OK;
|
|
|
|
}
|
|
|
|
|
2014-12-07 16:55:28 +01:00
|
|
|
/*
|
|
|
|
* Validate DDL command tags for event table_rewrite.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
validate_table_rewrite_tags(const char *filtervar, List *taglist)
|
|
|
|
{
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
foreach(lc, taglist)
|
|
|
|
{
|
|
|
|
const char *tag = strVal(lfirst(lc));
|
|
|
|
event_trigger_command_tag_check_result result;
|
|
|
|
|
|
|
|
result = check_table_rewrite_ddl_tag(tag);
|
|
|
|
if (result == EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
/* translator: %s represents an SQL statement name */
|
|
|
|
errmsg("event triggers are not supported for %s",
|
|
|
|
tag)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static event_trigger_command_tag_check_result
|
|
|
|
check_table_rewrite_ddl_tag(const char *tag)
|
|
|
|
{
|
2015-02-27 22:38:33 +01:00
|
|
|
if (pg_strcasecmp(tag, "ALTER TABLE") == 0 ||
|
|
|
|
pg_strcasecmp(tag, "ALTER TYPE") == 0)
|
2014-12-07 16:55:28 +01:00
|
|
|
return EVENT_TRIGGER_COMMAND_TAG_OK;
|
|
|
|
|
|
|
|
return EVENT_TRIGGER_COMMAND_TAG_NOT_SUPPORTED;
|
|
|
|
}
|
|
|
|
|
2012-07-18 16:16:16 +02:00
|
|
|
/*
|
|
|
|
* Complain about a duplicate filter variable.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
error_duplicate_filter_variable(const char *defname)
|
|
|
|
{
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("filter variable \"%s\" specified more than once",
|
2013-05-29 22:58:43 +02:00
|
|
|
defname)));
|
2012-07-18 16:16:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Insert the new pg_event_trigger row and record dependencies.
|
|
|
|
*/
|
2012-12-29 13:55:37 +01:00
|
|
|
static Oid
|
2012-07-18 16:16:16 +02:00
|
|
|
insert_event_trigger_tuple(char *trigname, char *eventname, Oid evtOwner,
|
|
|
|
Oid funcoid, List *taglist)
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
Relation tgrel;
|
|
|
|
Oid trigoid;
|
2012-07-18 16:16:16 +02:00
|
|
|
HeapTuple tuple;
|
|
|
|
Datum values[Natts_pg_trigger];
|
|
|
|
bool nulls[Natts_pg_trigger];
|
2013-06-13 01:49:50 +02:00
|
|
|
NameData evtnamedata,
|
|
|
|
evteventdata;
|
2013-05-29 22:58:43 +02:00
|
|
|
ObjectAddress myself,
|
|
|
|
referenced;
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
/* Open pg_event_trigger. */
|
|
|
|
tgrel = heap_open(EventTriggerRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
/* Build the new pg_trigger tuple. */
|
|
|
|
memset(nulls, false, sizeof(nulls));
|
2013-06-13 01:49:50 +02:00
|
|
|
namestrcpy(&evtnamedata, trigname);
|
|
|
|
values[Anum_pg_event_trigger_evtname - 1] = NameGetDatum(&evtnamedata);
|
|
|
|
namestrcpy(&evteventdata, eventname);
|
|
|
|
values[Anum_pg_event_trigger_evtevent - 1] = NameGetDatum(&evteventdata);
|
2012-07-18 16:16:16 +02:00
|
|
|
values[Anum_pg_event_trigger_evtowner - 1] = ObjectIdGetDatum(evtOwner);
|
|
|
|
values[Anum_pg_event_trigger_evtfoid - 1] = ObjectIdGetDatum(funcoid);
|
|
|
|
values[Anum_pg_event_trigger_evtenabled - 1] =
|
|
|
|
CharGetDatum(TRIGGER_FIRES_ON_ORIGIN);
|
|
|
|
if (taglist == NIL)
|
|
|
|
nulls[Anum_pg_event_trigger_evttags - 1] = true;
|
|
|
|
else
|
|
|
|
values[Anum_pg_event_trigger_evttags - 1] =
|
|
|
|
filter_list_to_array(taglist);
|
|
|
|
|
|
|
|
/* Insert heap tuple. */
|
|
|
|
tuple = heap_form_tuple(tgrel->rd_att, values, nulls);
|
2017-01-31 22:42:24 +01:00
|
|
|
trigoid = CatalogTupleInsert(tgrel, tuple);
|
2012-07-18 16:16:16 +02:00
|
|
|
heap_freetuple(tuple);
|
|
|
|
|
|
|
|
/* Depend on owner. */
|
|
|
|
recordDependencyOnOwner(EventTriggerRelationId, trigoid, evtOwner);
|
|
|
|
|
|
|
|
/* Depend on event trigger function. */
|
|
|
|
myself.classId = EventTriggerRelationId;
|
|
|
|
myself.objectId = trigoid;
|
|
|
|
myself.objectSubId = 0;
|
|
|
|
referenced.classId = ProcedureRelationId;
|
|
|
|
referenced.objectId = funcoid;
|
|
|
|
referenced.objectSubId = 0;
|
|
|
|
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
|
|
|
|
2013-12-30 20:00:02 +01:00
|
|
|
/* Depend on extension, if any. */
|
|
|
|
recordDependencyOnCurrentExtension(&myself, false);
|
|
|
|
|
|
|
|
/* Post creation hook for new event trigger */
|
2013-03-07 02:52:06 +01:00
|
|
|
InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
/* Close pg_event_trigger. */
|
|
|
|
heap_close(tgrel, RowExclusiveLock);
|
2012-12-29 13:55:37 +01:00
|
|
|
|
|
|
|
return trigoid;
|
2012-07-18 16:16:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In the parser, a clause like WHEN tag IN ('cmd1', 'cmd2') is represented
|
|
|
|
* by a DefElem whose value is a List of String nodes; in the catalog, we
|
|
|
|
* store the list of strings as a text array. This function transforms the
|
|
|
|
* former representation into the latter one.
|
|
|
|
*
|
|
|
|
* For cleanliness, we store command tags in the catalog as text. It's
|
|
|
|
* possible (although not currently anticipated) that we might have
|
|
|
|
* a case-sensitive filter variable in the future, in which case this would
|
|
|
|
* need some further adjustment.
|
|
|
|
*/
|
|
|
|
static Datum
|
|
|
|
filter_list_to_array(List *filterlist)
|
|
|
|
{
|
|
|
|
ListCell *lc;
|
|
|
|
Datum *data;
|
|
|
|
int i = 0,
|
|
|
|
l = list_length(filterlist);
|
|
|
|
|
|
|
|
data = (Datum *) palloc(l * sizeof(Datum));
|
|
|
|
|
|
|
|
foreach(lc, filterlist)
|
|
|
|
{
|
|
|
|
const char *value = strVal(lfirst(lc));
|
|
|
|
char *result,
|
|
|
|
*p;
|
|
|
|
|
|
|
|
result = pstrdup(value);
|
|
|
|
for (p = result; *p; p++)
|
|
|
|
*p = pg_ascii_toupper((unsigned char) *p);
|
|
|
|
data[i++] = PointerGetDatum(cstring_to_text(result));
|
|
|
|
pfree(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
return PointerGetDatum(construct_array(data, l, TEXTOID, -1, false, 'i'));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Guts of event trigger deletion.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
RemoveEventTriggerById(Oid trigOid)
|
|
|
|
{
|
|
|
|
Relation tgrel;
|
|
|
|
HeapTuple tup;
|
|
|
|
|
|
|
|
tgrel = heap_open(EventTriggerRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
tup = SearchSysCache1(EVENTTRIGGEROID, ObjectIdGetDatum(trigOid));
|
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
elog(ERROR, "cache lookup failed for event trigger %u", trigOid);
|
|
|
|
|
2017-02-01 22:13:30 +01:00
|
|
|
CatalogTupleDelete(tgrel, &tup->t_self);
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
ReleaseSysCache(tup);
|
|
|
|
|
|
|
|
heap_close(tgrel, RowExclusiveLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ALTER EVENT TRIGGER foo ENABLE|DISABLE|ENABLE ALWAYS|REPLICA
|
|
|
|
*/
|
2012-12-29 13:55:37 +01:00
|
|
|
Oid
|
2012-07-18 16:16:16 +02:00
|
|
|
AlterEventTrigger(AlterEventTrigStmt *stmt)
|
|
|
|
{
|
|
|
|
Relation tgrel;
|
|
|
|
HeapTuple tup;
|
2013-05-29 22:58:43 +02:00
|
|
|
Oid trigoid;
|
2012-07-18 16:16:16 +02:00
|
|
|
Form_pg_event_trigger evtForm;
|
2013-05-29 22:58:43 +02:00
|
|
|
char tgenabled = stmt->tgenabled;
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
tgrel = heap_open(EventTriggerRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
tup = SearchSysCacheCopy1(EVENTTRIGGERNAME,
|
|
|
|
CStringGetDatum(stmt->trigname));
|
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
errmsg("event trigger \"%s\" does not exist",
|
2013-05-29 22:58:43 +02:00
|
|
|
stmt->trigname)));
|
2012-12-29 13:55:37 +01:00
|
|
|
|
|
|
|
trigoid = HeapTupleGetOid(tup);
|
|
|
|
|
|
|
|
if (!pg_event_trigger_ownercheck(trigoid, GetUserId()))
|
2012-07-18 16:16:16 +02:00
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
|
|
|
|
stmt->trigname);
|
|
|
|
|
|
|
|
/* tuple is a copy, so we can modify it below */
|
|
|
|
evtForm = (Form_pg_event_trigger) GETSTRUCT(tup);
|
|
|
|
evtForm->evtenabled = tgenabled;
|
|
|
|
|
2017-01-31 22:42:24 +01:00
|
|
|
CatalogTupleUpdate(tgrel, &tup->t_self, tup);
|
2012-07-18 16:16:16 +02:00
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
InvokeObjectPostAlterHook(EventTriggerRelationId,
|
|
|
|
trigoid, 0);
|
|
|
|
|
2012-07-18 16:16:16 +02:00
|
|
|
/* clean up */
|
|
|
|
heap_freetuple(tup);
|
|
|
|
heap_close(tgrel, RowExclusiveLock);
|
2012-12-29 13:55:37 +01:00
|
|
|
|
|
|
|
return trigoid;
|
2012-07-18 16:16:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Change event trigger's owner -- by name
|
|
|
|
*/
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress
|
2012-07-18 16:16:16 +02:00
|
|
|
AlterEventTriggerOwner(const char *name, Oid newOwnerId)
|
|
|
|
{
|
2012-12-24 00:25:03 +01:00
|
|
|
Oid evtOid;
|
2012-07-18 16:16:16 +02:00
|
|
|
HeapTuple tup;
|
|
|
|
Relation rel;
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddress address;
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
rel = heap_open(EventTriggerRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
tup = SearchSysCacheCopy1(EVENTTRIGGERNAME, CStringGetDatum(name));
|
|
|
|
|
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
errmsg("event trigger \"%s\" does not exist", name)));
|
|
|
|
|
2012-12-24 00:25:03 +01:00
|
|
|
evtOid = HeapTupleGetOid(tup);
|
|
|
|
|
2012-07-18 16:16:16 +02:00
|
|
|
AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
|
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
ObjectAddressSet(address, EventTriggerRelationId, evtOid);
|
|
|
|
|
2012-07-18 16:16:16 +02:00
|
|
|
heap_freetuple(tup);
|
|
|
|
|
|
|
|
heap_close(rel, RowExclusiveLock);
|
2012-12-24 00:25:03 +01:00
|
|
|
|
Change many routines to return ObjectAddress rather than OID
The changed routines are mostly those that can be directly called by
ProcessUtilitySlow; the intention is to make the affected object
information more precise, in support for future event trigger changes.
Originally it was envisioned that the OID of the affected object would
be enough, and in most cases that is correct, but upon actually
implementing the event trigger changes it turned out that ObjectAddress
is more widely useful.
Additionally, some command execution routines grew an output argument
that's an object address which provides further info about the executed
command. To wit:
* for ALTER DOMAIN / ADD CONSTRAINT, it corresponds to the address of
the new constraint
* for ALTER OBJECT / SET SCHEMA, it corresponds to the address of the
schema that originally contained the object.
* for ALTER EXTENSION {ADD, DROP} OBJECT, it corresponds to the address
of the object added to or dropped from the extension.
There's no user-visible change in this commit, and no functional change
either.
Discussion: 20150218213255.GC6717@tamriel.snowman.net
Reviewed-By: Stephen Frost, Andres Freund
2015-03-03 18:10:50 +01:00
|
|
|
return address;
|
2012-07-18 16:16:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2014-02-07 20:43:03 +01:00
|
|
|
* Change event trigger owner, by OID
|
2012-07-18 16:16:16 +02:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
AlterEventTriggerOwner_oid(Oid trigOid, Oid newOwnerId)
|
|
|
|
{
|
|
|
|
HeapTuple tup;
|
|
|
|
Relation rel;
|
|
|
|
|
|
|
|
rel = heap_open(EventTriggerRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
tup = SearchSysCacheCopy1(EVENTTRIGGEROID, ObjectIdGetDatum(trigOid));
|
|
|
|
|
|
|
|
if (!HeapTupleIsValid(tup))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
2013-05-29 22:58:43 +02:00
|
|
|
errmsg("event trigger with OID %u does not exist", trigOid)));
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
AlterEventTriggerOwner_internal(rel, tup, newOwnerId);
|
|
|
|
|
|
|
|
heap_freetuple(tup);
|
|
|
|
|
|
|
|
heap_close(rel, RowExclusiveLock);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Internal workhorse for changing an event trigger's owner
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
|
|
|
|
{
|
|
|
|
Form_pg_event_trigger form;
|
|
|
|
|
|
|
|
form = (Form_pg_event_trigger) GETSTRUCT(tup);
|
|
|
|
|
|
|
|
if (form->evtowner == newOwnerId)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!pg_event_trigger_ownercheck(HeapTupleGetOid(tup), GetUserId()))
|
|
|
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_EVENT_TRIGGER,
|
|
|
|
NameStr(form->evtname));
|
|
|
|
|
|
|
|
/* New owner must be a superuser */
|
|
|
|
if (!superuser_arg(newOwnerId))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
|
2013-05-29 22:58:43 +02:00
|
|
|
errmsg("permission denied to change owner of event trigger \"%s\"",
|
|
|
|
NameStr(form->evtname)),
|
|
|
|
errhint("The owner of an event trigger must be a superuser.")));
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
form->evtowner = newOwnerId;
|
2017-01-31 22:42:24 +01:00
|
|
|
CatalogTupleUpdate(rel, &tup->t_self, tup);
|
2012-07-18 16:16:16 +02:00
|
|
|
|
|
|
|
/* Update owner dependency reference */
|
|
|
|
changeDependencyOnOwner(EventTriggerRelationId,
|
|
|
|
HeapTupleGetOid(tup),
|
|
|
|
newOwnerId);
|
2013-03-18 03:55:14 +01:00
|
|
|
|
|
|
|
InvokeObjectPostAlterHook(EventTriggerRelationId,
|
|
|
|
HeapTupleGetOid(tup), 0);
|
2012-07-18 16:16:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* get_event_trigger_oid - Look up an event trigger by name to find its OID.
|
|
|
|
*
|
|
|
|
* If missing_ok is false, throw an error if trigger not found. If
|
|
|
|
* true, just return InvalidOid.
|
|
|
|
*/
|
|
|
|
Oid
|
|
|
|
get_event_trigger_oid(const char *trigname, bool missing_ok)
|
|
|
|
{
|
|
|
|
Oid oid;
|
|
|
|
|
|
|
|
oid = GetSysCacheOid1(EVENTTRIGGERNAME, CStringGetDatum(trigname));
|
|
|
|
if (!OidIsValid(oid) && !missing_ok)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
errmsg("event trigger \"%s\" does not exist", trigname)));
|
|
|
|
return oid;
|
|
|
|
}
|
2012-07-20 17:38:47 +02:00
|
|
|
|
2013-01-22 00:00:24 +01:00
|
|
|
/*
|
|
|
|
* Return true when we want to fire given Event Trigger and false otherwise,
|
|
|
|
* filtering on the session replication role and the event trigger registered
|
|
|
|
* tags matching.
|
|
|
|
*/
|
|
|
|
static bool
|
2013-05-29 22:58:43 +02:00
|
|
|
filter_event_trigger(const char **tag, EventTriggerCacheItem *item)
|
2013-01-22 00:00:24 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Filter by session replication role, knowing that we never see disabled
|
|
|
|
* items down here.
|
|
|
|
*/
|
|
|
|
if (SessionReplicationRole == SESSION_REPLICATION_ROLE_REPLICA)
|
|
|
|
{
|
|
|
|
if (item->enabled == TRIGGER_FIRES_ON_ORIGIN)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (item->enabled == TRIGGER_FIRES_ON_REPLICA)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Filter by tags, if any were specified. */
|
2013-01-23 03:37:01 +01:00
|
|
|
if (item->ntags != 0 && bsearch(tag, item->tag,
|
2013-01-22 00:00:24 +01:00
|
|
|
item->ntags, sizeof(char *),
|
|
|
|
pg_qsort_strcmp) == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
/* if we reach that point, we're not filtering out this item */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-07-20 17:38:47 +02:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Setup for running triggers for the given event. Return value is an OID list
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
* of functions to run; if there are any, trigdata is filled with an
|
|
|
|
* appropriate EventTriggerData for them to receive.
|
2012-07-20 17:38:47 +02:00
|
|
|
*/
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
static List *
|
|
|
|
EventTriggerCommonSetup(Node *parsetree,
|
|
|
|
EventTriggerEvent event, const char *eventstr,
|
|
|
|
EventTriggerData *trigdata)
|
2012-07-20 17:38:47 +02:00
|
|
|
{
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
const char *tag;
|
2012-07-20 17:38:47 +02:00
|
|
|
List *cachelist;
|
|
|
|
ListCell *lc;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
List *runlist = NIL;
|
2012-12-12 01:28:31 +01:00
|
|
|
|
2012-07-20 17:38:47 +02:00
|
|
|
/*
|
|
|
|
* We want the list of command tags for which this procedure is actually
|
|
|
|
* invoked to match up exactly with the list that CREATE EVENT TRIGGER
|
|
|
|
* accepts. This debugging cross-check will throw an error if this
|
|
|
|
* function is invoked for a command tag that CREATE EVENT TRIGGER won't
|
2014-05-06 18:12:18 +02:00
|
|
|
* accept. (Unfortunately, there doesn't seem to be any simple, automated
|
2012-07-20 17:38:47 +02:00
|
|
|
* way to verify that CREATE EVENT TRIGGER doesn't accept extra stuff that
|
|
|
|
* never reaches this control point.)
|
|
|
|
*
|
|
|
|
* If this cross-check fails for you, you probably need to either adjust
|
|
|
|
* standard_ProcessUtility() not to invoke event triggers for the command
|
|
|
|
* type in question, or you need to adjust check_ddl_tag to accept the
|
|
|
|
* relevant command tag.
|
|
|
|
*/
|
|
|
|
#ifdef USE_ASSERT_CHECKING
|
|
|
|
{
|
|
|
|
const char *dbgtag;
|
|
|
|
|
|
|
|
dbgtag = CreateCommandTag(parsetree);
|
2014-12-07 16:55:28 +01:00
|
|
|
if (event == EVT_DDLCommandStart ||
|
2015-05-24 03:35:49 +02:00
|
|
|
event == EVT_DDLCommandEnd ||
|
2014-12-07 16:55:28 +01:00
|
|
|
event == EVT_SQLDrop)
|
|
|
|
{
|
|
|
|
if (check_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK)
|
|
|
|
elog(ERROR, "unexpected command tag \"%s\"", dbgtag);
|
|
|
|
}
|
|
|
|
else if (event == EVT_TableRewrite)
|
|
|
|
{
|
|
|
|
if (check_table_rewrite_ddl_tag(dbgtag) != EVENT_TRIGGER_COMMAND_TAG_OK)
|
|
|
|
elog(ERROR, "unexpected command tag \"%s\"", dbgtag);
|
|
|
|
}
|
2012-07-20 17:38:47 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Use cache to find triggers for this event; fast exit if none. */
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
cachelist = EventCacheLookup(event);
|
|
|
|
if (cachelist == NIL)
|
|
|
|
return NIL;
|
2012-07-20 17:38:47 +02:00
|
|
|
|
|
|
|
/* Get the command tag. */
|
|
|
|
tag = CreateCommandTag(parsetree);
|
|
|
|
|
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* Filter list of event triggers by command tag, and copy them into our
|
2016-11-08 21:33:57 +01:00
|
|
|
* memory context. Once we start running the command triggers, or indeed
|
2013-05-29 22:58:43 +02:00
|
|
|
* once we do anything at all that touches the catalogs, an invalidation
|
|
|
|
* might leave cachelist pointing at garbage, so we must do this before we
|
|
|
|
* can do much else.
|
2012-07-20 17:38:47 +02:00
|
|
|
*/
|
2013-05-29 22:58:43 +02:00
|
|
|
foreach(lc, cachelist)
|
2012-07-20 17:38:47 +02:00
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
EventTriggerCacheItem *item = lfirst(lc);
|
2012-07-20 17:38:47 +02:00
|
|
|
|
2013-01-22 00:00:24 +01:00
|
|
|
if (filter_event_trigger(&tag, item))
|
2012-07-20 17:38:47 +02:00
|
|
|
{
|
2013-01-22 00:00:24 +01:00
|
|
|
/* We must plan to fire this trigger. */
|
|
|
|
runlist = lappend_oid(runlist, item->fnoid);
|
2012-07-20 17:38:47 +02:00
|
|
|
}
|
2013-01-22 00:00:24 +01:00
|
|
|
}
|
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/* don't spend any more time on this if no functions to run */
|
|
|
|
if (runlist == NIL)
|
|
|
|
return NIL;
|
|
|
|
|
|
|
|
trigdata->type = T_EventTriggerData;
|
|
|
|
trigdata->event = eventstr;
|
|
|
|
trigdata->parsetree = parsetree;
|
|
|
|
trigdata->tag = tag;
|
|
|
|
|
|
|
|
return runlist;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fire ddl_command_start triggers.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerDDLCommandStart(Node *parsetree)
|
|
|
|
{
|
|
|
|
List *runlist;
|
2013-05-29 22:58:43 +02:00
|
|
|
EventTriggerData trigdata;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Event Triggers are completely disabled in standalone mode. There are
|
|
|
|
* (at least) two reasons for this:
|
|
|
|
*
|
|
|
|
* 1. A sufficiently broken event trigger might not only render the
|
|
|
|
* database unusable, but prevent disabling itself to fix the situation.
|
|
|
|
* In this scenario, restarting in standalone mode provides an escape
|
|
|
|
* hatch.
|
|
|
|
*
|
|
|
|
* 2. BuildEventTriggerCache relies on systable_beginscan_ordered, and
|
|
|
|
* therefore will malfunction if pg_event_trigger's indexes are damaged.
|
|
|
|
* To allow recovery from a damaged index, we need some operating mode
|
|
|
|
* wherein event triggers are disabled. (Or we could implement
|
|
|
|
* heapscan-and-sort logic for that case, but having disaster recovery
|
|
|
|
* scenarios depend on code that's otherwise untested isn't appetizing.)
|
|
|
|
*/
|
|
|
|
if (!IsUnderPostmaster)
|
|
|
|
return;
|
|
|
|
|
|
|
|
runlist = EventTriggerCommonSetup(parsetree,
|
2013-06-01 15:38:15 +02:00
|
|
|
EVT_DDLCommandStart,
|
|
|
|
"ddl_command_start",
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
&trigdata);
|
|
|
|
if (runlist == NIL)
|
|
|
|
return;
|
2013-01-22 00:00:24 +01:00
|
|
|
|
|
|
|
/* Run the triggers. */
|
|
|
|
EventTriggerInvoke(runlist, &trigdata);
|
|
|
|
|
|
|
|
/* Cleanup. */
|
|
|
|
list_free(runlist);
|
|
|
|
|
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* Make sure anything the event triggers did will be visible to the main
|
|
|
|
* command.
|
2013-01-22 00:00:24 +01:00
|
|
|
*/
|
|
|
|
CommandCounterIncrement();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fire ddl_command_end triggers.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerDDLCommandEnd(Node *parsetree)
|
|
|
|
{
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
List *runlist;
|
2013-05-29 22:58:43 +02:00
|
|
|
EventTriggerData trigdata;
|
2013-01-22 00:00:24 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* See EventTriggerDDLCommandStart for a discussion about why event
|
|
|
|
* triggers are disabled in single user mode.
|
|
|
|
*/
|
|
|
|
if (!IsUnderPostmaster)
|
|
|
|
return;
|
2012-07-20 17:38:47 +02:00
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
runlist = EventTriggerCommonSetup(parsetree,
|
|
|
|
EVT_DDLCommandEnd, "ddl_command_end",
|
|
|
|
&trigdata);
|
|
|
|
if (runlist == NIL)
|
|
|
|
return;
|
|
|
|
|
2013-01-22 00:00:24 +01:00
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* Make sure anything the main command did will be visible to the event
|
|
|
|
* triggers.
|
2013-01-22 00:00:24 +01:00
|
|
|
*/
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
CommandCounterIncrement();
|
2012-07-20 17:38:47 +02:00
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/* Run the triggers. */
|
|
|
|
EventTriggerInvoke(runlist, &trigdata);
|
2013-01-22 00:00:24 +01:00
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/* Cleanup. */
|
|
|
|
list_free(runlist);
|
|
|
|
}
|
2013-01-22 00:00:24 +01:00
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/*
|
|
|
|
* Fire sql_drop triggers.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerSQLDrop(Node *parsetree)
|
|
|
|
{
|
|
|
|
List *runlist;
|
2013-05-29 22:58:43 +02:00
|
|
|
EventTriggerData trigdata;
|
2013-01-22 00:00:24 +01:00
|
|
|
|
|
|
|
/*
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
* See EventTriggerDDLCommandStart for a discussion about why event
|
|
|
|
* triggers are disabled in single user mode.
|
2013-01-22 00:00:24 +01:00
|
|
|
*/
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
if (!IsUnderPostmaster)
|
|
|
|
return;
|
2013-01-22 00:00:24 +01:00
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Use current state to determine whether this event fires at all. If
|
2013-05-29 22:58:43 +02:00
|
|
|
* there are no triggers for the sql_drop event, then we don't have
|
|
|
|
* anything to do here. Note that dropped object collection is disabled
|
|
|
|
* if this is the case, so even if we were to try to run, the list would
|
|
|
|
* be empty.
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
*/
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
slist_is_empty(¤tEventTriggerState->SQLDropList))
|
|
|
|
return;
|
2012-07-20 17:38:47 +02:00
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
runlist = EventTriggerCommonSetup(parsetree,
|
|
|
|
EVT_SQLDrop, "sql_drop",
|
|
|
|
&trigdata);
|
2013-05-29 22:58:43 +02:00
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Nothing to do if run list is empty. Note this shouldn't happen,
|
2013-05-29 22:58:43 +02:00
|
|
|
* because if there are no sql_drop events, then objects-to-drop wouldn't
|
2015-05-20 18:44:46 +02:00
|
|
|
* have been collected in the first place and we would have quit above.
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
*/
|
|
|
|
if (runlist == NIL)
|
|
|
|
return;
|
2012-07-20 17:38:47 +02:00
|
|
|
|
2013-01-22 00:00:24 +01:00
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* Make sure anything the main command did will be visible to the event
|
|
|
|
* triggers.
|
2013-01-22 00:00:24 +01:00
|
|
|
*/
|
|
|
|
CommandCounterIncrement();
|
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* Make sure pg_event_trigger_dropped_objects only works when running
|
2014-05-06 18:12:18 +02:00
|
|
|
* these triggers. Use PG_TRY to ensure in_sql_drop is reset even when
|
2013-05-29 22:58:43 +02:00
|
|
|
* one trigger fails. (This is perhaps not necessary, as the currentState
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
* variable will be removed shortly by our caller, but it seems better to
|
|
|
|
* play safe.)
|
|
|
|
*/
|
|
|
|
currentEventTriggerState->in_sql_drop = true;
|
|
|
|
|
2012-07-20 17:38:47 +02:00
|
|
|
/* Run the triggers. */
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
PG_TRY();
|
|
|
|
{
|
|
|
|
EventTriggerInvoke(runlist, &trigdata);
|
|
|
|
}
|
|
|
|
PG_CATCH();
|
|
|
|
{
|
|
|
|
currentEventTriggerState->in_sql_drop = false;
|
|
|
|
PG_RE_THROW();
|
|
|
|
}
|
|
|
|
PG_END_TRY();
|
|
|
|
currentEventTriggerState->in_sql_drop = false;
|
2012-07-20 17:38:47 +02:00
|
|
|
|
|
|
|
/* Cleanup. */
|
|
|
|
list_free(runlist);
|
|
|
|
}
|
|
|
|
|
2014-12-07 16:55:28 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Fire table_rewrite triggers.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerTableRewrite(Node *parsetree, Oid tableOid, int reason)
|
|
|
|
{
|
|
|
|
List *runlist;
|
|
|
|
EventTriggerData trigdata;
|
|
|
|
|
|
|
|
elog(DEBUG1, "EventTriggerTableRewrite(%u)", tableOid);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Event Triggers are completely disabled in standalone mode. There are
|
|
|
|
* (at least) two reasons for this:
|
|
|
|
*
|
|
|
|
* 1. A sufficiently broken event trigger might not only render the
|
|
|
|
* database unusable, but prevent disabling itself to fix the situation.
|
|
|
|
* In this scenario, restarting in standalone mode provides an escape
|
|
|
|
* hatch.
|
|
|
|
*
|
|
|
|
* 2. BuildEventTriggerCache relies on systable_beginscan_ordered, and
|
|
|
|
* therefore will malfunction if pg_event_trigger's indexes are damaged.
|
|
|
|
* To allow recovery from a damaged index, we need some operating mode
|
|
|
|
* wherein event triggers are disabled. (Or we could implement
|
|
|
|
* heapscan-and-sort logic for that case, but having disaster recovery
|
|
|
|
* scenarios depend on code that's otherwise untested isn't appetizing.)
|
|
|
|
*/
|
|
|
|
if (!IsUnderPostmaster)
|
|
|
|
return;
|
|
|
|
|
|
|
|
runlist = EventTriggerCommonSetup(parsetree,
|
|
|
|
EVT_TableRewrite,
|
|
|
|
"table_rewrite",
|
|
|
|
&trigdata);
|
|
|
|
if (runlist == NIL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure pg_event_trigger_table_rewrite_oid only works when running
|
|
|
|
* these triggers. Use PG_TRY to ensure table_rewrite_oid is reset even
|
|
|
|
* when one trigger fails. (This is perhaps not necessary, as the
|
|
|
|
* currentState variable will be removed shortly by our caller, but it
|
|
|
|
* seems better to play safe.)
|
|
|
|
*/
|
|
|
|
currentEventTriggerState->table_rewrite_oid = tableOid;
|
|
|
|
currentEventTriggerState->table_rewrite_reason = reason;
|
|
|
|
|
|
|
|
/* Run the triggers. */
|
|
|
|
PG_TRY();
|
|
|
|
{
|
|
|
|
EventTriggerInvoke(runlist, &trigdata);
|
|
|
|
}
|
|
|
|
PG_CATCH();
|
|
|
|
{
|
|
|
|
currentEventTriggerState->table_rewrite_oid = InvalidOid;
|
|
|
|
currentEventTriggerState->table_rewrite_reason = 0;
|
|
|
|
PG_RE_THROW();
|
|
|
|
}
|
|
|
|
PG_END_TRY();
|
|
|
|
|
|
|
|
currentEventTriggerState->table_rewrite_oid = InvalidOid;
|
|
|
|
currentEventTriggerState->table_rewrite_reason = 0;
|
|
|
|
|
|
|
|
/* Cleanup. */
|
|
|
|
list_free(runlist);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure anything the event triggers did will be visible to the main
|
|
|
|
* command.
|
|
|
|
*/
|
|
|
|
CommandCounterIncrement();
|
|
|
|
}
|
|
|
|
|
2012-07-20 17:38:47 +02:00
|
|
|
/*
|
|
|
|
* Invoke each event trigger in a list of event triggers.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
EventTriggerInvoke(List *fn_oid_list, EventTriggerData *trigdata)
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
MemoryContext context;
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
ListCell *lc;
|
|
|
|
bool first = true;
|
2012-07-20 17:38:47 +02:00
|
|
|
|
2013-01-23 03:37:01 +01:00
|
|
|
/* Guard against stack overflow due to recursive event trigger */
|
|
|
|
check_stack_depth();
|
|
|
|
|
2012-07-20 17:38:47 +02:00
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* Let's evaluate event triggers in their own memory context, so that any
|
|
|
|
* leaks get cleaned up promptly.
|
2012-07-20 17:38:47 +02:00
|
|
|
*/
|
|
|
|
context = AllocSetContextCreate(CurrentMemoryContext,
|
|
|
|
"event trigger context",
|
Add macros to make AllocSetContextCreate() calls simpler and safer.
I found that half a dozen (nearly 5%) of our AllocSetContextCreate calls
had typos in the context-sizing parameters. While none of these led to
especially significant problems, they did create minor inefficiencies,
and it's now clear that expecting people to copy-and-paste those calls
accurately is not a great idea. Let's reduce the risk of future errors
by introducing single macros that encapsulate the common use-cases.
Three such macros are enough to cover all but two special-purpose contexts;
those two calls can be left as-is, I think.
While this patch doesn't in itself improve matters for third-party
extensions, it doesn't break anything for them either, and they can
gradually adopt the simplified notation over time.
In passing, change TopMemoryContext to use the default allocation
parameters. Formerly it could only be extended 8K at a time. That was
probably reasonable when this code was written; but nowadays we create
many more contexts than we did then, so that it's not unusual to have a
couple hundred K in TopMemoryContext, even without considering various
dubious code that sticks other things there. There seems no good reason
not to let it use growing blocks like most other contexts.
Back-patch to 9.6, mostly because that's still close enough to HEAD that
it's easy to do so, and keeping the branches in sync can be expected to
avoid some future back-patching pain. The bugs fixed by these changes
don't seem to be significant enough to justify fixing them further back.
Discussion: <21072.1472321324@sss.pgh.pa.us>
2016-08-27 23:50:38 +02:00
|
|
|
ALLOCSET_DEFAULT_SIZES);
|
2012-07-20 17:38:47 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(context);
|
|
|
|
|
|
|
|
/* Call each event trigger. */
|
2013-05-29 22:58:43 +02:00
|
|
|
foreach(lc, fn_oid_list)
|
2012-07-20 17:38:47 +02:00
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
Oid fnoid = lfirst_oid(lc);
|
|
|
|
FmgrInfo flinfo;
|
2012-07-20 17:38:47 +02:00
|
|
|
FunctionCallInfoData fcinfo;
|
|
|
|
PgStat_FunctionCallUsage fcusage;
|
|
|
|
|
2014-12-07 16:55:28 +01:00
|
|
|
elog(DEBUG1, "EventTriggerInvoke %u", fnoid);
|
|
|
|
|
2013-01-22 00:00:24 +01:00
|
|
|
/*
|
2013-05-29 22:58:43 +02:00
|
|
|
* We want each event trigger to be able to see the results of the
|
|
|
|
* previous event trigger's action. Caller is responsible for any
|
|
|
|
* command-counter increment that is needed between the event trigger
|
|
|
|
* and anything else in the transaction.
|
2013-01-22 00:00:24 +01:00
|
|
|
*/
|
|
|
|
if (first)
|
|
|
|
first = false;
|
|
|
|
else
|
|
|
|
CommandCounterIncrement();
|
|
|
|
|
2012-07-20 17:38:47 +02:00
|
|
|
/* Look up the function */
|
|
|
|
fmgr_info(fnoid, &flinfo);
|
|
|
|
|
|
|
|
/* Call the function, passing no arguments but setting a context. */
|
|
|
|
InitFunctionCallInfoData(fcinfo, &flinfo, 0,
|
|
|
|
InvalidOid, (Node *) trigdata, NULL);
|
|
|
|
pgstat_init_function_usage(&fcinfo, &fcusage);
|
|
|
|
FunctionCallInvoke(&fcinfo);
|
|
|
|
pgstat_end_function_usage(&fcusage, true);
|
|
|
|
|
|
|
|
/* Reclaim memory. */
|
|
|
|
MemoryContextReset(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Restore old memory context and delete the temporary one. */
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
MemoryContextDelete(context);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do event triggers support this object type?
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
EventTriggerSupportsObjectType(ObjectType obtype)
|
|
|
|
{
|
|
|
|
switch (obtype)
|
|
|
|
{
|
|
|
|
case OBJECT_DATABASE:
|
|
|
|
case OBJECT_TABLESPACE:
|
|
|
|
case OBJECT_ROLE:
|
|
|
|
/* no support for global objects */
|
|
|
|
return false;
|
|
|
|
case OBJECT_EVENT_TRIGGER:
|
|
|
|
/* no support for event triggers on event triggers */
|
|
|
|
return false;
|
2016-03-24 03:01:35 +01:00
|
|
|
case OBJECT_ACCESS_METHOD:
|
2013-04-11 16:59:47 +02:00
|
|
|
case OBJECT_AGGREGATE:
|
2015-03-16 16:06:34 +01:00
|
|
|
case OBJECT_AMOP:
|
|
|
|
case OBJECT_AMPROC:
|
2013-04-11 16:59:47 +02:00
|
|
|
case OBJECT_ATTRIBUTE:
|
|
|
|
case OBJECT_CAST:
|
|
|
|
case OBJECT_COLUMN:
|
|
|
|
case OBJECT_COLLATION:
|
|
|
|
case OBJECT_CONVERSION:
|
2015-03-11 23:23:47 +01:00
|
|
|
case OBJECT_DEFACL:
|
2014-12-23 19:31:29 +01:00
|
|
|
case OBJECT_DEFAULT:
|
2013-04-11 16:59:47 +02:00
|
|
|
case OBJECT_DOMAIN:
|
2014-12-23 13:06:44 +01:00
|
|
|
case OBJECT_DOMCONSTRAINT:
|
2013-04-11 16:59:47 +02:00
|
|
|
case OBJECT_EXTENSION:
|
|
|
|
case OBJECT_FDW:
|
|
|
|
case OBJECT_FOREIGN_SERVER:
|
|
|
|
case OBJECT_FOREIGN_TABLE:
|
|
|
|
case OBJECT_FUNCTION:
|
|
|
|
case OBJECT_INDEX:
|
|
|
|
case OBJECT_LANGUAGE:
|
|
|
|
case OBJECT_LARGEOBJECT:
|
|
|
|
case OBJECT_MATVIEW:
|
|
|
|
case OBJECT_OPCLASS:
|
|
|
|
case OBJECT_OPERATOR:
|
|
|
|
case OBJECT_OPFAMILY:
|
Row-Level Security Policies (RLS)
Building on the updatable security-barrier views work, add the
ability to define policies on tables to limit the set of rows
which are returned from a query and which are allowed to be added
to a table. Expressions defined by the policy for filtering are
added to the security barrier quals of the query, while expressions
defined to check records being added to a table are added to the
with-check options of the query.
New top-level commands are CREATE/ALTER/DROP POLICY and are
controlled by the table owner. Row Security is able to be enabled
and disabled by the owner on a per-table basis using
ALTER TABLE .. ENABLE/DISABLE ROW SECURITY.
Per discussion, ROW SECURITY is disabled on tables by default and
must be enabled for policies on the table to be used. If no
policies exist on a table with ROW SECURITY enabled, a default-deny
policy is used and no records will be visible.
By default, row security is applied at all times except for the
table owner and the superuser. A new GUC, row_security, is added
which can be set to ON, OFF, or FORCE. When set to FORCE, row
security will be applied even for the table owner and superusers.
When set to OFF, row security will be disabled when allowed and an
error will be thrown if the user does not have rights to bypass row
security.
Per discussion, pg_dump sets row_security = OFF by default to ensure
that exports and backups will have all data in the table or will
error if there are insufficient privileges to bypass row security.
A new option has been added to pg_dump, --enable-row-security, to
ask pg_dump to export with row security enabled.
A new role capability, BYPASSRLS, which can only be set by the
superuser, is added to allow other users to be able to bypass row
security using row_security = OFF.
Many thanks to the various individuals who have helped with the
design, particularly Robert Haas for his feedback.
Authors include Craig Ringer, KaiGai Kohei, Adam Brightwell, Dean
Rasheed, with additional changes and rework by me.
Reviewers have included all of the above, Greg Smith,
Jeff McCormick, and Robert Haas.
2014-09-19 17:18:35 +02:00
|
|
|
case OBJECT_POLICY:
|
2017-01-19 18:00:00 +01:00
|
|
|
case OBJECT_PUBLICATION:
|
|
|
|
case OBJECT_PUBLICATION_REL:
|
2013-04-11 16:59:47 +02:00
|
|
|
case OBJECT_RULE:
|
|
|
|
case OBJECT_SCHEMA:
|
|
|
|
case OBJECT_SEQUENCE:
|
2017-01-19 18:00:00 +01:00
|
|
|
case OBJECT_SUBSCRIPTION:
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
case OBJECT_STATISTIC_EXT:
|
2014-12-23 13:06:44 +01:00
|
|
|
case OBJECT_TABCONSTRAINT:
|
2013-04-11 16:59:47 +02:00
|
|
|
case OBJECT_TABLE:
|
2015-04-26 16:33:14 +02:00
|
|
|
case OBJECT_TRANSFORM:
|
2013-04-11 16:59:47 +02:00
|
|
|
case OBJECT_TRIGGER:
|
|
|
|
case OBJECT_TSCONFIGURATION:
|
|
|
|
case OBJECT_TSDICTIONARY:
|
|
|
|
case OBJECT_TSPARSER:
|
|
|
|
case OBJECT_TSTEMPLATE:
|
|
|
|
case OBJECT_TYPE:
|
2015-03-11 21:01:13 +01:00
|
|
|
case OBJECT_USER_MAPPING:
|
2013-04-11 16:59:47 +02:00
|
|
|
case OBJECT_VIEW:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do event triggers support this object class?
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
EventTriggerSupportsObjectClass(ObjectClass objclass)
|
|
|
|
{
|
|
|
|
switch (objclass)
|
|
|
|
{
|
|
|
|
case OCLASS_DATABASE:
|
|
|
|
case OCLASS_TBLSPACE:
|
|
|
|
case OCLASS_ROLE:
|
|
|
|
/* no support for global objects */
|
|
|
|
return false;
|
|
|
|
case OCLASS_EVENT_TRIGGER:
|
|
|
|
/* no support for event triggers on event triggers */
|
|
|
|
return false;
|
|
|
|
case OCLASS_CLASS:
|
|
|
|
case OCLASS_PROC:
|
|
|
|
case OCLASS_TYPE:
|
|
|
|
case OCLASS_CAST:
|
|
|
|
case OCLASS_COLLATION:
|
|
|
|
case OCLASS_CONSTRAINT:
|
|
|
|
case OCLASS_CONVERSION:
|
|
|
|
case OCLASS_DEFAULT:
|
|
|
|
case OCLASS_LANGUAGE:
|
|
|
|
case OCLASS_LARGEOBJECT:
|
|
|
|
case OCLASS_OPERATOR:
|
|
|
|
case OCLASS_OPCLASS:
|
|
|
|
case OCLASS_OPFAMILY:
|
|
|
|
case OCLASS_AMOP:
|
|
|
|
case OCLASS_AMPROC:
|
|
|
|
case OCLASS_REWRITE:
|
|
|
|
case OCLASS_TRIGGER:
|
|
|
|
case OCLASS_SCHEMA:
|
2015-04-26 16:33:14 +02:00
|
|
|
case OCLASS_TRANSFORM:
|
2013-04-11 16:59:47 +02:00
|
|
|
case OCLASS_TSPARSER:
|
|
|
|
case OCLASS_TSDICT:
|
|
|
|
case OCLASS_TSTEMPLATE:
|
|
|
|
case OCLASS_TSCONFIG:
|
|
|
|
case OCLASS_FDW:
|
|
|
|
case OCLASS_FOREIGN_SERVER:
|
|
|
|
case OCLASS_USER_MAPPING:
|
|
|
|
case OCLASS_DEFACL:
|
|
|
|
case OCLASS_EXTENSION:
|
Rename pg_rowsecurity -> pg_policy and other fixes
As pointed out by Robert, we should really have named pg_rowsecurity
pg_policy, as the objects stored in that catalog are policies. This
patch fixes that and updates the column names to start with 'pol' to
match the new catalog name.
The security consideration for COPY with row level security, also
pointed out by Robert, has also been addressed by remembering and
re-checking the OID of the relation initially referenced during COPY
processing, to make sure it hasn't changed under us by the time we
finish planning out the query which has been built.
Robert and Alvaro also commented on missing OCLASS and OBJECT entries
for POLICY (formerly ROWSECURITY or POLICY, depending) in various
places. This patch fixes that too, which also happens to add the
ability to COMMENT on policies.
In passing, attempt to improve the consistency of messages, comments,
and documentation as well. This removes various incarnations of
'row-security', 'row-level security', 'Row-security', etc, in favor
of 'policy', 'row level security' or 'row_security' as appropriate.
Happy Thanksgiving!
2014-11-27 07:06:36 +01:00
|
|
|
case OCLASS_POLICY:
|
2016-03-24 03:01:35 +01:00
|
|
|
case OCLASS_AM:
|
2017-01-19 18:00:00 +01:00
|
|
|
case OCLASS_PUBLICATION:
|
|
|
|
case OCLASS_PUBLICATION_REL:
|
|
|
|
case OCLASS_SUBSCRIPTION:
|
Implement multivariate n-distinct coefficients
Add support for explicitly declared statistic objects (CREATE
STATISTICS), allowing collection of statistics on more complex
combinations that individual table columns. Companion commands DROP
STATISTICS and ALTER STATISTICS ... OWNER TO / SET SCHEMA / RENAME are
added too. All this DDL has been designed so that more statistic types
can be added later on, such as multivariate most-common-values and
multivariate histograms between columns of a single table, leaving room
for permitting columns on multiple tables, too, as well as expressions.
This commit only adds support for collection of n-distinct coefficient
on user-specified sets of columns in a single table. This is useful to
estimate number of distinct groups in GROUP BY and DISTINCT clauses;
estimation errors there can cause over-allocation of memory in hashed
aggregates, for instance, so it's a worthwhile problem to solve. A new
special pseudo-type pg_ndistinct is used.
(num-distinct estimation was deemed sufficiently useful by itself that
this is worthwhile even if no further statistic types are added
immediately; so much so that another version of essentially the same
functionality was submitted by Kyotaro Horiguchi:
https://postgr.es/m/20150828.173334.114731693.horiguchi.kyotaro@lab.ntt.co.jp
though this commit does not use that code.)
Author: Tomas Vondra. Some code rework by Álvaro.
Reviewed-by: Dean Rasheed, David Rowley, Kyotaro Horiguchi, Jeff Janes,
Ideriha Takeshi
Discussion: https://postgr.es/m/543AFA15.4080608@fuzzy.cz
https://postgr.es/m/20170320190220.ixlaueanxegqd5gr@alvherre.pgsql
2017-03-24 18:06:10 +01:00
|
|
|
case OCLASS_STATISTIC_EXT:
|
2013-04-11 16:59:47 +02:00
|
|
|
return true;
|
2012-07-20 17:38:47 +02:00
|
|
|
}
|
2013-04-11 16:59:47 +02:00
|
|
|
|
2012-07-20 17:38:47 +02:00
|
|
|
return true;
|
|
|
|
}
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
2015-02-23 18:22:42 +01:00
|
|
|
bool
|
|
|
|
EventTriggerSupportsGrantObjectType(GrantObjectType objtype)
|
|
|
|
{
|
|
|
|
switch (objtype)
|
|
|
|
{
|
|
|
|
case ACL_OBJECT_DATABASE:
|
|
|
|
case ACL_OBJECT_TABLESPACE:
|
|
|
|
/* no support for global objects */
|
|
|
|
return false;
|
|
|
|
|
|
|
|
case ACL_OBJECT_COLUMN:
|
|
|
|
case ACL_OBJECT_RELATION:
|
|
|
|
case ACL_OBJECT_SEQUENCE:
|
|
|
|
case ACL_OBJECT_DOMAIN:
|
|
|
|
case ACL_OBJECT_FDW:
|
|
|
|
case ACL_OBJECT_FOREIGN_SERVER:
|
|
|
|
case ACL_OBJECT_FUNCTION:
|
|
|
|
case ACL_OBJECT_LANGUAGE:
|
|
|
|
case ACL_OBJECT_LARGEOBJECT:
|
|
|
|
case ACL_OBJECT_NAMESPACE:
|
|
|
|
case ACL_OBJECT_TYPE:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
Assert(false);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/*
|
|
|
|
* Prepare event trigger state for a new complete query to run, if necessary;
|
|
|
|
* returns whether this was done. If it was, EventTriggerEndCompleteQuery must
|
|
|
|
* be called when the query is done, regardless of whether it succeeds or fails
|
|
|
|
* -- so use of a PG_TRY block is mandatory.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
EventTriggerBeginCompleteQuery(void)
|
|
|
|
{
|
|
|
|
EventTriggerQueryState *state;
|
2013-05-29 22:58:43 +02:00
|
|
|
MemoryContext cxt;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
|
|
|
/*
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
* Currently, sql_drop, table_rewrite, ddl_command_end events are the only
|
|
|
|
* reason to have event trigger state at all; so if there are none, don't
|
|
|
|
* install one.
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
*/
|
|
|
|
if (!trackDroppedObjectsNeeded())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
cxt = AllocSetContextCreate(TopMemoryContext,
|
|
|
|
"event trigger state",
|
Add macros to make AllocSetContextCreate() calls simpler and safer.
I found that half a dozen (nearly 5%) of our AllocSetContextCreate calls
had typos in the context-sizing parameters. While none of these led to
especially significant problems, they did create minor inefficiencies,
and it's now clear that expecting people to copy-and-paste those calls
accurately is not a great idea. Let's reduce the risk of future errors
by introducing single macros that encapsulate the common use-cases.
Three such macros are enough to cover all but two special-purpose contexts;
those two calls can be left as-is, I think.
While this patch doesn't in itself improve matters for third-party
extensions, it doesn't break anything for them either, and they can
gradually adopt the simplified notation over time.
In passing, change TopMemoryContext to use the default allocation
parameters. Formerly it could only be extended 8K at a time. That was
probably reasonable when this code was written; but nowadays we create
many more contexts than we did then, so that it's not unusual to have a
couple hundred K in TopMemoryContext, even without considering various
dubious code that sticks other things there. There seems no good reason
not to let it use growing blocks like most other contexts.
Back-patch to 9.6, mostly because that's still close enough to HEAD that
it's easy to do so, and keeping the branches in sync can be expected to
avoid some future back-patching pain. The bugs fixed by these changes
don't seem to be significant enough to justify fixing them further back.
Discussion: <21072.1472321324@sss.pgh.pa.us>
2016-08-27 23:50:38 +02:00
|
|
|
ALLOCSET_DEFAULT_SIZES);
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
state = MemoryContextAlloc(cxt, sizeof(EventTriggerQueryState));
|
|
|
|
state->cxt = cxt;
|
|
|
|
slist_init(&(state->SQLDropList));
|
|
|
|
state->in_sql_drop = false;
|
2014-12-07 16:55:28 +01:00
|
|
|
state->table_rewrite_oid = InvalidOid;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
state->commandCollectionInhibited = currentEventTriggerState ?
|
|
|
|
currentEventTriggerState->commandCollectionInhibited : false;
|
|
|
|
state->currentCommand = NULL;
|
|
|
|
state->commandList = NIL;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
state->previous = currentEventTriggerState;
|
|
|
|
currentEventTriggerState = state;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Query completed (or errored out) -- clean up local state, return to previous
|
|
|
|
* one.
|
|
|
|
*
|
|
|
|
* Note: it's an error to call this routine if EventTriggerBeginCompleteQuery
|
|
|
|
* returned false previously.
|
|
|
|
*
|
|
|
|
* Note: this might be called in the PG_CATCH block of a failing transaction,
|
2014-05-06 18:12:18 +02:00
|
|
|
* so be wary of running anything unnecessary. (In particular, it's probably
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
* unwise to try to allocate memory.)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerEndCompleteQuery(void)
|
|
|
|
{
|
|
|
|
EventTriggerQueryState *prevstate;
|
|
|
|
|
|
|
|
prevstate = currentEventTriggerState->previous;
|
|
|
|
|
|
|
|
/* this avoids the need for retail pfree of SQLDropList items: */
|
|
|
|
MemoryContextDelete(currentEventTriggerState->cxt);
|
|
|
|
|
|
|
|
currentEventTriggerState = prevstate;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Do we need to keep close track of objects being dropped?
|
|
|
|
*
|
|
|
|
* This is useful because there is a cost to running with them enabled.
|
|
|
|
*/
|
|
|
|
bool
|
|
|
|
trackDroppedObjectsNeeded(void)
|
|
|
|
{
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
/*
|
|
|
|
* true if any sql_drop, table_rewrite, ddl_command_end event trigger
|
|
|
|
* exists
|
|
|
|
*/
|
2014-12-07 16:55:28 +01:00
|
|
|
return list_length(EventCacheLookup(EVT_SQLDrop)) > 0 ||
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
list_length(EventCacheLookup(EVT_TableRewrite)) > 0 ||
|
|
|
|
list_length(EventCacheLookup(EVT_DDLCommandEnd)) > 0;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Support for dropped objects information on event trigger functions.
|
|
|
|
*
|
|
|
|
* We keep the list of objects dropped by the current command in current
|
|
|
|
* state's SQLDropList (comprising SQLDropObject items). Each time a new
|
|
|
|
* command is to start, a clean EventTriggerQueryState is created; commands
|
|
|
|
* that drop objects do the dependency.c dance to drop objects, which
|
|
|
|
* populates the current state's SQLDropList; when the event triggers are
|
|
|
|
* invoked they can consume the list via pg_event_trigger_dropped_objects().
|
|
|
|
* When the command finishes, the EventTriggerQueryState is cleared, and
|
|
|
|
* the one from the previous command is restored (when no command is in
|
|
|
|
* execution, the current state is NULL).
|
|
|
|
*
|
|
|
|
* All this lets us support the case that an event trigger function drops
|
|
|
|
* objects "reentrantly".
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Register one object as being dropped by the current command.
|
|
|
|
*/
|
|
|
|
void
|
2014-12-19 19:00:45 +01:00
|
|
|
EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal)
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
SQLDropObject *obj;
|
|
|
|
MemoryContext oldcxt;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
|
|
|
if (!currentEventTriggerState)
|
|
|
|
return;
|
|
|
|
|
2013-04-11 16:59:47 +02:00
|
|
|
Assert(EventTriggerSupportsObjectClass(getObjectClass(object)));
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
2015-04-06 16:40:55 +02:00
|
|
|
/* don't report temp schemas except my own */
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
if (object->classId == NamespaceRelationId &&
|
2015-04-06 16:40:55 +02:00
|
|
|
(isAnyTempNamespace(object->objectId) &&
|
|
|
|
!isTempNamespace(object->objectId)))
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
|
|
|
|
|
|
|
|
obj = palloc0(sizeof(SQLDropObject));
|
|
|
|
obj->address = *object;
|
2014-12-19 19:00:45 +01:00
|
|
|
obj->original = original;
|
|
|
|
obj->normal = normal;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Obtain schema names from the object's catalog tuple, if one exists;
|
2013-05-29 22:58:43 +02:00
|
|
|
* this lets us skip objects in temp schemas. We trust that
|
|
|
|
* ObjectProperty contains all object classes that can be
|
|
|
|
* schema-qualified.
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
*/
|
|
|
|
if (is_objectclass_supported(object->classId))
|
|
|
|
{
|
|
|
|
Relation catalog;
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
|
|
|
catalog = heap_open(obj->address.classId, AccessShareLock);
|
|
|
|
tuple = get_catalog_object_by_oid(catalog, obj->address.objectId);
|
|
|
|
|
|
|
|
if (tuple)
|
|
|
|
{
|
|
|
|
AttrNumber attnum;
|
|
|
|
Datum datum;
|
|
|
|
bool isnull;
|
|
|
|
|
|
|
|
attnum = get_object_attnum_namespace(obj->address.classId);
|
|
|
|
if (attnum != InvalidAttrNumber)
|
|
|
|
{
|
|
|
|
datum = heap_getattr(tuple, attnum,
|
|
|
|
RelationGetDescr(catalog), &isnull);
|
|
|
|
if (!isnull)
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
Oid namespaceId;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
|
|
|
namespaceId = DatumGetObjectId(datum);
|
2015-04-06 16:40:55 +02:00
|
|
|
/* temp objects are only reported if they are my own */
|
|
|
|
if (isTempNamespace(namespaceId))
|
|
|
|
{
|
|
|
|
obj->schemaname = "pg_temp";
|
|
|
|
obj->istemp = true;
|
|
|
|
}
|
|
|
|
else if (isAnyTempNamespace(namespaceId))
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
{
|
|
|
|
pfree(obj);
|
|
|
|
heap_close(catalog, AccessShareLock);
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
return;
|
|
|
|
}
|
2015-04-06 16:40:55 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
obj->schemaname = get_namespace_name(namespaceId);
|
|
|
|
obj->istemp = false;
|
|
|
|
}
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (get_object_namensp_unique(obj->address.classId) &&
|
|
|
|
obj->address.objectSubId == 0)
|
|
|
|
{
|
|
|
|
attnum = get_object_attnum_name(obj->address.classId);
|
|
|
|
if (attnum != InvalidAttrNumber)
|
|
|
|
{
|
|
|
|
datum = heap_getattr(tuple, attnum,
|
|
|
|
RelationGetDescr(catalog), &isnull);
|
|
|
|
if (!isnull)
|
|
|
|
obj->objname = pstrdup(NameStr(*DatumGetName(datum)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
heap_close(catalog, AccessShareLock);
|
|
|
|
}
|
2015-04-06 16:40:55 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (object->classId == NamespaceRelationId &&
|
|
|
|
isTempNamespace(object->objectId))
|
|
|
|
obj->istemp = true;
|
|
|
|
}
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
2014-12-30 21:41:46 +01:00
|
|
|
/* object identity, objname and objargs */
|
|
|
|
obj->objidentity =
|
|
|
|
getObjectIdentityParts(&obj->address, &obj->addrnames, &obj->addrargs);
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
2014-12-30 21:41:46 +01:00
|
|
|
/* object type */
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
obj->objecttype = getObjectTypeDescription(&obj->address);
|
|
|
|
|
|
|
|
slist_push_head(&(currentEventTriggerState->SQLDropList), &obj->next);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pg_event_trigger_dropped_objects
|
|
|
|
*
|
|
|
|
* Make the list of dropped objects available to the user function run by the
|
|
|
|
* Event Trigger.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS)
|
|
|
|
{
|
2013-05-29 22:58:43 +02:00
|
|
|
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
Tuplestorestate *tupstore;
|
|
|
|
MemoryContext per_query_ctx;
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
slist_iter iter;
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Protect this function from being called out of context
|
|
|
|
*/
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
!currentEventTriggerState->in_sql_drop)
|
|
|
|
ereport(ERROR,
|
2015-04-08 20:26:50 +02:00
|
|
|
(errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
|
2013-05-29 22:58:43 +02:00
|
|
|
errmsg("%s can only be called in a sql_drop event trigger function",
|
|
|
|
"pg_event_trigger_dropped_objects()")));
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
|
|
|
/* check to see if caller supports us returning a tuplestore */
|
|
|
|
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that cannot accept a set")));
|
|
|
|
if (!(rsinfo->allowedModes & SFRM_Materialize))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("materialize mode required, but it is not allowed in this context")));
|
|
|
|
|
|
|
|
/* Build a tuple descriptor for our result type */
|
|
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
|
|
|
|
/* Build tuplestore to hold the result rows */
|
|
|
|
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
|
|
|
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
|
|
|
|
|
|
|
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
|
|
|
rsinfo->returnMode = SFRM_Materialize;
|
|
|
|
rsinfo->setResult = tupstore;
|
|
|
|
rsinfo->setDesc = tupdesc;
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
slist_foreach(iter, &(currentEventTriggerState->SQLDropList))
|
|
|
|
{
|
|
|
|
SQLDropObject *obj;
|
|
|
|
int i = 0;
|
2015-04-06 16:40:55 +02:00
|
|
|
Datum values[12];
|
|
|
|
bool nulls[12];
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
|
|
|
|
obj = slist_container(SQLDropObject, next, iter.cur);
|
|
|
|
|
|
|
|
MemSet(values, 0, sizeof(values));
|
|
|
|
MemSet(nulls, 0, sizeof(nulls));
|
|
|
|
|
|
|
|
/* classid */
|
|
|
|
values[i++] = ObjectIdGetDatum(obj->address.classId);
|
|
|
|
|
|
|
|
/* objid */
|
|
|
|
values[i++] = ObjectIdGetDatum(obj->address.objectId);
|
|
|
|
|
|
|
|
/* objsubid */
|
|
|
|
values[i++] = Int32GetDatum(obj->address.objectSubId);
|
|
|
|
|
2014-12-19 19:00:45 +01:00
|
|
|
/* original */
|
|
|
|
values[i++] = BoolGetDatum(obj->original);
|
|
|
|
|
|
|
|
/* normal */
|
|
|
|
values[i++] = BoolGetDatum(obj->normal);
|
|
|
|
|
2015-04-06 16:40:55 +02:00
|
|
|
/* is_temporary */
|
|
|
|
values[i++] = BoolGetDatum(obj->istemp);
|
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
/* object_type */
|
|
|
|
values[i++] = CStringGetTextDatum(obj->objecttype);
|
|
|
|
|
|
|
|
/* schema_name */
|
|
|
|
if (obj->schemaname)
|
|
|
|
values[i++] = CStringGetTextDatum(obj->schemaname);
|
|
|
|
else
|
|
|
|
nulls[i++] = true;
|
|
|
|
|
|
|
|
/* object_name */
|
|
|
|
if (obj->objname)
|
|
|
|
values[i++] = CStringGetTextDatum(obj->objname);
|
|
|
|
else
|
|
|
|
nulls[i++] = true;
|
|
|
|
|
|
|
|
/* object_identity */
|
|
|
|
if (obj->objidentity)
|
|
|
|
values[i++] = CStringGetTextDatum(obj->objidentity);
|
|
|
|
else
|
|
|
|
nulls[i++] = true;
|
|
|
|
|
2014-12-30 21:41:46 +01:00
|
|
|
/* address_names and address_args */
|
|
|
|
if (obj->addrnames)
|
|
|
|
{
|
|
|
|
values[i++] = PointerGetDatum(strlist_to_textarray(obj->addrnames));
|
|
|
|
|
|
|
|
if (obj->addrargs)
|
|
|
|
values[i++] = PointerGetDatum(strlist_to_textarray(obj->addrargs));
|
|
|
|
else
|
|
|
|
values[i++] = PointerGetDatum(construct_empty_array(TEXTOID));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nulls[i++] = true;
|
|
|
|
nulls[i++] = true;
|
|
|
|
}
|
|
|
|
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clean up and return the tuplestore */
|
|
|
|
tuplestore_donestoring(tupstore);
|
|
|
|
|
|
|
|
return (Datum) 0;
|
|
|
|
}
|
2014-12-07 16:55:28 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* pg_event_trigger_table_rewrite_oid
|
|
|
|
*
|
|
|
|
* Make the Oid of the table going to be rewritten available to the user
|
|
|
|
* function run by the Event Trigger.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_event_trigger_table_rewrite_oid(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Protect this function from being called out of context
|
|
|
|
*/
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
currentEventTriggerState->table_rewrite_oid == InvalidOid)
|
|
|
|
ereport(ERROR,
|
2015-04-08 20:26:50 +02:00
|
|
|
(errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
|
2015-05-24 03:35:49 +02:00
|
|
|
errmsg("%s can only be called in a table_rewrite event trigger function",
|
|
|
|
"pg_event_trigger_table_rewrite_oid()")));
|
2014-12-07 16:55:28 +01:00
|
|
|
|
|
|
|
PG_RETURN_OID(currentEventTriggerState->table_rewrite_oid);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* pg_event_trigger_table_rewrite_reason
|
|
|
|
*
|
|
|
|
* Make the rewrite reason available to the user.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_event_trigger_table_rewrite_reason(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Protect this function from being called out of context
|
|
|
|
*/
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
currentEventTriggerState->table_rewrite_reason == 0)
|
|
|
|
ereport(ERROR,
|
2015-04-08 20:26:50 +02:00
|
|
|
(errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
|
2015-05-24 03:35:49 +02:00
|
|
|
errmsg("%s can only be called in a table_rewrite event trigger function",
|
|
|
|
"pg_event_trigger_table_rewrite_reason()")));
|
2014-12-07 16:55:28 +01:00
|
|
|
|
|
|
|
PG_RETURN_INT32(currentEventTriggerState->table_rewrite_reason);
|
|
|
|
}
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
* Support for DDL command deparsing
|
|
|
|
*
|
|
|
|
* The routines below enable an event trigger function to obtain a list of
|
|
|
|
* DDL commands as they are executed. There are three main pieces to this
|
|
|
|
* feature:
|
|
|
|
*
|
|
|
|
* 1) Within ProcessUtilitySlow, or some sub-routine thereof, each DDL command
|
|
|
|
* adds a struct CollectedCommand representation of itself to the command list,
|
|
|
|
* using the routines below.
|
|
|
|
*
|
|
|
|
* 2) Some time after that, ddl_command_end fires and the command list is made
|
|
|
|
* available to the event trigger function via pg_event_trigger_ddl_commands();
|
|
|
|
* the complete command details are exposed as a column of type pg_ddl_command.
|
|
|
|
*
|
|
|
|
* 3) An extension can install a function capable of taking a value of type
|
|
|
|
* pg_ddl_command and transform it into some external, user-visible and/or
|
|
|
|
* -modifiable representation.
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Inhibit DDL command collection.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerInhibitCommandCollection(void)
|
|
|
|
{
|
|
|
|
if (!currentEventTriggerState)
|
|
|
|
return;
|
|
|
|
|
|
|
|
currentEventTriggerState->commandCollectionInhibited = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Re-establish DDL command collection.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerUndoInhibitCommandCollection(void)
|
|
|
|
{
|
|
|
|
if (!currentEventTriggerState)
|
|
|
|
return;
|
|
|
|
|
|
|
|
currentEventTriggerState->commandCollectionInhibited = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* EventTriggerCollectSimpleCommand
|
|
|
|
* Save data about a simple DDL command that was just executed
|
|
|
|
*
|
|
|
|
* address identifies the object being operated on. secondaryObject is an
|
|
|
|
* object address that was related in some way to the executed command; its
|
|
|
|
* meaning is command-specific.
|
|
|
|
*
|
|
|
|
* For instance, for an ALTER obj SET SCHEMA command, objtype is the type of
|
|
|
|
* object being moved, objectId is its OID, and secondaryOid is the OID of the
|
|
|
|
* old schema. (The destination schema OID can be obtained by catalog lookup
|
|
|
|
* of the object.)
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerCollectSimpleCommand(ObjectAddress address,
|
|
|
|
ObjectAddress secondaryObject,
|
|
|
|
Node *parsetree)
|
|
|
|
{
|
|
|
|
MemoryContext oldcxt;
|
|
|
|
CollectedCommand *command;
|
|
|
|
|
|
|
|
/* ignore if event trigger context not set, or collection disabled */
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
currentEventTriggerState->commandCollectionInhibited)
|
|
|
|
return;
|
|
|
|
|
|
|
|
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
|
|
|
|
|
|
|
|
command = palloc(sizeof(CollectedCommand));
|
|
|
|
|
|
|
|
command->type = SCT_Simple;
|
|
|
|
command->in_extension = creating_extension;
|
|
|
|
|
|
|
|
command->d.simple.address = address;
|
|
|
|
command->d.simple.secondaryObject = secondaryObject;
|
|
|
|
command->parsetree = copyObject(parsetree);
|
|
|
|
|
|
|
|
currentEventTriggerState->commandList = lappend(currentEventTriggerState->commandList,
|
2015-05-24 03:35:49 +02:00
|
|
|
command);
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* EventTriggerAlterTableStart
|
|
|
|
* Prepare to receive data on an ALTER TABLE command about to be executed
|
|
|
|
*
|
|
|
|
* Note we don't collect the command immediately; instead we keep it in
|
|
|
|
* currentCommand, and only when we're done processing the subcommands we will
|
|
|
|
* add it to the command list.
|
|
|
|
*
|
|
|
|
* XXX -- this API isn't considering the possibility of an ALTER TABLE command
|
|
|
|
* being called reentrantly by an event trigger function. Do we need stackable
|
2015-05-24 03:35:49 +02:00
|
|
|
* commands at this level? Perhaps at least we should detect the condition and
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
* raise an error.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerAlterTableStart(Node *parsetree)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
MemoryContext oldcxt;
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
CollectedCommand *command;
|
|
|
|
|
|
|
|
/* ignore if event trigger context not set, or collection disabled */
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
currentEventTriggerState->commandCollectionInhibited)
|
|
|
|
return;
|
|
|
|
|
|
|
|
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
|
|
|
|
|
|
|
|
command = palloc(sizeof(CollectedCommand));
|
|
|
|
|
|
|
|
command->type = SCT_AlterTable;
|
|
|
|
command->in_extension = creating_extension;
|
|
|
|
|
|
|
|
command->d.alterTable.classId = RelationRelationId;
|
|
|
|
command->d.alterTable.objectId = InvalidOid;
|
|
|
|
command->d.alterTable.subcmds = NIL;
|
|
|
|
command->parsetree = copyObject(parsetree);
|
|
|
|
|
|
|
|
currentEventTriggerState->currentCommand = command;
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remember the OID of the object being affected by an ALTER TABLE.
|
|
|
|
*
|
|
|
|
* This is needed because in some cases we don't know the OID until later.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerAlterTableRelid(Oid objectId)
|
|
|
|
{
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
currentEventTriggerState->commandCollectionInhibited)
|
|
|
|
return;
|
|
|
|
|
|
|
|
currentEventTriggerState->currentCommand->d.alterTable.objectId = objectId;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* EventTriggerCollectAlterTableSubcmd
|
|
|
|
* Save data about a single part of an ALTER TABLE.
|
|
|
|
*
|
|
|
|
* Several different commands go through this path, but apart from ALTER TABLE
|
|
|
|
* itself, they are all concerned with AlterTableCmd nodes that are generated
|
|
|
|
* internally, so that's all that this code needs to handle at the moment.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerCollectAlterTableSubcmd(Node *subcmd, ObjectAddress address)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
MemoryContext oldcxt;
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
CollectedATSubcmd *newsub;
|
|
|
|
|
|
|
|
/* ignore if event trigger context not set, or collection disabled */
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
currentEventTriggerState->commandCollectionInhibited)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Assert(IsA(subcmd, AlterTableCmd));
|
|
|
|
Assert(OidIsValid(currentEventTriggerState->currentCommand->d.alterTable.objectId));
|
|
|
|
|
|
|
|
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
|
|
|
|
|
|
|
|
newsub = palloc(sizeof(CollectedATSubcmd));
|
|
|
|
newsub->address = address;
|
|
|
|
newsub->parsetree = copyObject(subcmd);
|
|
|
|
|
|
|
|
currentEventTriggerState->currentCommand->d.alterTable.subcmds =
|
|
|
|
lappend(currentEventTriggerState->currentCommand->d.alterTable.subcmds, newsub);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* EventTriggerAlterTableEnd
|
|
|
|
* Finish up saving an ALTER TABLE command, and add it to command list.
|
|
|
|
*
|
2015-05-20 15:18:11 +02:00
|
|
|
* FIXME this API isn't considering the possibility that an xact/subxact is
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
* aborted partway through. Probably it's best to add an
|
|
|
|
* AtEOSubXact_EventTriggers() to fix this.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerAlterTableEnd(void)
|
|
|
|
{
|
|
|
|
/* ignore if event trigger context not set, or collection disabled */
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
currentEventTriggerState->commandCollectionInhibited)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* If no subcommands, don't collect */
|
|
|
|
if (list_length(currentEventTriggerState->currentCommand->d.alterTable.subcmds) != 0)
|
|
|
|
{
|
|
|
|
currentEventTriggerState->commandList =
|
|
|
|
lappend(currentEventTriggerState->commandList,
|
|
|
|
currentEventTriggerState->currentCommand);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pfree(currentEventTriggerState->currentCommand);
|
|
|
|
|
|
|
|
currentEventTriggerState->currentCommand = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* EventTriggerCollectGrant
|
|
|
|
* Save data about a GRANT/REVOKE command being executed
|
|
|
|
*
|
|
|
|
* This function creates a copy of the InternalGrant, as the original might
|
|
|
|
* not have the right lifetime.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerCollectGrant(InternalGrant *istmt)
|
|
|
|
{
|
|
|
|
MemoryContext oldcxt;
|
|
|
|
CollectedCommand *command;
|
2015-05-24 03:35:49 +02:00
|
|
|
InternalGrant *icopy;
|
|
|
|
ListCell *cell;
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
|
|
|
|
/* ignore if event trigger context not set, or collection disabled */
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
currentEventTriggerState->commandCollectionInhibited)
|
|
|
|
return;
|
|
|
|
|
|
|
|
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is tedious, but necessary.
|
|
|
|
*/
|
|
|
|
icopy = palloc(sizeof(InternalGrant));
|
|
|
|
memcpy(icopy, istmt, sizeof(InternalGrant));
|
|
|
|
icopy->objects = list_copy(istmt->objects);
|
|
|
|
icopy->grantees = list_copy(istmt->grantees);
|
|
|
|
icopy->col_privs = NIL;
|
|
|
|
foreach(cell, istmt->col_privs)
|
|
|
|
icopy->col_privs = lappend(icopy->col_privs, copyObject(lfirst(cell)));
|
|
|
|
|
|
|
|
/* Now collect it, using the copied InternalGrant */
|
|
|
|
command = palloc(sizeof(CollectedCommand));
|
|
|
|
command->type = SCT_Grant;
|
|
|
|
command->in_extension = creating_extension;
|
|
|
|
command->d.grant.istmt = icopy;
|
|
|
|
command->parsetree = NULL;
|
|
|
|
|
|
|
|
currentEventTriggerState->commandList =
|
|
|
|
lappend(currentEventTriggerState->commandList, command);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* EventTriggerCollectAlterOpFam
|
|
|
|
* Save data about an ALTER OPERATOR FAMILY ADD/DROP command being
|
|
|
|
* executed
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, Oid opfamoid,
|
2015-05-24 03:35:49 +02:00
|
|
|
List *operators, List *procedures)
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
MemoryContext oldcxt;
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
CollectedCommand *command;
|
|
|
|
|
|
|
|
/* ignore if event trigger context not set, or collection disabled */
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
currentEventTriggerState->commandCollectionInhibited)
|
|
|
|
return;
|
|
|
|
|
|
|
|
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
|
|
|
|
|
|
|
|
command = palloc(sizeof(CollectedCommand));
|
|
|
|
command->type = SCT_AlterOpFamily;
|
|
|
|
command->in_extension = creating_extension;
|
|
|
|
ObjectAddressSet(command->d.opfam.address,
|
|
|
|
OperatorFamilyRelationId, opfamoid);
|
|
|
|
command->d.opfam.operators = operators;
|
|
|
|
command->d.opfam.procedures = procedures;
|
2017-03-09 21:18:59 +01:00
|
|
|
command->parsetree = (Node *) copyObject(stmt);
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
|
|
|
|
currentEventTriggerState->commandList =
|
|
|
|
lappend(currentEventTriggerState->commandList, command);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* EventTriggerCollectCreateOpClass
|
|
|
|
* Save data about a CREATE OPERATOR CLASS command being executed
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, Oid opcoid,
|
2015-05-24 03:35:49 +02:00
|
|
|
List *operators, List *procedures)
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
MemoryContext oldcxt;
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
CollectedCommand *command;
|
|
|
|
|
|
|
|
/* ignore if event trigger context not set, or collection disabled */
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
currentEventTriggerState->commandCollectionInhibited)
|
|
|
|
return;
|
|
|
|
|
|
|
|
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
|
|
|
|
|
|
|
|
command = palloc0(sizeof(CollectedCommand));
|
|
|
|
command->type = SCT_CreateOpClass;
|
|
|
|
command->in_extension = creating_extension;
|
|
|
|
ObjectAddressSet(command->d.createopc.address,
|
|
|
|
OperatorClassRelationId, opcoid);
|
|
|
|
command->d.createopc.operators = operators;
|
|
|
|
command->d.createopc.procedures = procedures;
|
2017-03-09 21:18:59 +01:00
|
|
|
command->parsetree = (Node *) copyObject(stmt);
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
|
|
|
|
currentEventTriggerState->commandList =
|
|
|
|
lappend(currentEventTriggerState->commandList, command);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* EventTriggerCollectAlterTSConfig
|
|
|
|
* Save data about an ALTER TEXT SEARCH CONFIGURATION command being
|
|
|
|
* executed
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, Oid cfgId,
|
|
|
|
Oid *dictIds, int ndicts)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
MemoryContext oldcxt;
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
CollectedCommand *command;
|
|
|
|
|
|
|
|
/* ignore if event trigger context not set, or collection disabled */
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
currentEventTriggerState->commandCollectionInhibited)
|
|
|
|
return;
|
|
|
|
|
|
|
|
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
|
|
|
|
|
|
|
|
command = palloc0(sizeof(CollectedCommand));
|
|
|
|
command->type = SCT_AlterTSConfig;
|
|
|
|
command->in_extension = creating_extension;
|
|
|
|
ObjectAddressSet(command->d.atscfg.address,
|
|
|
|
TSConfigRelationId, cfgId);
|
|
|
|
command->d.atscfg.dictIds = palloc(sizeof(Oid) * ndicts);
|
|
|
|
memcpy(command->d.atscfg.dictIds, dictIds, sizeof(Oid) * ndicts);
|
|
|
|
command->d.atscfg.ndicts = ndicts;
|
2017-03-09 21:18:59 +01:00
|
|
|
command->parsetree = (Node *) copyObject(stmt);
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
|
|
|
|
currentEventTriggerState->commandList =
|
|
|
|
lappend(currentEventTriggerState->commandList, command);
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* EventTriggerCollectAlterDefPrivs
|
|
|
|
* Save data about an ALTER DEFAULT PRIVILEGES command being
|
|
|
|
* executed
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt)
|
|
|
|
{
|
2015-05-24 03:35:49 +02:00
|
|
|
MemoryContext oldcxt;
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
CollectedCommand *command;
|
|
|
|
|
|
|
|
/* ignore if event trigger context not set, or collection disabled */
|
|
|
|
if (!currentEventTriggerState ||
|
|
|
|
currentEventTriggerState->commandCollectionInhibited)
|
|
|
|
return;
|
|
|
|
|
|
|
|
oldcxt = MemoryContextSwitchTo(currentEventTriggerState->cxt);
|
|
|
|
|
|
|
|
command = palloc0(sizeof(CollectedCommand));
|
|
|
|
command->type = SCT_AlterDefaultPrivileges;
|
|
|
|
command->d.defprivs.objtype = stmt->action->objtype;
|
|
|
|
command->in_extension = creating_extension;
|
2017-03-09 21:18:59 +01:00
|
|
|
command->parsetree = (Node *) copyObject(stmt);
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
|
|
|
|
currentEventTriggerState->commandList =
|
|
|
|
lappend(currentEventTriggerState->commandList, command);
|
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* In a ddl_command_end event trigger, this function reports the DDL commands
|
|
|
|
* being run.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
Tuplestorestate *tupstore;
|
|
|
|
MemoryContext per_query_ctx;
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Protect this function from being called out of context
|
|
|
|
*/
|
|
|
|
if (!currentEventTriggerState)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_E_R_I_E_EVENT_TRIGGER_PROTOCOL_VIOLATED),
|
|
|
|
errmsg("%s can only be called in an event trigger function",
|
|
|
|
"pg_event_trigger_ddl_commands()")));
|
|
|
|
|
|
|
|
/* check to see if caller supports us returning a tuplestore */
|
|
|
|
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that cannot accept a set")));
|
|
|
|
if (!(rsinfo->allowedModes & SFRM_Materialize))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("materialize mode required, but it is not allowed in this context")));
|
|
|
|
|
|
|
|
/* Build a tuple descriptor for our result type */
|
|
|
|
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
|
|
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
|
|
|
|
/* Build tuplestore to hold the result rows */
|
|
|
|
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
|
|
|
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
|
|
|
|
|
|
|
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
|
|
|
rsinfo->returnMode = SFRM_Materialize;
|
|
|
|
rsinfo->setResult = tupstore;
|
|
|
|
rsinfo->setDesc = tupdesc;
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
foreach(lc, currentEventTriggerState->commandList)
|
|
|
|
{
|
|
|
|
CollectedCommand *cmd = lfirst(lc);
|
|
|
|
Datum values[9];
|
|
|
|
bool nulls[9];
|
|
|
|
ObjectAddress addr;
|
|
|
|
int i = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For IF NOT EXISTS commands that attempt to create an existing
|
|
|
|
* object, the returned OID is Invalid. Don't return anything.
|
|
|
|
*
|
|
|
|
* One might think that a viable alternative would be to look up the
|
2015-05-24 03:35:49 +02:00
|
|
|
* Oid of the existing object and run the deparse with that. But
|
|
|
|
* since the parse tree might be different from the one that created
|
|
|
|
* the object in the first place, we might not end up in a consistent
|
|
|
|
* state anyway.
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
*/
|
|
|
|
if (cmd->type == SCT_Simple &&
|
|
|
|
!OidIsValid(cmd->d.simple.address.objectId))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
MemSet(nulls, 0, sizeof(nulls));
|
|
|
|
|
|
|
|
switch (cmd->type)
|
|
|
|
{
|
|
|
|
case SCT_Simple:
|
|
|
|
case SCT_AlterTable:
|
|
|
|
case SCT_AlterOpFamily:
|
|
|
|
case SCT_CreateOpClass:
|
|
|
|
case SCT_AlterTSConfig:
|
|
|
|
{
|
|
|
|
char *identity;
|
|
|
|
char *type;
|
|
|
|
char *schema = NULL;
|
|
|
|
|
|
|
|
if (cmd->type == SCT_Simple)
|
|
|
|
addr = cmd->d.simple.address;
|
|
|
|
else if (cmd->type == SCT_AlterTable)
|
|
|
|
ObjectAddressSet(addr,
|
|
|
|
cmd->d.alterTable.classId,
|
|
|
|
cmd->d.alterTable.objectId);
|
|
|
|
else if (cmd->type == SCT_AlterOpFamily)
|
|
|
|
addr = cmd->d.opfam.address;
|
|
|
|
else if (cmd->type == SCT_CreateOpClass)
|
|
|
|
addr = cmd->d.createopc.address;
|
|
|
|
else if (cmd->type == SCT_AlterTSConfig)
|
|
|
|
addr = cmd->d.atscfg.address;
|
|
|
|
|
|
|
|
type = getObjectTypeDescription(&addr);
|
|
|
|
identity = getObjectIdentity(&addr);
|
|
|
|
|
|
|
|
/*
|
2015-05-24 03:35:49 +02:00
|
|
|
* Obtain schema name, if any ("pg_temp" if a temp
|
|
|
|
* object). If the object class is not in the supported
|
|
|
|
* list here, we assume it's a schema-less object type,
|
|
|
|
* and thus "schema" remains set to NULL.
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
*/
|
|
|
|
if (is_objectclass_supported(addr.classId))
|
|
|
|
{
|
|
|
|
AttrNumber nspAttnum;
|
|
|
|
|
|
|
|
nspAttnum = get_object_attnum_namespace(addr.classId);
|
|
|
|
if (nspAttnum != InvalidAttrNumber)
|
|
|
|
{
|
|
|
|
Relation catalog;
|
|
|
|
HeapTuple objtup;
|
|
|
|
Oid schema_oid;
|
|
|
|
bool isnull;
|
|
|
|
|
|
|
|
catalog = heap_open(addr.classId, AccessShareLock);
|
|
|
|
objtup = get_catalog_object_by_oid(catalog,
|
|
|
|
addr.objectId);
|
|
|
|
if (!HeapTupleIsValid(objtup))
|
|
|
|
elog(ERROR, "cache lookup failed for object %u/%u",
|
|
|
|
addr.classId, addr.objectId);
|
|
|
|
schema_oid =
|
|
|
|
heap_getattr(objtup, nspAttnum,
|
2015-05-24 03:35:49 +02:00
|
|
|
RelationGetDescr(catalog), &isnull);
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
if (isnull)
|
|
|
|
elog(ERROR,
|
2015-05-24 03:35:49 +02:00
|
|
|
"invalid null namespace in object %u/%u/%d",
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
addr.classId, addr.objectId, addr.objectSubId);
|
|
|
|
/* XXX not quite get_namespace_name_or_temp */
|
|
|
|
if (isAnyTempNamespace(schema_oid))
|
|
|
|
schema = pstrdup("pg_temp");
|
|
|
|
else
|
|
|
|
schema = get_namespace_name(schema_oid);
|
|
|
|
|
|
|
|
heap_close(catalog, AccessShareLock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* classid */
|
|
|
|
values[i++] = ObjectIdGetDatum(addr.classId);
|
|
|
|
/* objid */
|
|
|
|
values[i++] = ObjectIdGetDatum(addr.objectId);
|
|
|
|
/* objsubid */
|
|
|
|
values[i++] = Int32GetDatum(addr.objectSubId);
|
|
|
|
/* command tag */
|
|
|
|
values[i++] = CStringGetTextDatum(CreateCommandTag(cmd->parsetree));
|
|
|
|
/* object_type */
|
|
|
|
values[i++] = CStringGetTextDatum(type);
|
|
|
|
/* schema */
|
|
|
|
if (schema == NULL)
|
|
|
|
nulls[i++] = true;
|
|
|
|
else
|
|
|
|
values[i++] = CStringGetTextDatum(schema);
|
|
|
|
/* identity */
|
|
|
|
values[i++] = CStringGetTextDatum(identity);
|
|
|
|
/* in_extension */
|
|
|
|
values[i++] = BoolGetDatum(cmd->in_extension);
|
|
|
|
/* command */
|
|
|
|
values[i++] = PointerGetDatum(cmd);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCT_AlterDefaultPrivileges:
|
|
|
|
/* classid */
|
|
|
|
nulls[i++] = true;
|
|
|
|
/* objid */
|
|
|
|
nulls[i++] = true;
|
|
|
|
/* objsubid */
|
|
|
|
nulls[i++] = true;
|
|
|
|
/* command tag */
|
|
|
|
values[i++] = CStringGetTextDatum(CreateCommandTag(cmd->parsetree));
|
|
|
|
/* object_type */
|
|
|
|
values[i++] = CStringGetTextDatum(stringify_adefprivs_objtype(
|
2015-05-24 03:35:49 +02:00
|
|
|
cmd->d.defprivs.objtype));
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
/* schema */
|
|
|
|
nulls[i++] = true;
|
|
|
|
/* identity */
|
|
|
|
nulls[i++] = true;
|
|
|
|
/* in_extension */
|
|
|
|
values[i++] = BoolGetDatum(cmd->in_extension);
|
|
|
|
/* command */
|
|
|
|
values[i++] = PointerGetDatum(cmd);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SCT_Grant:
|
|
|
|
/* classid */
|
|
|
|
nulls[i++] = true;
|
|
|
|
/* objid */
|
|
|
|
nulls[i++] = true;
|
|
|
|
/* objsubid */
|
|
|
|
nulls[i++] = true;
|
|
|
|
/* command tag */
|
|
|
|
values[i++] = CStringGetTextDatum(cmd->d.grant.istmt->is_grant ?
|
|
|
|
"GRANT" : "REVOKE");
|
|
|
|
/* object_type */
|
|
|
|
values[i++] = CStringGetTextDatum(stringify_grantobjtype(
|
2015-05-24 03:35:49 +02:00
|
|
|
cmd->d.grant.istmt->objtype));
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
/* schema */
|
|
|
|
nulls[i++] = true;
|
|
|
|
/* identity */
|
|
|
|
nulls[i++] = true;
|
|
|
|
/* in_extension */
|
|
|
|
values[i++] = BoolGetDatum(cmd->in_extension);
|
|
|
|
/* command */
|
|
|
|
values[i++] = PointerGetDatum(cmd);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clean up and return the tuplestore */
|
|
|
|
tuplestore_donestoring(tupstore);
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return the GrantObjectType as a string, as it would appear in GRANT and
|
|
|
|
* REVOKE commands.
|
|
|
|
*/
|
|
|
|
static const char *
|
|
|
|
stringify_grantobjtype(GrantObjectType objtype)
|
|
|
|
{
|
|
|
|
switch (objtype)
|
|
|
|
{
|
|
|
|
case ACL_OBJECT_COLUMN:
|
|
|
|
return "COLUMN";
|
|
|
|
case ACL_OBJECT_RELATION:
|
|
|
|
return "TABLE";
|
|
|
|
case ACL_OBJECT_SEQUENCE:
|
|
|
|
return "SEQUENCE";
|
|
|
|
case ACL_OBJECT_DATABASE:
|
|
|
|
return "DATABASE";
|
|
|
|
case ACL_OBJECT_DOMAIN:
|
|
|
|
return "DOMAIN";
|
|
|
|
case ACL_OBJECT_FDW:
|
|
|
|
return "FOREIGN DATA WRAPPER";
|
|
|
|
case ACL_OBJECT_FOREIGN_SERVER:
|
|
|
|
return "FOREIGN SERVER";
|
|
|
|
case ACL_OBJECT_FUNCTION:
|
|
|
|
return "FUNCTION";
|
|
|
|
case ACL_OBJECT_LANGUAGE:
|
|
|
|
return "LANGUAGE";
|
|
|
|
case ACL_OBJECT_LARGEOBJECT:
|
|
|
|
return "LARGE OBJECT";
|
|
|
|
case ACL_OBJECT_NAMESPACE:
|
|
|
|
return "SCHEMA";
|
|
|
|
case ACL_OBJECT_TABLESPACE:
|
|
|
|
return "TABLESPACE";
|
|
|
|
case ACL_OBJECT_TYPE:
|
|
|
|
return "TYPE";
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized type %d", objtype);
|
2015-05-24 03:35:49 +02:00
|
|
|
return "???"; /* keep compiler quiet */
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return the GrantObjectType as a string; as above, but use the spelling
|
|
|
|
* in ALTER DEFAULT PRIVILEGES commands instead.
|
|
|
|
*/
|
|
|
|
static const char *
|
|
|
|
stringify_adefprivs_objtype(GrantObjectType objtype)
|
|
|
|
{
|
|
|
|
switch (objtype)
|
|
|
|
{
|
|
|
|
case ACL_OBJECT_RELATION:
|
|
|
|
return "TABLES";
|
|
|
|
break;
|
|
|
|
case ACL_OBJECT_FUNCTION:
|
|
|
|
return "FUNCTIONS";
|
|
|
|
break;
|
|
|
|
case ACL_OBJECT_SEQUENCE:
|
|
|
|
return "SEQUENCES";
|
|
|
|
break;
|
|
|
|
case ACL_OBJECT_TYPE:
|
|
|
|
return "TYPES";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized type %d", objtype);
|
2015-05-24 03:35:49 +02:00
|
|
|
return "???"; /* keep compiler quiet */
|
Allow on-the-fly capture of DDL event details
This feature lets user code inspect and take action on DDL events.
Whenever a ddl_command_end event trigger is installed, DDL actions
executed are saved to a list which can be inspected during execution of
a function attached to ddl_command_end.
The set-returning function pg_event_trigger_ddl_commands can be used to
list actions so captured; it returns data about the type of command
executed, as well as the affected object. This is sufficient for many
uses of this feature. For the cases where it is not, we also provide a
"command" column of a new pseudo-type pg_ddl_command, which is a
pointer to a C structure that can be accessed by C code. The struct
contains all the info necessary to completely inspect and even
reconstruct the executed command.
There is no actual deparse code here; that's expected to come later.
What we have is enough infrastructure that the deparsing can be done in
an external extension. The intention is that we will add some deparsing
code in a later release, as an in-core extension.
A new test module is included. It's probably insufficient as is, but it
should be sufficient as a starting point for a more complete and
future-proof approach.
Authors: Álvaro Herrera, with some help from Andres Freund, Ian Barwick,
Abhijit Menon-Sen.
Reviews by Andres Freund, Robert Haas, Amit Kapila, Michael Paquier,
Craig Ringer, David Steele.
Additional input from Chris Browne, Dimitri Fontaine, Stephen Frost,
Petr Jelínek, Tom Lane, Jim Nasby, Steven Singer, Pavel Stěhule.
Based on original work by Dimitri Fontaine, though I didn't use his
code.
Discussion:
https://www.postgresql.org/message-id/m2txrsdzxa.fsf@2ndQuadrant.fr
https://www.postgresql.org/message-id/20131108153322.GU5809@eldon.alvh.no-ip.org
https://www.postgresql.org/message-id/20150215044814.GL3391@alvh.no-ip.org
2015-05-12 00:14:31 +02:00
|
|
|
}
|
|
|
|
}
|