pgsql-v9.2-prep-creation-hook-part-3.v1.patch
application/octet-stream
Filename: pgsql-v9.2-prep-creation-hook-part-3.v1.patch
Type: application/octet-stream
Part: 2
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v9
| File | + | − |
|---|---|---|
| contrib/sepgsql/expected/create.out | 28 | 0 |
| contrib/sepgsql/hooks.c | 10 | 1 |
| contrib/sepgsql/relation.c | 143 | 70 |
| contrib/sepgsql/sepgsql.h | 10 | 1 |
| contrib/sepgsql/sql/create.sql | 8 | 0 |
| contrib/sepgsql/test_sepgsql | 28 | 0 |
| src/backend/bootstrap/bootparse.y | 2 | 1 |
| src/backend/catalog/heap.c | 5 | 2 |
| src/backend/catalog/toasting.c | 2 | 1 |
| src/backend/commands/cluster.c | 2 | 1 |
| src/backend/commands/tablecmds.c | 7 | 1 |
| src/backend/executor/execMain.c | 10 | 1 |
| src/include/catalog/heap.h | 2 | 1 |
| src/include/catalog/objectaccess.h | 30 | 0 |
contrib/sepgsql/expected/create.out | 28 +++++
contrib/sepgsql/hooks.c | 11 ++-
contrib/sepgsql/relation.c | 213 +++++++++++++++++++++++------------
contrib/sepgsql/sepgsql.h | 11 ++-
contrib/sepgsql/sql/create.sql | 8 ++
contrib/sepgsql/test_sepgsql | 28 +++++
src/backend/bootstrap/bootparse.y | 3 +-
src/backend/catalog/heap.c | 7 +-
src/backend/catalog/toasting.c | 3 +-
src/backend/commands/cluster.c | 3 +-
src/backend/commands/tablecmds.c | 8 +-
src/backend/executor/execMain.c | 11 ++-
src/include/catalog/heap.h | 3 +-
src/include/catalog/objectaccess.h | 30 +++++
14 files changed, 287 insertions(+), 80 deletions(-)
diff --git a/contrib/sepgsql/expected/create.out b/contrib/sepgsql/expected/create.out
index 3293a73..d450dc5 100644
--- a/contrib/sepgsql/expected/create.out
+++ b/contrib/sepgsql/expected/create.out
@@ -16,8 +16,36 @@ LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_
CREATE SCHEMA regtest_schema;
LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
SET search_path = regtest_schema, public;
+CREATE TABLE regtest_table (x serial primary key, y text);
+NOTICE: CREATE TABLE will create implicit sequence "regtest_table_x_seq" for serial column "regtest_table.x"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_table_x_seq"
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column tableoid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column cmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column xmax"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column cmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column xmin"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column ctid"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column x"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table column y"
+NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "regtest_table_pkey" for table "regtest_table"
+CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 10;
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view"
+CREATE SEQUENCE regtest_seq;
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG: SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq"
+CREATE TYPE regtest_type AS (a int, b text);
+LOG: SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
--
-- clean-up
--
DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
DROP SCHEMA IF EXISTS regtest_schema CASCADE;
+NOTICE: drop cascades to 4 other objects
+DETAIL: drop cascades to table regtest_table
+drop cascades to view regtest_view
+drop cascades to sequence regtest_seq
+drop cascades to type regtest_type
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index 2b62a75..aa56d9c 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -146,6 +146,15 @@ sepgsql_object_prep_create(Oid classId, Oid objectId, int subId,
sepgsql_schema_prep_create(args->pg_namespace.nspname);
break;
+ case RelationRelationId:
+ sepgsql_relation_prep_create(cinfo,
+ args->pg_class.relname,
+ args->pg_class.relkind,
+ args->pg_class.namespaceId,
+ args->pg_class.tablespaceId,
+ args->pg_class.tupdesc);
+ break;
+
default:
/* Ignore unsupported object classes */
break;
@@ -181,7 +190,7 @@ sepgsql_object_post_create(Oid classId, Oid objectId, int subId,
case RelationRelationId:
if (subId == 0)
- sepgsql_relation_post_create(objectId);
+ sepgsql_relation_post_create(cinfo, objectId);
else
sepgsql_attribute_post_create(objectId, subId);
break;
diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c
index 0767382..09f80d7 100644
--- a/contrib/sepgsql/relation.c
+++ b/contrib/sepgsql/relation.c
@@ -13,6 +13,7 @@
#include "access/genam.h"
#include "access/heapam.h"
#include "access/sysattr.h"
+#include "catalog/heap.h"
#include "catalog/indexing.h"
#include "catalog/dependency.h"
#include "catalog/pg_attribute.h"
@@ -113,102 +114,174 @@ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
}
/*
- * sepgsql_relation_post_create
+ * sepgsql_relation_prep_create
*
- * The post creation hook of relation/attribute
+ * This routine computes default security label of relation and columns
+ * if relation is a table, then checks permissions to create them.
*/
void
-sepgsql_relation_post_create(Oid relOid)
+sepgsql_relation_prep_create(sepgsql_creation_info *info,
+ const char *relname, char relkind,
+ Oid namespaceId, Oid tablespaceId,
+ TupleDesc tupdesc)
{
- Relation rel;
- ScanKeyData skey;
- SysScanDesc sscan;
- HeapTuple tuple;
- Form_pg_class classForm;
- ObjectAddress object;
+ char *scontext;
+ char *tcontext;
+ char *ncontext;
+ char *acontext;
+ char audit_name[2 * NAMEDATALEN + 16];
uint16 tclass;
- char *scontext; /* subject */
- char *tcontext; /* schema */
- char *rcontext; /* relation */
- char *ccontext; /* column */
+ ObjectAddress object;
/*
- * Fetch catalog record of the new relation. Because pg_class entry is not
- * visible right now, we need to scan the catalog using SnapshotSelf.
+ * so check db_schema:{add_name} permission
*/
- rel = heap_open(RelationRelationId, AccessShareLock);
-
- ScanKeyInit(&skey,
- ObjectIdAttributeNumber,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(relOid));
-
- sscan = systable_beginscan(rel, ClassOidIndexId, true,
- SnapshotSelf, 1, &skey);
+ object.classId = NamespaceRelationId;
+ object.objectId = namespaceId;
+ object.objectSubId = 0;
+ sepgsql_avc_check_perms(&object,
+ SEPG_CLASS_DB_SCHEMA,
+ SEPG_DB_SCHEMA__ADD_NAME,
+ getObjectDescription(&object),
+ true);
+ /*
+ * compute default security label of new relation
+ */
+ switch (relkind)
+ {
+ case RELKIND_RELATION:
+ tclass = SEPG_CLASS_DB_TABLE;
+ snprintf(audit_name, sizeof(audit_name), "table %s", relname);
+ break;
- tuple = systable_getnext(sscan);
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "catalog lookup failed for relation %u", relOid);
+ case RELKIND_SEQUENCE:
+ tclass = SEPG_CLASS_DB_SEQUENCE;
+ snprintf(audit_name, sizeof(audit_name), "sequence %s", relname);
+ break;
- classForm = (Form_pg_class) GETSTRUCT(tuple);
+ case RELKIND_VIEW:
+ tclass = SEPG_CLASS_DB_VIEW;
+ snprintf(audit_name, sizeof(audit_name), "view %s", relname);
+ break;
- if (classForm->relkind == RELKIND_RELATION)
- tclass = SEPG_CLASS_DB_TABLE;
- else if (classForm->relkind == RELKIND_SEQUENCE)
- tclass = SEPG_CLASS_DB_SEQUENCE;
- else if (classForm->relkind == RELKIND_VIEW)
- tclass = SEPG_CLASS_DB_VIEW;
- else
- goto out; /* No need to assign individual labels */
-
- /*
- * Compute a default security label when we create a new relation object
- * under the specified namespace.
- */
+ default:
+ /*
+ * No need to check permission any more, if relation is not
+ * a table, sequence or view.
+ */
+ info->ncontext = NULL;
+ info->nattrs = 0;
+ info->acontexts = NULL;
+ return;
+ }
scontext = sepgsql_get_client_label();
- tcontext = sepgsql_get_label(NamespaceRelationId,
- classForm->relnamespace, 0);
- rcontext = sepgsql_compute_create(scontext, tcontext, tclass);
+ tcontext = sepgsql_get_label(NamespaceRelationId, namespaceId, 0);
+ ncontext = sepgsql_compute_create(scontext, tcontext, tclass);
+ info->ncontext = ncontext;
/*
- * Assign the default security label on the new relation
+ * check db_xxx:{create} permission
*/
- object.classId = RelationRelationId;
- object.objectId = relOid;
- object.objectSubId = 0;
- SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, rcontext);
-
+ sepgsql_avc_check_perms_label(ncontext,
+ tclass,
+ SEPG_DB_TABLE__CREATE,
+ audit_name,
+ true);
/*
- * We also assigns a default security label on columns of the new regular
- * tables.
+ * compute default security label of columns, and check
+ * db_column:{create} permission, if relkind == RELKIND_RELATION
*/
- if (classForm->relkind == RELKIND_RELATION)
+ if (relkind == RELKIND_RELATION)
{
- AttrNumber index;
+ AttrNumber attnum;
+ int shift = - FirstLowInvalidHeapAttributeNumber - 1;
- ccontext = sepgsql_compute_create(scontext, rcontext,
+ /*
+ * XXX - upcoming libselinux allows case handling when a new
+ * object that has a particular name, but it is not supported
+ * right now. So, we omit to compute default security label
+ * for each columns, because it shall be uniform when same
+ * client create columns under the same table.
+ */
+ acontext = sepgsql_compute_create(scontext, ncontext,
SEPG_CLASS_DB_COLUMN);
- for (index = FirstLowInvalidHeapAttributeNumber + 1;
- index <= classForm->relnatts;
- index++)
+
+ info->nattrs = tupdesc->natts;
+ info->acontexts = palloc0(sizeof(const char *) *
+ (tupdesc->natts + shift + 1));
+
+ for (attnum = FirstLowInvalidHeapAttributeNumber + 1;
+ attnum <= tupdesc->natts;
+ attnum++)
{
- if (index == InvalidAttrNumber)
- continue;
+ Form_pg_attribute attr;
- if (index == ObjectIdAttributeNumber && !classForm->relhasoids)
+ if (attnum == InvalidAttrNumber ||
+ (attnum == ObjectIdAttributeNumber && !tupdesc->tdhasoid))
+ {
+ info->acontexts[attnum + shift] = NULL;
continue;
+ }
+ /* check db_column:{create} permission */
+ if (attnum < 0)
+ attr = SystemAttributeDefinition(attnum, true);
+ else
+ attr = tupdesc->attrs[attnum - 1];
+ snprintf(audit_name, sizeof(audit_name), "table %s column %s",
+ relname, NameStr(attr->attname));
- object.classId = RelationRelationId;
- object.objectId = relOid;
- object.objectSubId = index;
- SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ccontext);
+ sepgsql_avc_check_perms_label(acontext,
+ SEPG_CLASS_DB_COLUMN,
+ SEPG_DB_COLUMN__CREATE,
+ audit_name,
+ true);
+ info->acontexts[attnum + shift] = acontext;
}
- pfree(ccontext);
}
- pfree(rcontext);
-out:
- systable_endscan(sscan);
- heap_close(rel, AccessShareLock);
+ else
+ {
+ info->nattrs = 0;
+ info->acontexts = NULL;
+ }
+}
+
+/*
+ * sepgsql_relation_post_create
+ *
+ * The post creation hook of relation/attribute
+ */
+void
+sepgsql_relation_post_create(sepgsql_creation_info *info,
+ Oid relationOid)
+{
+ ObjectAddress object;
+ AttrNumber attnum;
+ int shift = - FirstLowInvalidHeapAttributeNumber - 1;
+
+ if (!info || !info->ncontext)
+ return;
+
+ object.classId = RelationRelationId;
+ object.objectId = relationOid;
+ object.objectSubId = 0;
+ SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, info->ncontext);
+
+ if (!info->acontexts)
+ return;
+
+ for (attnum = FirstLowInvalidHeapAttributeNumber + 1;
+ attnum <= info->nattrs;
+ attnum++)
+ {
+ if (!info->acontexts[attnum + shift])
+ continue;
+
+ object.classId = RelationRelationId;
+ object.objectId = relationOid;
+ object.objectSubId = attnum;
+ SetSecurityLabel(&object, SEPGSQL_LABEL_TAG,
+ info->acontexts[attnum + shift]);
+ }
}
/*
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index b4a3e4d..cd9c4c6 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -226,6 +226,10 @@ typedef struct {
/* a default security label to be assigned on */
const char *ncontext;
+
+ /* a default security label of columns (only for tables) */
+ AttrNumber nattrs;
+ const char **acontexts;
} sepgsql_creation_info;
/*
@@ -323,7 +327,12 @@ extern void sepgsql_schema_relabel(Oid namespaceId, const char *seclabel);
extern void sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum);
extern void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
const char *seclabel);
-extern void sepgsql_relation_post_create(Oid relOid);
+extern void sepgsql_relation_prep_create(sepgsql_creation_info *info,
+ const char *relname, char relkind,
+ Oid namespaceId, Oid tablespaceId,
+ TupleDesc tupdesc);
+extern void sepgsql_relation_post_create(sepgsql_creation_info *info,
+ Oid relationOid);
extern void sepgsql_relation_relabel(Oid relOid, const char *seclabel);
/*
diff --git a/contrib/sepgsql/sql/create.sql b/contrib/sepgsql/sql/create.sql
index 9ce1db9..4e12411 100644
--- a/contrib/sepgsql/sql/create.sql
+++ b/contrib/sepgsql/sql/create.sql
@@ -13,6 +13,14 @@ CREATE SCHEMA regtest_schema;
SET search_path = regtest_schema, public;
+CREATE TABLE regtest_table (x serial primary key, y text);
+
+CREATE VIEW regtest_view AS SELECT * FROM regtest_table WHERE x < 10;
+
+CREATE SEQUENCE regtest_seq;
+
+CREATE TYPE regtest_type AS (a int, b text);
+
--
-- clean-up
--
diff --git a/contrib/sepgsql/test_sepgsql b/contrib/sepgsql/test_sepgsql
index 52237e6..4e43e97 100755
--- a/contrib/sepgsql/test_sepgsql
+++ b/contrib/sepgsql/test_sepgsql
@@ -163,6 +163,34 @@ if [ "${POLICY_STATUS}" != on ]; then
exit 1
fi
+# Verify that sepgsql_enable_users_ddl is active.
+echo -n "checking whether DDL is allowed ... "
+POLICY_STATUS=`getsebool sepgsql_enable_users_ddl | awk '{print $3}'`
+echo ${POLICY_STATUS:-failed}
+if [ "${POLICY_STATUS}" != on ]; then
+ echo ""
+ echo "The SELinux boolean 'sepgsql_enable_users_ddl' must be"
+ echo "turned on in order to enable the rules necessary to run the"
+ echo "regression tests."
+ echo ""
+ if [ "${POLICY_STATUS}" = "" ]; then
+ echo "We attempted to determine the state of this Boolean using"
+ echo "'getsebool', but that command did not produce the expected"
+ echo "output. Please verify that getsebool is available and in"
+ echo "your PATH."
+ else
+ echo "You can turn on this variable using the following commands:"
+ echo ""
+ echo " \$ sudo setsebool sepgsql_enable_users_ddl on"
+ echo ""
+ echo "For security reasons, it is suggested that you turn off this"
+ echo "variable unless you want unprivileged users to execute"
+ echo "DDL commands."
+ fi
+ echo ""
+ exit 1
+fi
+
# 'psql' command must be executable from test domain
echo -n "checking whether we can run psql ... "
CMD_PSQL="${PG_BINDIR}/psql"
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index d0a0e92..4ca33ab 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -248,7 +248,8 @@ Boot_CreateStmt:
ONCOMMIT_NOOP,
(Datum) 0,
false,
- true);
+ true,
+ (Datum) 0);
elog(DEBUG4, "relation created with OID %u", id);
}
do_end();
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index e11d896..84613f7 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -993,7 +993,8 @@ heap_create_with_catalog(const char *relname,
OnCommitAction oncommit,
Datum reloptions,
bool use_user_acl,
- bool allow_system_table_mods)
+ bool allow_system_table_mods,
+ Datum hook_private)
{
Relation pg_class_desc;
Relation new_rel_desc;
@@ -1279,7 +1280,9 @@ heap_create_with_catalog(const char *relname,
}
/* Post creation hook for new relation */
- InvokeObjectAccessHook(OAT_POST_CREATE, RelationRelationId, relid, 0);
+ InvokeObjectAccessHookArg(OAT_POST_CREATE,
+ RelationRelationId, relid, 0,
+ hook_private);
/*
* Store any supplied constraints and defaults.
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 3a40e8b..a28c423 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -228,7 +228,8 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
ONCOMMIT_NOOP,
reloptions,
false,
- true);
+ true,
+ (Datum) 0);
Assert(toast_relid != InvalidOid);
/* make the toast relation visible, else heap_open will fail */
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index edec44d..08ad2bc 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -645,7 +645,8 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace)
ONCOMMIT_NOOP,
reloptions,
false,
- true);
+ true,
+ (Datum) 0);
Assert(OIDNewHeap != InvalidOid);
ReleaseSysCache(tuple);
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index c4622c0..a8b5a56 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -410,6 +410,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
List *rawDefaults;
List *cookedDefaults;
Datum reloptions;
+ Datum hook_private = 0;
ListCell *listptr;
AttrNumber attnum;
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
@@ -575,6 +576,10 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
}
}
+ /* Prep-creation hook for new relation */
+ InvokePrepCreateRelationHook(&hook_private, relname, relkind,
+ namespaceId, tablespaceId, descriptor);
+
/*
* Create the relation. Inherited defaults and constraints are passed in
* for immediate handling --- since they don't need parsing, they can be
@@ -599,7 +604,8 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
stmt->oncommit,
reloptions,
true,
- allowSystemTableMods);
+ allowSystemTableMods,
+ hook_private);
/* Store inheritance information for new rel. */
StoreCatalogInheritance(relationId, inheritOids);
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index fd7a9ed..8d97d1e 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -43,6 +43,7 @@
#include "access/xact.h"
#include "catalog/heap.h"
#include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
#include "catalog/toasting.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
@@ -2393,6 +2394,7 @@ OpenIntoRel(QueryDesc *queryDesc)
Oid namespaceId;
Oid tablespaceId;
Datum reloptions;
+ Datum hook_private = 0;
Oid intoRelationId;
DR_intorel *myState;
static char *validnsps[] = HEAP_RELOPT_NAMESPACES;
@@ -2458,6 +2460,12 @@ OpenIntoRel(QueryDesc *queryDesc)
get_tablespace_name(tablespaceId));
}
+ /* Prep-creation hook for new relation */
+ InvokePrepCreateRelationHook(&hook_private, intoName,
+ RELKIND_RELATION,
+ namespaceId, tablespaceId,
+ queryDesc->tupDesc);
+
/* Parse and validate any reloptions */
reloptions = transformRelOptions((Datum) 0,
into->options,
@@ -2486,7 +2494,8 @@ OpenIntoRel(QueryDesc *queryDesc)
into->onCommit,
reloptions,
true,
- allowSystemTableMods);
+ allowSystemTableMods,
+ hook_private);
Assert(intoRelationId != InvalidOid);
/*
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index aee2d88..ca4d6a1 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -65,7 +65,8 @@ extern Oid heap_create_with_catalog(const char *relname,
OnCommitAction oncommit,
Datum reloptions,
bool use_user_acl,
- bool allow_system_table_mods);
+ bool allow_system_table_mods,
+ Datum hook_private);
extern void heap_drop_with_catalog(Oid relid);
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index cb5c396..d151ee5 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -10,6 +10,8 @@
#ifndef OBJECTACCESS_H
#define OBJECTACCESS_H
+#include "access/tupdesc.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
@@ -55,6 +57,14 @@ typedef union
Datum *private; /* common */
const char *nspname; /* name of new schema */
} pg_namespace;
+ struct {
+ Datum *private; /* common */
+ const char *relname; /* name of new relation */
+ char relkind;
+ Oid namespaceId;
+ Oid tablespaceId;
+ TupleDesc tupdesc;
+ } pg_class;
} ObjectAccessCreateObjectArgs;
/*
@@ -121,4 +131,24 @@ extern PGDLLIMPORT object_access_hook_type object_access_hook;
} \
} while(0)
+#define InvokePrepCreateRelationHook(_private,_relname,_relkind, \
+ _namespace,_tablespace,_tupdesc) \
+ do { \
+ if (object_access_hook) \
+ { \
+ ObjectAccessCreateObjectArgs __args; \
+ \
+ __args.pg_class.private = (_private); \
+ __args.pg_class.relname = (_relname); \
+ __args.pg_class.relkind = (_relkind); \
+ __args.pg_class.namespaceId = (_namespace); \
+ __args.pg_class.tablespaceId = (_tablespace); \
+ __args.pg_class.tupdesc = (_tupdesc); \
+ \
+ (*object_access_hook)(OAT_PREP_CREATE, \
+ RelationRelationId, InvalidOid, 0, \
+ PointerGetDatum(&__args)); \
+ } \
+ } while(0)
+
#endif /* OBJECTACCESS_H */