 contrib/sepgsql/expected/ddl.out   |  53 ++++++++++++++
 contrib/sepgsql/hooks.c            |  82 +++++----------------
 contrib/sepgsql/relation.c         | 146 ++++++++++++++++++++++++++++++++++++-
 contrib/sepgsql/sepgsql.h          |   2 +-
 contrib/sepgsql/sql/ddl.sql        |  12 +++
 doc/src/sgml/sepgsql.sgml          |   7 ++
 src/backend/bootstrap/bootparse.y  |   1 +
 src/backend/catalog/heap.c         |  14 +++-
 src/backend/catalog/index.c        |  15 +++-
 src/backend/catalog/toasting.c     |   3 +-
 src/backend/commands/cluster.c     |   1 +
 src/backend/commands/indexcmds.c   |   2 +-
 src/backend/commands/tablecmds.c   |   3 +-
 src/include/catalog/heap.h         |   3 +-
 src/include/catalog/index.h        |   3 +-
 src/include/catalog/objectaccess.h |  13 ++++
 16 files changed, 284 insertions(+), 76 deletions(-)

diff --git a/contrib/sepgsql/expected/ddl.out b/contrib/sepgsql/expected/ddl.out
index e7a8d9c..1f7ea88 100644
--- a/contrib/sepgsql/expected/ddl.out
+++ b/contrib/sepgsql/expected/ddl.out
@@ -34,6 +34,8 @@ LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_
 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"
+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 { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table"
 ALTER TABLE regtest_table ADD COLUMN z int;
 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 z"
 CREATE TABLE regtest_table_2 (a int) WITH OIDS;
@@ -93,6 +95,55 @@ LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfine
 LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function regtest_func_2(integer)"
 RESET SESSION AUTHORIZATION;
 --
+-- ALTER and CREATE/DROP extra attribute permissions
+--
+CREATE TABLE regtest_table_4 (x int primary key, y int, z int);
+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_4"
+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_4 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_4 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_4 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_4 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_4 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_4 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_4 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_4 column y"
+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_4 column z"
+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 { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+CREATE INDEX regtest_index_tbl4_y ON regtest_table_4(y);
+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 { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+CREATE INDEX regtest_index_tbl4_z ON regtest_table_4(z);
+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 { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+ALTER TABLE regtest_table_4 ALTER COLUMN y TYPE float;
+DROP INDEX regtest_index_tbl4_y;
+LOG:  SELinux: allowed { remove_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 { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+ALTER TABLE regtest_table_4
+      ADD CONSTRAINT regtest_tbl4_con EXCLUDE USING btree (z WITH =);
+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 { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+DROP TABLE regtest_table_4 CASCADE;
+LOG:  SELinux: allowed { remove_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 { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+LOG:  SELinux: allowed { remove_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 { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+LOG:  SELinux: allowed { remove_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 { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+LOG:  SELinux: allowed { remove_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 { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_4"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column tableoid"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column cmax"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column xmax"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column cmin"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column xmin"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column ctid"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column x"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column y"
+LOG:  SELinux: allowed { drop } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_4 column z"
+--
 -- DROP Permission checks (with clean-up)
 --
 DROP FUNCTION regtest_func(text,int[]);
@@ -115,6 +166,8 @@ DROP TABLE regtest_table;
 LOG:  SELinux: allowed { remove_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 { drop } 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 { remove_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 { setattr } 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 { remove_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 { drop } 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 { drop } 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 { drop } 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"
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index f3cf1c5..0c3feb4 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -38,7 +38,6 @@ void		_PG_init(void);
 static object_access_hook_type next_object_access_hook = NULL;
 static ExecutorCheckPerms_hook_type next_exec_check_perms_hook = NULL;
 static ProcessUtility_hook_type next_ProcessUtility_hook = NULL;
-static ExecutorStart_hook_type next_ExecutorStart_hook = NULL;
 
 /*
  * Contextual information on DDL commands
@@ -97,14 +96,23 @@ sepgsql_object_access(ObjectAccessType access,
 	switch (access)
 	{
 		case OAT_POST_CREATE:
+			{
+				ObjectAccessPostCreate *post_create_arg = arg;
+				bool	is_internal = false;
+
+				if (post_create_arg)
+					is_internal = post_create_arg->is_internal;
+
 			switch (classId)
 			{
 				case DatabaseRelationId:
+					Assert(!is_internal);
 					sepgsql_database_post_create(objectId,
 									sepgsql_context_info.createdb_dtemplate);
 					break;
 
 				case NamespaceRelationId:
+					Assert(!is_internal);
 					sepgsql_schema_post_create(objectId);
 					break;
 
@@ -113,25 +121,16 @@ sepgsql_object_access(ObjectAccessType access,
 					{
 						/*
 						 * All cases we want to apply permission checks on
-						 * creation of a new relation are invocation of the
-						 * heap_create_with_catalog via DefineRelation or
-						 * OpenIntoRel. Elsewhere, we need neither assignment
-						 * of security label nor permission checks.
+						 * creation of a new relation are invocation in the
+						 * context being intended by users. Elsewhere, we
+						 * need neither assignment of security label nor
+						 * permission checks towards the case of toast
+						 * relation or index rebuild due to ALTER TABLE.
 						 */
-						switch (sepgsql_context_info.cmdtype)
-						{
-							case T_CreateStmt:
-							case T_ViewStmt:
-							case T_CreateSeqStmt:
-							case T_CompositeTypeStmt:
-							case T_CreateForeignTableStmt:
-							case T_SelectStmt:
-								sepgsql_relation_post_create(objectId);
-								break;
-							default:
-								/* via make_new_heap() */
-								break;
-						}
+						if (is_internal)
+							break;
+
+						sepgsql_relation_post_create(objectId);
 					}
 					else
 						sepgsql_attribute_post_create(objectId, subId);
@@ -145,6 +144,7 @@ sepgsql_object_access(ObjectAccessType access,
 					/* Ignore unsupported object classes */
 					break;
 			}
+			}
 			break;
 
 		case OAT_DROP:
@@ -216,46 +216,6 @@ sepgsql_exec_check_perms(List *rangeTabls, bool abort)
 }
 
 /*
- * sepgsql_executor_start
- *
- * It saves contextual information during ExecutorStart to distinguish
- * a case with/without permission checks later.
- */
-static void
-sepgsql_executor_start(QueryDesc *queryDesc, int eflags)
-{
-	sepgsql_context_info_t saved_context_info = sepgsql_context_info;
-
-	PG_TRY();
-	{
-		if (queryDesc->operation == CMD_SELECT)
-			sepgsql_context_info.cmdtype = T_SelectStmt;
-		else if (queryDesc->operation == CMD_INSERT)
-			sepgsql_context_info.cmdtype = T_InsertStmt;
-		else if (queryDesc->operation == CMD_DELETE)
-			sepgsql_context_info.cmdtype = T_DeleteStmt;
-		else if (queryDesc->operation == CMD_UPDATE)
-			sepgsql_context_info.cmdtype = T_UpdateStmt;
-
-		/*
-		 * XXX - If queryDesc->operation is not above four cases, an error
-		 * shall be raised on the following executor stage soon.
-		 */
-		if (next_ExecutorStart_hook)
-			(*next_ExecutorStart_hook) (queryDesc, eflags);
-		else
-			standard_ExecutorStart(queryDesc, eflags);
-	}
-	PG_CATCH();
-	{
-		sepgsql_context_info = saved_context_info;
-		PG_RE_THROW();
-	}
-	PG_END_TRY();
-	sepgsql_context_info = saved_context_info;
-}
-
-/*
  * sepgsql_utility_command
  *
  * It tries to rough-grained control on utility commands; some of them can
@@ -425,10 +385,6 @@ _PG_init(void)
 	next_ProcessUtility_hook = ProcessUtility_hook;
 	ProcessUtility_hook = sepgsql_utility_command;
 
-	/* ExecutorStart hook */
-	next_ExecutorStart_hook = ExecutorStart_hook;
-	ExecutorStart_hook = sepgsql_executor_start;
-
 	/* init contextual info */
 	memset(&sepgsql_context_info, 0, sizeof(sepgsql_context_info));
 }
diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c
index 4ab7fc8..02b0af9 100644
--- a/contrib/sepgsql/relation.c
+++ b/contrib/sepgsql/relation.c
@@ -23,11 +23,14 @@
 #include "utils/fmgroids.h"
 #include "utils/catcache.h"
 #include "utils/lsyscache.h"
+#include "utils/rel.h"
 #include "utils/syscache.h"
 #include "utils/tqual.h"
 
 #include "sepgsql.h"
 
+static void		sepgsql_index_modify(Oid indexOid);
+
 /*
  * sepgsql_attribute_post_create
  *
@@ -201,8 +204,8 @@ sepgsql_relation_post_create(Oid relOid)
 	HeapTuple	tuple;
 	Form_pg_class classForm;
 	ObjectAddress object;
-	uint16		tclass;
-	const char *tclass_text;
+	uint16		tclass = 0;
+	const char *tclass_text = NULL;
 	char	   *scontext;		/* subject */
 	char	   *tcontext;		/* schema */
 	char	   *rcontext;		/* relation */
@@ -243,6 +246,9 @@ sepgsql_relation_post_create(Oid relOid)
 			tclass = SEPG_CLASS_DB_VIEW;
 			tclass_text = "view";
 			break;
+		case RELKIND_INDEX:
+			if (classForm->relnamespace != PG_TOAST_NAMESPACE)
+				break;
 		default:
 			goto out;
 	}
@@ -258,6 +264,17 @@ sepgsql_relation_post_create(Oid relOid)
 							SEPG_DB_SCHEMA__ADD_NAME,
 							getObjectDescription(&object),
 							true);
+	/*
+	 * Index shall be handled as an extra attribute of the tables being
+	 * indexed on, so it does not have its own security label and 'setattr'
+	 * permission should be applied on the table, instead of 'create' on
+	 * the index itself.
+	 */
+	if (classForm->relkind == RELKIND_INDEX)
+	{
+		sepgsql_index_modify(relOid);
+		goto out;
+	}
 
 	/*
 	 * Compute a default security label when we create a new relation object
@@ -367,7 +384,8 @@ sepgsql_relation_drop(Oid relOid)
 		tclass = SEPG_CLASS_DB_SEQUENCE;
 	else if (relkind == RELKIND_VIEW)
 		tclass = SEPG_CLASS_DB_VIEW;
-	else
+	else if (relkind != RELKIND_INDEX ||
+			 get_rel_namespace(relOid) == PG_TOAST_NAMESPACE)
 		return;
 
 	/*
@@ -386,6 +404,16 @@ sepgsql_relation_drop(Oid relOid)
 	pfree(audit_name);
 
 	/*
+	 * We consider deletion of index should be handled as modifying extra
+	 * attribute of the table being indexed.
+	 */
+	if (relkind == RELKIND_INDEX)
+	{
+		sepgsql_index_modify(relOid);
+		return;
+	}
+
+	/*
 	 * check db_table/sequence/view:{drop} permission
 	 */
 	object.classId = RelationRelationId;
@@ -486,3 +514,115 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel)
 								  true);
 	pfree(audit_name);
 }
+
+/*
+ * sepgsql_relation_setattr
+ *
+ * It checks privileges to set attribute of the supplied relation
+ */
+void
+sepgsql_relation_setattr(Oid relOid)
+{
+	ObjectAddress object;
+	char	   *audit_name;
+	char		relkind;
+	uint16_t	tclass = 0;
+
+	relkind = get_rel_relkind(relOid);
+	if (relkind == RELKIND_RELATION)
+		tclass = SEPG_CLASS_DB_TABLE;
+	else if (relkind == RELKIND_SEQUENCE)
+		tclass = SEPG_CLASS_DB_SEQUENCE;
+	else if (relkind == RELKIND_VIEW)
+		tclass = SEPG_CLASS_DB_VIEW;
+	else
+	{
+		if (relkind == RELKIND_INDEX)
+			sepgsql_index_modify(relOid);
+		return;
+	}
+
+	object.classId = RelationRelationId;
+	object.objectId = relOid;
+	object.objectSubId = 0;
+	audit_name = getObjectDescription(&object);
+
+	/*
+	 * XXX - we should add check related to namespace stuff,
+	 * when object_access_hook get support ALTER statement.
+	 * Right now, here is no invocation path on ALTER ...
+	 * RENAME TO / SET SCHEMA.
+	 */
+
+	/*
+	 * check db_xxx:{setattr} permission
+	 */
+	sepgsql_avc_check_perms(&object,
+							tclass,
+							SEPG_DB_TABLE__SETATTR,
+							audit_name,
+							true);
+	pfree(audit_name);
+}
+
+/*
+ * sepgsql_relation_setattr_extra
+ *
+ * It checks permission of the relation being referenced by extra
+ * attributes such as entries of pg_index. As core PostgreSQL doing,
+ * sepgsql also does not deal with the entries as individual "object",
+ * thus, modification of these entries shall be considered as setting
+ * a particular attribute of relation.
+ */
+static void
+sepgsql_relation_setattr_extra(Relation catalog,
+							   Oid catindex_id,
+							   Oid extra_oid,
+							   AttrNumber anum_relation_id,
+							   AttrNumber anum_extra_id)
+{
+	ScanKeyData	skey;
+	SysScanDesc	sscan;
+	HeapTuple	tuple;
+	Datum		datum;
+	bool		isnull;
+
+	ScanKeyInit(&skey, anum_extra_id,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(extra_oid));
+
+	sscan = systable_beginscan(catalog, catindex_id, true,
+							   SnapshotSelf, 1, &skey);
+	tuple = systable_getnext(sscan);
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "catalog lookup failed for object %u in catalog \"%s\"",
+			 extra_oid, RelationGetRelationName(catalog));
+
+	datum = heap_getattr(tuple, anum_relation_id,
+						 RelationGetDescr(catalog), &isnull);
+	Assert(!isnull);
+
+	sepgsql_relation_setattr(DatumGetObjectId(datum));
+
+	systable_endscan(sscan);
+}
+
+/*
+ * sepgsql_index_modify
+ *
+ * handler when an index was created, dropped or updated; that checks
+ * setattr permission of the table being indexed on.
+ */
+static void
+sepgsql_index_modify(Oid indexOid)
+{
+	Relation	catalog = heap_open(IndexRelationId, AccessShareLock);
+
+	/* check db_table:{setattr} permission of the table being indexed */
+	sepgsql_relation_setattr_extra(catalog,
+								   IndexRelidIndexId,
+								   indexOid,
+								   Anum_pg_index_indrelid,
+								   Anum_pg_index_indexrelid);
+	heap_close(catalog, AccessShareLock);
+}
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index 9c89eaa..b6dcb86 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -145,7 +145,6 @@
 #define SEPG_DB_TABLE__INSERT				(1<<8)
 #define SEPG_DB_TABLE__DELETE				(1<<9)
 #define SEPG_DB_TABLE__LOCK					(1<<10)
-#define SEPG_DB_TABLE__INDEXON				(1<<11)
 
 #define SEPG_DB_SEQUENCE__CREATE			(SEPG_DB_DATABASE__CREATE)
 #define SEPG_DB_SEQUENCE__DROP				(SEPG_DB_DATABASE__DROP)
@@ -312,6 +311,7 @@ extern void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
 extern void sepgsql_relation_post_create(Oid relOid);
 extern void sepgsql_relation_drop(Oid relOid);
 extern void sepgsql_relation_relabel(Oid relOid, const char *seclabel);
+extern void sepgsql_relation_setattr(Oid relOid);
 
 /*
  * proc.c
diff --git a/contrib/sepgsql/sql/ddl.sql b/contrib/sepgsql/sql/ddl.sql
index 8dd57e0..5afe1ba 100644
--- a/contrib/sepgsql/sql/ddl.sql
+++ b/contrib/sepgsql/sql/ddl.sql
@@ -60,6 +60,18 @@ CREATE FUNCTION regtest_func_2(int) RETURNS bool LANGUAGE plpgsql
 RESET SESSION AUTHORIZATION;
 
 --
+-- ALTER and CREATE/DROP extra attribute permissions
+--
+CREATE TABLE regtest_table_4 (x int primary key, y int, z int);
+CREATE INDEX regtest_index_tbl4_y ON regtest_table_4(y);
+CREATE INDEX regtest_index_tbl4_z ON regtest_table_4(z);
+ALTER TABLE regtest_table_4 ALTER COLUMN y TYPE float;
+DROP INDEX regtest_index_tbl4_y;
+ALTER TABLE regtest_table_4
+      ADD CONSTRAINT regtest_tbl4_con EXCLUDE USING btree (z WITH =);
+DROP TABLE regtest_table_4 CASCADE;
+
+--
 -- DROP Permission checks (with clean-up)
 --
 
diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml
index ff083a0..cd99ed1 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -450,6 +450,13 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
    </para>
 
    <para>
+    In case when an object that performs as extra attributes towards main
+    object, such as indexes or trigger, is created or dropped,
+    <literal>setattr</> permission will be checked on the main object,
+    instead of the extra attribute itself.
+   </para>
+
+   <para>
     When <xref linkend="sql-security-label"> is executed, <literal>setattr</>
     and <literal>relabelfrom</> will be checked on the object being relabeled
     with its old security label, then <literal>relabelto</> with the supplied
diff --git a/src/backend/bootstrap/bootparse.y b/src/backend/bootstrap/bootparse.y
index ec634f1..fd681dc 100644
--- a/src/backend/bootstrap/bootparse.y
+++ b/src/backend/bootstrap/bootparse.y
@@ -247,6 +247,7 @@ Boot_CreateStmt:
 													  ONCOMMIT_NOOP,
 													  (Datum) 0,
 													  false,
+													  true,
 													  true);
 						elog(DEBUG4, "relation created with OID %u", id);
 					}
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index c80df41..6edd11f 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -985,7 +985,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,
+						 bool is_internal)
 {
 	Relation	pg_class_desc;
 	Relation	new_rel_desc;
@@ -1275,8 +1276,15 @@ heap_create_with_catalog(const char *relname,
 	}
 
 	/* Post creation hook for new relation */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   RelationRelationId, relid, 0, NULL);
+	if (object_access_hook)
+	{
+		ObjectAccessPostCreate	post_create_args;
+
+		memset(&post_create_args, 0, sizeof(ObjectAccessPostCreate));
+		post_create_args.is_internal = is_internal;
+		(*object_access_hook)(OAT_POST_CREATE, RelationRelationId,
+							  relid, 0, &post_create_args);
+    }
 
 	/*
 	 * Store any supplied constraints and defaults.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 464950b..f2a3a06 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -33,6 +33,7 @@
 #include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/index.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_operator.h"
@@ -686,7 +687,8 @@ index_create(Relation heapRelation,
 			 bool initdeferred,
 			 bool allow_system_table_mods,
 			 bool skip_build,
-			 bool concurrent)
+			 bool concurrent,
+			 bool is_internal)
 {
 	Oid			heapRelationId = RelationGetRelid(heapRelation);
 	Relation	pg_class;
@@ -1018,6 +1020,17 @@ index_create(Relation heapRelation,
 		Assert(!initdeferred);
 	}
 
+	/* Post creation hook for new index */
+	if (object_access_hook)
+	{
+		ObjectAccessPostCreate	post_create_args;
+
+		memset(&post_create_args, 0, sizeof(ObjectAccessPostCreate));
+		post_create_args.is_internal = is_internal;
+		(*object_access_hook)(OAT_POST_CREATE, RelationRelationId,
+							  indexRelationId, 0, &post_create_args);
+	}
+
 	/*
 	 * Advance the command counter so that we can see the newly-entered
 	 * catalog tuples for the index.
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 1feffd2..2979819 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -226,6 +226,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
 										   ONCOMMIT_NOOP,
 										   reloptions,
 										   false,
+										   true,
 										   true);
 	Assert(toast_relid != InvalidOid);
 
@@ -279,7 +280,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, Datum reloptio
 				 rel->rd_rel->reltablespace,
 				 collationObjectId, classObjectId, coloptions, (Datum) 0,
 				 true, false, false, false,
-				 true, false, false);
+				 true, false, false, true);
 
 	heap_close(toast_rel, NoLock);
 
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index cfec413..de71a35 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -643,6 +643,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace)
 										  ONCOMMIT_NOOP,
 										  reloptions,
 										  false,
+										  true,
 										  true);
 	Assert(OIDNewHeap != InvalidOid);
 
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index a58101e..dd46cf9 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -596,7 +596,7 @@ DefineIndex(IndexStmt *stmt,
 					 stmt->isconstraint, stmt->deferrable, stmt->initdeferred,
 					 allowSystemTableMods,
 					 skip_build || stmt->concurrent,
-					 stmt->concurrent);
+					 stmt->concurrent, !check_rights);
 
 	/* Add any requested comment */
 	if (stmt->idxcomment != NULL)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 359d478..378b29d 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -630,7 +630,8 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
 										  stmt->oncommit,
 										  reloptions,
 										  true,
-										  allowSystemTableMods);
+										  allowSystemTableMods,
+										  false);
 
 	/* Store inheritance information for new rel. */
 	StoreCatalogInheritance(relationId, inheritOids);
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index bc8c63a..1465456 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -66,7 +66,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,
+						 bool is_internal);
 
 extern void heap_create_init_fork(Relation rel);
 
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index eb417ce..298641b 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -50,7 +50,8 @@ extern Oid index_create(Relation heapRelation,
 			 bool initdeferred,
 			 bool allow_system_table_mods,
 			 bool skip_build,
-			 bool concurrent);
+			 bool concurrent,
+			 bool is_internal);
 
 extern void index_constraint_create(Relation heapRelation,
 						Oid indexRelationId,
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index 3b40dbc..b4b84a6 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -31,6 +31,19 @@ typedef enum ObjectAccessType
 } ObjectAccessType;
 
 /*
+ * 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;
+
+/*
  * Arguments of OAT_DROP event
  */
 typedef struct