sepgsql-v9.3-post-alter-support.v1.patch

application/octet-stream

Filename: sepgsql-v9.3-post-alter-support.v1.patch
Type: application/octet-stream
Part: 0
Message: [v9.3] OAT_POST_ALTER object access hooks

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/database.c 27 0
contrib/sepgsql/expected/alter.out 177 0
contrib/sepgsql/expected/ddl.out 9 0
contrib/sepgsql/hooks.c 48 0
contrib/sepgsql/proc.c 88 2
contrib/sepgsql/relation.c 79 8
contrib/sepgsql/schema.c 51 0
contrib/sepgsql/sepgsql.h 7 0
contrib/sepgsql/sql/alter.sql 128 0
contrib/sepgsql/sql/ddl.sql 6 0
contrib/sepgsql/test_sepgsql 1 1
doc/src/sgml/sepgsql.sgml 18 3
src/backend/catalog/aclchk.c 5 0
src/backend/catalog/heap.c 36 12
src/backend/catalog/index.c 7 3
src/backend/catalog/pg_constraint.c 18 3
src/backend/catalog/pg_db_role_setting.c 10 0
src/backend/catalog/pg_type.c 3 0
src/backend/commands/alter.c 11 0
src/backend/commands/cluster.c 2 2
src/backend/commands/collationcmds.c 4 0
src/backend/commands/dbcommands.c 16 0
src/backend/commands/event_trigger.c 3 0
src/backend/commands/extension.c 11 0
src/backend/commands/foreigncmds.c 16 0
src/backend/commands/functioncmds.c 2 1
src/backend/commands/opclasscmds.c 8 0
src/backend/commands/schemacmds.c 8 0
src/backend/commands/sequence.c 5 0
src/backend/commands/tablecmds.c 110 16
src/backend/commands/tablespace.c 4 0
src/backend/commands/trigger.c 19 3
src/backend/commands/tsearchcmds.c 5 0
src/backend/commands/typecmds.c 35 3
src/backend/commands/user.c 5 0
src/backend/rewrite/rewriteDefine.c 2 0
src/include/catalog/heap.h 4 2
src/include/catalog/index.h 2 1
src/include/catalog/objectaccess.h 28 0
src/include/catalog/pg_constraint.h 2 1
src/include/commands/tablecmds.h 1 1
 contrib/sepgsql/database.c               |  27 +++++
 contrib/sepgsql/expected/alter.out       | 177 +++++++++++++++++++++++++++++++
 contrib/sepgsql/expected/ddl.out         |   9 ++
 contrib/sepgsql/hooks.c                  |  48 +++++++++
 contrib/sepgsql/proc.c                   |  90 +++++++++++++++-
 contrib/sepgsql/relation.c               |  87 +++++++++++++--
 contrib/sepgsql/schema.c                 |  51 +++++++++
 contrib/sepgsql/sepgsql.h                |   7 ++
 contrib/sepgsql/sql/alter.sql            | 128 ++++++++++++++++++++++
 contrib/sepgsql/sql/ddl.sql              |   6 ++
 contrib/sepgsql/test_sepgsql             |   2 +-
 doc/src/sgml/sepgsql.sgml                |  21 +++-
 src/backend/catalog/aclchk.c             |   5 +
 src/backend/catalog/heap.c               |  48 ++++++---
 src/backend/catalog/index.c              |  10 +-
 src/backend/catalog/pg_constraint.c      |  21 +++-
 src/backend/catalog/pg_db_role_setting.c |  10 ++
 src/backend/catalog/pg_type.c            |   3 +
 src/backend/commands/alter.c             |  11 ++
 src/backend/commands/cluster.c           |   4 +-
 src/backend/commands/collationcmds.c     |   4 +
 src/backend/commands/dbcommands.c        |  16 +++
 src/backend/commands/event_trigger.c     |   3 +
 src/backend/commands/extension.c         |  11 ++
 src/backend/commands/foreigncmds.c       |  16 +++
 src/backend/commands/functioncmds.c      |   3 +-
 src/backend/commands/opclasscmds.c       |   8 ++
 src/backend/commands/schemacmds.c        |   8 ++
 src/backend/commands/sequence.c          |   5 +
 src/backend/commands/tablecmds.c         | 126 +++++++++++++++++++---
 src/backend/commands/tablespace.c        |   4 +
 src/backend/commands/trigger.c           |  22 +++-
 src/backend/commands/tsearchcmds.c       |   5 +
 src/backend/commands/typecmds.c          |  38 ++++++-
 src/backend/commands/user.c              |   5 +
 src/backend/rewrite/rewriteDefine.c      |   2 +
 src/include/catalog/heap.h               |   6 +-
 src/include/catalog/index.h              |   3 +-
 src/include/catalog/objectaccess.h       |  28 +++++
 src/include/catalog/pg_constraint.h      |   3 +-
 src/include/commands/tablecmds.h         |   2 +-
 41 files changed, 1021 insertions(+), 62 deletions(-)

diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c
index c15f2d0..942d179 100644
--- a/contrib/sepgsql/database.c
+++ b/contrib/sepgsql/database.c
@@ -149,6 +149,33 @@ sepgsql_database_drop(Oid databaseId)
 }
 
 /*
+ * sepgsql_database_post_alter
+ *
+ * It checks privileges to alter the supplied database
+ */
+void
+sepgsql_database_setattr(Oid databaseId)
+{
+	ObjectAddress object;
+	char	   *audit_name;
+
+	/*
+	 * check db_database:{setattr} permission
+	 */
+	object.classId = DatabaseRelationId;
+	object.objectId = databaseId;
+	object.objectSubId = 0;
+	audit_name = getObjectDescription(&object);
+
+	sepgsql_avc_check_perms(&object,
+							SEPG_CLASS_DB_DATABASE,
+							SEPG_DB_DATABASE__SETATTR,
+							audit_name,
+							true);
+	pfree(audit_name);
+}
+
+/*
  * sepgsql_database_relabel
  *
  * It checks privileges to relabel the supplied database with the `seclabel'
diff --git a/contrib/sepgsql/expected/alter.out b/contrib/sepgsql/expected/alter.out
new file mode 100644
index 0000000..42dac64
--- /dev/null
+++ b/contrib/sepgsql/expected/alter.out
@@ -0,0 +1,177 @@
+--
+-- Test for various ALTER statements
+--
+-- clean-up in case a prior regression run failed
+SET client_min_messages TO 'warning';
+DROP DATABASE IF EXISTS regtest_sepgsql_test_database_1;
+DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
+DROP USER IF EXISTS regtest_sepgsql_test_user;
+RESET client_min_messages;
+SELECT sepgsql_getcon();	-- confirm client privilege
+              sepgsql_getcon               
+-------------------------------------------
+ unconfined_u:unconfined_r:unconfined_t:s0
+(1 row)
+
+--
+-- CREATE Objects to be altered (with debug_audit being silent)
+--
+CREATE DATABASE regtest_sepgsql_test_database_1;
+CREATE USER regtest_sepgsql_test_user;
+CREATE SCHEMA regtest_schema_1;
+CREATE SCHEMA regtest_schema_2;
+GRANT ALL ON SCHEMA regtest_schema_1 TO public;
+GRANT ALL ON SCHEMA regtest_schema_2  TO public;
+SET search_path = regtest_schema_1, regtest_schema_2, public;
+CREATE TABLE regtest_table_1 (a int, b text);
+CREATE TABLE regtest_table_2 (c text) inherits (regtest_table_1);
+CREATE TABLE regtest_table_3 (x int primary key, y text);
+CREATE SEQUENCE regtest_seq_1;
+CREATE VIEW regtest_view_1 AS SELECT * FROM regtest_table_1 WHERE a > 0;
+CREATE FUNCTION regtest_func_1 (text) RETURNS bool
+  AS 'BEGIN RETURN true; END' LANGUAGE 'plpgsql';
+-- switch on debug_audit
+SET sepgsql.debug_audit = true;
+SET client_min_messages = LOG;
+--
+-- ALTER xxx OWNER TO
+--
+ALTER DATABASE regtest_sepgsql_test_database_1 OWNER TO regtest_sepgsql_test_user;
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="database regtest_sepgsql_test_database_1"
+ALTER SCHEMA regtest_schema_1 OWNER TO regtest_sepgsql_test_user;
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema_1"
+ALTER TABLE regtest_table_1 OWNER TO regtest_sepgsql_test_user;
+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_1"
+ALTER SEQUENCE regtest_seq_1 OWNER TO regtest_sepgsql_test_user;
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq_1"
+ALTER VIEW regtest_view_1 OWNER TO regtest_sepgsql_test_user;
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view_1"
+ALTER FUNCTION regtest_func_1(text) OWNER TO regtest_sepgsql_test_user;
+LOG:  SELinux: allowed { setattr } 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_1(text)"
+--
+-- ALTER xxx SET SCHEMA
+--
+ALTER TABLE regtest_table_1 SET SCHEMA regtest_schema_2;
+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_1"
+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_2"
+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_1"
+ALTER SEQUENCE regtest_seq_1 SET SCHEMA regtest_schema_2;
+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_1"
+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_2"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq_1"
+ALTER VIEW regtest_view_1 SET SCHEMA regtest_schema_2;
+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_1"
+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_2"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view_1"
+ALTER FUNCTION regtest_func_1(text) SET SCHEMA regtest_schema_2;
+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_1"
+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_1"
+LOG:  SELinux: allowed { setattr } 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_1(text)"
+--
+-- ALTER xxx RENAME TO
+--
+ALTER DATABASE regtest_sepgsql_test_database_1 RENAME TO regtest_sepgsql_test_database;
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="database regtest_sepgsql_test_database_1"
+ALTER SCHEMA regtest_schema_1 RENAME TO regtest_schema;
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema_1"
+ALTER TABLE regtest_table_1 RENAME TO regtest_table;
+LOG:  SELinux: allowed { add_name 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_2"
+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_1"
+ALTER SEQUENCE regtest_seq_1 RENAME TO regtest_seq;
+LOG:  SELinux: allowed { add_name 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_2"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq_1"
+ALTER VIEW regtest_view_1 RENAME TO regtest_view;
+LOG:  SELinux: allowed { add_name 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_2"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view_1"
+ALTER FUNCTION regtest_func_1(text) RENAME TO regtest_func;
+LOG:  SELinux: allowed { add_name 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_2"
+LOG:  SELinux: allowed { setattr } 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_1(text)"
+SET search_path = regtest_schema, regtest_schema_2, public;
+--
+-- misc ALTER commands
+--
+ALTER DATABASE regtest_sepgsql_test_database CONNECTION LIMIT 999;
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_db_t:s0 tclass=db_database name="database regtest_sepgsql_test_database"
+ALTER DATABASE regtest_sepgsql_test_database SET search_path TO regtest_schema, public; -- not supported yet
+ALTER TABLE regtest_table ADD COLUMN d float;
+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 d"
+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_2 column d"
+ALTER TABLE regtest_table DROP COLUMN d;
+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_2 column d"
+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 d"
+ALTER TABLE regtest_table ALTER b SET DEFAULT 'abcd';   -- not supported yet
+ALTER TABLE regtest_table ALTER b SET DEFAULT 'XYZ';    -- not supported yet
+ALTER TABLE regtest_table ALTER b DROP DEFAULT;         -- not supported yet
+ALTER TABLE regtest_table ALTER b SET NOT NULL;
+LOG:  SELinux: allowed { setattr } 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 b"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column b"
+ALTER TABLE regtest_table ALTER b DROP NOT NULL;
+LOG:  SELinux: allowed { setattr } 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 b"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column b"
+ALTER TABLE regtest_table ALTER b SET STATISTICS -1;
+LOG:  SELinux: allowed { setattr } 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 b"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column b"
+ALTER TABLE regtest_table ALTER b SET (n_distinct = 999);
+LOG:  SELinux: allowed { setattr } 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 b"
+ALTER TABLE regtest_table ALTER b SET STORAGE PLAIN;
+LOG:  SELinux: allowed { setattr } 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 b"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_2 column b"
+ALTER TABLE regtest_table ADD CONSTRAINT test_fk FOREIGN KEY (a) REFERENCES regtest_table_3(x); -- not supported
+LOG:  SELinux: allowed { select } 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 { select } 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 a"
+LOG:  SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_3"
+LOG:  SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column x"
+LOG:  SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table"
+CONTEXT:  SQL statement "SELECT fk."a" FROM ONLY "regtest_schema_2"."regtest_table" fk LEFT OUTER JOIN ONLY "regtest_schema"."regtest_table_3" pk ON ( pk."x" OPERATOR(pg_catalog.=) fk."a") WHERE pk."x" IS NULL AND (fk."a" IS NOT NULL)"
+LOG:  SELinux: allowed { select } 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 a"
+CONTEXT:  SQL statement "SELECT fk."a" FROM ONLY "regtest_schema_2"."regtest_table" fk LEFT OUTER JOIN ONLY "regtest_schema"."regtest_table_3" pk ON ( pk."x" OPERATOR(pg_catalog.=) fk."a") WHERE pk."x" IS NULL AND (fk."a" IS NOT NULL)"
+LOG:  SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_table name="table regtest_table_3"
+CONTEXT:  SQL statement "SELECT fk."a" FROM ONLY "regtest_schema_2"."regtest_table" fk LEFT OUTER JOIN ONLY "regtest_schema"."regtest_table_3" pk ON ( pk."x" OPERATOR(pg_catalog.=) fk."a") WHERE pk."x" IS NULL AND (fk."a" IS NOT NULL)"
+LOG:  SELinux: allowed { select } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_table_t:s0 tclass=db_column name="table regtest_table_3 column x"
+CONTEXT:  SQL statement "SELECT fk."a" FROM ONLY "regtest_schema_2"."regtest_table" fk LEFT OUTER JOIN ONLY "regtest_schema"."regtest_table_3" pk ON ( pk."x" OPERATOR(pg_catalog.=) fk."a") WHERE pk."x" IS NULL AND (fk."a" IS NOT NULL)"
+ALTER TABLE regtest_table ADD CONSTRAINT test_ck CHECK (b like '%abc%') NOT VALID;      -- not supported
+ALTER TABLE regtest_table VALIDATE CONSTRAINT test_ck;  -- not supported
+ALTER TABLE regtest_table DROP CONSTRAINT test_ck;      -- not supported
+CREATE TRIGGER regtest_test_trig BEFORE UPDATE ON regtest_table
+    FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+ALTER TABLE regtest_table DISABLE TRIGGER regtest_test_trig;    -- not supported
+ALTER TABLE regtest_table ENABLE  TRIGGER regtest_test_trig;    -- not supported
+CREATE RULE regtest_test_rule AS ON INSERT TO regtest_table_3 DO ALSO NOTHING;
+ALTER TABLE regtest_table_3 DISABLE RULE regtest_test_rule;     -- not supported
+ALTER TABLE regtest_table_3 ENABLE RULE regtest_test_rule;      -- not supported
+ALTER TABLE regtest_table SET WITH OIDS;
+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 oid"
+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_2 column oid"
+ALTER TABLE regtest_table SET WITHOUT OIDS;
+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_2 column oid"
+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 oid"
+ALTER TABLE regtest_table SET (fillfactor = 75);
+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 RESET (fillfactor);
+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_2 NO INHERIT regtest_table;   -- not supported
+ALTER TABLE regtest_table_2 INHERIT regtest_table;      -- not supported
+-- TODO: where we should put object_access_hook for AT_SetTableSpace
+ALTER TABLE regtest_table SET TABLESPACE pg_default;
+ALTER VIEW regtest_view SET (security_barrier);
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_view_t:s0 tclass=db_view name="view regtest_view"
+ALTER SEQUENCE regtest_seq INCREMENT BY 10 START WITH 1000;
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq"
+--
+-- clean-up objects
+--
+RESET sepgsql.debug_audit;
+RESET client_min_messages;
+DROP DATABASE regtest_sepgsql_test_database;
+DROP SCHEMA regtest_schema CASCADE;
+NOTICE:  drop cascades to 3 other objects
+DETAIL:  drop cascades to table regtest_table_2
+drop cascades to table regtest_table_3
+drop cascades to constraint test_fk on table regtest_table
+DROP SCHEMA regtest_schema_2 CASCADE;
+NOTICE:  drop cascades to 4 other objects
+DETAIL:  drop cascades to table regtest_table
+drop cascades to sequence regtest_seq
+drop cascades to view regtest_view
+drop cascades to function regtest_func(text)
+DROP USER regtest_sepgsql_test_user;
diff --git a/contrib/sepgsql/expected/ddl.out b/contrib/sepgsql/expected/ddl.out
index 1f7ea88..d60c65b 100644
--- a/contrib/sepgsql/expected/ddl.out
+++ b/contrib/sepgsql/expected/ddl.out
@@ -1,6 +1,11 @@
 --
 -- Regression Test for DDL of Object Permission Checks
 --
+-- clean-up in case a prior regression run failed
+SET client_min_messages TO 'warning';
+DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
+DROP USER IF EXISTS regtest_sepgsql_test_user;
+RESET client_min_messages;
 -- confirm required permissions using audit messages
 SELECT sepgsql_getcon();	-- confirm client privilege
               sepgsql_getcon               
@@ -36,6 +41,7 @@ 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 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"
+LOG:  SELinux: allowed { setattr } 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"
 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;
@@ -61,6 +67,7 @@ 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_comptype 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"
 CREATE FUNCTION regtest_func(text,int[]) RETURNS bool LANGUAGE plpgsql
 	   AS 'BEGIN RAISE NOTICE ''regtest_func => %'', $1; RETURN true; END';
 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"
@@ -86,6 +93,7 @@ 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_3 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_3 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_3 column y"
+LOG:  SELinux: allowed { setattr } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_table_3_y_seq"
 CREATE VIEW regtest_view_2 AS SELECT * FROM regtest_table_3 WHERE x < 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 { 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_2"
@@ -118,6 +126,7 @@ 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;
+LOG:  SELinux: allowed { setattr } 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"
 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"
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index ab55d6e..8f3a2d7 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -188,6 +188,54 @@ sepgsql_object_access(ObjectAccessType access,
 			}
 			break;
 
+		case OAT_POST_ALTER:
+			{
+				ObjectAccessPostAlter  *pa_arg = arg;
+				bool	is_internal = (!pa_arg ? false : pa_arg->is_internal);
+
+				switch (classId)
+				{
+					case DatabaseRelationId:
+						Assert(!is_internal);
+						sepgsql_database_setattr(objectId);
+						break;
+
+					case NamespaceRelationId:
+						Assert(!is_internal);
+						sepgsql_schema_setattr(objectId);
+						break;
+
+					case RelationRelationId:
+						if (subId == 0)
+                        {
+							/*
+							 * A case when we don't want to apply permission
+							 * check is that relation is internally altered
+							 * without user's intention. E.g, no need to
+							 * check on toast table/index to be renamed at
+							 * end of the table rewrites.
+							 */
+							if (is_internal)
+                                break;
+
+							sepgsql_relation_setattr(objectId);
+                        }
+                        else
+                            sepgsql_attribute_setattr(objectId, subId);
+						break;
+
+					case ProcedureRelationId:
+						Assert(!is_internal);
+						sepgsql_proc_setattr(objectId);
+						break;
+
+					default:
+						/* Ignore unsupported object classes */
+						break;
+				}
+			}
+			break;
+
 		default:
 			elog(ERROR, "unexpected object access type: %d", (int) access);
 			break;
diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c
index fbd358a..6124f00 100644
--- a/contrib/sepgsql/proc.c
+++ b/contrib/sepgsql/proc.c
@@ -23,6 +23,7 @@
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
+#include "utils/syscache.h"
 #include "utils/tqual.h"
 
 #include "sepgsql.h"
@@ -43,6 +44,7 @@ sepgsql_proc_post_create(Oid functionId)
 	char	   *scontext;
 	char	   *tcontext;
 	char	   *ncontext;
+	uint32		required;
 	int			i;
 	StringInfoData audit_name;
 	ObjectAddress object;
@@ -96,7 +98,7 @@ sepgsql_proc_post_create(Oid functionId)
 									  SEPG_CLASS_DB_PROCEDURE);
 
 	/*
-	 * check db_procedure:{create} permission
+	 * check db_procedure:{create (install)} permission
 	 */
 	initStringInfo(&audit_name);
 	appendStringInfo(&audit_name, "function %s(", NameStr(proForm->proname));
@@ -110,9 +112,13 @@ sepgsql_proc_post_create(Oid functionId)
 	}
 	appendStringInfoChar(&audit_name, ')');
 
+	required = SEPG_DB_PROCEDURE__CREATE;
+	if (proForm->proleakproof)
+		required |= SEPG_DB_PROCEDURE__INSTALL;
+
 	sepgsql_avc_check_perms_label(ncontext,
 								  SEPG_CLASS_DB_PROCEDURE,
-								  SEPG_DB_PROCEDURE__CREATE,
+								  required,
 								  audit_name.data,
 								  true);
 
@@ -214,3 +220,83 @@ sepgsql_proc_relabel(Oid functionId, const char *seclabel)
 								  true);
 	pfree(audit_name);
 }
+
+/*
+ * sepgsql_proc_setattr
+ *
+ * It checks privileges to alter the supplied function.
+ */
+void
+sepgsql_proc_setattr(Oid functionId)
+{
+	Relation		rel;
+	ScanKeyData		skey;
+	SysScanDesc		sscan;
+	HeapTuple		oldtup;
+	HeapTuple		newtup;
+	Form_pg_proc	oldform;
+	Form_pg_proc	newform;
+	uint32			required;
+	ObjectAddress	object;
+	char		   *audit_name;
+
+	/*
+	 * Fetch newer catalog
+	 */
+	rel = heap_open(ProcedureRelationId, AccessShareLock);
+
+	ScanKeyInit(&skey,
+				ObjectIdAttributeNumber,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(functionId));
+
+	sscan = systable_beginscan(rel, ProcedureOidIndexId, true,
+							   SnapshotSelf, 1, &skey);
+	newtup = systable_getnext(sscan);
+	if (!HeapTupleIsValid(newtup))
+		elog(ERROR, "catalog lookup failed for function %u", functionId);
+	newform = (Form_pg_proc) GETSTRUCT(newtup);
+
+	/*
+	 * Fetch older catalog
+	 */
+	oldtup = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionId));
+	if (!HeapTupleIsValid(oldtup))
+		elog(ERROR, "cache lookup failed for function %u", functionId);
+	oldform = (Form_pg_proc) GETSTRUCT(oldtup);
+
+	/*
+	 * Does this ALTER command takes operation to namespace?
+	 */
+	if (newform->pronamespace != oldform->pronamespace)
+	{
+		sepgsql_schema_remove_name(oldform->pronamespace);
+		sepgsql_schema_add_name(oldform->pronamespace);
+	}
+	if (strcmp(NameStr(newform->proname), NameStr(oldform->proname)) != 0)
+		sepgsql_schema_rename(oldform->pronamespace);
+
+	/*
+	 * check db_procedure:{setattr (install)} permission
+	 */
+	required = SEPG_DB_PROCEDURE__SETATTR;
+	if (!oldform->proleakproof && newform->proleakproof)
+		required |= SEPG_DB_PROCEDURE__INSTALL;
+
+	object.classId = ProcedureRelationId;
+	object.objectId = functionId;
+	object.objectSubId = 0;
+	audit_name = getObjectDescription(&object);
+
+	sepgsql_avc_check_perms(&object,
+							SEPG_CLASS_DB_PROCEDURE,
+                            required,
+							audit_name,
+							true);
+	/* cleanups */
+	pfree(audit_name);
+
+	ReleaseSysCache(oldtup);
+	systable_endscan(sscan);
+	heap_close(rel, AccessShareLock);
+}
diff --git a/contrib/sepgsql/relation.c b/contrib/sepgsql/relation.c
index 783f330..12116eb 100644
--- a/contrib/sepgsql/relation.c
+++ b/contrib/sepgsql/relation.c
@@ -191,6 +191,36 @@ sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
 }
 
 /*
+ * sepgsql_attribute_setattr
+ *
+ * It checks privileges to alter the supplied column.
+ */
+void
+sepgsql_attribute_setattr(Oid relOid, AttrNumber attnum)
+{
+	ObjectAddress object;
+	char	   *audit_name;
+
+	if (get_rel_relkind(relOid) != RELKIND_RELATION)
+		return;
+
+	/*
+	 * check db_column:{setattr} permission
+	 */
+	object.classId = RelationRelationId;
+	object.objectId = relOid;
+	object.objectSubId = attnum;
+	audit_name = getObjectDescription(&object);
+
+	sepgsql_avc_check_perms(&object,
+							SEPG_CLASS_DB_COLUMN,
+							SEPG_DB_COLUMN__SETATTR,
+							audit_name,
+							true);
+	pfree(audit_name);
+}
+
+/*
  * sepgsql_relation_post_create
  *
  * The post creation hook of relation/attribute
@@ -520,7 +550,6 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel)
 								  true);
 	pfree(audit_name);
 }
-
 /*
  * sepgsql_relation_setattr
  *
@@ -529,6 +558,13 @@ sepgsql_relation_relabel(Oid relOid, const char *seclabel)
 void
 sepgsql_relation_setattr(Oid relOid)
 {
+	Relation		rel;
+	ScanKeyData		skey;
+	SysScanDesc		sscan;
+	HeapTuple		oldtup;
+	HeapTuple		newtup;
+	Form_pg_class	oldform;
+	Form_pg_class	newform;
 	ObjectAddress object;
 	char	   *audit_name;
 	uint16_t	tclass;
@@ -553,26 +589,61 @@ sepgsql_relation_setattr(Oid relOid)
 			return;
 	}
 
-	object.classId = RelationRelationId;
-	object.objectId = relOid;
-	object.objectSubId = 0;
-	audit_name = getObjectDescription(&object);
+	/*
+	 * Fetch newer catalog
+	 */
+	rel = heap_open(RelationRelationId, AccessShareLock);
+
+	ScanKeyInit(&skey,
+				ObjectIdAttributeNumber,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(relOid));
+
+	sscan = systable_beginscan(rel, ClassOidIndexId, true,
+							   SnapshotSelf, 1, &skey);
+
+	newtup = systable_getnext(sscan);
+	if (!HeapTupleIsValid(newtup))
+		elog(ERROR, "catalog lookup failed for relation %u", relOid);
+	newform = (Form_pg_class) GETSTRUCT(newtup);
 
 	/*
-	 * XXX - we should add checks related to namespace stuff, when
-	 * object_access_hook get support for ALTER statement.  Right now, there is
-	 * no invocation path on ALTER ...  RENAME TO / SET SCHEMA.
+	 * Fetch older catalog
 	 */
+	oldtup = SearchSysCache1(RELOID, ObjectIdGetDatum(relOid));
+	if (!HeapTupleIsValid(oldtup))
+		elog(ERROR, "cache lookup failed for relation %u", relOid);
+	oldform = (Form_pg_class) GETSTRUCT(oldtup);
+
+	/*
+	 * Does this ALTER command takes operation to namespace?
+	 */
+	if (newform->relnamespace != oldform->relnamespace)
+	{
+		sepgsql_schema_remove_name(oldform->relnamespace);
+		sepgsql_schema_add_name(newform->relnamespace);
+	}
+	if (strcmp(NameStr(newform->relname), NameStr(oldform->relname)) != 0)
+		sepgsql_schema_rename(oldform->relnamespace);
 
 	/*
 	 * check db_xxx:{setattr} permission
 	 */
+	object.classId = RelationRelationId;
+	object.objectId = relOid;
+	object.objectSubId = 0;
+	audit_name = getObjectDescription(&object);
+
 	sepgsql_avc_check_perms(&object,
 							tclass,
 							SEPG_DB_TABLE__SETATTR,
 							audit_name,
 							true);
 	pfree(audit_name);
+
+	ReleaseSysCache(oldtup);
+	systable_endscan(sscan);
+	heap_close(rel, AccessShareLock);
 }
 
 /*
diff --git a/contrib/sepgsql/schema.c b/contrib/sepgsql/schema.c
index e063e39..240a6d9 100644
--- a/contrib/sepgsql/schema.c
+++ b/contrib/sepgsql/schema.c
@@ -162,3 +162,54 @@ sepgsql_schema_relabel(Oid namespaceId, const char *seclabel)
 								  true);
 	pfree(audit_name);
 }
+
+/*
+ * sepgsql_schema_check_perms
+ *
+ * utility routine to check db_schema:{xxx} permissions
+ */
+static void
+check_schema_perms(Oid namespaceId, uint32 required)
+{
+	ObjectAddress object;
+	char	   *audit_name;
+
+	object.classId = NamespaceRelationId;
+	object.objectId = namespaceId;
+	object.objectSubId = 0;
+	audit_name = getObjectDescription(&object);
+
+	sepgsql_avc_check_perms(&object,
+							SEPG_CLASS_DB_SCHEMA,
+							required,
+							audit_name,
+							true);
+	pfree(audit_name);
+}
+
+/* db_schema:{setattr} permission */
+void
+sepgsql_schema_setattr(Oid namespaceId)
+{
+	check_schema_perms(namespaceId, SEPG_DB_SCHEMA__SETATTR);
+}
+
+void
+sepgsql_schema_add_name(Oid namespaceId)
+{
+	check_schema_perms(namespaceId, SEPG_DB_SCHEMA__ADD_NAME);
+}
+
+void
+sepgsql_schema_remove_name(Oid namespaceId)
+{
+	check_schema_perms(namespaceId, SEPG_DB_SCHEMA__REMOVE_NAME);
+}
+
+void
+sepgsql_schema_rename(Oid namespaceId)
+{
+	check_schema_perms(namespaceId,
+					   SEPG_DB_SCHEMA__ADD_NAME |
+					   SEPG_DB_SCHEMA__REMOVE_NAME);
+}
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index b6dcb86..4251c97 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -293,6 +293,7 @@ extern void sepgsql_database_post_create(Oid databaseId,
 							 const char *dtemplate);
 extern void sepgsql_database_drop(Oid databaseId);
 extern void sepgsql_database_relabel(Oid databaseId, const char *seclabel);
+extern void sepgsql_database_setattr(Oid databaseId);
 
 /*
  * schema.c
@@ -300,6 +301,10 @@ extern void sepgsql_database_relabel(Oid databaseId, const char *seclabel);
 extern void sepgsql_schema_post_create(Oid namespaceId);
 extern void sepgsql_schema_drop(Oid namespaceId);
 extern void sepgsql_schema_relabel(Oid namespaceId, const char *seclabel);
+extern void sepgsql_schema_setattr(Oid namespaceId);
+extern void sepgsql_schema_add_name(Oid namespaceId);
+extern void sepgsql_schema_remove_name(Oid namespaceId);
+extern void sepgsql_schema_rename(Oid namespaceId);
 
 /*
  * relation.c
@@ -308,6 +313,7 @@ extern void sepgsql_attribute_post_create(Oid relOid, AttrNumber attnum);
 extern void sepgsql_attribute_drop(Oid relOid, AttrNumber attnum);
 extern void sepgsql_attribute_relabel(Oid relOid, AttrNumber attnum,
 						  const char *seclabel);
+extern void sepgsql_attribute_setattr(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);
@@ -319,5 +325,6 @@ extern void sepgsql_relation_setattr(Oid relOid);
 extern void sepgsql_proc_post_create(Oid functionId);
 extern void sepgsql_proc_drop(Oid functionId);
 extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel);
+extern void sepgsql_proc_setattr(Oid functionId);
 
 #endif   /* SEPGSQL_H */
diff --git a/contrib/sepgsql/sql/alter.sql b/contrib/sepgsql/sql/alter.sql
new file mode 100644
index 0000000..e494ace
--- /dev/null
+++ b/contrib/sepgsql/sql/alter.sql
@@ -0,0 +1,128 @@
+--
+-- Test for various ALTER statements
+--
+
+-- clean-up in case a prior regression run failed
+SET client_min_messages TO 'warning';
+DROP DATABASE IF EXISTS regtest_sepgsql_test_database_1;
+DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
+DROP USER IF EXISTS regtest_sepgsql_test_user;
+RESET client_min_messages;
+
+-- @SECURITY-CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0
+
+--
+-- CREATE Objects to be altered (with debug_audit being silent)
+--
+CREATE DATABASE regtest_sepgsql_test_database_1;
+
+CREATE USER regtest_sepgsql_test_user;
+
+CREATE SCHEMA regtest_schema_1;
+CREATE SCHEMA regtest_schema_2;
+
+GRANT ALL ON SCHEMA regtest_schema_1 TO public;
+GRANT ALL ON SCHEMA regtest_schema_2  TO public;
+
+SET search_path = regtest_schema_1, regtest_schema_2, public;
+
+CREATE TABLE regtest_table_1 (a int, b text);
+
+CREATE TABLE regtest_table_2 (c text) inherits (regtest_table_1);
+
+CREATE TABLE regtest_table_3 (x int primary key, y text);
+
+CREATE SEQUENCE regtest_seq_1;
+
+CREATE VIEW regtest_view_1 AS SELECT * FROM regtest_table_1 WHERE a > 0;
+
+CREATE FUNCTION regtest_func_1 (text) RETURNS bool
+  AS 'BEGIN RETURN true; END' LANGUAGE 'plpgsql';
+
+-- switch on debug_audit
+SET sepgsql.debug_audit = true;
+SET client_min_messages = LOG;
+
+--
+-- ALTER xxx OWNER TO
+--
+ALTER DATABASE regtest_sepgsql_test_database_1 OWNER TO regtest_sepgsql_test_user;
+ALTER SCHEMA regtest_schema_1 OWNER TO regtest_sepgsql_test_user;
+ALTER TABLE regtest_table_1 OWNER TO regtest_sepgsql_test_user;
+ALTER SEQUENCE regtest_seq_1 OWNER TO regtest_sepgsql_test_user;
+ALTER VIEW regtest_view_1 OWNER TO regtest_sepgsql_test_user;
+ALTER FUNCTION regtest_func_1(text) OWNER TO regtest_sepgsql_test_user;
+
+--
+-- ALTER xxx SET SCHEMA
+--
+ALTER TABLE regtest_table_1 SET SCHEMA regtest_schema_2;
+ALTER SEQUENCE regtest_seq_1 SET SCHEMA regtest_schema_2;
+ALTER VIEW regtest_view_1 SET SCHEMA regtest_schema_2;
+ALTER FUNCTION regtest_func_1(text) SET SCHEMA regtest_schema_2;
+
+--
+-- ALTER xxx RENAME TO
+--
+ALTER DATABASE regtest_sepgsql_test_database_1 RENAME TO regtest_sepgsql_test_database;
+ALTER SCHEMA regtest_schema_1 RENAME TO regtest_schema;
+ALTER TABLE regtest_table_1 RENAME TO regtest_table;
+ALTER SEQUENCE regtest_seq_1 RENAME TO regtest_seq;
+ALTER VIEW regtest_view_1 RENAME TO regtest_view;
+ALTER FUNCTION regtest_func_1(text) RENAME TO regtest_func;
+
+SET search_path = regtest_schema, regtest_schema_2, public;
+
+--
+-- misc ALTER commands
+--
+ALTER DATABASE regtest_sepgsql_test_database CONNECTION LIMIT 999;
+ALTER DATABASE regtest_sepgsql_test_database SET search_path TO regtest_schema, public; -- not supported yet
+
+ALTER TABLE regtest_table ADD COLUMN d float;
+ALTER TABLE regtest_table DROP COLUMN d;
+ALTER TABLE regtest_table ALTER b SET DEFAULT 'abcd';   -- not supported yet
+ALTER TABLE regtest_table ALTER b SET DEFAULT 'XYZ';    -- not supported yet
+ALTER TABLE regtest_table ALTER b DROP DEFAULT;         -- not supported yet
+ALTER TABLE regtest_table ALTER b SET NOT NULL;
+ALTER TABLE regtest_table ALTER b DROP NOT NULL;
+ALTER TABLE regtest_table ALTER b SET STATISTICS -1;
+ALTER TABLE regtest_table ALTER b SET (n_distinct = 999);
+ALTER TABLE regtest_table ALTER b SET STORAGE PLAIN;
+ALTER TABLE regtest_table ADD CONSTRAINT test_fk FOREIGN KEY (a) REFERENCES regtest_table_3(x); -- not supported
+ALTER TABLE regtest_table ADD CONSTRAINT test_ck CHECK (b like '%abc%') NOT VALID;      -- not supported
+ALTER TABLE regtest_table VALIDATE CONSTRAINT test_ck;  -- not supported
+ALTER TABLE regtest_table DROP CONSTRAINT test_ck;      -- not supported
+
+CREATE TRIGGER regtest_test_trig BEFORE UPDATE ON regtest_table
+    FOR EACH ROW EXECUTE PROCEDURE suppress_redundant_updates_trigger();
+
+ALTER TABLE regtest_table DISABLE TRIGGER regtest_test_trig;    -- not supported
+ALTER TABLE regtest_table ENABLE  TRIGGER regtest_test_trig;    -- not supported
+
+CREATE RULE regtest_test_rule AS ON INSERT TO regtest_table_3 DO ALSO NOTHING;
+ALTER TABLE regtest_table_3 DISABLE RULE regtest_test_rule;     -- not supported
+ALTER TABLE regtest_table_3 ENABLE RULE regtest_test_rule;      -- not supported
+
+ALTER TABLE regtest_table SET WITH OIDS;
+ALTER TABLE regtest_table SET WITHOUT OIDS;
+ALTER TABLE regtest_table SET (fillfactor = 75);
+ALTER TABLE regtest_table RESET (fillfactor);
+ALTER TABLE regtest_table_2 NO INHERIT regtest_table;   -- not supported
+ALTER TABLE regtest_table_2 INHERIT regtest_table;      -- not supported
+-- TODO: where we should put object_access_hook for AT_SetTableSpace
+ALTER TABLE regtest_table SET TABLESPACE pg_default;
+
+ALTER VIEW regtest_view SET (security_barrier);
+
+ALTER SEQUENCE regtest_seq INCREMENT BY 10 START WITH 1000;
+
+--
+-- clean-up objects
+--
+RESET sepgsql.debug_audit;
+RESET client_min_messages;
+DROP DATABASE regtest_sepgsql_test_database;
+DROP SCHEMA regtest_schema CASCADE;
+DROP SCHEMA regtest_schema_2 CASCADE;
+DROP USER regtest_sepgsql_test_user;
diff --git a/contrib/sepgsql/sql/ddl.sql b/contrib/sepgsql/sql/ddl.sql
index 5afe1ba..c91c4cf 100644
--- a/contrib/sepgsql/sql/ddl.sql
+++ b/contrib/sepgsql/sql/ddl.sql
@@ -2,6 +2,12 @@
 -- Regression Test for DDL of Object Permission Checks
 --
 
+-- clean-up in case a prior regression run failed
+SET client_min_messages TO 'warning';
+DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
+DROP USER IF EXISTS regtest_sepgsql_test_user;
+RESET client_min_messages;
+
 -- confirm required permissions using audit messages
 -- @SECURITY-CONTEXT=unconfined_u:unconfined_r:unconfined_t:s0
 SET sepgsql.debug_audit = true;
diff --git a/contrib/sepgsql/test_sepgsql b/contrib/sepgsql/test_sepgsql
index 473004f..eac14ff 100755
--- a/contrib/sepgsql/test_sepgsql
+++ b/contrib/sepgsql/test_sepgsql
@@ -259,6 +259,6 @@ echo "found ${NUM}"
 echo
 echo "============== running sepgsql regression tests       =============="
 
-make REGRESS="label dml ddl misc" REGRESS_OPTS="--launcher ./launcher" installcheck
+make REGRESS="label dml ddl alter misc" REGRESS_OPTS="--launcher ./launcher" installcheck
 
 # exit with the exit code provided by "make"
diff --git a/doc/src/sgml/sepgsql.sgml b/doc/src/sgml/sepgsql.sgml
index 522aa8b..a9141ff 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -438,21 +438,36 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
     On creation of objects within a particular schema (tables, views,
     sequences and procedures), <literal>add_name</> will be also checked
     on the schema, not only <literal>create</> on the new object itself.
+    On <xref linkend="sql-createfunction">, <literal>install</> permission
+    will be checked if <literal>leakproof</> attribute was given, not only
+    <literal>create</> on the new function.
    </para>
 
    <para>
     When <literal>DROP</> command is executed, <literal>drop</> will be
     checked on the object being removed for each object types.  Permissions
-    will not be checked for objects dropped indirectly via <literal>CASCADE</>.
+    will also be checked for objects dropped indirectly via <literal>CASCADE</>.
     Deletion of objects contained within a particular schema (tables, views,
     sequences and procedures) additionally requires
     <literal>remove_name</> on the schema.
    </para>
 
    <para>
+    When <literal>ALTER</> command is executed, <literal>setattr</> will be
+    checked on the object being modified for each object types. 
+    In addition, <literal>add_name</> and <literal>remove_name</> permission
+    will be checked towards relevant schema when we try to rename or set
+    new schema on the altered object.
+    A few additional checks are applied depending on object types.
+    On <xref linkend="sql-alterfunction">, <literal>install</> permission
+    will be checked if <literal>leakproof</> attribute was turned on, not
+    only <literal>setattr</> on the new function.
+   </para>
+
+   <para>
     When objects that are subsidiary of other objects (such as a table's indexes
-    or triggers) are created or dropped, <literal>setattr</> permission will be
-    checked on the main object, instead of the subsidiary object itself.
+    or triggers) are created, dropped or altered, <literal>setattr</> permission
+    will be checked on the main object, instead of the subsidiary object itself.
    </para>
 
    <para>
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 4e4c7af..b011027 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -25,6 +25,7 @@
 #include "catalog/catalog.h"
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_conversion.h"
@@ -1288,6 +1289,10 @@ SetDefaultACL(InternalDefaultACL *iacls)
 							  iacls->roleid,
 							  noldmembers, oldmembers,
 							  nnewmembers, newmembers);
+
+		/* Post alter hook of this default ACL */
+		InvokeObjectAccessHook(OAT_POST_ALTER, DefaultAclRelationId,
+							   HeapTupleGetOid(newtuple), 0, NULL);
 	}
 
 	if (HeapTupleIsValid(tuple))
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 8818b68..b37d865 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -94,8 +94,9 @@ static Oid AddNewRelationType(const char *typeName,
 static void RelationRemoveInheritance(Oid relid);
 static void StoreRelCheck(Relation rel, char *ccname, Node *expr,
 			  bool is_validated, bool is_local, int inhcount,
-			  bool is_no_inherit);
-static void StoreConstraints(Relation rel, List *cooked_constraints);
+			  bool is_no_inherit, bool is_internal);
+static void StoreConstraints(Relation rel, List *cooked_constraints,
+							 bool is_internal);
 static bool MergeWithExistingConstraint(Relation rel, char *ccname, Node *expr,
 							bool allow_merge, bool is_local,
 							bool is_no_inherit);
@@ -1293,7 +1294,7 @@ heap_create_with_catalog(const char *relname,
 	 * entry, so the relation must be valid and self-consistent at this point.
 	 * In particular, there are not yet constraints and defaults anywhere.
 	 */
-	StoreConstraints(new_rel_desc, cooked_constraints);
+	StoreConstraints(new_rel_desc, cooked_constraints, is_internal);
 
 	/*
 	 * If there's a special on-commit action, remember it
@@ -1806,7 +1807,8 @@ heap_drop_with_catalog(Oid relid)
  * Store a default expression for column attnum of relation rel.
  */
 void
-StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr)
+StoreAttrDefault(Relation rel, AttrNumber attnum,
+				 Node *expr, bool is_internal)
 {
 	char	   *adbin;
 	char	   *adsrc;
@@ -1898,6 +1900,24 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr)
 	 * Record dependencies on objects used in the expression, too.
 	 */
 	recordDependencyOnExpr(&defobject, expr, NIL, DEPENDENCY_NORMAL);
+
+	/*
+	 * Post creation hook of this attribute defaults
+	 *
+	 * XXX - Note that ALTER TABLE ALTER COLUMN SET/DROP DEFAULT is
+	 * implemented with a couple of deletion/creation of the attribute's
+	 * default entry, so the callee should check existence of an older
+	 * version of this entry if needed to distinguish.
+	 */
+	if (object_access_hook)
+	{
+		ObjectAccessPostCreate	pc_arg;
+
+		memset(&pc_arg, 0, sizeof(ObjectAccessPostCreate));
+		pc_arg.is_internal = is_internal;
+		(*object_access_hook)(OAT_POST_CREATE, AttrDefaultRelationId,
+							  RelationGetRelid(rel), attnum, (void *)&pc_arg);
+	}
 }
 
 /*
@@ -1909,7 +1929,7 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr)
 static void
 StoreRelCheck(Relation rel, char *ccname, Node *expr,
 			  bool is_validated, bool is_local, int inhcount,
-			  bool is_no_inherit)
+			  bool is_no_inherit, bool is_internal)
 {
 	char	   *ccbin;
 	char	   *ccsrc;
@@ -1993,7 +2013,8 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr,
 						  ccsrc,	/* Source form of check constraint */
 						  is_local,		/* conislocal */
 						  inhcount,		/* coninhcount */
-						  is_no_inherit);		/* connoinherit */
+						  is_no_inherit,		/* connoinherit */
+						  is_internal);	/* internally constructed? */
 
 	pfree(ccbin);
 	pfree(ccsrc);
@@ -2008,7 +2029,7 @@ StoreRelCheck(Relation rel, char *ccname, Node *expr,
  * and StoreRelCheck (see AddRelationNewConstraints()).
  */
 static void
-StoreConstraints(Relation rel, List *cooked_constraints)
+StoreConstraints(Relation rel, List *cooked_constraints, bool is_internal)
 {
 	int			numchecks = 0;
 	ListCell   *lc;
@@ -2030,11 +2051,12 @@ StoreConstraints(Relation rel, List *cooked_constraints)
 		switch (con->contype)
 		{
 			case CONSTR_DEFAULT:
-				StoreAttrDefault(rel, con->attnum, con->expr);
+				StoreAttrDefault(rel, con->attnum, con->expr, is_internal);
 				break;
 			case CONSTR_CHECK:
 				StoreRelCheck(rel, con->name, con->expr, !con->skip_validation,
-						   con->is_local, con->inhcount, con->is_no_inherit);
+							  con->is_local, con->inhcount,
+							  con->is_no_inherit, is_internal);
 				numchecks++;
 				break;
 			default:
@@ -2060,6 +2082,7 @@ StoreConstraints(Relation rel, List *cooked_constraints)
  * newConstraints: list of Constraint nodes
  * allow_merge: TRUE if check constraints may be merged with existing ones
  * is_local: TRUE if definition is local, FALSE if it's inherited
+ * is_internal: TRUE if constraint is constructed unless user's intention
  *
  * All entries in newColDefaults will be processed.  Entries in newConstraints
  * will be processed only if they are CONSTR_CHECK type.
@@ -2077,7 +2100,8 @@ AddRelationNewConstraints(Relation rel,
 						  List *newColDefaults,
 						  List *newConstraints,
 						  bool allow_merge,
-						  bool is_local)
+						  bool is_local,
+						  bool is_internal)
 {
 	List	   *cookedConstraints = NIL;
 	TupleDesc	tupleDesc;
@@ -2140,7 +2164,7 @@ AddRelationNewConstraints(Relation rel,
 			(IsA(expr, Const) &&((Const *) expr)->constisnull))
 			continue;
 
-		StoreAttrDefault(rel, colDef->attnum, expr);
+		StoreAttrDefault(rel, colDef->attnum, expr, is_internal);
 
 		cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));
 		cooked->contype = CONSTR_DEFAULT;
@@ -2266,7 +2290,7 @@ AddRelationNewConstraints(Relation rel,
 		 * OK, store it.
 		 */
 		StoreRelCheck(rel, ccname, expr, !cdef->skip_validation, is_local,
-					  is_local ? 0 : 1, cdef->is_no_inherit);
+					  is_local ? 0 : 1, cdef->is_no_inherit, is_internal);
 
 		numchecks++;
 
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index d2d91c1..0622c52 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -926,7 +926,8 @@ index_create(Relation heapRelation,
 									false,		/* already marked primary */
 									false,		/* pg_index entry is OK */
 									false,		/* no old dependencies */
-									allow_system_table_mods);
+									allow_system_table_mods,
+									is_internal);
 		}
 		else
 		{
@@ -1107,6 +1108,7 @@ index_create(Relation heapRelation,
  * remove_old_dependencies: if true, remove existing dependencies of index
  *		on table's columns
  * allow_system_table_mods: allow table to be a system catalog
+ * is_internal: index is constructed due to internal process
  */
 void
 index_constraint_create(Relation heapRelation,
@@ -1119,7 +1121,8 @@ index_constraint_create(Relation heapRelation,
 						bool mark_as_primary,
 						bool update_pgindex,
 						bool remove_old_dependencies,
-						bool allow_system_table_mods)
+						bool allow_system_table_mods,
+						bool is_internal)
 {
 	Oid			namespaceId = RelationGetNamespace(heapRelation);
 	ObjectAddress myself,
@@ -1184,7 +1187,8 @@ index_constraint_create(Relation heapRelation,
 								   NULL,
 								   true,		/* islocal */
 								   0,	/* inhcount */
-								   true);		/* noinherit */
+								   true,		/* noinherit */
+								   is_internal);
 
 	/*
 	 * Register the index as internally dependent on the constraint.
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 5e8c6da..be7c08d 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -68,7 +68,8 @@ CreateConstraintEntry(const char *constraintName,
 					  const char *conSrc,
 					  bool conIsLocal,
 					  int conInhCount,
-					  bool conNoInherit)
+					  bool conNoInherit,
+					  bool is_internal)
 {
 	Relation	conDesc;
 	Oid			conOid;
@@ -367,9 +368,15 @@ CreateConstraintEntry(const char *constraintName,
 	}
 
 	/* Post creation hook for new constraint */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ConstraintRelationId, conOid, 0, NULL);
+	if (object_access_hook)
+	{
+		ObjectAccessPostCreate	pc_arg;
 
+		memset(&pc_arg, 0, sizeof(ObjectAccessPostCreate));
+		pc_arg.is_internal = is_internal;
+		(*object_access_hook)(OAT_POST_CREATE, ConstraintRelationId,
+							  conOid, 0, (void *) &pc_arg);
+	}
 	return conOid;
 }
 
@@ -666,6 +673,10 @@ RenameConstraintById(Oid conId, const char *newname)
 	/* update the system catalog indexes */
 	CatalogUpdateIndexes(conDesc, tuple);
 
+	/* Post alter hook for this constraint */
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   ConstraintRelationId, conId, 0, NULL);
+
 	heap_freetuple(tuple);
 	heap_close(conDesc, RowExclusiveLock);
 }
@@ -736,6 +747,10 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 			 * dependency on the namespace, so we don't need to do
 			 * changeDependencyFor().
 			 */
+
+			/* Post alter hook for the constraint */
+			InvokeObjectAccessHook(OAT_POST_ALTER, ConstraintRelationId,
+								   thisobj.objectId, 0, NULL);
 		}
 
 		add_exact_object_address(&thisobj, objsMoved);
diff --git a/src/backend/catalog/pg_db_role_setting.c b/src/backend/catalog/pg_db_role_setting.c
index 616980c..f07a953 100644
--- a/src/backend/catalog/pg_db_role_setting.c
+++ b/src/backend/catalog/pg_db_role_setting.c
@@ -14,6 +14,7 @@
 #include "access/heapam.h"
 #include "access/htup_details.h"
 #include "catalog/indexing.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_db_role_setting.h"
 #include "utils/fmgroids.h"
 #include "utils/rel.h"
@@ -159,7 +160,16 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
 		/* Update indexes */
 		CatalogUpdateIndexes(rel, newtuple);
 	}
+	/* Post alter hook for this database-role-settings */
+	if (object_access_hook)
+	{
+		ObjectAccessPostAlter	pa_arg;
 
+		memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
+		pa_arg.auxiliary_id = roleid;
+		(*object_access_hook)(OAT_POST_ALTER, DbRoleSettingRelationId,
+							  databaseid, 0, (void *) &pa_arg);
+	}
 	systable_endscan(scan);
 
 	/* Close pg_db_role_setting, but keep lock till commit */
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 49133ee..c9db427 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -714,6 +714,9 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
 	/* update the system catalog indexes */
 	CatalogUpdateIndexes(pg_type_desc, tuple);
 
+	/* Post alter hook for this type */
+	InvokeObjectAccessHook(OAT_POST_ALTER, TypeRelationId, typeOid, 0, NULL);
+
 	heap_freetuple(tuple);
 	heap_close(pg_type_desc, RowExclusiveLock);
 
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 39fa510..2bf54c2 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -19,6 +19,7 @@
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_largeobject.h"
 #include "catalog/pg_largeobject_metadata.h"
 #include "catalog/pg_namespace.h"
@@ -295,6 +296,10 @@ AlterObjectRename(ObjectType objtype, List *objname, List *objargs,
 	pfree(values);
 	pfree(nulls);
 	pfree(replaces);
+
+	/* Post alter hook for the object */
+	InvokeObjectAccessHook(OAT_POST_ALTER, address.classId,
+						   address.objectId, address.objectSubId, NULL);
 }
 
 /*
@@ -654,6 +659,9 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
 	changeDependencyFor(classId, objid,
 						NamespaceRelationId, oldNspOid, nspOid);
 
+	/* Post alter hook for the object */
+	InvokeObjectAccessHook(OAT_POST_ALTER, classId, objid, 0, NULL);
+
 	return oldNspOid;
 }
 
@@ -930,5 +938,8 @@ AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
 		pfree(values);
 		pfree(nulls);
 		pfree(replaces);
+
+		/* Post alter hook for the object */
+		InvokeObjectAccessHook(OAT_POST_ALTER, classId, objectId, 0, NULL);
 	}
 }
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index de71a35..aed571d 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -1487,13 +1487,13 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 			snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u",
 					 OIDOldHeap);
 			RenameRelationInternal(newrel->rd_rel->reltoastrelid,
-								   NewToastName);
+								   NewToastName, true);
 
 			/* ... and its index too */
 			snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index",
 					 OIDOldHeap);
 			RenameRelationInternal(toastidx,
-								   NewToastName);
+								   NewToastName, true);
 		}
 		relation_close(newrel, NoLock);
 	}
diff --git a/src/backend/commands/collationcmds.c b/src/backend/commands/collationcmds.c
index ec22d11..3c7e166 100644
--- a/src/backend/commands/collationcmds.c
+++ b/src/backend/commands/collationcmds.c
@@ -20,6 +20,7 @@
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_collation_fn.h"
 #include "commands/alter.h"
@@ -203,6 +204,9 @@ RenameCollation(List *name, const char *newname)
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
 
+	/* Post alter hook of this collation */
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   CollationRelationId, collationOid, 0, NULL);
 	heap_freetuple(tup);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index cdbce97..1747654 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -973,6 +973,10 @@ RenameDatabase(const char *oldname, const char *newname)
 	simple_heap_update(rel, &newtup->t_self, newtup);
 	CatalogUpdateIndexes(rel, newtup);
 
+	/* Post alter hook for this database */
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   DatabaseRelationId, db_id, 0, NULL);
+
 	/*
 	 * Close pg_database, but keep lock till commit.
 	 */
@@ -1208,6 +1212,10 @@ movedb(const char *dbname, const char *tblspcname)
 		/* Update indexes */
 		CatalogUpdateIndexes(pgdbrel, newtuple);
 
+		/* Post alter hook for this database */
+		InvokeObjectAccessHook(OAT_POST_ALTER, DatabaseRelationId,
+							   HeapTupleGetOid(newtuple), 0, NULL);
+
 		systable_endscan(sysscan);
 
 		/*
@@ -1402,6 +1410,10 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
 	/* Update indexes */
 	CatalogUpdateIndexes(rel, newtuple);
 
+	/* Post alter hook for this database */
+	InvokeObjectAccessHook(OAT_POST_ALTER, DatabaseRelationId,
+						   HeapTupleGetOid(newtuple), 0, NULL);
+
 	systable_endscan(scan);
 
 	/* Close pg_database, but keep lock till commit */
@@ -1533,6 +1545,10 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
 		/* Update owner dependency reference */
 		changeDependencyOnOwner(DatabaseRelationId, HeapTupleGetOid(tuple),
 								newOwnerId);
+
+		/* Post alter hook for the database */
+		InvokeObjectAccessHook(OAT_POST_ALTER, DatabaseRelationId,
+							   HeapTupleGetOid(tuple), 0, NULL);
 	}
 
 	systable_endscan(scan);
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 2e24e0d..fa49118 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -492,6 +492,9 @@ AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 	changeDependencyOnOwner(EventTriggerRelationId,
 							HeapTupleGetOid(tup),
 							newOwnerId);
+	/* Post alter hook for the event trigger */
+	InvokeObjectAccessHook(OAT_POST_ALTER, EventTriggerRelationId,
+						   HeapTupleGetOid(tup), 0, NULL);
 }
 
 /*
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 47631be..ffb23ab 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2361,6 +2361,10 @@ AlterExtensionNamespace(List *names, const char *newschema)
 	/* update dependencies to point to the new schema */
 	changeDependencyFor(ExtensionRelationId, extensionOid,
 						NamespaceRelationId, oldNspOid, nspOid);
+
+	/* Post alter hook for the extension */
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   ExtensionRelationId, extensionOid, 0, NULL);
 }
 
 /*
@@ -2641,6 +2645,10 @@ ApplyExtensionUpdates(Oid extensionOid,
 			recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
 		}
 
+		/* Post alter hook for this extension */
+		InvokeObjectAccessHook(OAT_POST_ALTER, ExtensionRelationId,
+							   extensionOid, 0, NULL);
+
 		/*
 		 * Finally, execute the update script file
 		 */
@@ -2746,6 +2754,9 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 											DEPENDENCY_EXTENSION) != 1)
 			elog(ERROR, "unexpected number of extension dependency records");
 	}
+	/* Post alter hook of this extension */
+	InvokeObjectAccessHook(OAT_POST_ALTER, ExtensionRelationId,
+						   extension.objectId, 0, NULL);
 
 	/*
 	 * If get_object_address() opened the relation for us, we close it to keep
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 2d73d2d..905c6b0 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -240,6 +240,11 @@ AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerI
 		changeDependencyOnOwner(ForeignDataWrapperRelationId,
 								HeapTupleGetOid(tup),
 								newOwnerId);
+
+		/* Post alter hook for the FDW */
+		InvokeObjectAccessHook(OAT_POST_ALTER,
+							   ForeignDataWrapperRelationId,
+							   HeapTupleGetOid(tup), 0, NULL);
 	}
 }
 
@@ -343,6 +348,11 @@ AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 		/* Update owner dependency reference */
 		changeDependencyOnOwner(ForeignServerRelationId, HeapTupleGetOid(tup),
 								newOwnerId);
+
+		/* Post alter hook for the foreign server */
+        InvokeObjectAccessHook(OAT_POST_ALTER,
+							   ForeignServerRelationId,
+							   HeapTupleGetOid(tup), 0, NULL);
 	}
 }
 
@@ -752,6 +762,9 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
 	}
+	/* Post alter hook of this FDW */
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   ForeignDataWrapperRelationId, fdwId, 0, NULL);
 
 	heap_close(rel, RowExclusiveLock);
 }
@@ -980,6 +993,9 @@ AlterForeignServer(AlterForeignServerStmt *stmt)
 	simple_heap_update(rel, &tp->t_self, tp);
 	CatalogUpdateIndexes(rel, tp);
 
+	/* Post alter hook of this foreign server */
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   ForeignServerRelationId, srvId, 0, NULL);
 	heap_freetuple(tp);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index d5b86db..1ede99f 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1168,7 +1168,8 @@ AlterFunction(AlterFunctionStmt *stmt)
 	/* Do the update */
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
-
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   ProcedureRelationId, funcOid, 0, NULL);
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 }
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 7aae0d1..281203a 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -1372,6 +1372,10 @@ storeOperators(List *opfamilyname, Oid amoid,
 			referenced.objectSubId = 0;
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
+		/* Post create hook of this access method operator */
+		InvokeObjectAccessHook(OAT_POST_CREATE,
+							   AccessMethodOperatorRelationId,
+							   entryoid, 0, NULL);
 	}
 
 	heap_close(rel, RowExclusiveLock);
@@ -1471,6 +1475,10 @@ storeProcedures(List *opfamilyname, Oid amoid,
 			referenced.objectSubId = 0;
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 		}
+		/* Post create hook of access method procedure */
+		InvokeObjectAccessHook(OAT_POST_CREATE,
+							   AccessMethodProcedureRelationId,
+							   entryoid, 0, NULL);
 	}
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index e69c86b..dc162fe 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -21,6 +21,7 @@
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_namespace.h"
 #include "commands/dbcommands.h"
 #include "commands/schemacmds.h"
@@ -235,6 +236,9 @@ RenameSchema(const char *oldname, const char *newname)
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
 
+	InvokeObjectAccessHook(OAT_POST_ALTER, NamespaceRelationId,
+						   HeapTupleGetOid(tup), 0, NULL);
+
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 }
@@ -362,6 +366,10 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
 		/* Update owner dependency reference */
 		changeDependencyOnOwner(NamespaceRelationId, HeapTupleGetOid(tup),
 								newOwnerId);
+
+		/* Post alter hook for the namespace */
+		InvokeObjectAccessHook(OAT_POST_ALTER, NamespaceRelationId,
+							   HeapTupleGetOid(tup), 0, NULL);
 	}
 
 }
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 4f55830..39a894c 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -19,6 +19,7 @@
 #include "access/xlogutils.h"
 #include "catalog/dependency.h"
 #include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_type.h"
 #include "commands/defrem.h"
 #include "commands/sequence.h"
@@ -482,6 +483,10 @@ AlterSequence(AlterSeqStmt *stmt)
 	if (owned_by)
 		process_owned_by(seqrel, owned_by);
 
+	/* Post alter hook of this sequence */
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   RelationRelationId, relid, 0, NULL);
+
 	relation_close(seqrel, NoLock);
 }
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index f88bf79..810b1e6 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -663,7 +663,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId)
 	 */
 	if (rawDefaults || stmt->constraints)
 		AddRelationNewConstraints(rel, rawDefaults, stmt->constraints,
-								  true, true);
+								  true, true, false);
 
 	/*
 	 * Clean up.  We keep lock on new relation (although it shouldn't be
@@ -1965,6 +1965,17 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
 
 	recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL);
 
+	/* Post creation hook of this inheritance */
+	if (object_access_hook)
+	{
+		ObjectAccessPostAlter	pa_arg;
+
+		memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
+		pa_arg.auxiliary_id = parentOid;
+		(*object_access_hook)(OAT_POST_ALTER, InheritsRelationId,
+							  relationId, 0, (void *) &pa_arg);
+	}
+
 	/*
 	 * Mark the parent as having subclasses.
 	 */
@@ -2223,6 +2234,10 @@ renameatt_internal(Oid myrelid,
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, atttup);
 
+	/* Post alter hook for this attribute */
+	InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+						   myrelid, attnum, NULL);
+
 	heap_freetuple(atttup);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -2367,7 +2382,7 @@ rename_constraint_internal(Oid myrelid,
 			|| con->contype == CONSTRAINT_UNIQUE
 			|| con->contype == CONSTRAINT_EXCLUSION))
 		/* rename the index; this renames the constraint as well */
-		RenameRelationInternal(con->conindid, newconname);
+		RenameRelationInternal(con->conindid, newconname, false);
 	else
 		RenameConstraintById(constraintOid, newconname);
 
@@ -2443,7 +2458,7 @@ RenameRelation(RenameStmt *stmt)
 	}
 
 	/* Do the work */
-	RenameRelationInternal(relid, stmt->newname);
+	RenameRelationInternal(relid, stmt->newname, false);
 }
 
 /*
@@ -2456,7 +2471,7 @@ RenameRelation(RenameStmt *stmt)
  *			  sequence, AFAIK there's no need for it to be there.
  */
 void
-RenameRelationInternal(Oid myrelid, const char *newrelname)
+RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal)
 {
 	Relation	targetrelation;
 	Relation	relrelation;	/* for RELATION relation */
@@ -2498,6 +2513,17 @@ RenameRelationInternal(Oid myrelid, const char *newrelname)
 	/* keep the system catalog indexes current */
 	CatalogUpdateIndexes(relrelation, reltup);
 
+	/* Post alter hook for this relation */
+	if (object_access_hook)
+	{
+		ObjectAccessPostAlter	pa_arg;
+
+		memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
+		pa_arg.is_internal = is_internal;
+		(*object_access_hook)(OAT_POST_ALTER, RelationRelationId,
+							  myrelid, 0, (void *) &pa_arg);
+	}
+
 	heap_freetuple(reltup);
 	heap_close(relrelation, RowExclusiveLock);
 
@@ -4500,7 +4526,8 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
 		 * This function is intended for CREATE TABLE, so it processes a
 		 * _list_ of defaults, but we just do one.
 		 */
-		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true);
+		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
+								  false, true, false);
 
 		/* Make the additional catalog changes visible */
 		CommandCounterIncrement();
@@ -4834,6 +4861,9 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
 
 		/* keep the system catalog indexes current */
 		CatalogUpdateIndexes(attr_rel, tuple);
+
+		InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+							   RelationGetRelid(rel), attnum, NULL);
 	}
 
 	heap_close(attr_rel, RowExclusiveLock);
@@ -4884,6 +4914,9 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
 		/* keep the system catalog indexes current */
 		CatalogUpdateIndexes(attr_rel, tuple);
 
+		InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+							   RelationGetRelid(rel), attnum, NULL);
+
 		/* Tell Phase 3 it needs to test the constraint */
 		tab->new_notnull = true;
 	}
@@ -4942,7 +4975,8 @@ ATExecColumnDefault(Relation rel, const char *colName,
 		 * This function is intended for CREATE TABLE, so it processes a
 		 * _list_ of defaults, but we just do one.
 		 */
-		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL, false, true);
+		AddRelationNewConstraints(rel, list_make1(rawEnt), NIL,
+								  false, false, false);
 	}
 }
 
@@ -5026,6 +5060,8 @@ ATExecSetStatistics(Relation rel, const char *colName, Node *newValue, LOCKMODE
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, tuple);
 
+	InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+						   RelationGetRelid(rel), attrtuple->attnum, NULL);
 	heap_freetuple(tuple);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -5083,13 +5119,16 @@ ATExecSetOptions(Relation rel, const char *colName, Node *options,
 	repl_repl[Anum_pg_attribute_attoptions - 1] = true;
 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrelation),
 								 repl_val, repl_null, repl_repl);
-	ReleaseSysCache(tuple);
 
 	/* Update system catalog. */
 	simple_heap_update(attrelation, &newtuple->t_self, newtuple);
 	CatalogUpdateIndexes(attrelation, newtuple);
+	InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+						   RelationGetRelid(rel), attrtuple->attnum, NULL);
 	heap_freetuple(newtuple);
 
+	ReleaseSysCache(tuple);
+
 	heap_close(attrelation, RowExclusiveLock);
 }
 
@@ -5159,6 +5198,8 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, tuple);
 
+	InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+						   RelationGetRelid(rel), attrtuple->attnum, NULL);
 	heap_freetuple(tuple);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -5473,7 +5514,7 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
 		ereport(NOTICE,
 				(errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"",
 						indexName, constraintName)));
-		RenameRelationInternal(index_oid, constraintName);
+		RenameRelationInternal(index_oid, constraintName, false);
 	}
 
 	/* Extra checks needed if making primary key */
@@ -5497,7 +5538,13 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
 							stmt->primary,
 							true, /* update pg_index */
 							true, /* remove old dependencies */
-							allowSystemTableMods);
+							allowSystemTableMods,
+							false);	/* is_internal */
+
+	/* Post creation hook of this index */
+	InvokeObjectAccessHook(OAT_POST_CREATE,
+						   RelationRelationId,
+						   index_oid, 0, NULL);
 
 	index_close(indexRel, NoLock);
 }
@@ -5609,7 +5656,8 @@ ATAddCheckConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	newcons = AddRelationNewConstraints(rel, NIL,
 										list_make1(copyObject(constr)),
 										recursing,		/* allow_merge */
-										!recursing);	/* is_local */
+										!recursing,		/* is_local */
+										is_readd);		/* is_internal */
 
 	/* Add each to-be-validated constraint to Phase 3's queue */
 	foreach(lcon, newcons)
@@ -6059,7 +6107,8 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
 									  NULL,
 									  true,		/* islocal */
 									  0,		/* inhcount */
-									  true);	/* isnoinherit */
+									  true,		/* isnoinherit */
+									  false);	/* is_internal */
 
 	/*
 	 * Create the triggers that will enforce the constraint.
@@ -6241,6 +6290,8 @@ ATExecValidateConstraint(Relation rel, char *constrName, bool recurse,
 		copy_con->convalidated = true;
 		simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
 		CatalogUpdateIndexes(conrel, copyTuple);
+		InvokeObjectAccessHook(OAT_POST_ALTER, ConstraintRelationId,
+							   HeapTupleGetOid(tuple), 0, NULL);
 		heap_freetuple(copyTuple);
 	}
 
@@ -7666,6 +7717,10 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 	 */
 	RemoveStatistics(RelationGetRelid(rel), attnum);
 
+	/* Post alter hook of this column */
+	InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+						   RelationGetRelid(rel), attnum, NULL);
+
 	/*
 	 * Update the default, if present, by brute force --- remove and re-add
 	 * the default.  Probably unsafe to take shortcuts, since the new version
@@ -7685,7 +7740,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 		RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
 						  true);
 
-		StoreAttrDefault(rel, attnum, defaultexpr);
+		StoreAttrDefault(rel, attnum, defaultexpr, true);
 	}
 
 	/* Cleanup */
@@ -7776,10 +7831,12 @@ ATExecAlterColumnGenericOptions(Relation rel,
 
 	newtuple = heap_modify_tuple(tuple, RelationGetDescr(attrel),
 								 repl_val, repl_null, repl_repl);
-	ReleaseSysCache(tuple);
 
 	simple_heap_update(attrel, &newtuple->t_self, newtuple);
 	CatalogUpdateIndexes(attrel, newtuple);
+	InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+						   RelationGetRelid(rel), atttableform->attnum, NULL);
+	ReleaseSysCache(tuple);
 
 	heap_close(attrel, RowExclusiveLock);
 
@@ -8190,7 +8247,9 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 
 		simple_heap_update(class_rel, &newtuple->t_self, newtuple);
 		CatalogUpdateIndexes(class_rel, newtuple);
-
+		InvokeObjectAccessHook(OAT_POST_ALTER,
+							   RelationRelationId,
+							   relationOid, 0, NULL);
 		heap_freetuple(newtuple);
 
 		/*
@@ -8414,6 +8473,10 @@ ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
 
 	/* And do the work */
 	mark_index_clustered(rel, indexOid);
+
+	/* Post alter hook of this relation */
+	InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+						   RelationGetRelid(rel), 0, NULL);
 }
 
 /*
@@ -8426,6 +8489,10 @@ static void
 ATExecDropCluster(Relation rel, LOCKMODE lockmode)
 {
 	mark_index_clustered(rel, InvalidOid);
+
+	/* Post alter hook of this relation */
+	InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+						   RelationGetRelid(rel), 0, NULL);
 }
 
 /*
@@ -8545,6 +8612,9 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 
 	CatalogUpdateIndexes(pgclass, newtuple);
 
+	InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+						   RelationGetRelid(rel), 0, NULL);
+
 	heap_freetuple(newtuple);
 
 	ReleaseSysCache(tuple);
@@ -8602,6 +8672,9 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 
 		CatalogUpdateIndexes(pgclass, newtuple);
 
+		InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+							   RelationGetRelid(toastrel), 0, NULL);
+
 		heap_freetuple(newtuple);
 
 		ReleaseSysCache(tuple);
@@ -9260,6 +9333,7 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
 				attributeTuple,
 				constraintTuple;
 	List	   *connames;
+	Oid			inhparent = InvalidOid;
 	bool		found = false;
 
 	/*
@@ -9288,8 +9362,6 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
 
 	while (HeapTupleIsValid(inheritsTuple = systable_getnext(scan)))
 	{
-		Oid			inhparent;
-
 		inhparent = ((Form_pg_inherits) GETSTRUCT(inheritsTuple))->inhparent;
 		if (inhparent == RelationGetRelid(parent_rel))
 		{
@@ -9428,6 +9500,17 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
 						   RelationRelationId,
 						   RelationGetRelid(parent_rel));
 
+	/* Post alter hook of this inherits */
+	if (object_access_hook)
+	{
+		ObjectAccessPostAlter	pa_arg;
+
+		memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
+		pa_arg.auxiliary_id = RelationGetRelid(parent_rel);
+		(*object_access_hook)(OAT_POST_ALTER, InheritsRelationId,
+							  RelationGetRelid(rel), 0, (void *) &pa_arg);
+	}
+
 	/* keep our lock on the parent relation until commit */
 	heap_close(parent_rel, NoLock);
 }
@@ -9610,6 +9693,8 @@ ATExecAddOf(Relation rel, const TypeName *ofTypename, LOCKMODE lockmode)
 	((Form_pg_class) GETSTRUCT(classtuple))->reloftype = typeid;
 	simple_heap_update(relationRelation, &classtuple->t_self, classtuple);
 	CatalogUpdateIndexes(relationRelation, classtuple);
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   RelationRelationId, relid, 0, NULL);
 	heap_freetuple(classtuple);
 	heap_close(relationRelation, RowExclusiveLock);
 
@@ -9650,6 +9735,8 @@ ATExecDropOf(Relation rel, LOCKMODE lockmode)
 	((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
 	simple_heap_update(relationRelation, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(relationRelation, tuple);
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   RelationRelationId, relid, 0, NULL);
 	heap_freetuple(tuple);
 	heap_close(relationRelation, RowExclusiveLock);
 }
@@ -9719,6 +9806,9 @@ ATExecGenericOptions(Relation rel, List *options)
 	simple_heap_update(ftrel, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(ftrel, tuple);
 
+	InvokeObjectAccessHook(OAT_POST_ALTER, RelationRelationId,
+						   RelationGetRelid(rel), 0, NULL);
+
 	heap_close(ftrel, RowExclusiveLock);
 
 	heap_freetuple(tuple);
@@ -9872,6 +9962,10 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
 				 NameStr(classForm->relname));
 
 		add_exact_object_address(&thisobj, objsMoved);
+
+		/* Post alter hook for this relation */
+		InvokeObjectAccessHook(OAT_POST_ALTER,
+							   RelationRelationId, relOid, 0, NULL);
 	}
 
 	heap_freetuple(classTup);
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 08899ae..65b5a44 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -880,6 +880,8 @@ RenameTableSpace(const char *oldname, const char *newname)
 	simple_heap_update(rel, &newtuple->t_self, newtuple);
 	CatalogUpdateIndexes(rel, newtuple);
 
+	InvokeObjectAccessHook(OAT_POST_ALTER, TableSpaceRelationId,
+						   HeapTupleGetOid(newtuple), 0, NULL);
 	heap_close(rel, NoLock);
 }
 
@@ -943,6 +945,8 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
 	/* Update system catalog. */
 	simple_heap_update(rel, &newtuple->t_self, newtuple);
 	CatalogUpdateIndexes(rel, newtuple);
+	InvokeObjectAccessHook(OAT_POST_CREATE, TableSpaceRelationId,
+						   HeapTupleGetOid(tup), 0, NULL);
 	heap_freetuple(newtuple);
 
 	/* Conclude heap scan. */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 98b8207..0e67894 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -445,7 +445,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 											  NULL,
 											  true,		/* islocal */
 											  0,		/* inhcount */
-											  true);	/* isnoinherit */
+											  true,		/* isnoinherit */
+											  isInternal);	/* is_internal */
 	}
 
 	/*
@@ -741,8 +742,15 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 							   DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new trigger */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TriggerRelationId, trigoid, 0, NULL);
+	if (object_access_hook)
+	{
+		ObjectAccessPostAlter	pa_arg;
+
+		memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
+		pa_arg.is_internal = isInternal;
+		(*object_access_hook)(OAT_POST_CREATE, TriggerRelationId,
+							  trigoid, 0, (void *) &pa_arg);
+	}
 
 	/* Keep lock on target rel until end of xact */
 	heap_close(rel, NoLock);
@@ -1274,6 +1282,10 @@ renametrig(RenameStmt *stmt)
 		/* keep system catalog indexes current */
 		CatalogUpdateIndexes(tgrel, tuple);
 
+		/* Post alter hook for this trigger */
+		InvokeObjectAccessHook(OAT_POST_ALTER, TriggerRelationId,
+							   HeapTupleGetOid(tuple), 0, NULL);
+
 		/*
 		 * Invalidate relation's relcache entry so that other backends (and
 		 * this one too!) are sent SI message to make them rebuild relcache
@@ -1383,6 +1395,10 @@ EnableDisableTrigger(Relation rel, const char *tgname,
 			/* Keep catalog indexes current */
 			CatalogUpdateIndexes(tgrel, newtup);
 
+			/* Post alter hook for this trigger */
+			InvokeObjectAccessHook(OAT_POST_ALTER, TriggerRelationId,
+								   HeapTupleGetOid(newtup), 0, NULL);
+
 			heap_freetuple(newtup);
 
 			changed = true;
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 9dbfa0c..a842c3a 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -610,6 +610,8 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
 
 	CatalogUpdateIndexes(rel, newtup);
 
+	InvokeObjectAccessHook(OAT_POST_CREATE,
+						   TSDictionaryRelationId, dictId, 0, NULL);
 	/*
 	 * NOTE: because we only support altering the options, not the template,
 	 * there is no need to update dependencies.  This might have to change if
@@ -1175,6 +1177,9 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
 	/* Update dependencies */
 	makeConfigurationDependencies(tup, true, relMap);
 
+	InvokeObjectAccessHook(OAT_POST_ALTER, TSConfigMapRelationId,
+						   HeapTupleGetOid(tup), 0, NULL);
+
 	heap_close(relMap, RowExclusiveLock);
 
 	ReleaseSysCache(tup);
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 8418096..421e33c 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -39,6 +39,7 @@
 #include "catalog/dependency.h"
 #include "catalog/heap.h"
 #include "catalog/indexing.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_authid.h"
 #include "catalog/pg_collation.h"
 #include "catalog/pg_constraint.h"
@@ -1191,6 +1192,10 @@ AlterEnum(AlterEnumStmt *stmt)
 				 stmt->newValNeighbor, stmt->newValIsAfter, 
 				 stmt->skipIfExists);
 
+	/* Post alter hook of this enum type */
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   TypeRelationId, enum_type_oid, 0, NULL);
+
 	ReleaseSysCache(tup);
 }
 
@@ -2164,7 +2169,9 @@ AlterDomainDefault(List *names, Node *defaultRaw)
 							 typTup->typcollation,
 							 defaultExpr,
 							 true);		/* Rebuild is true */
-
+	/* Post alter hook of this domain */
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   TypeRelationId, domainoid, 0, NULL);
 	/* Clean up */
 	heap_close(rel, NoLock);
 	heap_freetuple(newtuple);
@@ -2261,6 +2268,9 @@ AlterDomainNotNull(List *names, bool notNull)
 
 	CatalogUpdateIndexes(typrel, tup);
 
+	/* Post alter hook of this domain */
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   TypeRelationId, domainoid, 0, NULL);
 	/* Clean up */
 	heap_freetuple(tup);
 	heap_close(typrel, RowExclusiveLock);
@@ -2542,6 +2552,8 @@ AlterDomainValidateConstraint(List *names, char *constrName)
 	copy_con->convalidated = true;
 	simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
 	CatalogUpdateIndexes(conrel, copyTuple);
+	InvokeObjectAccessHook(OAT_POST_ALTER, ConstraintRelationId,
+						   HeapTupleGetOid(copyTuple), 0, NULL);
 	heap_freetuple(copyTuple);
 
 	systable_endscan(scan);
@@ -2940,7 +2952,8 @@ domainAddConstraint(Oid domainOid, Oid domainNamespace, Oid baseTypeOid,
 						  ccsrc,	/* Source form of check constraint */
 						  true, /* is local */
 						  0,	/* inhcount */
-						  false);		/* connoinherit */
+						  false,	/* connoinherit */
+						  false);	/* is_internal */
 
 	/*
 	 * Return the compiled constraint expression so the calling routine can
@@ -3135,7 +3148,7 @@ RenameType(RenameStmt *stmt)
 	 * RenameRelationInternal will call RenameTypeInternal automatically.
 	 */
 	if (typTup->typtype == TYPTYPE_COMPOSITE)
-		RenameRelationInternal(typTup->typrelid, newTypeName);
+		RenameRelationInternal(typTup->typrelid, newTypeName, false);
 	else
 		RenameTypeInternal(typeOid, newTypeName,
 						   typTup->typnamespace);
@@ -3256,6 +3269,16 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
 			/* Update owner dependency reference */
 			changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
 
+			/*
+			 * Post alter hook for this type
+			 *
+			 * XXX - we don't put is_internal flag here, even if this type
+			 * is an implicit array, because the callee can determine it
+			 * according to the contents of catalog entry.
+			 */
+			InvokeObjectAccessHook(OAT_POST_ALTER,
+								   TypeRelationId, typeOid, 0, NULL);
+
 			/* If it has an array type, update that too */
 			if (OidIsValid(typTup->typarray))
 				AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
@@ -3276,6 +3299,8 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
  *
  * hasDependEntry should be TRUE if type is expected to have a pg_shdepend
  * entry (ie, it's not a table rowtype nor an array type).
+ * is_primary_ops should be TRUE if this function is invoked with user's
+ * direct operation (e.g, shdepReassignOwned). Elsewhere, 
  */
 void
 AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
@@ -3309,6 +3334,10 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
 	if (OidIsValid(typTup->typarray))
 		AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
 
+	/* Post alter hook for the type */
+	InvokeObjectAccessHook(OAT_POST_ALTER,
+						   TypeRelationId, typeOid, 0, NULL);
+
 	/* Clean up */
 	heap_close(rel, RowExclusiveLock);
 }
@@ -3494,6 +3523,9 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
 			elog(ERROR, "failed to change schema dependency for type %s",
 				 format_type_be(typeOid));
 
+	/* Post alter hook for this type */
+	InvokeObjectAccessHook(OAT_POST_ALTER, TypeRelationId, typeOid, 0, NULL);
+
 	heap_freetuple(tup);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index f178167..930646f 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -776,6 +776,9 @@ AlterRole(AlterRoleStmt *stmt)
 	/* Update indexes */
 	CatalogUpdateIndexes(pg_authid_rel, new_tuple);
 
+	/* Post alter hook of this role */
+	InvokeObjectAccessHook(OAT_POST_ALTER, AuthIdRelationId, roleid, 0, NULL);
+
 	ReleaseSysCache(tuple);
 	heap_freetuple(new_tuple);
 
@@ -1136,6 +1139,8 @@ RenameRole(const char *oldname, const char *newname)
 
 	CatalogUpdateIndexes(rel, newtuple);
 
+	InvokeObjectAccessHook(OAT_POST_ALTER, AuthIdRelationId, roleid, 0, NULL);
+
 	ReleaseSysCache(oldtuple);
 
 	/*
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 55b0fed..3a8de01 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -732,6 +732,8 @@ EnableDisableRule(Relation rel, const char *rulename,
 		/* keep system catalog indexes current */
 		CatalogUpdateIndexes(pg_rewrite_desc, ruletup);
 
+		InvokeObjectAccessHook(OAT_POST_ALTER, RewriteRelationId,
+							   HeapTupleGetOid(ruletup), 0, NULL);
 		changed = true;
 	}
 
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index a35829b..5d335e0 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -95,9 +95,11 @@ extern List *AddRelationNewConstraints(Relation rel,
 						  List *newColDefaults,
 						  List *newConstraints,
 						  bool allow_merge,
-						  bool is_local);
+						  bool is_local,
+						  bool is_internal);
 
-extern void StoreAttrDefault(Relation rel, AttrNumber attnum, Node *expr);
+extern void StoreAttrDefault(Relation rel, AttrNumber attnum,
+							 Node *expr, bool is_internal);
 
 extern Node *cookDefault(ParseState *pstate,
 			Node *raw_default,
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 298641b..1352474 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -63,7 +63,8 @@ extern void index_constraint_create(Relation heapRelation,
 						bool mark_as_primary,
 						bool update_pgindex,
 						bool remove_old_dependencies,
-						bool allow_system_table_mods);
+						bool allow_system_table_mods,
+						bool is_internal);
 
 extern void index_drop(Oid indexId, bool concurrent);
 
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index b4b84a6..68d5e86 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -22,12 +22,18 @@
  * OAT_DROP should be invoked just before deletion of objects; typically
  * deleteOneObject(). Its arguments are packed within ObjectAccessDrop.
  *
+ * OAT_POST_ALTER should be invoked just after the object is altered.
+ * The command-counter is not incremented prior to invocation of this hook,
+ * extension can reference two different version of system catalog using
+ * SnapshotNow and SnapshotSelf, to identify which field was altered.
+ *
  * Other types may be added in the future.
  */
 typedef enum ObjectAccessType
 {
 	OAT_POST_CREATE,
 	OAT_DROP,
+	OAT_POST_ALTER,
 } ObjectAccessType;
 
 /*
@@ -56,6 +62,28 @@ typedef struct
 } ObjectAccessDrop;
 
 /*
+ * Arguments of OAT_POST_ALTER event
+ */
+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;
+
+	/*
+	 * This flag informs extensions whether the context of this alter
+	 * is invoked by user's operations, or not. E.g, it shall be dealt
+	 * as internal stuff on indexing due to type changes.
+	 */
+	bool		is_internal;
+} ObjectAccessPostAlter;
+
+/*
  * Hook, and a macro to invoke it.
  */
 typedef void (*object_access_hook_type) (ObjectAccessType access,
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index e4e9c40..9c88e51 100644
--- a/src/include/catalog/pg_constraint.h
+++ b/src/include/catalog/pg_constraint.h
@@ -232,7 +232,8 @@ extern Oid CreateConstraintEntry(const char *constraintName,
 					  const char *conSrc,
 					  bool conIsLocal,
 					  int conInhCount,
-					  bool conNoInherit);
+					  bool conNoInherit,
+					  bool is_internal);
 
 extern void RemoveConstraintById(Oid conId);
 extern void RenameConstraintById(Oid conId, const char *newname);
diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h
index 4f32062..2ddcbc6 100644
--- a/src/include/commands/tablecmds.h
+++ b/src/include/commands/tablecmds.h
@@ -58,7 +58,7 @@ extern void RenameConstraint(RenameStmt *stmt);
 extern void RenameRelation(RenameStmt *stmt);
 
 extern void RenameRelationInternal(Oid myrelid,
-					   const char *newrelname);
+					   const char *newrelname, bool is_internal);
 
 extern void find_composite_type_dependencies(Oid typeOid,
 								 Relation origRelation,