diff options
| author | Alvaro Herrera | 2015-05-11 22:14:31 +0000 |
|---|---|---|
| committer | Alvaro Herrera | 2015-05-11 22:14:31 +0000 |
| commit | b488c580aef4e05f39be5daaab6464da5b22a494 (patch) | |
| tree | 79e7605ff000293710de977a5389a8fbf615f702 /src/include | |
| parent | fa2642438f189c2b169ace3ac1df19533b9c7781 (diff) | |
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
Diffstat (limited to 'src/include')
| -rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
| -rw-r--r-- | src/include/catalog/opfam_internal.h | 28 | ||||
| -rw-r--r-- | src/include/catalog/pg_proc.h | 11 | ||||
| -rw-r--r-- | src/include/catalog/pg_type.h | 4 | ||||
| -rw-r--r-- | src/include/commands/defrem.h | 1 | ||||
| -rw-r--r-- | src/include/commands/event_trigger.h | 26 | ||||
| -rw-r--r-- | src/include/commands/extension.h | 2 | ||||
| -rw-r--r-- | src/include/nodes/parsenodes.h | 10 | ||||
| -rw-r--r-- | src/include/tcop/deparse_utility.h | 105 | ||||
| -rw-r--r-- | src/include/utils/aclchk_internal.h | 45 | ||||
| -rw-r--r-- | src/include/utils/builtins.h | 5 |
11 files changed, 237 insertions, 2 deletions
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 662ba27a414..80176dd287a 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201505091 +#define CATALOG_VERSION_NO 201505111 #endif diff --git a/src/include/catalog/opfam_internal.h b/src/include/catalog/opfam_internal.h new file mode 100644 index 00000000000..f01dcbe3e31 --- /dev/null +++ b/src/include/catalog/opfam_internal.h @@ -0,0 +1,28 @@ +/*------------------------------------------------------------------------- + * + * opfam_internal.h + * + * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/opfam_internal.h + * + *------------------------------------------------------------------------- + */ +#ifndef OPFAM_INTERNAL_H +#define OPFAM_INTERNAL_H + +/* + * We use lists of this struct type to keep track of both operators and + * procedures while building or adding to an opfamily. + */ +typedef struct +{ + Oid object; /* operator or support proc's OID */ + int number; /* strategy or support proc number */ + Oid lefttype; /* lefttype */ + Oid righttype; /* righttype */ + Oid sortfamily; /* ordering operator's sort opfamily, or 0 */ +} OpFamilyMember; + +#endif /* OPFAM_INTERNAL_H */ diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 5fa65d63a87..41838c0a8d3 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -233,6 +233,15 @@ DATA(insert OID = 84 ( boolne PGNSP PGUID 12 1 0 0 0 f f f t t f i 2 0 16 DATA(insert OID = 89 ( version PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 25 "" _null_ _null_ _null_ _null_ _null_ pgsql_version _null_ _null_ _null_ )); DESCR("PostgreSQL version string"); +DATA(insert OID = 86 ( pg_ddl_command_in PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 32 "2275" _null_ _null_ _null_ _null_ _null_ pg_ddl_command_in _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 87 ( pg_ddl_command_out PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 2275 "32" _null_ _null_ _null_ _null_ _null_ pg_ddl_command_out _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 88 ( pg_ddl_command_recv PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 32 "2281" _null_ _null_ _null_ _null_ _null_ pg_ddl_command_recv _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 90 ( pg_ddl_command_send PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 17 "32" _null_ _null_ _null_ _null_ _null_ pg_ddl_command_send _null_ _null_ _null_ )); +DESCR("I/O"); + /* OIDS 100 - 199 */ DATA(insert OID = 101 ( eqsel PGNSP PGUID 12 1 0 0 0 f f f f t f s 4 0 701 "2281 26 2281 23" _null_ _null_ _null_ _null_ _null_ eqsel _null_ _null_ _null_ )); @@ -5163,6 +5172,8 @@ DATA(insert OID = 4566 ( pg_event_trigger_table_rewrite_oid PGNSP PGUID 12 1 0 DESCR("return Oid of the table getting rewritten"); DATA(insert OID = 4567 ( pg_event_trigger_table_rewrite_reason PGNSP PGUID 12 1 0 0 0 f f f f t f s 0 0 23 "" _null_ _null_ _null_ _null_ _null_ pg_event_trigger_table_rewrite_reason _null_ _null_ _null_ )); DESCR("return reason code for table getting rewritten"); +DATA(insert OID = 4568 ( pg_event_trigger_ddl_commands PGNSP PGUID 12 10 100 0 0 f f f f t t s 0 0 2249 "" "{26,26,23,25,25,25,25,16,32}" "{o,o,o,o,o,o,o,o,o}" "{classid, objid, objsubid, command_tag, object_type, schema_name, object_identity, in_extension, command}" _null_ _null_ pg_event_trigger_ddl_commands _null_ _null_ _null_ )); +DESCR("list DDL actions being executed by the current command"); /* generic transition functions for ordered-set aggregates */ DATA(insert OID = 3970 ( ordered_set_transition PGNSP PGUID 12 1 0 0 0 f f f f f f i 2 0 2281 "2281 2276" _null_ _null_ _null_ _null_ _null_ ordered_set_transition _null_ _null_ _null_ )); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 24933539aab..4284a704d3c 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -364,6 +364,10 @@ DATA(insert OID = 194 ( pg_node_tree PGNSP PGUID -1 f b S f t \054 0 0 0 pg_node DESCR("string representing an internal node tree"); #define PGNODETREEOID 194 +DATA(insert OID = 32 ( pg_ddl_command PGNSP PGUID SIZEOF_POINTER t p P f t \054 0 0 0 pg_ddl_command_in pg_ddl_command_out pg_ddl_command_recv pg_ddl_command_send - - - ALIGNOF_POINTER p f 0 -1 0 0 _null_ _null_ _null_ )); +DESCR("internal type for passing CollectedCommand"); +#define PGDDLCOMMANDOID 32 + /* OIDS 200 - 299 */ DATA(insert OID = 210 ( smgr PGNSP PGUID 2 t b U f t \054 0 0 0 smgrin smgrout - - - - - s p f 0 -1 0 0 _null_ _null_ _null_ )); diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 335f09cba4c..c3a1748e00f 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -90,6 +90,7 @@ extern void IsThereOpClassInNamespace(const char *opcname, Oid opcmethod, extern void IsThereOpFamilyInNamespace(const char *opfname, Oid opfmethod, Oid opfnamespace); extern Oid get_am_oid(const char *amname, bool missing_ok); +extern char *get_am_name(Oid amOid); extern Oid get_opclass_oid(Oid amID, List *opclassname, bool missing_ok); extern Oid get_opfamily_oid(Oid amID, List *opfamilyname, bool missing_ok); diff --git a/src/include/commands/event_trigger.h b/src/include/commands/event_trigger.h index 7eb21560856..579e1ef8bd2 100644 --- a/src/include/commands/event_trigger.h +++ b/src/include/commands/event_trigger.h @@ -17,6 +17,8 @@ #include "catalog/objectaddress.h" #include "catalog/pg_event_trigger.h" #include "nodes/parsenodes.h" +#include "utils/aclchk_internal.h" +#include "tcop/deparse_utility.h" typedef struct EventTriggerData { @@ -60,4 +62,28 @@ extern bool trackDroppedObjectsNeeded(void); extern void EventTriggerSQLDropAddObject(const ObjectAddress *object, bool original, bool normal); +extern void EventTriggerInhibitCommandCollection(void); +extern void EventTriggerUndoInhibitCommandCollection(void); + +extern void EventTriggerCollectSimpleCommand(ObjectAddress address, + ObjectAddress secondaryObject, + Node *parsetree); + +extern void EventTriggerAlterTableStart(Node *parsetree); +extern void EventTriggerAlterTableRelid(Oid objectId); +extern void EventTriggerCollectAlterTableSubcmd(Node *subcmd, + ObjectAddress address); +extern void EventTriggerAlterTableEnd(void); + +extern void EventTriggerCollectGrant(InternalGrant *istmt); +extern void EventTriggerCollectAlterOpFam(AlterOpFamilyStmt *stmt, + Oid opfamoid, List *operators, + List *procedures); +extern void EventTriggerCollectCreateOpClass(CreateOpClassStmt *stmt, + Oid opcoid, List *operators, + List *procedures); +extern void EventTriggerCollectAlterTSConfig(AlterTSConfigurationStmt *stmt, + Oid cfgId, Oid *dictIds, int ndicts); +extern void EventTriggerCollectAlterDefPrivs(AlterDefaultPrivilegesStmt *stmt); + #endif /* EVENT_TRIGGER_H */ diff --git a/src/include/commands/extension.h b/src/include/commands/extension.h index 40ecea2fee4..0423350c9aa 100644 --- a/src/include/commands/extension.h +++ b/src/include/commands/extension.h @@ -24,7 +24,7 @@ * on the current pg_extension object for each SQL object created by its * installation script. */ -extern bool creating_extension; +extern PGDLLIMPORT bool creating_extension; extern Oid CurrentExtensionObject; diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 91ca9c6fd0e..556c1c5d9da 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2911,9 +2911,19 @@ typedef struct AlterTSDictionaryStmt /* * TS Configuration stmts: DefineStmt, RenameStmt and DropStmt are default */ +typedef enum AlterTSConfigType +{ + ALTER_TSCONFIG_ADD_MAPPING, + ALTER_TSCONFIG_ALTER_MAPPING_FOR_TOKEN, + ALTER_TSCONFIG_REPLACE_DICT, + ALTER_TSCONFIG_REPLACE_DICT_FOR_TOKEN, + ALTER_TSCONFIG_DROP_MAPPING +} AlterTSConfigType; + typedef struct AlterTSConfigurationStmt { NodeTag type; + AlterTSConfigType kind; /* ALTER_TSCONFIG_ADD_MAPPING, etc */ List *cfgname; /* qualified name (list of Value strings) */ /* diff --git a/src/include/tcop/deparse_utility.h b/src/include/tcop/deparse_utility.h new file mode 100644 index 00000000000..b6bcbeb3174 --- /dev/null +++ b/src/include/tcop/deparse_utility.h @@ -0,0 +1,105 @@ +/*------------------------------------------------------------------------- + * + * deparse_utility.h + * + * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/tcop/deparse_utility.h + * + *------------------------------------------------------------------------- + */ +#ifndef DEPARSE_UTILITY_H +#define DEPARSE_UTILITY_H + +#include "access/attnum.h" +#include "catalog/objectaddress.h" +#include "nodes/nodes.h" +#include "utils/aclchk_internal.h" + + +/* + * Support for keeping track of collected commands. + */ +typedef enum CollectedCommandType +{ + SCT_Simple, + SCT_AlterTable, + SCT_Grant, + SCT_AlterOpFamily, + SCT_AlterDefaultPrivileges, + SCT_CreateOpClass, + SCT_AlterTSConfig +} CollectedCommandType; + +/* + * For ALTER TABLE commands, we keep a list of the subcommands therein. + */ +typedef struct CollectedATSubcmd +{ + ObjectAddress address; /* affected column, constraint, index, ... */ + Node *parsetree; +} CollectedATSubcmd; + +typedef struct CollectedCommand +{ + CollectedCommandType type; + bool in_extension; + Node *parsetree; + + union + { + /* most commands */ + struct + { + ObjectAddress address; + ObjectAddress secondaryObject; + } simple; + + /* ALTER TABLE, and internal uses thereof */ + struct + { + Oid objectId; + Oid classId; + List *subcmds; + } alterTable; + + /* GRANT / REVOKE */ + struct + { + InternalGrant *istmt; + } grant; + + /* ALTER OPERATOR FAMILY */ + struct + { + ObjectAddress address; + List *operators; + List *procedures; + } opfam; + + /* CREATE OPERATOR CLASS */ + struct + { + ObjectAddress address; + List *operators; + List *procedures; + } createopc; + + /* ALTER TEXT SEARCH CONFIGURATION ADD/ALTER/DROP MAPPING */ + struct + { + ObjectAddress address; + Oid *dictIds; + int ndicts; + } atscfg; + + /* ALTER DEFAULT PRIVILEGES */ + struct + { + GrantObjectType objtype; + } defprivs; + } d; +} CollectedCommand; + +#endif /* DEPARSE_UTILITY_H */ diff --git a/src/include/utils/aclchk_internal.h b/src/include/utils/aclchk_internal.h new file mode 100644 index 00000000000..0855bf1d0d2 --- /dev/null +++ b/src/include/utils/aclchk_internal.h @@ -0,0 +1,45 @@ +/*------------------------------------------------------------------------- + * + * aclchk_internal.h + * + * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/aclchk_internal.h + * + *------------------------------------------------------------------------- + */ +#ifndef ACLCHK_INTERNAL_H +#define ACLCHK_INTERNAL_H + +#include "nodes/parsenodes.h" +#include "nodes/pg_list.h" + +/* + * The information about one Grant/Revoke statement, in internal format: object + * and grantees names have been turned into Oids, the privilege list is an + * AclMode bitmask. If 'privileges' is ACL_NO_RIGHTS (the 0 value) and + * all_privs is true, 'privileges' will be internally set to the right kind of + * ACL_ALL_RIGHTS_*, depending on the object type (NB - this will modify the + * InternalGrant struct!) + * + * Note: 'all_privs' and 'privileges' represent object-level privileges only. + * There might also be column-level privilege specifications, which are + * represented in col_privs (this is a list of untransformed AccessPriv nodes). + * Column privileges are only valid for objtype ACL_OBJECT_RELATION. + */ +typedef struct +{ + bool is_grant; + GrantObjectType objtype; + List *objects; + bool all_privs; + AclMode privileges; + List *col_privs; + List *grantees; + bool grant_option; + DropBehavior behavior; +} InternalGrant; + + +#endif /* ACLCHK_INTERNAL_H */ diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index a90bfe29e9f..1140c17792b 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -576,6 +576,10 @@ extern Datum pg_node_tree_in(PG_FUNCTION_ARGS); extern Datum pg_node_tree_out(PG_FUNCTION_ARGS); extern Datum pg_node_tree_recv(PG_FUNCTION_ARGS); extern Datum pg_node_tree_send(PG_FUNCTION_ARGS); +extern Datum pg_ddl_command_in(PG_FUNCTION_ARGS); +extern Datum pg_ddl_command_out(PG_FUNCTION_ARGS); +extern Datum pg_ddl_command_recv(PG_FUNCTION_ARGS); +extern Datum pg_ddl_command_send(PG_FUNCTION_ARGS); /* regexp.c */ extern Datum nameregexeq(PG_FUNCTION_ARGS); @@ -1231,6 +1235,7 @@ extern Datum unique_key_recheck(PG_FUNCTION_ARGS); extern Datum pg_event_trigger_dropped_objects(PG_FUNCTION_ARGS); extern Datum pg_event_trigger_table_rewrite_oid(PG_FUNCTION_ARGS); extern Datum pg_event_trigger_table_rewrite_reason(PG_FUNCTION_ARGS); +extern Datum pg_event_trigger_ddl_commands(PG_FUNCTION_ARGS); /* commands/extension.c */ extern Datum pg_available_extensions(PG_FUNCTION_ARGS); |
