2010-11-25 17:48:49 +01:00
|
|
|
/*
|
|
|
|
* objectaccess.h
|
|
|
|
*
|
|
|
|
* Object access hooks.
|
|
|
|
*
|
2022-01-08 01:04:57 +01:00
|
|
|
* Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
|
2010-11-25 17:48:49 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef OBJECTACCESS_H
|
|
|
|
#define OBJECTACCESS_H
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Object access hooks are intended to be called just before or just after
|
|
|
|
* performing certain actions on a SQL object. This is intended as
|
2014-09-01 12:01:29 +02:00
|
|
|
* infrastructure for security or logging plugins.
|
2010-11-25 17:48:49 +01:00
|
|
|
*
|
2012-05-02 15:27:34 +02:00
|
|
|
* OAT_POST_CREATE should be invoked just after the object is created.
|
2010-11-25 17:48:49 +01:00
|
|
|
* Typically, this is done after inserting the primary catalog records and
|
|
|
|
* associated dependencies.
|
|
|
|
*
|
2012-03-09 20:34:56 +01:00
|
|
|
* OAT_DROP should be invoked just before deletion of objects; typically
|
|
|
|
* deleteOneObject(). Its arguments are packed within ObjectAccessDrop.
|
|
|
|
*
|
2013-03-18 03:55:14 +01:00
|
|
|
* OAT_POST_ALTER should be invoked just after the object is altered,
|
|
|
|
* but before the command counter is incremented. An extension using the
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
* hook can use a current MVCC snapshot to get the old version of the tuple,
|
|
|
|
* and can use SnapshotSelf to get the new version of the tuple.
|
2013-03-18 03:55:14 +01:00
|
|
|
*
|
2013-04-05 14:51:31 +02:00
|
|
|
* OAT_NAMESPACE_SEARCH should be invoked prior to object name lookup under
|
|
|
|
* a particular namespace. This event is equivalent to usage permission
|
2013-04-12 14:39:38 +02:00
|
|
|
* on a schema under the default access control mechanism.
|
2013-04-05 14:51:31 +02:00
|
|
|
*
|
2013-04-12 14:55:56 +02:00
|
|
|
* OAT_FUNCTION_EXECUTE should be invoked prior to function execution.
|
|
|
|
* This event is almost equivalent to execute permission on functions,
|
|
|
|
* except for the case when execute permission is checked during object
|
|
|
|
* creation or altering, because OAT_POST_CREATE or OAT_POST_ALTER are
|
|
|
|
* sufficient for extensions to track these kind of checks.
|
|
|
|
*
|
2019-11-23 16:39:20 +01:00
|
|
|
* OAT_TRUNCATE should be invoked just before truncation of objects. This
|
|
|
|
* event is equivalent to truncate permission on a relation under the
|
|
|
|
* default access control mechanism.
|
|
|
|
*
|
2010-11-25 17:48:49 +01:00
|
|
|
* Other types may be added in the future.
|
|
|
|
*/
|
|
|
|
typedef enum ObjectAccessType
|
|
|
|
{
|
|
|
|
OAT_POST_CREATE,
|
2012-03-09 20:34:56 +01:00
|
|
|
OAT_DROP,
|
2013-03-07 02:52:06 +01:00
|
|
|
OAT_POST_ALTER,
|
2013-04-05 14:51:31 +02:00
|
|
|
OAT_NAMESPACE_SEARCH,
|
2019-11-23 16:39:20 +01:00
|
|
|
OAT_FUNCTION_EXECUTE,
|
|
|
|
OAT_TRUNCATE
|
2010-11-25 17:48:49 +01:00
|
|
|
} ObjectAccessType;
|
|
|
|
|
2012-10-23 23:07:26 +02:00
|
|
|
/*
|
|
|
|
* Arguments of OAT_POST_CREATE event
|
|
|
|
*/
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This flag informs extensions whether the context of this creation is
|
|
|
|
* invoked by user's operations, or not. E.g, it shall be dealt as
|
|
|
|
* internal stuff on toast tables or indexes due to type changes.
|
|
|
|
*/
|
|
|
|
bool is_internal;
|
|
|
|
} ObjectAccessPostCreate;
|
|
|
|
|
2010-11-25 17:48:49 +01:00
|
|
|
/*
|
2012-03-09 20:34:56 +01:00
|
|
|
* Arguments of OAT_DROP event
|
2010-11-25 17:48:49 +01:00
|
|
|
*/
|
2012-03-09 20:34:56 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Flags to inform extensions the context of this deletion. Also see
|
|
|
|
* PERFORM_DELETION_* in dependency.h
|
|
|
|
*/
|
|
|
|
int dropflags;
|
|
|
|
} ObjectAccessDrop;
|
2010-11-25 17:48:49 +01:00
|
|
|
|
2012-03-09 20:34:56 +01:00
|
|
|
/*
|
2013-03-18 03:55:14 +01:00
|
|
|
* Arguments of OAT_POST_ALTER event
|
2012-03-09 20:34:56 +01:00
|
|
|
*/
|
2013-03-18 03:55:14 +01:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* This identifier is used when system catalog takes two IDs to identify a
|
|
|
|
* particular tuple of the catalog. It is only used when the caller want
|
|
|
|
* to identify an entry of pg_inherits, pg_db_role_setting or
|
|
|
|
* pg_user_mapping. Elsewhere, InvalidOid should be set.
|
|
|
|
*/
|
|
|
|
Oid auxiliary_id;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If this flag is set, the user hasn't requested that the object be
|
|
|
|
* altered, but we're doing it anyway for some internal reason.
|
|
|
|
* Permissions-checking hooks may want to skip checks if, say, we're alter
|
|
|
|
* the constraints of a temporary heap during CLUSTER.
|
|
|
|
*/
|
|
|
|
bool is_internal;
|
|
|
|
} ObjectAccessPostAlter;
|
|
|
|
|
2013-04-05 14:51:31 +02:00
|
|
|
/*
|
|
|
|
* Arguments of OAT_NAMESPACE_SEARCH
|
|
|
|
*/
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If true, hook should report an error when permission to search this
|
|
|
|
* schema is denied.
|
|
|
|
*/
|
|
|
|
bool ereport_on_violation;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is, in essence, an out parameter. Core code should initialize
|
|
|
|
* this to true, and any extension that wants to deny access should reset
|
|
|
|
* it to false. But an extension should be careful never to store a true
|
|
|
|
* value here, so that in case there are multiple extensions access is
|
|
|
|
* only allowed if all extensions agree.
|
|
|
|
*/
|
|
|
|
bool result;
|
|
|
|
} ObjectAccessNamespaceSearch;
|
|
|
|
|
2022-03-22 14:06:15 +01:00
|
|
|
/* Plugin provides a hook function matching one or both of these signatures. */
|
2010-11-25 17:48:49 +01:00
|
|
|
typedef void (*object_access_hook_type) (ObjectAccessType access,
|
|
|
|
Oid classId,
|
|
|
|
Oid objectId,
|
2012-03-09 20:34:56 +01:00
|
|
|
int subId,
|
|
|
|
void *arg);
|
2010-11-25 17:48:49 +01:00
|
|
|
|
2022-03-22 14:06:15 +01:00
|
|
|
typedef void (*object_access_hook_type_str) (ObjectAccessType access,
|
|
|
|
Oid classId,
|
|
|
|
const char *objectStr,
|
|
|
|
int subId,
|
|
|
|
void *arg);
|
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
/* Plugin sets this variable to a suitable hook function. */
|
2010-11-25 17:48:49 +01:00
|
|
|
extern PGDLLIMPORT object_access_hook_type object_access_hook;
|
2022-03-22 14:06:15 +01:00
|
|
|
extern PGDLLIMPORT object_access_hook_type_str object_access_hook_str;
|
|
|
|
|
2010-11-25 17:48:49 +01:00
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
/* Core code uses these functions to call the hook (see macros below). */
|
2013-03-07 02:52:06 +01:00
|
|
|
extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
|
|
|
|
bool is_internal);
|
|
|
|
extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
|
|
|
|
int dropflags);
|
2019-11-23 16:39:20 +01:00
|
|
|
extern void RunObjectTruncateHook(Oid objectId);
|
2013-03-18 03:55:14 +01:00
|
|
|
extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
|
|
|
|
Oid auxiliaryId, bool is_internal);
|
2018-03-07 15:02:57 +01:00
|
|
|
extern bool RunNamespaceSearchHook(Oid objectId, bool ereport_on_violation);
|
2013-04-12 14:55:56 +02:00
|
|
|
extern void RunFunctionExecuteHook(Oid objectId);
|
2013-03-18 03:55:14 +01:00
|
|
|
|
2022-03-22 14:06:15 +01:00
|
|
|
/* String versions */
|
2022-09-20 04:18:36 +02:00
|
|
|
extern void RunObjectPostCreateHookStr(Oid classId, const char *objectName, int subId,
|
2022-03-22 14:06:15 +01:00
|
|
|
bool is_internal);
|
2022-09-20 04:18:36 +02:00
|
|
|
extern void RunObjectDropHookStr(Oid classId, const char *objectName, int subId,
|
2022-03-22 14:06:15 +01:00
|
|
|
int dropflags);
|
2022-09-20 04:18:36 +02:00
|
|
|
extern void RunObjectTruncateHookStr(const char *objectName);
|
|
|
|
extern void RunObjectPostAlterHookStr(Oid classId, const char *objectName, int subId,
|
2022-03-22 14:06:15 +01:00
|
|
|
Oid auxiliaryId, bool is_internal);
|
2022-09-20 04:18:36 +02:00
|
|
|
extern bool RunNamespaceSearchHookStr(const char *objectName, bool ereport_on_violation);
|
|
|
|
extern void RunFunctionExecuteHookStr(const char *objectName);
|
2022-03-22 14:06:15 +01:00
|
|
|
|
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
/*
|
|
|
|
* The following macros are wrappers around the functions above; these should
|
|
|
|
* normally be used to invoke the hook in lieu of calling the above functions
|
|
|
|
* directly.
|
|
|
|
*/
|
2013-03-07 02:52:06 +01:00
|
|
|
|
|
|
|
#define InvokeObjectPostCreateHook(classId,objectId,subId) \
|
|
|
|
InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
|
|
|
|
#define InvokeObjectPostCreateHookArg(classId,objectId,subId,is_internal) \
|
|
|
|
do { \
|
|
|
|
if (object_access_hook) \
|
|
|
|
RunObjectPostCreateHook((classId),(objectId),(subId), \
|
|
|
|
(is_internal)); \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define InvokeObjectDropHook(classId,objectId,subId) \
|
|
|
|
InvokeObjectDropHookArg((classId),(objectId),(subId),0)
|
|
|
|
#define InvokeObjectDropHookArg(classId,objectId,subId,dropflags) \
|
2012-03-09 20:34:56 +01:00
|
|
|
do { \
|
|
|
|
if (object_access_hook) \
|
2013-03-07 02:52:06 +01:00
|
|
|
RunObjectDropHook((classId),(objectId),(subId), \
|
|
|
|
(dropflags)); \
|
2010-11-25 17:48:49 +01:00
|
|
|
} while(0)
|
|
|
|
|
2019-11-23 16:39:20 +01:00
|
|
|
#define InvokeObjectTruncateHook(objectId) \
|
|
|
|
do { \
|
|
|
|
if (object_access_hook) \
|
|
|
|
RunObjectTruncateHook(objectId); \
|
|
|
|
} while(0)
|
|
|
|
|
2013-03-18 03:55:14 +01:00
|
|
|
#define InvokeObjectPostAlterHook(classId,objectId,subId) \
|
|
|
|
InvokeObjectPostAlterHookArg((classId),(objectId),(subId), \
|
|
|
|
InvalidOid,false)
|
|
|
|
#define InvokeObjectPostAlterHookArg(classId,objectId,subId, \
|
|
|
|
auxiliaryId,is_internal) \
|
|
|
|
do { \
|
|
|
|
if (object_access_hook) \
|
|
|
|
RunObjectPostAlterHook((classId),(objectId),(subId), \
|
|
|
|
(auxiliaryId),(is_internal)); \
|
|
|
|
} while(0)
|
|
|
|
|
2013-04-05 14:51:31 +02:00
|
|
|
#define InvokeNamespaceSearchHook(objectId, ereport_on_violation) \
|
|
|
|
(!object_access_hook \
|
|
|
|
? true \
|
|
|
|
: RunNamespaceSearchHook((objectId), (ereport_on_violation)))
|
|
|
|
|
2013-04-12 14:55:56 +02:00
|
|
|
#define InvokeFunctionExecuteHook(objectId) \
|
|
|
|
do { \
|
|
|
|
if (object_access_hook) \
|
|
|
|
RunFunctionExecuteHook(objectId); \
|
|
|
|
} while(0)
|
|
|
|
|
2022-03-22 14:06:15 +01:00
|
|
|
|
|
|
|
#define InvokeObjectPostCreateHookStr(classId,objectName,subId) \
|
|
|
|
InvokeObjectPostCreateHookArgStr((classId),(objectName),(subId),false)
|
|
|
|
#define InvokeObjectPostCreateHookArgStr(classId,objectName,subId,is_internal) \
|
|
|
|
do { \
|
|
|
|
if (object_access_hook_str) \
|
|
|
|
RunObjectPostCreateHookStr((classId),(objectName),(subId), \
|
|
|
|
(is_internal)); \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define InvokeObjectDropHookStr(classId,objectName,subId) \
|
|
|
|
InvokeObjectDropHookArgStr((classId),(objectName),(subId),0)
|
|
|
|
#define InvokeObjectDropHookArgStr(classId,objectName,subId,dropflags) \
|
|
|
|
do { \
|
|
|
|
if (object_access_hook_str) \
|
|
|
|
RunObjectDropHookStr((classId),(objectName),(subId), \
|
|
|
|
(dropflags)); \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define InvokeObjectTruncateHookStr(objectName) \
|
|
|
|
do { \
|
|
|
|
if (object_access_hook_str) \
|
|
|
|
RunObjectTruncateHookStr(objectName); \
|
|
|
|
} while(0)
|
|
|
|
|
2022-04-06 19:24:33 +02:00
|
|
|
#define InvokeObjectPostAlterHookStr(classId,objectName,subId) \
|
2022-03-22 14:06:15 +01:00
|
|
|
InvokeObjectPostAlterHookArgStr((classId),(objectName),(subId), \
|
|
|
|
InvalidOid,false)
|
|
|
|
#define InvokeObjectPostAlterHookArgStr(classId,objectName,subId, \
|
|
|
|
auxiliaryId,is_internal) \
|
|
|
|
do { \
|
|
|
|
if (object_access_hook_str) \
|
|
|
|
RunObjectPostAlterHookStr((classId),(objectName),(subId), \
|
|
|
|
(auxiliaryId),(is_internal)); \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
#define InvokeNamespaceSearchHookStr(objectName, ereport_on_violation) \
|
|
|
|
(!object_access_hook_str \
|
|
|
|
? true \
|
|
|
|
: RunNamespaceSearchHookStr((objectName), (ereport_on_violation)))
|
|
|
|
|
|
|
|
#define InvokeFunctionExecuteHookStr(objectName) \
|
|
|
|
do { \
|
|
|
|
if (object_access_hook_str) \
|
|
|
|
RunFunctionExecuteHookStr(objectName); \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
2010-11-25 17:48:49 +01:00
|
|
|
#endif /* OBJECTACCESS_H */
|