[v9.3] OAT_POST_ALTER object access hooks

Started by Kohei KaiGaiabout 13 years ago23 messages
#1Kohei KaiGai
kaigai@kaigai.gr.jp
1 attachment(s)

The attached patch adds a new event type of object_access_hook;
named OAT_POST_ALTER. As literal, it allows extensions to catch
controls just after system catalogs are updated.
It also adds sepgsql permission check capability on some ALTER
commands, but not any.

The hooks are designed to locate between heap update's and next
command-counter increment, to allow extensions to reference
both of older and newer version of catalog entry.
Unless CCI is called, we can reference older one with SnapshotNow,
and newer one with SnapshotSelf, as attached sepgsql code doing
to detect namespace / name changes.
As we discussed before, it is a significant point to pick-up which
information should be delivered to extensions through the hooks,
to avoid design too specific for a particular extension's requirement.
I believe it is the best way to inform which fields were updated on
the relevant ALTER command.

The OAT_POST_ALTER can take two arguments. The one is
"is_internal" flag similar to DROP or POST_CREATE hook.
The other is "auxiliary_id" field to identify a particular entry of
the catalog that takes a couple of IDs; E.g, pg_db_role_setting
or pg_inherits.

It might be noticed that some OAT_POST_CREATE hooks are
also added on the code path being invoked on some ALTER
commands, such as StoreAttrDefault, storeOperators or
storeProcedures. These routines insert / delete subsidiary
objects of others, but the "main" object is not touched in this
code path. So, it makes hard to inform what was updated in
this operation without these additional OAT_POST_CREATE.

Regarding to sepgsql portion, I added logic to check "setattr"
permission of only "main" object to simplify the patch.
Later, I will also add logic for subsidiary objects like triggers
or rules towards relation.

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

sepgsql-v9.3-post-alter-support.v1.patchapplication/octet-stream; name=sepgsql-v9.3-post-alter-support.v1.patchDownload
 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,
#2Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Kohei KaiGai (#1)
1 attachment(s)
Re: [v9.3] OAT_POST_ALTER object access hooks

Sorry, I missed the attached version.
Please use this revision.

2012/11/15 Kohei KaiGai <kaigai@kaigai.gr.jp>:

The attached patch adds a new event type of object_access_hook;
named OAT_POST_ALTER. As literal, it allows extensions to catch
controls just after system catalogs are updated.
It also adds sepgsql permission check capability on some ALTER
commands, but not any.

The hooks are designed to locate between heap update's and next
command-counter increment, to allow extensions to reference
both of older and newer version of catalog entry.
Unless CCI is called, we can reference older one with SnapshotNow,
and newer one with SnapshotSelf, as attached sepgsql code doing
to detect namespace / name changes.
As we discussed before, it is a significant point to pick-up which
information should be delivered to extensions through the hooks,
to avoid design too specific for a particular extension's requirement.
I believe it is the best way to inform which fields were updated on
the relevant ALTER command.

The OAT_POST_ALTER can take two arguments. The one is
"is_internal" flag similar to DROP or POST_CREATE hook.
The other is "auxiliary_id" field to identify a particular entry of
the catalog that takes a couple of IDs; E.g, pg_db_role_setting
or pg_inherits.

It might be noticed that some OAT_POST_CREATE hooks are
also added on the code path being invoked on some ALTER
commands, such as StoreAttrDefault, storeOperators or
storeProcedures. These routines insert / delete subsidiary
objects of others, but the "main" object is not touched in this
code path. So, it makes hard to inform what was updated in
this operation without these additional OAT_POST_CREATE.

Regarding to sepgsql portion, I added logic to check "setattr"
permission of only "main" object to simplify the patch.
Later, I will also add logic for subsidiary objects like triggers
or rules towards relation.

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

sepgsql-v9.3-post-alter-support.v2.patchapplication/octet-stream; name=sepgsql-v9.3-post-alter-support.v2.patchDownload
 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..6a4b529 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_ALTER, 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..5090e1a 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_ALTER,
+						   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,
#3Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Kohei KaiGai (#2)
Re: [v9.3] OAT_POST_ALTER object access hooks

Kohei KaiGai wrote:

Sorry, I missed the attached version.
Please use this revision.

All those direct uses of object_access_hook make me think that the
InvokeObjectAccessHook() macro we have is insufficient. Maybe we could
have InvokeObjectAccessHookArg1() so that instead of

+   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);
+   }

we can have

InvokeObjectAccessHookWithArgs1(OAT_POST_CREATE, AttrDefaultRelationId,
RelationGetRelid(rel), attnum,
ObjectAccessPostCreate, is_internal, is_internal)

which would expand into the above. (Since ObjectAccessPostCreate has
two members, we presumably need InvokeObjectAccessHookWithArgs2 as
well. But that doesn't seem to be used anywhere, so maybe that struct
member is not necessary?)

The second hunk to alter.c does not apply anymore; please rebase.

--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#4Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Alvaro Herrera (#3)
Re: [v9.3] OAT_POST_ALTER object access hooks

2012/11/19 Alvaro Herrera <alvherre@2ndquadrant.com>:

Kohei KaiGai wrote:

Sorry, I missed the attached version.
Please use this revision.

All those direct uses of object_access_hook make me think that the
InvokeObjectAccessHook() macro we have is insufficient. Maybe we could
have InvokeObjectAccessHookArg1() so that instead of

+   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);
+   }

we can have

InvokeObjectAccessHookWithArgs1(OAT_POST_CREATE, AttrDefaultRelationId,
RelationGetRelid(rel), attnum,
ObjectAccessPostCreate, is_internal, is_internal)

which would expand into the above. (Since ObjectAccessPostCreate has
two members, we presumably need InvokeObjectAccessHookWithArgs2 as
well. But that doesn't seem to be used anywhere, so maybe that struct
member is not necessary?)

I'd like to have catalog/objectaccess.c to wrap-up invocation of hooks, rather
than doing all the stuffs with macros. It allows to use local variables, unlike
macros; that has a risk of naming conflict with temporary variable for
ObjectAccessPostCreate.

So, how about to have a following definition for example?

void
InvokePostAlterHookArgs(Oid classId, Oid objectId, int subId,
Oid auxiliaryId, bool is_internal)
{
if (object_access_hook)
{
ObjectAccessPostAlter pa_arg;

memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
pa_arg.auxiliary_id = auxiliary_id;
pa_arg.is_internal = is_internal;
(*object_access_hook)(OAT_POST_ALTER,
classId, objectId, subId,
(void *) &pa_arg);
}
}

and

#define InvokePostAlterHook(classId, objectId, subId) \
InvokePostAlterHookArgs(classId, objectId, subId, InvalidOid, false)

for most points to call.

Even if ObjectAccessPostCreate is extended in the future version, it does not
take changes on most of hook invocation points.
We will be also able to have same semantics on OAT_POST_CREATE and
OAT_DROP as well.

The second hunk to alter.c does not apply anymore; please rebase.

OK,

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

#5Alvaro Herrera
alvherre@2ndquadrant.com
In reply to: Kohei KaiGai (#4)
Re: [v9.3] OAT_POST_ALTER object access hooks

Kohei KaiGai wrote:

I'd like to have catalog/objectaccess.c to wrap-up invocation of hooks, rather
than doing all the stuffs with macros. It allows to use local variables, unlike
macros; that has a risk of naming conflict with temporary variable for
ObjectAccessPostCreate.

No objection from me.

--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

#6Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Alvaro Herrera (#5)
Re: [v9.3] OAT_POST_ALTER object access hooks

The second hunk to alter.c does not apply anymore; please rebase.

OK,

Oops, I assumed the patch for ALTER RENAME TO reworks. Sorry.

2012/11/20 Alvaro Herrera <alvherre@2ndquadrant.com>:

Kohei KaiGai wrote:

I'd like to have catalog/objectaccess.c to wrap-up invocation of hooks, rather
than doing all the stuffs with macros. It allows to use local variables, unlike
macros; that has a risk of naming conflict with temporary variable for
ObjectAccessPostCreate.

No objection from me.

--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

--
KaiGai Kohei <kaigai@kaigai.gr.jp>

#7Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Kohei KaiGai (#6)
2 attachment(s)
Re: [v9.3] OAT_POST_ALTER object access hooks

2012/11/20 Kohei KaiGai <kaigai@kaigai.gr.jp>:

The second hunk to alter.c does not apply anymore; please rebase.

OK,

Oops, I assumed the patch for ALTER RENAME TO reworks. Sorry.

2012/11/20 Alvaro Herrera <alvherre@2ndquadrant.com>:

Kohei KaiGai wrote:

I'd like to have catalog/objectaccess.c to wrap-up invocation of hooks, rather
than doing all the stuffs with macros. It allows to use local variables, unlike
macros; that has a risk of naming conflict with temporary variable for
ObjectAccessPostCreate.

No objection from me.

The attached patches are revised version of the previous one.
Please note that it assumes my reworks patch on ALTER ... RENAME TO
being applied on top of this patch.

The part-1 stuff simply adds wrap-up functions for object_access_hook.
InvokeObjectPostCreateHookArg() and InvokeObjectDropHookArg() replace
existing invocations of hooks with OAT_POST_CREATE and OAT_DROP.
In case of invocation without argument, callers can use their shorten form
defined in objectaccess.h.

The part-2 stuff is a main portion of this patch.
It newly adds OAT_POST_ALTER event type that shall be invoked just
after catalog updates. Extension side can see the identified object with
SnapshotNow for older version and SnapshotSelf for newer version, thus,
it can know which fields were updated around this event.

I still have a few points to be discussed.
* Do we need OAT_POST_ALTER hook even if no fields were updated
actually? In case when ALTER SET OWNER, it checks object's ownership
only when current and new user-id is not same. Right now, I follow this
manner on OAT_POST_ALTER invocation.
However, I'm inclined to consider the hook should be invoked when no
fields are actually updated also. (It allows extension-side to determine
necessity of processing something.)

* When tablespace of relation was changed, it seems to me the point to
invoke OAT_POST_ALTER hook should be "after" ATRewriteTable().
However, it usually long time to rewrite whole the table if it already have
large number of rows. I'm not 100% certain to put hook here, so this
version does not support hook when tablespace changes.

Any comments please.

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

sepgsql-v9.3-post-alter-support.v3.part-1.patchapplication/octet-stream; name=sepgsql-v9.3-post-alter-support.v3.part-1.patchDownload
 src/backend/catalog/Makefile               |    3 +-
 src/backend/catalog/dependency.c           |   10 +----
 src/backend/catalog/heap.c                 |   10 +----
 src/backend/catalog/index.c                |   11 +----
 src/backend/catalog/objectaccess.c         |   63 ++++++++++++++++++++++++++++
 src/backend/catalog/pg_collation.c         |    3 +-
 src/backend/catalog/pg_constraint.c        |    3 +-
 src/backend/catalog/pg_conversion.c        |    3 +-
 src/backend/catalog/pg_namespace.c         |    3 +-
 src/backend/catalog/pg_operator.c          |    6 +--
 src/backend/catalog/pg_proc.c              |    3 +-
 src/backend/catalog/pg_type.c              |    6 +--
 src/backend/commands/dbcommands.c          |   12 +-----
 src/backend/commands/event_trigger.c       |    3 +-
 src/backend/commands/extension.c           |    3 +-
 src/backend/commands/foreigncmds.c         |    9 ++--
 src/backend/commands/functioncmds.c        |    3 +-
 src/backend/commands/opclasscmds.c         |    6 +--
 src/backend/commands/proclang.c            |    3 +-
 src/backend/commands/tablecmds.c           |    3 +-
 src/backend/commands/tablespace.c          |   12 +-----
 src/backend/commands/trigger.c             |    3 +-
 src/backend/commands/tsearchcmds.c         |   12 ++----
 src/backend/commands/user.c                |   12 +-----
 src/backend/rewrite/rewriteDefine.c        |    3 +-
 src/backend/storage/large_object/inv_api.c |    3 +-
 src/backend/utils/init/globals.c           |    7 ----
 src/include/catalog/objectaccess.h         |   15 ++++---
 28 files changed, 111 insertions(+), 122 deletions(-)

diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index df6da1f..c4d3f3c 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -11,7 +11,8 @@ top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
 OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
-       objectaddress.o pg_aggregate.o pg_collation.o pg_constraint.o pg_conversion.o \
+       objectaccess.o objectaddress.o pg_aggregate.o pg_collation.o \
+       pg_constraint.o pg_conversion.o \
        pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \
        pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \
        pg_type.o storage.o toasting.o
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 0b61c97..2d822a4 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -997,14 +997,8 @@ deleteOneObject(const ObjectAddress *object, Relation depRel, int flags)
 	HeapTuple	tup;
 
 	/* DROP hook of the objects being removed */
-	if (object_access_hook)
-	{
-		ObjectAccessDrop drop_arg;
-
-		drop_arg.dropflags = flags;
-		InvokeObjectAccessHook(OAT_DROP, object->classId, object->objectId,
-							   object->objectSubId, &drop_arg);
-	}
+	InvokeObjectDropHookArg(object->classId, object->objectId,
+							object->objectSubId, flags);
 
 	/*
 	 * Close depRel if we are doing a drop concurrently.  The object deletion
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index d93d273..54de9a7 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1277,15 +1277,7 @@ heap_create_with_catalog(const char *relname,
 	}
 
 	/* Post creation hook for new relation */
-	if (object_access_hook)
-	{
-		ObjectAccessPostCreate	post_create_args;
-
-		memset(&post_create_args, 0, sizeof(ObjectAccessPostCreate));
-		post_create_args.is_internal = is_internal;
-		(*object_access_hook)(OAT_POST_CREATE, RelationRelationId,
-							  relid, 0, &post_create_args);
-    }
+	InvokeObjectPostCreateHookArg(RelationRelationId, relid, 0, is_internal);
 
 	/*
 	 * Store any supplied constraints and defaults.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 92e8de1..36bc5d2 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1026,15 +1026,8 @@ index_create(Relation heapRelation,
 	}
 
 	/* Post creation hook for new index */
-	if (object_access_hook)
-	{
-		ObjectAccessPostCreate	post_create_args;
-
-		memset(&post_create_args, 0, sizeof(ObjectAccessPostCreate));
-		post_create_args.is_internal = is_internal;
-		(*object_access_hook)(OAT_POST_CREATE, RelationRelationId,
-							  indexRelationId, 0, &post_create_args);
-	}
+	InvokeObjectPostCreateHookArg(RelationRelationId,
+								  indexRelationId, 0, is_internal);
 
 	/*
 	 * Advance the command counter so that we can see the newly-entered
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
new file mode 100644
index 0000000..9dae242
--- /dev/null
+++ b/src/backend/catalog/objectaccess.c
@@ -0,0 +1,63 @@
+/* -------------------------------------------------------------------------
+ *
+ * objectaccess.c
+ *		functions for object_access_hook on various events
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "catalog/objectaccess.h"
+
+/*
+ * Hook on object accesses.  This is intended as infrastructure for security
+ * and logging plugins.
+ */
+object_access_hook_type object_access_hook = NULL;
+
+/*
+ * InvokeObjectPostCreateHookArg
+ *
+ * It is entrypoint of OAT_POST_CREATE event
+ */
+void
+InvokeObjectPostCreateHookArg(Oid classId, Oid objectId, int subId,
+							  bool is_internal)
+{
+	ObjectAccessPostCreate	pc_arg;
+
+	if (!object_access_hook)
+		return;
+
+	memset(&pc_arg, 0, sizeof(ObjectAccessPostCreate));
+	pc_arg.is_internal = is_internal;
+
+	(*object_access_hook)(OAT_POST_CREATE,
+						  classId, objectId, subId,
+						  (void *) &pc_arg);
+}
+
+/*
+ * InvokeObjectDropHookArg
+ *
+ * It is entrypoint of OAT_DROP event
+ */
+void
+InvokeObjectDropHookArg(Oid classId, Oid objectId, int subId,
+				  int dropflags)
+{
+	ObjectAccessDrop	drop_arg;
+
+	if (!object_access_hook)
+		return;
+
+	memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
+	drop_arg.dropflags = dropflags;
+
+	(*object_access_hook)(OAT_DROP,
+						  classId, objectId, subId,
+						  (void *) &drop_arg);
+}
diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c
index 6020d16..0c25554 100644
--- a/src/backend/catalog/pg_collation.c
+++ b/src/backend/catalog/pg_collation.c
@@ -136,8 +136,7 @@ CollationCreate(const char *collname, Oid collnamespace,
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new collation */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   CollationRelationId, oid, 0, NULL);
+	InvokeObjectPostCreateHook(CollationRelationId, oid, 0);
 
 	heap_freetuple(tup);
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 5e8c6da..1e6d947 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -367,8 +367,7 @@ CreateConstraintEntry(const char *constraintName,
 	}
 
 	/* Post creation hook for new constraint */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ConstraintRelationId, conOid, 0, NULL);
+	InvokeObjectPostCreateHook(ConstraintRelationId, conOid, 0);
 
 	return conOid;
 }
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index 68f1aa7..caef609 100644
--- a/src/backend/catalog/pg_conversion.c
+++ b/src/backend/catalog/pg_conversion.c
@@ -136,8 +136,7 @@ ConversionCreate(const char *conname, Oid connamespace,
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new conversion */
-	InvokeObjectAccessHook(OAT_POST_CREATE, ConversionRelationId,
-						   HeapTupleGetOid(tup), 0, NULL);
+	InvokeObjectPostCreateHook(ConversionRelationId, HeapTupleGetOid(tup), 0);
 
 	heap_freetuple(tup);
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c
index 098df22..b322ff6 100644
--- a/src/backend/catalog/pg_namespace.c
+++ b/src/backend/catalog/pg_namespace.c
@@ -96,8 +96,7 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
 		recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new schema */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   NamespaceRelationId, nspoid, 0, NULL);
+	InvokeObjectPostCreateHook(NamespaceRelationId, nspoid, 0);
 
 	return nspoid;
 }
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 88af345..bd44333 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -275,8 +275,7 @@ OperatorShellMake(const char *operatorName,
 	heap_freetuple(tup);
 
 	/* Post creation hook for new shell operator */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorRelationId, operatorObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
 
 	/*
 	 * Make sure the tuple is visible for subsequent lookups/updates.
@@ -544,8 +543,7 @@ OperatorCreate(const char *operatorName,
 	makeOperatorDependencies(tup);
 
 	/* Post creation hook for new operator */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorRelationId, operatorObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
 
 	heap_close(pg_operator_desc, RowExclusiveLock);
 
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index ba73264..444ee78 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -661,8 +661,7 @@ ProcedureCreate(const char *procedureName,
 	heap_freetuple(tup);
 
 	/* Post creation hook for new function */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ProcedureRelationId, retval, 0, NULL);
+	InvokeObjectPostCreateHook(ProcedureRelationId, retval, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 49133ee..cf0ebcc 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -163,8 +163,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
 								 false);
 
 	/* Post creation hook for new shell type */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TypeRelationId, typoid, 0, NULL);
+	InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
 
 	/*
 	 * clean up and return the type-oid
@@ -476,8 +475,7 @@ TypeCreate(Oid newTypeOid,
 								 rebuildDeps);
 
 	/* Post creation hook for new type */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TypeRelationId, typeObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
 
 	/*
 	 * finish up
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 3c13c47..09c06ed 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -520,8 +520,7 @@ createdb(const CreatedbStmt *stmt)
 	copyTemplateDependencies(src_dboid, dboid);
 
 	/* Post creation hook for new database */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   DatabaseRelationId, dboid, 0, NULL);
+	InvokeObjectPostCreateHook(DatabaseRelationId, dboid, 0);
 
 	/*
 	 * Force a checkpoint before starting the copy. This will force dirty
@@ -784,14 +783,7 @@ dropdb(const char *dbname, bool missing_ok)
 					   dbname);
 
 	/* DROP hook for the database being removed */
-	if (object_access_hook)
-	{
-		ObjectAccessDrop drop_arg;
-
-		memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
-		InvokeObjectAccessHook(OAT_DROP,
-							   DatabaseRelationId, db_id, 0, &drop_arg);
-	}
+	InvokeObjectDropHook(DatabaseRelationId, db_id, 0);
 
 	/*
 	 * Disallow dropping a DB that is marked istemplate.  This is just to
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 2e24e0d..97dde84 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -307,8 +307,7 @@ insert_event_trigger_tuple(char *trigname, char *eventname, Oid evtOwner,
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new operator family */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   EventTriggerRelationId, trigoid, 0, NULL);
+	InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
 
 	/* Close pg_event_trigger. */
 	heap_close(tgrel, RowExclusiveLock);
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 47631be..e45de83 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1560,8 +1560,7 @@ InsertExtensionTuple(const char *extName, Oid extOwner,
 		recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
 	}
 	/* Post creation hook for new extension */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ExtensionRelationId, extensionOid, 0, NULL);
+	InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
 
 	return extensionOid;
 }
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 2d73d2d..e2f86d2 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -589,8 +589,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new foreign data wrapper */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ForeignDataWrapperRelationId, fdwId, 0, NULL);
+	InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
@@ -886,8 +885,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new foreign server */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ForeignServerRelationId, srvId, 0, NULL);
+	InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
@@ -1127,8 +1125,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new user mapping */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   UserMappingRelationId, umId, 0, NULL);
+	InvokeObjectPostCreateHook(UserMappingRelationId, umId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index cf0613f..26a806b 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1610,8 +1610,7 @@ CreateCast(CreateCastStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new cast */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   CastRelationId, castid, 0, NULL);
+	InvokeObjectPostCreateHook(CastRelationId, castid, 0);
 
 	heap_freetuple(tuple);
 
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 044ddd3..c8e0e75 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -309,8 +309,7 @@ CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new operator family */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorFamilyRelationId, opfamilyoid, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
@@ -710,8 +709,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new operator class */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorClassRelationId, opclassoid, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 6526b7e..2e446b5 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -429,8 +429,7 @@ create_proc_lang(const char *languageName, bool replace,
 	}
 
 	/* Post creation hook for new procedural language */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   LanguageRelationId, myself.objectId, 0, NULL);
+	InvokeObjectPostCreateHook(LanguageRelationId, myself.objectId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 4065740..d516e2a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4462,8 +4462,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	heap_freetuple(reltup);
 
 	/* Post creation hook for new attribute */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   RelationRelationId, myrelid, newattnum, NULL);
+	InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
 
 	heap_close(pgclass, RowExclusiveLock);
 
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index d80b3a6..e794ecf 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -331,8 +331,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
 	recordDependencyOnOwner(TableSpaceRelationId, tablespaceoid, ownerId);
 
 	/* Post creation hook for new tablespace */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TableSpaceRelationId, tablespaceoid, 0, NULL);
+	InvokeObjectPostCreateHook(TableSpaceRelationId, tablespaceoid, 0);
 
 	create_tablespace_directories(location, tablespaceoid);
 
@@ -437,14 +436,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
 					   tablespacename);
 
 	/* DROP hook for the tablespace being removed */
-	if (object_access_hook)
-	{
-		ObjectAccessDrop drop_arg;
-
-		memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
-		InvokeObjectAccessHook(OAT_DROP, TableSpaceRelationId,
-							   tablespaceoid, 0, &drop_arg);
-	}
+	InvokeObjectDropHook(TableSpaceRelationId, tablespaceoid, 0);
 
 	/*
 	 * Remove the pg_tablespace tuple (this will roll back if we fail below)
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 91ef779..4a369a4 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -741,8 +741,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 							   DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new trigger */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TriggerRelationId, trigoid, 0, NULL);
+	InvokeObjectPostCreateHook(TriggerRelationId, trigoid, 0);
 
 	/* Keep lock on target rel until end of xact */
 	heap_close(rel, NoLock);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 9dbfa0c..64e9885 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -272,8 +272,7 @@ DefineTSParser(List *names, List *parameters)
 	makeParserDependencies(tup);
 
 	/* Post creation hook for new text search parser */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSParserRelationId, prsOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSParserRelationId, prsOid, 0);
 
 	heap_freetuple(tup);
 
@@ -477,8 +476,7 @@ DefineTSDictionary(List *names, List *parameters)
 	makeDictionaryDependencies(tup);
 
 	/* Post creation hook for new text search dictionary */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSDictionaryRelationId, dictOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSDictionaryRelationId, dictOid, 0);
 
 	heap_freetuple(tup);
 
@@ -790,8 +788,7 @@ DefineTSTemplate(List *names, List *parameters)
 	makeTSTemplateDependencies(tup);
 
 	/* Post creation hook for new text search template */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSTemplateRelationId, dictOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSTemplateRelationId, dictOid, 0);
 
 	heap_freetuple(tup);
 
@@ -1084,8 +1081,7 @@ DefineTSConfiguration(List *names, List *parameters)
 	makeConfigurationDependencies(tup, false, mapRel);
 
 	/* Post creation hook for new text search configuration */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSConfigRelationId, cfgOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSConfigRelationId, cfgOid, 0);
 
 	heap_freetuple(tup);
 
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index f178167..c1b7b93 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -426,8 +426,7 @@ CreateRole(CreateRoleStmt *stmt)
 				GetUserId(), false);
 
 	/* Post creation hook for new role */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   AuthIdRelationId, roleid, 0, NULL);
+	InvokeObjectPostCreateHook(AuthIdRelationId, roleid, 0);
 
 	/*
 	 * Close pg_authid, but keep lock till commit.
@@ -935,14 +934,7 @@ DropRole(DropRoleStmt *stmt)
 					 errmsg("must be superuser to drop superusers")));
 
 		/* DROP hook for the role being removed */
-		if (object_access_hook)
-		{
-			ObjectAccessDrop drop_arg;
-
-			memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
-			InvokeObjectAccessHook(OAT_DROP,
-								   AuthIdRelationId, roleid, 0, &drop_arg);
-		}
+		InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
 
 		/*
 		 * Lock the role, so nobody can add dependencies to her while we drop
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 55b0fed..17e3513 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -179,8 +179,7 @@ InsertRule(char *rulname,
 	}
 
 	/* Post creation hook for new rule */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   RewriteRelationId, rewriteObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(RewriteRelationId, rewriteObjectId, 0);
 
 	heap_close(pg_rewrite_desc, RowExclusiveLock);
 
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index ad8424b..b2c8781 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -218,8 +218,7 @@ inv_create(Oid lobjId)
 							lobjId_new, GetUserId());
 
 	/* Post creation hook for new large object */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   LargeObjectRelationId, lobjId_new, 0, NULL);
+	InvokeObjectPostCreateHook(LargeObjectRelationId, lobjId_new, 0);
 
 	/*
 	 * Advance command counter to make new tuple visible to later operations.
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 4b66bd3..ce072ab 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -18,7 +18,6 @@
  */
 #include "postgres.h"
 
-#include "catalog/objectaccess.h"
 #include "libpq/pqcomm.h"
 #include "miscadmin.h"
 #include "storage/backendid.h"
@@ -124,9 +123,3 @@ int			VacuumCostBalance = 0;		/* working state for vacuum */
 bool		VacuumCostActive = false;
 
 int			GinFuzzySearchLimit = 0;
-
-/*
- * Hook on object accesses.  This is intended as infrastructure for security
- * and logging plugins.
- */
-object_access_hook_type object_access_hook = NULL;
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index b4b84a6..9d1937d 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -66,11 +66,14 @@ typedef void (*object_access_hook_type) (ObjectAccessType access,
 
 extern PGDLLIMPORT object_access_hook_type object_access_hook;
 
-#define InvokeObjectAccessHook(access,classId,objectId,subId,arg)	\
-	do {															\
-		if (object_access_hook)										\
-			(*object_access_hook)((access),(classId),				\
-								  (objectId),(subId),(arg));		\
-	} while(0)
+extern void InvokeObjectPostCreateHookArg(Oid classId, Oid objectId, int subId,
+										  bool is_internal);
+extern void InvokeObjectDropHookArg(Oid classId, Oid objectId, int subId,
+									int dropflags);
+
+#define InvokeObjectPostCreateHook(classId,objectId,subId)	\
+	InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
+#define InvokeObjectDropHook(classId,objectId,subId)	\
+	InvokeObjectDropHookArg((classId),(objectId),(subId),0)
 
 #endif   /* OBJECTACCESS_H */
sepgsql-v9.3-post-alter-support.v3.part-2.patchapplication/octet-stream; name=sepgsql-v9.3-post-alter-support.v3.part-2.patchDownload
 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               |   41 +++++--
 src/backend/catalog/index.c              |   12 +-
 src/backend/catalog/objectaccess.c       |   23 ++++
 src/backend/catalog/pg_constraint.c      |   13 ++-
 src/backend/catalog/pg_db_role_setting.c |    5 +-
 src/backend/catalog/pg_type.c            |    3 +
 src/backend/commands/alter.c             |   10 ++
 src/backend/commands/cluster.c           |   12 +-
 src/backend/commands/collationcmds.c     |    1 +
 src/backend/commands/dbcommands.c        |   15 +++
 src/backend/commands/event_trigger.c     |    3 +
 src/backend/commands/extension.c         |    8 ++
 src/backend/commands/foreigncmds.c       |   13 +++
 src/backend/commands/functioncmds.c      |    2 +-
 src/backend/commands/opclasscmds.c       |    6 +
 src/backend/commands/schemacmds.c        |    7 ++
 src/backend/commands/sequence.c          |    4 +
 src/backend/commands/tablecmds.c         |   94 +++++++++++++---
 src/backend/commands/tablespace.c        |    3 +
 src/backend/commands/trigger.c           |   14 ++-
 src/backend/commands/tsearchcmds.c       |    5 +
 src/backend/commands/typecmds.c          |   28 ++++-
 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       |   32 ++++++
 src/include/catalog/pg_constraint.h      |    3 +-
 src/include/commands/cluster.h           |    2 +-
 src/include/commands/tablecmds.h         |    2 +-
 43 files changed, 970 insertions(+), 65 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..88ef2e5 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 */
+		InvokeObjectPostAlterHook(DefaultAclRelationId,
+								  HeapTupleGetOid(newtuple), 0);
 	}
 
 	if (HeapTupleIsValid(tuple))
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 54de9a7..f482656 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -95,8 +95,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);
@@ -1286,7 +1287,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
@@ -1799,7 +1800,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;
@@ -1891,6 +1893,17 @@ 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.
+	 */
+	InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
+								  RelationGetRelid(rel), attnum, is_internal);
 }
 
 /*
@@ -1902,7 +1915,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;
@@ -1986,7 +1999,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);
@@ -2001,7 +2015,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;
@@ -2023,11 +2037,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:
@@ -2053,6 +2068,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.
@@ -2070,7 +2086,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;
@@ -2133,7 +2150,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;
@@ -2259,7 +2276,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 36bc5d2..398b7a5 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -931,7 +931,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
 		{
@@ -1105,6 +1106,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,
@@ -1117,7 +1119,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,
@@ -1182,7 +1185,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.
@@ -1291,6 +1295,8 @@ index_constraint_create(Relation heapRelation,
 		{
 			simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
 			CatalogUpdateIndexes(pg_index, indexTuple);
+			InvokeObjectPostAlterHookArg(IndexRelationId, indexRelationId, 0,
+										 InvalidOid, is_internal);
 		}
 
 		heap_freetuple(indexTuple);
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
index 9dae242..6fa1676 100644
--- a/src/backend/catalog/objectaccess.c
+++ b/src/backend/catalog/objectaccess.c
@@ -61,3 +61,26 @@ InvokeObjectDropHookArg(Oid classId, Oid objectId, int subId,
 						  classId, objectId, subId,
 						  (void *) &drop_arg);
 }
+
+/*
+ * InvokeObjectPostAlterHookArg
+ *
+ * It is entrypoint of OAT_POST_ALTER event
+ */
+void
+InvokeObjectPostAlterHookArg(Oid classId, Oid objectId, int subId,
+							 Oid auxiliaryId, bool is_internal)
+{
+	ObjectAccessPostAlter	pa_arg;
+
+	if (!object_access_hook)
+		return;
+
+	memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
+	pa_arg.auxiliary_id = auxiliaryId;
+	pa_arg.is_internal = is_internal;
+
+	(*object_access_hook)(OAT_POST_ALTER,
+						  classId, objectId, subId,
+						  (void *) &pa_arg);
+}
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 1e6d947..7b6b698 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,7 +368,8 @@ CreateConstraintEntry(const char *constraintName,
 	}
 
 	/* Post creation hook for new constraint */
-	InvokeObjectPostCreateHook(ConstraintRelationId, conOid, 0);
+	InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0,
+								  is_internal);
 
 	return conOid;
 }
@@ -665,6 +667,9 @@ RenameConstraintById(Oid conId, const char *newname)
 	/* update the system catalog indexes */
 	CatalogUpdateIndexes(conDesc, tuple);
 
+	/* Post alter hook for this constraint */
+	InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0);
+
 	heap_freetuple(tuple);
 	heap_close(conDesc, RowExclusiveLock);
 }
@@ -735,6 +740,10 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 			 * dependency on the namespace, so we don't need to do
 			 * changeDependencyFor().
 			 */
+
+			/* Post alter hook for the constraint */
+			InvokeObjectPostAlterHook(ConstraintRelationId,
+									  thisobj.objectId, 0);
 		}
 
 		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..9a0ead7 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,9 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
 		/* Update indexes */
 		CatalogUpdateIndexes(rel, newtuple);
 	}
-
+	/* Post alter hook for this database-role-settings */
+	InvokeObjectPostAlterHookArg(DbRoleSettingRelationId,
+								 databaseid, 0, roleid, false);
 	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 cf0ebcc..8c756eb 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -712,6 +712,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 */
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	heap_freetuple(tuple);
 	heap_close(pg_type_desc, RowExclusiveLock);
 
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 6f08210..5abdc34 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"
@@ -177,6 +178,9 @@ AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
 	simple_heap_update(rel, &oldtup->t_self, newtup);
 	CatalogUpdateIndexes(rel, newtup);
 
+	/* Post alter hook of the object */
+	InvokeObjectPostAlterHook(classId, objectId, 0);
+
 	/* Release memory */
 	pfree(values);
 	pfree(nulls);
@@ -560,6 +564,9 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
 	changeDependencyFor(classId, objid,
 						NamespaceRelationId, oldNspOid, nspOid);
 
+	/* Post alter hook for the object */
+	InvokeObjectPostAlterHook(classId, objid, 0);
+
 	return oldNspOid;
 }
 
@@ -836,5 +843,8 @@ AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
 		pfree(values);
 		pfree(nulls);
 		pfree(replaces);
+
+		/* Post alter hook for the object */
+		InvokeObjectPostAlterHook(classId, objectId, 0);
 	}
 }
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index c3deb56..f996cab 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -26,6 +26,7 @@
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
 #include "catalog/toasting.h"
 #include "commands/cluster.h"
 #include "commands/tablecmds.h"
@@ -465,7 +466,7 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMOD
  * otherwise concurrent executions of RelationGetIndexList could miss indexes.
  */
 void
-mark_index_clustered(Relation rel, Oid indexOid)
+mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
 {
 	HeapTuple	indexTuple;
 	Form_pg_index indexForm;
@@ -525,6 +526,9 @@ mark_index_clustered(Relation rel, Oid indexOid)
 			simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
 			CatalogUpdateIndexes(pg_index, indexTuple);
 		}
+		/* Post object alter hook of this index */
+		InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
+									 InvalidOid, is_internal);
 		heap_freetuple(indexTuple);
 	}
 
@@ -552,7 +556,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid,
 
 	/* Mark the correct index as clustered */
 	if (OidIsValid(indexOid))
-		mark_index_clustered(OldHeap, indexOid);
+		mark_index_clustered(OldHeap, indexOid, true);
 
 	/* Remember if it's a system catalog */
 	is_system_catalog = IsSystemRelation(OldHeap);
@@ -1495,13 +1499,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 458b573..9eecd2b 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"
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 09c06ed..4b6915d 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -965,6 +965,9 @@ RenameDatabase(const char *oldname, const char *newname)
 	simple_heap_update(rel, &newtup->t_self, newtup);
 	CatalogUpdateIndexes(rel, newtup);
 
+	/* Post alter hook for this database */
+	InvokeObjectPostAlterHook(DatabaseRelationId, db_id, 0);
+
 	/*
 	 * Close pg_database, but keep lock till commit.
 	 */
@@ -1200,6 +1203,10 @@ movedb(const char *dbname, const char *tblspcname)
 		/* Update indexes */
 		CatalogUpdateIndexes(pgdbrel, newtuple);
 
+		/* Post alter hook for this database */
+		InvokeObjectPostAlterHook(DatabaseRelationId,
+								  HeapTupleGetOid(newtuple), 0);
+
 		systable_endscan(sysscan);
 
 		/*
@@ -1394,6 +1401,10 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
 	/* Update indexes */
 	CatalogUpdateIndexes(rel, newtuple);
 
+	/* Post alter hook for this database */
+	InvokeObjectPostAlterHook(DatabaseRelationId,
+							  HeapTupleGetOid(newtuple), 0);
+
 	systable_endscan(scan);
 
 	/* Close pg_database, but keep lock till commit */
@@ -1525,6 +1536,10 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
 		/* Update owner dependency reference */
 		changeDependencyOnOwner(DatabaseRelationId, HeapTupleGetOid(tuple),
 								newOwnerId);
+
+		/* Post alter hook for the database */
+		InvokeObjectPostAlterHook(DatabaseRelationId,
+								  HeapTupleGetOid(tuple), 0);
 	}
 
 	systable_endscan(scan);
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 97dde84..ad32c9b 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -491,6 +491,9 @@ AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 	changeDependencyOnOwner(EventTriggerRelationId,
 							HeapTupleGetOid(tup),
 							newOwnerId);
+	/* Post alter hook for the event trigger */
+	InvokeObjectPostAlterHook(EventTriggerRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index e45de83..d067fec 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2360,6 +2360,9 @@ 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 */
+	InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
 }
 
 /*
@@ -2640,6 +2643,9 @@ ApplyExtensionUpdates(Oid extensionOid,
 			recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
 		}
 
+		/* Post alter hook for this extension */
+		InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
+
 		/*
 		 * Finally, execute the update script file
 		 */
@@ -2745,6 +2751,8 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 											DEPENDENCY_EXTENSION) != 1)
 			elog(ERROR, "unexpected number of extension dependency records");
 	}
+	/* Post alter hook of this extension */
+	InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
 
 	/*
 	 * 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 e2f86d2..152f07a 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -240,6 +240,10 @@ AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerI
 		changeDependencyOnOwner(ForeignDataWrapperRelationId,
 								HeapTupleGetOid(tup),
 								newOwnerId);
+
+		/* Post alter hook for the FDW */
+		InvokeObjectPostAlterHook(ForeignDataWrapperRelationId,
+								  HeapTupleGetOid(tup), 0);
 	}
 }
 
@@ -343,6 +347,10 @@ AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 		/* Update owner dependency reference */
 		changeDependencyOnOwner(ForeignServerRelationId, HeapTupleGetOid(tup),
 								newOwnerId);
+
+		/* Post alter hook for the foreign server */
+		InvokeObjectPostAlterHook(ForeignServerRelationId,
+								  HeapTupleGetOid(tup), 0);
 	}
 }
 
@@ -751,6 +759,8 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
 	}
+	/* Post alter hook of this FDW */
+	InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
@@ -978,6 +988,9 @@ AlterForeignServer(AlterForeignServerStmt *stmt)
 	simple_heap_update(rel, &tp->t_self, tp);
 	CatalogUpdateIndexes(rel, tp);
 
+	/* Post alter hook of this foreign server */
+	InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);
+
 	heap_freetuple(tp);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 26a806b..91f9fdc 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1222,7 +1222,7 @@ AlterFunction(AlterFunctionStmt *stmt)
 	/* Do the update */
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
-
+	InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 }
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index c8e0e75..35f10b5 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -1370,6 +1370,9 @@ storeOperators(List *opfamilyname, Oid amoid,
 			referenced.objectSubId = 0;
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
+		/* Post create hook of this access method operator */
+		InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
+								   entryoid, 0);
 	}
 
 	heap_close(rel, RowExclusiveLock);
@@ -1469,6 +1472,9 @@ storeProcedures(List *opfamilyname, Oid amoid,
 			referenced.objectSubId = 0;
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 		}
+		/* Post create hook of access method procedure */
+		InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
+								   entryoid, 0);
 	}
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index e69c86b..d1fa45c 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,8 @@ RenameSchema(const char *oldname, const char *newname)
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
 
+	InvokeObjectPostAlterHook(NamespaceRelationId, HeapTupleGetOid(tup), 0);
+
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 }
@@ -362,6 +365,10 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
 		/* Update owner dependency reference */
 		changeDependencyOnOwner(NamespaceRelationId, HeapTupleGetOid(tup),
 								newOwnerId);
+
+		/* Post alter hook for the namespace */
+		InvokeObjectPostAlterHook(NamespaceRelationId,
+								  HeapTupleGetOid(tup), 0);
 	}
 
 }
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 634ce3f..3829003 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,9 @@ AlterSequence(AlterSeqStmt *stmt)
 	if (owned_by)
 		process_owned_by(seqrel, owned_by);
 
+	/* Post alter hook of this sequence */
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
+
 	relation_close(seqrel, NoLock);
 }
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d516e2a..3b970b2 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
@@ -1955,6 +1955,11 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
 
 	recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL);
 
+	/* Post creation hook of this inheritance */
+	InvokeObjectPostAlterHookArg(InheritsRelationId,
+								 relationId, 0,
+								 parentOid, false);
+
 	/*
 	 * Mark the parent as having subclasses.
 	 */
@@ -2213,6 +2218,9 @@ renameatt_internal(Oid myrelid,
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, atttup);
 
+	/* Post alter hook for this attribute */
+	InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
+
 	heap_freetuple(atttup);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -2357,7 +2365,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);
 
@@ -2433,7 +2441,7 @@ RenameRelation(RenameStmt *stmt)
 	}
 
 	/* Do the work */
-	RenameRelationInternal(relid, stmt->newname);
+	RenameRelationInternal(relid, stmt->newname, false);
 }
 
 /*
@@ -2446,7 +2454,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 */
@@ -2488,6 +2496,10 @@ RenameRelationInternal(Oid myrelid, const char *newrelname)
 	/* keep the system catalog indexes current */
 	CatalogUpdateIndexes(relrelation, reltup);
 
+	/* Post alter hook for this relation */
+	InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
+								 InvalidOid, is_internal);
+
 	heap_freetuple(reltup);
 	heap_close(relrelation, RowExclusiveLock);
 
@@ -4489,7 +4501,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();
@@ -4825,8 +4838,10 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
 
 		/* keep the system catalog indexes current */
 		CatalogUpdateIndexes(attr_rel, tuple);
-	}
 
+		InvokeObjectPostAlterHook(RelationRelationId,
+								  RelationGetRelid(rel), attnum);
+	}
 	heap_close(attr_rel, RowExclusiveLock);
 }
 
@@ -4875,6 +4890,9 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
 		/* keep the system catalog indexes current */
 		CatalogUpdateIndexes(attr_rel, tuple);
 
+		InvokeObjectPostAlterHook(RelationRelationId,
+								  RelationGetRelid(rel), attnum);
+
 		/* Tell Phase 3 it needs to test the constraint */
 		tab->new_notnull = true;
 	}
@@ -4933,7 +4951,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, true, false);
 	}
 }
 
@@ -5017,6 +5036,9 @@ ATExecSetStatistics(Relation rel, const char *colName, Node *newValue, LOCKMODE
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, tuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(tuple);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -5074,13 +5096,17 @@ 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);
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(newtuple);
 
+	ReleaseSysCache(tuple);
+
 	heap_close(attrelation, RowExclusiveLock);
 }
 
@@ -5150,6 +5176,9 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, tuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(tuple);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -5464,7 +5493,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 */
@@ -5488,7 +5517,8 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
 							stmt->primary,
 							true, /* update pg_index */
 							true, /* remove old dependencies */
-							allowSystemTableMods);
+							allowSystemTableMods,
+							false);	/* is_internal */
 
 	index_close(indexRel, NoLock);
 }
@@ -5600,7 +5630,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)
@@ -6050,7 +6081,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.
@@ -6232,6 +6264,8 @@ ATExecValidateConstraint(Relation rel, char *constrName, bool recurse,
 		copy_con->convalidated = true;
 		simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
 		CatalogUpdateIndexes(conrel, copyTuple);
+		InvokeObjectPostAlterHook(ConstraintRelationId,
+								  HeapTupleGetOid(tuple), 0);
 		heap_freetuple(copyTuple);
 	}
 
@@ -7659,6 +7693,10 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 	 */
 	RemoveStatistics(RelationGetRelid(rel), attnum);
 
+	/* Post alter hook of this column */
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
+
 	/*
 	 * Update the default, if present, by brute force --- remove and re-add
 	 * the default.  Probably unsafe to take shortcuts, since the new version
@@ -7678,7 +7716,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 		RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
 						  true);
 
-		StoreAttrDefault(rel, attnum, defaultexpr);
+		StoreAttrDefault(rel, attnum, defaultexpr, true);
 	}
 
 	/* Cleanup */
@@ -7769,10 +7807,13 @@ 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);
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  atttableform->attnum);
+	ReleaseSysCache(tuple);
 
 	heap_close(attrel, RowExclusiveLock);
 
@@ -8183,7 +8224,7 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 
 		simple_heap_update(class_rel, &newtuple->t_self, newtuple);
 		CatalogUpdateIndexes(class_rel, newtuple);
-
+		InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
 		heap_freetuple(newtuple);
 
 		/*
@@ -8406,7 +8447,7 @@ ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
 	check_index_is_clusterable(rel, indexOid, false, lockmode);
 
 	/* And do the work */
-	mark_index_clustered(rel, indexOid);
+	mark_index_clustered(rel, indexOid, false);
 }
 
 /*
@@ -8418,7 +8459,7 @@ ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
 static void
 ATExecDropCluster(Relation rel, LOCKMODE lockmode)
 {
-	mark_index_clustered(rel, InvalidOid);
+	mark_index_clustered(rel, InvalidOid, false);
 }
 
 /*
@@ -8538,6 +8579,8 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 
 	CatalogUpdateIndexes(pgclass, newtuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
+
 	heap_freetuple(newtuple);
 
 	ReleaseSysCache(tuple);
@@ -8595,6 +8638,10 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 
 		CatalogUpdateIndexes(pgclass, newtuple);
 
+		InvokeObjectPostAlterHookArg(RelationRelationId,
+									 RelationGetRelid(toastrel), 0,
+									 InvalidOid, true);
+
 		heap_freetuple(newtuple);
 
 		ReleaseSysCache(tuple);
@@ -9421,6 +9468,11 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
 						   RelationRelationId,
 						   RelationGetRelid(parent_rel));
 
+	/* Post alter hook of this inherits */
+	InvokeObjectPostAlterHookArg(InheritsRelationId,
+								 RelationGetRelid(rel), 0,
+								 RelationGetRelid(parent_rel), false);
+
 	/* keep our lock on the parent relation until commit */
 	heap_close(parent_rel, NoLock);
 }
@@ -9603,6 +9655,7 @@ 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);
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
 	heap_freetuple(classtuple);
 	heap_close(relationRelation, RowExclusiveLock);
 
@@ -9643,6 +9696,7 @@ ATExecDropOf(Relation rel, LOCKMODE lockmode)
 	((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
 	simple_heap_update(relationRelation, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(relationRelation, tuple);
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
 	heap_freetuple(tuple);
 	heap_close(relationRelation, RowExclusiveLock);
 }
@@ -9712,6 +9766,9 @@ ATExecGenericOptions(Relation rel, List *options)
 	simple_heap_update(ftrel, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(ftrel, tuple);
 
+	InvokeObjectPostAlterHook(ForeignTableRelationId,
+							  RelationGetRelid(rel), 0);
+
 	heap_close(ftrel, RowExclusiveLock);
 
 	heap_freetuple(tuple);
@@ -9865,6 +9922,9 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
 				 NameStr(classForm->relname));
 
 		add_exact_object_address(&thisobj, objsMoved);
+
+		/* Post alter hook for this relation */
+		InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
 	}
 
 	heap_freetuple(classTup);
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index e794ecf..ade5d75 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -862,6 +862,8 @@ RenameTableSpace(const char *oldname, const char *newname)
 	/* OK, update the entry */
 	AlterObjectRename_internal(rel, tableSpaceId, newname);
 
+	InvokeObjectPostAlterHook(TableSpaceRelationId, tableSpaceId, 0);
+
 	heap_close(rel, NoLock);
 }
 
@@ -925,6 +927,7 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
 	/* Update system catalog. */
 	simple_heap_update(rel, &newtuple->t_self, newtuple);
 	CatalogUpdateIndexes(rel, newtuple);
+	InvokeObjectPostAlterHook(TableSpaceRelationId, HeapTupleGetOid(tup), 0);
 	heap_freetuple(newtuple);
 
 	/* Conclude heap scan. */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 4a369a4..9a66a5b 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,7 +742,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 							   DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new trigger */
-	InvokeObjectPostCreateHook(TriggerRelationId, trigoid, 0);
+	InvokeObjectPostCreateHookArg(TriggerRelationId, trigoid, 0,
+								  isInternal);
 
 	/* Keep lock on target rel until end of xact */
 	heap_close(rel, NoLock);
@@ -1273,6 +1275,10 @@ renametrig(RenameStmt *stmt)
 		/* keep system catalog indexes current */
 		CatalogUpdateIndexes(tgrel, tuple);
 
+		/* Post alter hook for this trigger */
+		InvokeObjectPostAlterHook(TriggerRelationId,
+								  HeapTupleGetOid(tuple), 0);
+
 		/*
 		 * Invalidate relation's relcache entry so that other backends (and
 		 * this one too!) are sent SI message to make them rebuild relcache
@@ -1382,6 +1388,10 @@ EnableDisableTrigger(Relation rel, const char *tgname,
 			/* Keep catalog indexes current */
 			CatalogUpdateIndexes(tgrel, newtup);
 
+			/* Post alter hook for this trigger */
+			InvokeObjectPostAlterHook(TriggerRelationId,
+									  HeapTupleGetOid(newtup), 0);
+
 			heap_freetuple(newtup);
 
 			changed = true;
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 64e9885..61342d2 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -608,6 +608,8 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
 
 	CatalogUpdateIndexes(rel, newtup);
 
+	InvokeObjectPostAlterHook(TSDictionaryRelationId, dictId, 0);
+
 	/*
 	 * NOTE: because we only support altering the options, not the template,
 	 * there is no need to update dependencies.  This might have to change if
@@ -1171,6 +1173,9 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
 	/* Update dependencies */
 	makeConfigurationDependencies(tup, true, relMap);
 
+	InvokeObjectPostAlterHook(TSConfigMapRelationId,
+							  HeapTupleGetOid(tup), 0);
+
 	heap_close(relMap, RowExclusiveLock);
 
 	ReleaseSysCache(tup);
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 8418096..c33538c 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,9 @@ AlterEnum(AlterEnumStmt *stmt)
 				 stmt->newValNeighbor, stmt->newValIsAfter, 
 				 stmt->skipIfExists);
 
+	/* Post alter hook of this enum type */
+	InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
+
 	ReleaseSysCache(tup);
 }
 
@@ -2164,7 +2168,8 @@ AlterDomainDefault(List *names, Node *defaultRaw)
 							 typTup->typcollation,
 							 defaultExpr,
 							 true);		/* Rebuild is true */
-
+	/* Post alter hook of this domain */
+	InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
 	/* Clean up */
 	heap_close(rel, NoLock);
 	heap_freetuple(newtuple);
@@ -2261,6 +2266,9 @@ AlterDomainNotNull(List *names, bool notNull)
 
 	CatalogUpdateIndexes(typrel, tup);
 
+	/* Post alter hook of this domain */
+	InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
+
 	/* Clean up */
 	heap_freetuple(tup);
 	heap_close(typrel, RowExclusiveLock);
@@ -2542,6 +2550,8 @@ AlterDomainValidateConstraint(List *names, char *constrName)
 	copy_con->convalidated = true;
 	simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
 	CatalogUpdateIndexes(conrel, copyTuple);
+	InvokeObjectPostAlterHook(ConstraintRelationId,
+							  HeapTupleGetOid(copyTuple), 0);
 	heap_freetuple(copyTuple);
 
 	systable_endscan(scan);
@@ -2940,7 +2950,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 +3146,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 +3267,9 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
 			/* Update owner dependency reference */
 			changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
 
+			/* Post alter hook of this type */
+			InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 			/* If it has an array type, update that too */
 			if (OidIsValid(typTup->typarray))
 				AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
@@ -3276,6 +3290,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 +3325,9 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
 	if (OidIsValid(typTup->typarray))
 		AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
 
+	/* Post alter hook for the type */
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	/* Clean up */
 	heap_close(rel, RowExclusiveLock);
 }
@@ -3494,6 +3513,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 */
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	heap_freetuple(tup);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index c1b7b93..2b17675 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -775,6 +775,9 @@ AlterRole(AlterRoleStmt *stmt)
 	/* Update indexes */
 	CatalogUpdateIndexes(pg_authid_rel, new_tuple);
 
+	/* Post alter hook of this role */
+	InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
+
 	ReleaseSysCache(tuple);
 	heap_freetuple(new_tuple);
 
@@ -1128,6 +1131,8 @@ RenameRole(const char *oldname, const char *newname)
 
 	CatalogUpdateIndexes(rel, newtuple);
 
+	InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
+
 	ReleaseSysCache(oldtuple);
 
 	/*
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 17e3513..b27d35e 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -731,6 +731,8 @@ EnableDisableRule(Relation rel, const char *rulename,
 		/* keep system catalog indexes current */
 		CatalogUpdateIndexes(pg_rewrite_desc, ruletup);
 
+		InvokeObjectPostAlterHook(RewriteRelationId,
+								  HeapTupleGetOid(ruletup), 0);
 		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 b96099f..225ee73 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -72,7 +72,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 9d1937d..614d8e7 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,
@@ -70,10 +98,14 @@ extern void InvokeObjectPostCreateHookArg(Oid classId, Oid objectId, int subId,
 										  bool is_internal);
 extern void InvokeObjectDropHookArg(Oid classId, Oid objectId, int subId,
 									int dropflags);
+extern void InvokeObjectPostAlterHookArg(Oid classId, Oid objectId, int subId,
+										 Oid auxiliaryId, bool is_internal);
 
 #define InvokeObjectPostCreateHook(classId,objectId,subId)	\
 	InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
 #define InvokeObjectDropHook(classId,objectId,subId)	\
 	InvokeObjectDropHookArg((classId),(objectId),(subId),0)
+#define InvokeObjectPostAlterHook(classId,objectId,subId)	\
+	InvokeObjectPostAlterHookArg((classId),(objectId),(subId),InvalidOid,false)
 
 #endif   /* OBJECTACCESS_H */
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/cluster.h b/src/include/commands/cluster.h
index 21b2a58..490b3ba 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -23,7 +23,7 @@ extern void cluster_rel(Oid tableOid, Oid indexOid, bool recheck,
 			bool verbose, int freeze_min_age, int freeze_table_age);
 extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
 						   bool recheck, LOCKMODE lockmode);
-extern void mark_index_clustered(Relation rel, Oid indexOid);
+extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
 
 extern Oid	make_new_heap(Oid OIDOldHeap, Oid NewTableSpace);
 extern void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
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,
#8Robert Haas
robertmhaas@gmail.com
In reply to: Kohei KaiGai (#4)
Re: [v9.3] OAT_POST_ALTER object access hooks

On Tue, Nov 20, 2012 at 8:43 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

I'd like to have catalog/objectaccess.c to wrap-up invocation of hooks, rather
than doing all the stuffs with macros. It allows to use local variables, unlike
macros; that has a risk of naming conflict with temporary variable for
ObjectAccessPostCreate.

So, how about to have a following definition for example?

void
InvokePostAlterHookArgs(Oid classId, Oid objectId, int subId,
Oid auxiliaryId, bool is_internal)
{
if (object_access_hook)
{
ObjectAccessPostAlter pa_arg;

memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
pa_arg.auxiliary_id = auxiliary_id;
pa_arg.is_internal = is_internal;
(*object_access_hook)(OAT_POST_ALTER,
classId, objectId, subId,
(void *) &pa_arg);
}
}

and

#define InvokePostAlterHook(classId, objectId, subId) \
InvokePostAlterHookArgs(classId, objectId, subId, InvalidOid, false)

for most points to call.

This has the disadvantage of incurring the overhead of a function call
even if (as will typically be the case) there is no object access
hook. I still prefer having the if (object_access_hook) test in the
macro, though of course I have no problem with having the macro call
a function if it's set.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#9Robert Haas
robertmhaas@gmail.com
In reply to: Kohei KaiGai (#7)
Re: [v9.3] OAT_POST_ALTER object access hooks

On Sat, Dec 1, 2012 at 2:57 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

* Do we need OAT_POST_ALTER hook even if no fields were updated
actually? In case when ALTER SET OWNER, it checks object's ownership
only when current and new user-id is not same. Right now, I follow this
manner on OAT_POST_ALTER invocation.
However, I'm inclined to consider the hook should be invoked when no
fields are actually updated also. (It allows extension-side to determine
necessity of processing something.)

I agree. I think it should always be called.

* When tablespace of relation was changed, it seems to me the point to
invoke OAT_POST_ALTER hook should be "after" ATRewriteTable().
However, it usually long time to rewrite whole the table if it already have
large number of rows. I'm not 100% certain to put hook here, so this
version does not support hook when tablespace changes.

Well, if it's a post-alter hook, it should presumably happen as close
to the end of processing as possible. But are you sure that's really
what you want? I would think that for SE-Linux you'd be wanting to
get control much earlier in the process.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#10Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Robert Haas (#8)
Re: [v9.3] OAT_POST_ALTER object access hooks

2012/12/3 Robert Haas <robertmhaas@gmail.com>:

On Tue, Nov 20, 2012 at 8:43 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

I'd like to have catalog/objectaccess.c to wrap-up invocation of hooks, rather
than doing all the stuffs with macros. It allows to use local variables, unlike
macros; that has a risk of naming conflict with temporary variable for
ObjectAccessPostCreate.

So, how about to have a following definition for example?

void
InvokePostAlterHookArgs(Oid classId, Oid objectId, int subId,
Oid auxiliaryId, bool is_internal)
{
if (object_access_hook)
{
ObjectAccessPostAlter pa_arg;

memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
pa_arg.auxiliary_id = auxiliary_id;
pa_arg.is_internal = is_internal;
(*object_access_hook)(OAT_POST_ALTER,
classId, objectId, subId,
(void *) &pa_arg);
}
}

and

#define InvokePostAlterHook(classId, objectId, subId) \
InvokePostAlterHookArgs(classId, objectId, subId, InvalidOid, false)

for most points to call.

This has the disadvantage of incurring the overhead of a function call
even if (as will typically be the case) there is no object access
hook. I still prefer having the if (object_access_hook) test in the
macro, though of course I have no problem with having the macro call
a function if it's set.

OK, I'll adjust the macro definitions to reduce empty function calls.

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#11Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Robert Haas (#9)
Re: [v9.3] OAT_POST_ALTER object access hooks

2012/12/3 Robert Haas <robertmhaas@gmail.com>:

On Sat, Dec 1, 2012 at 2:57 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

* Do we need OAT_POST_ALTER hook even if no fields were updated
actually? In case when ALTER SET OWNER, it checks object's ownership
only when current and new user-id is not same. Right now, I follow this
manner on OAT_POST_ALTER invocation.
However, I'm inclined to consider the hook should be invoked when no
fields are actually updated also. (It allows extension-side to determine
necessity of processing something.)

I agree. I think it should always be called.

OK, I'll move the point to invoke hooks into outside of the if-block.

* When tablespace of relation was changed, it seems to me the point to
invoke OAT_POST_ALTER hook should be "after" ATRewriteTable().
However, it usually long time to rewrite whole the table if it already have
large number of rows. I'm not 100% certain to put hook here, so this
version does not support hook when tablespace changes.

Well, if it's a post-alter hook, it should presumably happen as close
to the end of processing as possible. But are you sure that's really
what you want? I would think that for SE-Linux you'd be wanting to
get control much earlier in the process.

In my preference, an error shall be raised prior to whole of the table
rewrite stuff; it can take exclusive table lock during possible TB or PB
of disk-i/o. Even if sepgsql got control after all and raise an access
control error, I'm not happy so much. :-(

As we discussed before, it is hard to determine which attributes shall
be informed to extension via object_access_hook, so the proposed
post-alter hook (that allows to compare older and newer versions)
works fine on 99% cases.
However, I'm inclined to handle SET TABLESPACE as an exception
of this scenario. For example, an idea is to define OAT_PREP_ALTER
event additionally, but only invoked very limited cases that takes
unignorable side-effects until system catalog updates.
For consistency of hook, OAT_POST_ALTER event may also ought
to be invoked just after catalog updates of pg_class->reltablespace,
but is_internal=true.

How about your opinion?

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#12Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Kohei KaiGai (#11)
2 attachment(s)
Re: [v9.3] OAT_POST_ALTER object access hooks

Revised patches are attached.

At the part-1, I adjusted macro definitions to have NULL check for
object_access_hook prior to its invocation, as follows:

+#define InvokeObjectPostCreateHook(classId,objectId,subId)         \
+   InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
+#define InvokeObjectPostCreateHookArg(classId,objectId,subId,is_internal) \
+   do {                                                            \
+       if (object_access_hook)                                     \
+           RunObjectPostCreateHook((classId),(objectId),(subId),   \
+                                   (is_internal));                 \
+   } while(0)

At the part-2, I adjusted invocation points of the hook, to allow
extensions to get control even if no fields are actually updated.
Typically, it was moved to outside of the if-block that checks
whether old-owner is identical with new-owner on ALTER OWNER
TO commands.
Also, I added OAT_PREP_ALTER event type to handle case of
ALTER ... SET TABLESPACE command well, to prevent unauthorized
execution of whole of the table rewrite, even though it shall be eventually
blocked by OAT_POST_ALTER event.

Thanks,

2012/12/3 Kohei KaiGai <kaigai@kaigai.gr.jp>:

2012/12/3 Robert Haas <robertmhaas@gmail.com>:

On Sat, Dec 1, 2012 at 2:57 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

* Do we need OAT_POST_ALTER hook even if no fields were updated
actually? In case when ALTER SET OWNER, it checks object's ownership
only when current and new user-id is not same. Right now, I follow this
manner on OAT_POST_ALTER invocation.
However, I'm inclined to consider the hook should be invoked when no
fields are actually updated also. (It allows extension-side to determine
necessity of processing something.)

I agree. I think it should always be called.

OK, I'll move the point to invoke hooks into outside of the if-block.

* When tablespace of relation was changed, it seems to me the point to
invoke OAT_POST_ALTER hook should be "after" ATRewriteTable().
However, it usually long time to rewrite whole the table if it already have
large number of rows. I'm not 100% certain to put hook here, so this
version does not support hook when tablespace changes.

Well, if it's a post-alter hook, it should presumably happen as close
to the end of processing as possible. But are you sure that's really
what you want? I would think that for SE-Linux you'd be wanting to
get control much earlier in the process.

In my preference, an error shall be raised prior to whole of the table
rewrite stuff; it can take exclusive table lock during possible TB or PB
of disk-i/o. Even if sepgsql got control after all and raise an access
control error, I'm not happy so much. :-(

As we discussed before, it is hard to determine which attributes shall
be informed to extension via object_access_hook, so the proposed
post-alter hook (that allows to compare older and newer versions)
works fine on 99% cases.
However, I'm inclined to handle SET TABLESPACE as an exception
of this scenario. For example, an idea is to define OAT_PREP_ALTER
event additionally, but only invoked very limited cases that takes
unignorable side-effects until system catalog updates.
For consistency of hook, OAT_POST_ALTER event may also ought
to be invoked just after catalog updates of pg_class->reltablespace,
but is_internal=true.

How about your opinion?

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

sepgsql-v9.3-post-alter-support.v4.part-2.patchapplication/octet-stream; name=sepgsql-v9.3-post-alter-support.v4.part-2.patchDownload
 contrib/sepgsql/database.c               |   27 +++++
 contrib/sepgsql/expected/alter.out       |  192 ++++++++++++++++++++++++++++++
 contrib/sepgsql/expected/ddl.out         |    9 ++
 contrib/sepgsql/hooks.c                  |   66 ++++++++++
 contrib/sepgsql/proc.c                   |   90 +++++++++++++-
 contrib/sepgsql/relation.c               |  103 ++++++++++++++--
 contrib/sepgsql/schema.c                 |   51 ++++++++
 contrib/sepgsql/sepgsql.h                |    8 ++
 contrib/sepgsql/sql/alter.sql            |  136 +++++++++++++++++++++
 contrib/sepgsql/sql/ddl.sql              |    6 +
 contrib/sepgsql/test_sepgsql             |    2 +-
 doc/src/sgml/sepgsql.sgml                |   21 +++-
 src/backend/catalog/aclchk.c             |    9 ++
 src/backend/catalog/heap.c               |   41 +++++--
 src/backend/catalog/index.c              |   12 +-
 src/backend/catalog/objectaccess.c       |   45 +++++++
 src/backend/catalog/pg_constraint.c      |   11 +-
 src/backend/catalog/pg_db_role_setting.c |    5 +-
 src/backend/catalog/pg_type.c            |    3 +
 src/backend/commands/alter.c             |    9 ++
 src/backend/commands/cluster.c           |   20 +++-
 src/backend/commands/collationcmds.c     |    1 +
 src/backend/commands/dbcommands.c        |   13 ++
 src/backend/commands/event_trigger.c     |    3 +
 src/backend/commands/extension.c         |    8 ++
 src/backend/commands/foreigncmds.c       |   11 ++
 src/backend/commands/functioncmds.c      |    2 +-
 src/backend/commands/opclasscmds.c       |    6 +
 src/backend/commands/schemacmds.c        |    7 +-
 src/backend/commands/sequence.c          |    4 +
 src/backend/commands/tablecmds.c         |   99 ++++++++++++---
 src/backend/commands/tablespace.c        |    3 +
 src/backend/commands/trigger.c           |   13 +-
 src/backend/commands/tsearchcmds.c       |    5 +
 src/backend/commands/typecmds.c          |   28 ++++-
 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       |   74 ++++++++++++
 src/include/catalog/pg_constraint.h      |    3 +-
 src/include/commands/cluster.h           |    2 +-
 src/include/commands/tablecmds.h         |    2 +-
 43 files changed, 1101 insertions(+), 65 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..ef9abb3
--- /dev/null
+++ b/contrib/sepgsql/expected/alter.out
@@ -0,0 +1,192 @@
+--
+-- 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
+--
+-- XXX: It should take db_xxx:{setattr} permission checks even if
+--      owner is not actually changed.
+--
+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 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 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 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 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 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 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
+ALTER TABLE regtest_table SET TABLESPACE pg_default;
+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 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..5ba3dd9 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -188,6 +188,72 @@ sepgsql_object_access(ObjectAccessType access,
 			}
 			break;
 
+		case OAT_PREP_ALTER:
+			{
+				ObjectAccessPrepAlter *pa_arg = arg;
+
+				switch (classId)
+				{
+					case RelationRelationId:
+						Assert(subId == 0);
+						sepgsql_relation_set_tablespace(objectId,
+														pa_arg->tablespaceId);
+						break;
+					default:
+						/* Ignore unsupported object classes */
+						break;
+				}
+			}
+			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..7ed4da9 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
@@ -529,6 +559,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 +590,78 @@ 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);
+
+	/*
+	 * 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);
 
 	/*
-	 * 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.
+	 * 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);
+}
+
+/*
+ * sepgsql_relation_set_tablespace
+ *
+ * It checks privileges to set tablespace of the supplied relation
+ */
+void
+sepgsql_relation_set_tablespace(Oid relOid, Oid tablespaceId)
+{
+	/* check db_xxx:{setattr} permission */
+	sepgsql_relation_setattr(relOid);
+
+	/*
+	 * XXX - In the future version, we also check db_tuple:{use}
+	 * permission onto relevant tuple in the pg_tablespace catalog.
+	 */
 }
 
 /*
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..94ecbb0 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,10 +313,12 @@ 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);
 extern void sepgsql_relation_setattr(Oid relOid);
+extern void sepgsql_relation_set_tablespace(Oid relOid, Oid tablespaceId);
 
 /*
  * proc.c
@@ -319,5 +326,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..4bded7e
--- /dev/null
+++ b/contrib/sepgsql/sql/alter.sql
@@ -0,0 +1,136 @@
+--
+-- 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
+--
+-- XXX: It should take db_xxx:{setattr} permission checks even if
+--      owner is not actually changed.
+--
+ALTER DATABASE regtest_sepgsql_test_database_1 OWNER TO regtest_sepgsql_test_user;
+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 SCHEMA regtest_schema_1 OWNER TO regtest_sepgsql_test_user;
+ALTER TABLE regtest_table_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 SEQUENCE regtest_seq_1 OWNER TO regtest_sepgsql_test_user;
+ALTER VIEW regtest_view_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 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
+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..07788d9 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,14 @@ SetDefaultACL(InternalDefaultACL *iacls)
 							  iacls->roleid,
 							  noldmembers, oldmembers,
 							  nnewmembers, newmembers);
+
+		/* Post create or alter hook of this default ACL */
+		if (isNew)
+			InvokeObjectPostCreateHook(DefaultAclRelationId,
+									   HeapTupleGetOid(newtuple), 0);
+		else
+			InvokeObjectPostAlterHook(DefaultAclRelationId,
+									  HeapTupleGetOid(newtuple), 0);
 	}
 
 	if (HeapTupleIsValid(tuple))
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 54de9a7..f482656 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -95,8 +95,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);
@@ -1286,7 +1287,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
@@ -1799,7 +1800,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;
@@ -1891,6 +1893,17 @@ 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.
+	 */
+	InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
+								  RelationGetRelid(rel), attnum, is_internal);
 }
 
 /*
@@ -1902,7 +1915,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;
@@ -1986,7 +1999,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);
@@ -2001,7 +2015,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;
@@ -2023,11 +2037,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:
@@ -2053,6 +2068,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.
@@ -2070,7 +2086,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;
@@ -2133,7 +2150,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;
@@ -2259,7 +2276,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 b1091ac..bc20725 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -932,7 +932,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
 		{
@@ -1106,6 +1107,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,
@@ -1118,7 +1120,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,
@@ -1183,7 +1186,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.
@@ -1292,6 +1296,8 @@ index_constraint_create(Relation heapRelation,
 		{
 			simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
 			CatalogUpdateIndexes(pg_index, indexTuple);
+			InvokeObjectPostAlterHookArg(IndexRelationId, indexRelationId, 0,
+										 InvalidOid, is_internal);
 		}
 
 		heap_freetuple(indexTuple);
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
index 79c1136..cf48bef 100644
--- a/src/backend/catalog/objectaccess.c
+++ b/src/backend/catalog/objectaccess.c
@@ -61,3 +61,48 @@ RunObjectDropHook(Oid classId, Oid objectId, int subId,
 						  classId, objectId, subId,
 						  (void *) &drop_arg);
 }
+
+/*
+ * RunObjectPrepAlterHook
+ *
+ * It is entrypoint of OAT_PREP_ALTER event
+ */
+void
+RunObjectPrepAlterHook(Oid classId, Oid objectId, int subId,
+					   Oid tablespaceId)
+{
+	ObjectAccessPrepAlter	pa_arg;
+
+	/* XXX - should be checked at caller side */
+	Assert(object_access_hook != NULL);
+
+	memset(&pa_arg, 0, sizeof(ObjectAccessPrepAlter));
+	pa_arg.tablespaceId = tablespaceId;
+
+	(*object_access_hook)(OAT_PREP_ALTER,
+						  classId, objectId, subId,
+						  (void *) &pa_arg);
+}
+
+/*
+ * RunObjectPostAlterHook
+ *
+ * It is entrypoint of OAT_POST_ALTER event
+ */
+void
+RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
+					   Oid auxiliaryId, bool is_internal)
+{
+	ObjectAccessPostAlter	pa_arg;
+
+	/* XXX - should be checked at caller side */
+	Assert(object_access_hook != NULL);
+
+	memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
+	pa_arg.auxiliary_id = auxiliaryId;
+	pa_arg.is_internal = is_internal;
+
+	(*object_access_hook)(OAT_POST_ALTER,
+						  classId, objectId, subId,
+						  (void *) &pa_arg);
+}
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 1e6d947..de5bc81 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,7 +368,8 @@ CreateConstraintEntry(const char *constraintName,
 	}
 
 	/* Post creation hook for new constraint */
-	InvokeObjectPostCreateHook(ConstraintRelationId, conOid, 0);
+	InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0,
+								  is_internal);
 
 	return conOid;
 }
@@ -665,6 +667,9 @@ RenameConstraintById(Oid conId, const char *newname)
 	/* update the system catalog indexes */
 	CatalogUpdateIndexes(conDesc, tuple);
 
+	/* Post alter hook for this constraint */
+	InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0);
+
 	heap_freetuple(tuple);
 	heap_close(conDesc, RowExclusiveLock);
 }
@@ -736,6 +741,8 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 			 * changeDependencyFor().
 			 */
 		}
+		/* Post alter hook for the constraint */
+		InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0);
 
 		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..9a0ead7 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,9 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
 		/* Update indexes */
 		CatalogUpdateIndexes(rel, newtuple);
 	}
-
+	/* Post alter hook for this database-role-settings */
+	InvokeObjectPostAlterHookArg(DbRoleSettingRelationId,
+								 databaseid, 0, roleid, false);
 	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 cf0ebcc..8c756eb 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -712,6 +712,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 */
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	heap_freetuple(tuple);
 	heap_close(pg_type_desc, RowExclusiveLock);
 
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 6f08210..5b257ff 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"
@@ -177,6 +178,9 @@ AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
 	simple_heap_update(rel, &oldtup->t_self, newtup);
 	CatalogUpdateIndexes(rel, newtup);
 
+	/* Post alter hook of the object */
+	InvokeObjectPostAlterHook(classId, objectId, 0);
+
 	/* Release memory */
 	pfree(values);
 	pfree(nulls);
@@ -560,6 +564,9 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
 	changeDependencyFor(classId, objid,
 						NamespaceRelationId, oldNspOid, nspOid);
 
+	/* Post alter hook for the object */
+	InvokeObjectPostAlterHook(classId, objid, 0);
+
 	return oldNspOid;
 }
 
@@ -837,4 +844,6 @@ AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
 		pfree(nulls);
 		pfree(replaces);
 	}
+	/* Post alter hook for the object */
+	InvokeObjectPostAlterHook(classId, objectId, 0);
 }
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index c3deb56..65abd20 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -26,6 +26,7 @@
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
 #include "catalog/toasting.h"
 #include "commands/cluster.h"
 #include "commands/tablecmds.h"
@@ -465,7 +466,7 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMOD
  * otherwise concurrent executions of RelationGetIndexList could miss indexes.
  */
 void
-mark_index_clustered(Relation rel, Oid indexOid)
+mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
 {
 	HeapTuple	indexTuple;
 	Form_pg_index indexForm;
@@ -525,6 +526,9 @@ mark_index_clustered(Relation rel, Oid indexOid)
 			simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
 			CatalogUpdateIndexes(pg_index, indexTuple);
 		}
+		/* Post object alter hook of this index */
+		InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
+									 InvalidOid, is_internal);
 		heap_freetuple(indexTuple);
 	}
 
@@ -552,7 +556,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid,
 
 	/* Mark the correct index as clustered */
 	if (OidIsValid(indexOid))
-		mark_index_clustered(OldHeap, indexOid);
+		mark_index_clustered(OldHeap, indexOid, true);
 
 	/* Remember if it's a system catalog */
 	is_system_catalog = IsSystemRelation(OldHeap);
@@ -1257,6 +1261,14 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 	}
 
 	/*
+	 * Post alter hook of these relations, but with is_internal=true
+	 */
+	InvokeObjectPostAlterHookArg(RelationRelationId, r1, 0,
+								 InvalidOid, true);
+	InvokeObjectPostAlterHookArg(RelationRelationId, r2, 0,
+								 InvalidOid, true);
+
+	/*
 	 * If we have toast tables associated with the relations being swapped,
 	 * deal with them too.
 	 */
@@ -1495,13 +1507,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 458b573..9eecd2b 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"
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 09c06ed..8695a52 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -965,6 +965,9 @@ RenameDatabase(const char *oldname, const char *newname)
 	simple_heap_update(rel, &newtup->t_self, newtup);
 	CatalogUpdateIndexes(rel, newtup);
 
+	/* Post alter hook for this database */
+	InvokeObjectPostAlterHook(DatabaseRelationId, db_id, 0);
+
 	/*
 	 * Close pg_database, but keep lock till commit.
 	 */
@@ -1200,6 +1203,10 @@ movedb(const char *dbname, const char *tblspcname)
 		/* Update indexes */
 		CatalogUpdateIndexes(pgdbrel, newtuple);
 
+		/* Post alter hook for this database */
+		InvokeObjectPostAlterHook(DatabaseRelationId,
+								  HeapTupleGetOid(newtuple), 0);
+
 		systable_endscan(sysscan);
 
 		/*
@@ -1394,6 +1401,10 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
 	/* Update indexes */
 	CatalogUpdateIndexes(rel, newtuple);
 
+	/* Post alter hook for this database */
+	InvokeObjectPostAlterHook(DatabaseRelationId,
+							  HeapTupleGetOid(newtuple), 0);
+
 	systable_endscan(scan);
 
 	/* Close pg_database, but keep lock till commit */
@@ -1526,6 +1537,8 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
 		changeDependencyOnOwner(DatabaseRelationId, HeapTupleGetOid(tuple),
 								newOwnerId);
 	}
+	/* Post alter hook for the database */
+	InvokeObjectPostAlterHook(DatabaseRelationId, HeapTupleGetOid(tuple), 0);
 
 	systable_endscan(scan);
 
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 97dde84..ad32c9b 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -491,6 +491,9 @@ AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 	changeDependencyOnOwner(EventTriggerRelationId,
 							HeapTupleGetOid(tup),
 							newOwnerId);
+	/* Post alter hook for the event trigger */
+	InvokeObjectPostAlterHook(EventTriggerRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index e45de83..d067fec 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2360,6 +2360,9 @@ 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 */
+	InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
 }
 
 /*
@@ -2640,6 +2643,9 @@ ApplyExtensionUpdates(Oid extensionOid,
 			recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
 		}
 
+		/* Post alter hook for this extension */
+		InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
+
 		/*
 		 * Finally, execute the update script file
 		 */
@@ -2745,6 +2751,8 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 											DEPENDENCY_EXTENSION) != 1)
 			elog(ERROR, "unexpected number of extension dependency records");
 	}
+	/* Post alter hook of this extension */
+	InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
 
 	/*
 	 * 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 e2f86d2..5cb6c2f 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -241,6 +241,9 @@ AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerI
 								HeapTupleGetOid(tup),
 								newOwnerId);
 	}
+	/* Post alter hook for the FDW */
+	InvokeObjectPostAlterHook(ForeignDataWrapperRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
@@ -344,6 +347,9 @@ AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 		changeDependencyOnOwner(ForeignServerRelationId, HeapTupleGetOid(tup),
 								newOwnerId);
 	}
+	/* Post alter hook for the foreign server */
+	InvokeObjectPostAlterHook(ForeignServerRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
@@ -751,6 +757,8 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
 	}
+	/* Post alter hook of this FDW */
+	InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
@@ -978,6 +986,9 @@ AlterForeignServer(AlterForeignServerStmt *stmt)
 	simple_heap_update(rel, &tp->t_self, tp);
 	CatalogUpdateIndexes(rel, tp);
 
+	/* Post alter hook of this foreign server */
+	InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);
+
 	heap_freetuple(tp);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 26a806b..91f9fdc 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1222,7 +1222,7 @@ AlterFunction(AlterFunctionStmt *stmt)
 	/* Do the update */
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
-
+	InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 }
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index c8e0e75..35f10b5 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -1370,6 +1370,9 @@ storeOperators(List *opfamilyname, Oid amoid,
 			referenced.objectSubId = 0;
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
+		/* Post create hook of this access method operator */
+		InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
+								   entryoid, 0);
 	}
 
 	heap_close(rel, RowExclusiveLock);
@@ -1469,6 +1472,9 @@ storeProcedures(List *opfamilyname, Oid amoid,
 			referenced.objectSubId = 0;
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 		}
+		/* Post create hook of access method procedure */
+		InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
+								   entryoid, 0);
 	}
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index e69c86b..9d4d75e 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,8 @@ RenameSchema(const char *oldname, const char *newname)
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
 
+	InvokeObjectPostAlterHook(NamespaceRelationId, HeapTupleGetOid(tup), 0);
+
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 }
@@ -363,5 +366,7 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
 		changeDependencyOnOwner(NamespaceRelationId, HeapTupleGetOid(tup),
 								newOwnerId);
 	}
-
+	/* Post alter hook for the namespace */
+	InvokeObjectPostAlterHook(NamespaceRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 634ce3f..3829003 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,9 @@ AlterSequence(AlterSeqStmt *stmt)
 	if (owned_by)
 		process_owned_by(seqrel, owned_by);
 
+	/* Post alter hook of this sequence */
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
+
 	relation_close(seqrel, NoLock);
 }
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d516e2a..90b00fe 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
@@ -1955,6 +1955,11 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
 
 	recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL);
 
+	/* Post creation hook of this inheritance */
+	InvokeObjectPostAlterHookArg(InheritsRelationId,
+								 relationId, 0,
+								 parentOid, false);
+
 	/*
 	 * Mark the parent as having subclasses.
 	 */
@@ -2213,6 +2218,9 @@ renameatt_internal(Oid myrelid,
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, atttup);
 
+	/* Post alter hook for this attribute */
+	InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
+
 	heap_freetuple(atttup);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -2357,7 +2365,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);
 
@@ -2433,7 +2441,7 @@ RenameRelation(RenameStmt *stmt)
 	}
 
 	/* Do the work */
-	RenameRelationInternal(relid, stmt->newname);
+	RenameRelationInternal(relid, stmt->newname, false);
 }
 
 /*
@@ -2446,7 +2454,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 */
@@ -2488,6 +2496,10 @@ RenameRelationInternal(Oid myrelid, const char *newrelname)
 	/* keep the system catalog indexes current */
 	CatalogUpdateIndexes(relrelation, reltup);
 
+	/* Post alter hook for this relation */
+	InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
+								 InvalidOid, is_internal);
+
 	heap_freetuple(reltup);
 	heap_close(relrelation, RowExclusiveLock);
 
@@ -3309,7 +3321,9 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			 */
 			break;
 		case AT_SetTableSpace:	/* SET TABLESPACE */
-
+			InvokeObjectPrepAlterHookArg(RelationRelationId,
+										 RelationGetRelid(rel), 0,
+										 tab->newTableSpace);
 			/*
 			 * Nothing to do here; Phase 3 does the work
 			 */
@@ -4489,7 +4503,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();
@@ -4826,6 +4841,8 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
 		/* keep the system catalog indexes current */
 		CatalogUpdateIndexes(attr_rel, tuple);
 	}
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
 
 	heap_close(attr_rel, RowExclusiveLock);
 }
@@ -4878,6 +4895,8 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
 		/* Tell Phase 3 it needs to test the constraint */
 		tab->new_notnull = true;
 	}
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
 
 	heap_close(attr_rel, RowExclusiveLock);
 }
@@ -4933,7 +4952,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, true, false);
 	}
 }
 
@@ -5017,6 +5037,9 @@ ATExecSetStatistics(Relation rel, const char *colName, Node *newValue, LOCKMODE
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, tuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(tuple);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -5074,13 +5097,17 @@ 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);
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(newtuple);
 
+	ReleaseSysCache(tuple);
+
 	heap_close(attrelation, RowExclusiveLock);
 }
 
@@ -5150,6 +5177,9 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, tuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(tuple);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -5464,7 +5494,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 */
@@ -5488,7 +5518,8 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
 							stmt->primary,
 							true, /* update pg_index */
 							true, /* remove old dependencies */
-							allowSystemTableMods);
+							allowSystemTableMods,
+							false);	/* is_internal */
 
 	index_close(indexRel, NoLock);
 }
@@ -5600,7 +5631,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)
@@ -6050,7 +6082,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.
@@ -6232,6 +6265,8 @@ ATExecValidateConstraint(Relation rel, char *constrName, bool recurse,
 		copy_con->convalidated = true;
 		simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
 		CatalogUpdateIndexes(conrel, copyTuple);
+		InvokeObjectPostAlterHook(ConstraintRelationId,
+								  HeapTupleGetOid(tuple), 0);
 		heap_freetuple(copyTuple);
 	}
 
@@ -7659,6 +7694,10 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 	 */
 	RemoveStatistics(RelationGetRelid(rel), attnum);
 
+	/* Post alter hook of this column */
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
+
 	/*
 	 * Update the default, if present, by brute force --- remove and re-add
 	 * the default.  Probably unsafe to take shortcuts, since the new version
@@ -7678,7 +7717,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 		RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
 						  true);
 
-		StoreAttrDefault(rel, attnum, defaultexpr);
+		StoreAttrDefault(rel, attnum, defaultexpr, true);
 	}
 
 	/* Cleanup */
@@ -7769,10 +7808,13 @@ 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);
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  atttableform->attnum);
+	ReleaseSysCache(tuple);
 
 	heap_close(attrel, RowExclusiveLock);
 
@@ -8244,6 +8286,8 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 			change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
 		}
 	}
+	/* Post alter hook of this relation */
+	InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
 
 	ReleaseSysCache(tuple);
 	heap_close(class_rel, RowExclusiveLock);
@@ -8406,7 +8450,7 @@ ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
 	check_index_is_clusterable(rel, indexOid, false, lockmode);
 
 	/* And do the work */
-	mark_index_clustered(rel, indexOid);
+	mark_index_clustered(rel, indexOid, false);
 }
 
 /*
@@ -8418,7 +8462,7 @@ ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
 static void
 ATExecDropCluster(Relation rel, LOCKMODE lockmode)
 {
-	mark_index_clustered(rel, InvalidOid);
+	mark_index_clustered(rel, InvalidOid, false);
 }
 
 /*
@@ -8538,6 +8582,8 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 
 	CatalogUpdateIndexes(pgclass, newtuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
+
 	heap_freetuple(newtuple);
 
 	ReleaseSysCache(tuple);
@@ -8595,6 +8641,10 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 
 		CatalogUpdateIndexes(pgclass, newtuple);
 
+		InvokeObjectPostAlterHookArg(RelationRelationId,
+									 RelationGetRelid(toastrel), 0,
+									 InvalidOid, true);
+
 		heap_freetuple(newtuple);
 
 		ReleaseSysCache(tuple);
@@ -8732,7 +8782,9 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	rd_rel->relfilenode = newrelfilenode;
 	simple_heap_update(pg_class, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(pg_class, tuple);
-
+	InvokeObjectPostAlterHookArg(RelationRelationId,
+								 RelationGetRelid(rel), 0,
+								 InvalidOid, true);
 	heap_freetuple(tuple);
 
 	heap_close(pg_class, RowExclusiveLock);
@@ -9421,6 +9473,11 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
 						   RelationRelationId,
 						   RelationGetRelid(parent_rel));
 
+	/* Post alter hook of this inherits */
+	InvokeObjectPostAlterHookArg(InheritsRelationId,
+								 RelationGetRelid(rel), 0,
+								 RelationGetRelid(parent_rel), false);
+
 	/* keep our lock on the parent relation until commit */
 	heap_close(parent_rel, NoLock);
 }
@@ -9603,6 +9660,7 @@ 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);
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
 	heap_freetuple(classtuple);
 	heap_close(relationRelation, RowExclusiveLock);
 
@@ -9643,6 +9701,7 @@ ATExecDropOf(Relation rel, LOCKMODE lockmode)
 	((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
 	simple_heap_update(relationRelation, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(relationRelation, tuple);
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
 	heap_freetuple(tuple);
 	heap_close(relationRelation, RowExclusiveLock);
 }
@@ -9712,6 +9771,9 @@ ATExecGenericOptions(Relation rel, List *options)
 	simple_heap_update(ftrel, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(ftrel, tuple);
 
+	InvokeObjectPostAlterHook(ForeignTableRelationId,
+							  RelationGetRelid(rel), 0);
+
 	heap_close(ftrel, RowExclusiveLock);
 
 	heap_freetuple(tuple);
@@ -9865,6 +9927,9 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
 				 NameStr(classForm->relname));
 
 		add_exact_object_address(&thisobj, objsMoved);
+
+		/* Post alter hook for this relation */
+		InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
 	}
 
 	heap_freetuple(classTup);
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index e794ecf..ade5d75 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -862,6 +862,8 @@ RenameTableSpace(const char *oldname, const char *newname)
 	/* OK, update the entry */
 	AlterObjectRename_internal(rel, tableSpaceId, newname);
 
+	InvokeObjectPostAlterHook(TableSpaceRelationId, tableSpaceId, 0);
+
 	heap_close(rel, NoLock);
 }
 
@@ -925,6 +927,7 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
 	/* Update system catalog. */
 	simple_heap_update(rel, &newtuple->t_self, newtuple);
 	CatalogUpdateIndexes(rel, newtuple);
+	InvokeObjectPostAlterHook(TableSpaceRelationId, HeapTupleGetOid(tup), 0);
 	heap_freetuple(newtuple);
 
 	/* Conclude heap scan. */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 4a369a4..311edef 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,7 +742,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 							   DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new trigger */
-	InvokeObjectPostCreateHook(TriggerRelationId, trigoid, 0);
+	InvokeObjectPostCreateHookArg(TriggerRelationId, trigoid, 0,
+								  isInternal);
 
 	/* Keep lock on target rel until end of xact */
 	heap_close(rel, NoLock);
@@ -1273,6 +1275,10 @@ renametrig(RenameStmt *stmt)
 		/* keep system catalog indexes current */
 		CatalogUpdateIndexes(tgrel, tuple);
 
+		/* Post alter hook for this trigger */
+		InvokeObjectPostAlterHook(TriggerRelationId,
+								  HeapTupleGetOid(tuple), 0);
+
 		/*
 		 * Invalidate relation's relcache entry so that other backends (and
 		 * this one too!) are sent SI message to make them rebuild relcache
@@ -1386,6 +1392,9 @@ EnableDisableTrigger(Relation rel, const char *tgname,
 
 			changed = true;
 		}
+		/* Post alter hook for this trigger */
+		InvokeObjectPostAlterHook(TriggerRelationId,
+								  HeapTupleGetOid(tuple), 0);
 	}
 
 	systable_endscan(tgscan);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 64e9885..61342d2 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -608,6 +608,8 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
 
 	CatalogUpdateIndexes(rel, newtup);
 
+	InvokeObjectPostAlterHook(TSDictionaryRelationId, dictId, 0);
+
 	/*
 	 * NOTE: because we only support altering the options, not the template,
 	 * there is no need to update dependencies.  This might have to change if
@@ -1171,6 +1173,9 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
 	/* Update dependencies */
 	makeConfigurationDependencies(tup, true, relMap);
 
+	InvokeObjectPostAlterHook(TSConfigMapRelationId,
+							  HeapTupleGetOid(tup), 0);
+
 	heap_close(relMap, RowExclusiveLock);
 
 	ReleaseSysCache(tup);
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 36de6d7..b9fff13 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"
@@ -1210,6 +1211,9 @@ AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
 				 stmt->newValNeighbor, stmt->newValIsAfter,
 				 stmt->skipIfExists);
 
+	/* Post alter hook of this enum type */
+	InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
+
 	ReleaseSysCache(tup);
 }
 
@@ -2183,7 +2187,8 @@ AlterDomainDefault(List *names, Node *defaultRaw)
 							 typTup->typcollation,
 							 defaultExpr,
 							 true);		/* Rebuild is true */
-
+	/* Post alter hook of this domain */
+	InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
 	/* Clean up */
 	heap_close(rel, NoLock);
 	heap_freetuple(newtuple);
@@ -2280,6 +2285,9 @@ AlterDomainNotNull(List *names, bool notNull)
 
 	CatalogUpdateIndexes(typrel, tup);
 
+	/* Post alter hook of this domain */
+	InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
+
 	/* Clean up */
 	heap_freetuple(tup);
 	heap_close(typrel, RowExclusiveLock);
@@ -2561,6 +2569,8 @@ AlterDomainValidateConstraint(List *names, char *constrName)
 	copy_con->convalidated = true;
 	simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
 	CatalogUpdateIndexes(conrel, copyTuple);
+	InvokeObjectPostAlterHook(ConstraintRelationId,
+							  HeapTupleGetOid(copyTuple), 0);
 	heap_freetuple(copyTuple);
 
 	systable_endscan(scan);
@@ -2959,7 +2969,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
@@ -3154,7 +3165,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);
@@ -3275,6 +3286,9 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
 			/* Update owner dependency reference */
 			changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
 
+			/* Post alter hook of this type */
+			InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 			/* If it has an array type, update that too */
 			if (OidIsValid(typTup->typarray))
 				AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
@@ -3295,6 +3309,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,
@@ -3328,6 +3344,9 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
 	if (OidIsValid(typTup->typarray))
 		AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
 
+	/* Post alter hook for the type */
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	/* Clean up */
 	heap_close(rel, RowExclusiveLock);
 }
@@ -3513,6 +3532,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 */
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	heap_freetuple(tup);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index c1b7b93..2b17675 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -775,6 +775,9 @@ AlterRole(AlterRoleStmt *stmt)
 	/* Update indexes */
 	CatalogUpdateIndexes(pg_authid_rel, new_tuple);
 
+	/* Post alter hook of this role */
+	InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
+
 	ReleaseSysCache(tuple);
 	heap_freetuple(new_tuple);
 
@@ -1128,6 +1131,8 @@ RenameRole(const char *oldname, const char *newname)
 
 	CatalogUpdateIndexes(rel, newtuple);
 
+	InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
+
 	ReleaseSysCache(oldtuple);
 
 	/*
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 17e3513..6f7e87d 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -733,6 +733,8 @@ EnableDisableRule(Relation rel, const char *rulename,
 
 		changed = true;
 	}
+	InvokeObjectPostAlterHook(RewriteRelationId,
+							  HeapTupleGetOid(ruletup), 0);
 
 	heap_freetuple(ruletup);
 	heap_close(pg_rewrite_desc, RowExclusiveLock);
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 b96099f..225ee73 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -72,7 +72,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 3e080ba..aac090a 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -22,12 +22,23 @@
  * OAT_DROP should be invoked just before deletion of objects; typically
  * deleteOneObject(). Its arguments are packed within ObjectAccessDrop.
  *
+ * OAT_PREP_ALTER should be invoked prior to actual works of alter commends,
+ * but limited on some cases when OAT_POST_ALTER does not work well. Right
+ * now, all the cases of this events are ALTER TABLE ... SET TABLESPACE.
+ *
+ * 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_PREP_ALTER,
+	OAT_POST_ALTER,
 } ObjectAccessType;
 
 /*
@@ -56,6 +67,43 @@ typedef struct
 } ObjectAccessDrop;
 
 /*
+ * Arguments of OAT_PREP_ALTER event
+ */
+typedef struct
+{
+	/*
+	 * It is used to inform Oid of new tablespace on ALTER TABLE ... SET
+	 * TABLESPACE command. Its system catalog is updated after whole the
+	 * table rewrite even if it is very large, so we put prep-alter hook
+	 * prior to actual works.
+	 */
+	Oid			tablespaceId;
+} ObjectAccessPrepAlter;
+
+
+/*
+ * 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,
@@ -70,6 +118,10 @@ extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
 									bool is_internal);
 extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
 							  int dropflags);
+extern void RunObjectPrepAlterHook(Oid classId, Oid objectId, int subId,
+								   Oid tablespaceId);
+extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
+								   Oid auxiliaryId, bool is_internal);
 
 #define InvokeObjectPostCreateHook(classId,objectId,subId)			\
 	InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
@@ -89,4 +141,26 @@ extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
 							  (dropflags));							\
 	} while(0)
 
+#define InvokeObjectPrepAlterHook(classId,objectId,subId)			\
+	InvokeObjectPrepAlterHookArg((classId),(objectId),(subId),		\
+								 InvalidOid)
+#define InvokeObjectPrepAlterHookArg(classId,objectId,subId,		\
+									 tablespaceId)					\
+	do {															\
+		if (object_access_hook)										\
+			RunObjectPrepAlterHook((classId),(objectId),(subId),	\
+								   (tablespaceId));					\
+	} while(0)
+
+#define InvokeObjectPostAlterHook(classId,objectId,subId)			\
+	InvokeObjectPostAlterHookArg((classId),(objectId),(subId),		\
+								 InvalidOid,false)
+#define InvokeObjectPostAlterHookArg(classId,objectId,subId,		\
+									 auxiliaryId,is_internal)		\
+	do {															\
+		if (object_access_hook)										\
+			RunObjectPostAlterHook((classId),(objectId),(subId),	\
+								   (auxiliaryId),(is_internal));	\
+	} while(0)
+
 #endif   /* OBJECTACCESS_H */
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/cluster.h b/src/include/commands/cluster.h
index 21b2a58..490b3ba 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -23,7 +23,7 @@ extern void cluster_rel(Oid tableOid, Oid indexOid, bool recheck,
 			bool verbose, int freeze_min_age, int freeze_table_age);
 extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
 						   bool recheck, LOCKMODE lockmode);
-extern void mark_index_clustered(Relation rel, Oid indexOid);
+extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
 
 extern Oid	make_new_heap(Oid OIDOldHeap, Oid NewTableSpace);
 extern void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
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,
sepgsql-v9.3-post-alter-support.v4.part-1.patchapplication/octet-stream; name=sepgsql-v9.3-post-alter-support.v4.part-1.patchDownload
 src/backend/catalog/Makefile               |    3 +-
 src/backend/catalog/dependency.c           |   10 +----
 src/backend/catalog/heap.c                 |   10 +----
 src/backend/catalog/index.c                |   11 +----
 src/backend/catalog/objectaccess.c         |   63 ++++++++++++++++++++++++++++
 src/backend/catalog/pg_collation.c         |    3 +-
 src/backend/catalog/pg_constraint.c        |    3 +-
 src/backend/catalog/pg_conversion.c        |    3 +-
 src/backend/catalog/pg_namespace.c         |    3 +-
 src/backend/catalog/pg_operator.c          |    6 +--
 src/backend/catalog/pg_proc.c              |    3 +-
 src/backend/catalog/pg_type.c              |    6 +--
 src/backend/commands/dbcommands.c          |   12 +-----
 src/backend/commands/event_trigger.c       |    3 +-
 src/backend/commands/extension.c           |    3 +-
 src/backend/commands/foreigncmds.c         |    9 ++--
 src/backend/commands/functioncmds.c        |    3 +-
 src/backend/commands/opclasscmds.c         |    6 +--
 src/backend/commands/proclang.c            |    3 +-
 src/backend/commands/tablecmds.c           |    3 +-
 src/backend/commands/tablespace.c          |   12 +-----
 src/backend/commands/trigger.c             |    3 +-
 src/backend/commands/tsearchcmds.c         |   12 ++----
 src/backend/commands/user.c                |   12 +-----
 src/backend/rewrite/rewriteDefine.c        |    3 +-
 src/backend/storage/large_object/inv_api.c |    3 +-
 src/backend/utils/init/globals.c           |    7 ----
 src/include/catalog/objectaccess.h         |   22 ++++++++--
 28 files changed, 121 insertions(+), 119 deletions(-)

diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index df6da1f..c4d3f3c 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -11,7 +11,8 @@ top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
 OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
-       objectaddress.o pg_aggregate.o pg_collation.o pg_constraint.o pg_conversion.o \
+       objectaccess.o objectaddress.o pg_aggregate.o pg_collation.o \
+       pg_constraint.o pg_conversion.o \
        pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \
        pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \
        pg_type.o storage.o toasting.o
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index cefa82c..9f0cdcb 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -997,14 +997,8 @@ deleteOneObject(const ObjectAddress *object, Relation *depRel, int flags)
 	HeapTuple	tup;
 
 	/* DROP hook of the objects being removed */
-	if (object_access_hook)
-	{
-		ObjectAccessDrop drop_arg;
-
-		drop_arg.dropflags = flags;
-		InvokeObjectAccessHook(OAT_DROP, object->classId, object->objectId,
-							   object->objectSubId, &drop_arg);
-	}
+	InvokeObjectDropHookArg(object->classId, object->objectId,
+							object->objectSubId, flags);
 
 	/*
 	 * Close depRel if we are doing a drop concurrently.  The object deletion
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index d93d273..54de9a7 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1277,15 +1277,7 @@ heap_create_with_catalog(const char *relname,
 	}
 
 	/* Post creation hook for new relation */
-	if (object_access_hook)
-	{
-		ObjectAccessPostCreate	post_create_args;
-
-		memset(&post_create_args, 0, sizeof(ObjectAccessPostCreate));
-		post_create_args.is_internal = is_internal;
-		(*object_access_hook)(OAT_POST_CREATE, RelationRelationId,
-							  relid, 0, &post_create_args);
-    }
+	InvokeObjectPostCreateHookArg(RelationRelationId, relid, 0, is_internal);
 
 	/*
 	 * Store any supplied constraints and defaults.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 66012ac..b1091ac 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1027,15 +1027,8 @@ index_create(Relation heapRelation,
 	}
 
 	/* Post creation hook for new index */
-	if (object_access_hook)
-	{
-		ObjectAccessPostCreate	post_create_args;
-
-		memset(&post_create_args, 0, sizeof(ObjectAccessPostCreate));
-		post_create_args.is_internal = is_internal;
-		(*object_access_hook)(OAT_POST_CREATE, RelationRelationId,
-							  indexRelationId, 0, &post_create_args);
-	}
+	InvokeObjectPostCreateHookArg(RelationRelationId,
+								  indexRelationId, 0, is_internal);
 
 	/*
 	 * Advance the command counter so that we can see the newly-entered
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
new file mode 100644
index 0000000..79c1136
--- /dev/null
+++ b/src/backend/catalog/objectaccess.c
@@ -0,0 +1,63 @@
+/* -------------------------------------------------------------------------
+ *
+ * objectaccess.c
+ *		functions for object_access_hook on various events
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "catalog/objectaccess.h"
+
+/*
+ * Hook on object accesses.  This is intended as infrastructure for security
+ * and logging plugins.
+ */
+object_access_hook_type object_access_hook = NULL;
+
+/*
+ * RunObjectPostCreateHook
+ *
+ * It is entrypoint of OAT_POST_CREATE event
+ */
+void
+RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
+						bool is_internal)
+{
+	ObjectAccessPostCreate	pc_arg;
+
+	/* XXX - should be checked at caller side */
+	Assert(object_access_hook != NULL);
+
+	memset(&pc_arg, 0, sizeof(ObjectAccessPostCreate));
+	pc_arg.is_internal = is_internal;
+
+	(*object_access_hook)(OAT_POST_CREATE,
+						  classId, objectId, subId,
+						  (void *) &pc_arg);
+}
+
+/*
+ * RunObjectDropHook
+ *
+ * It is entrypoint of OAT_DROP event
+ */
+void
+RunObjectDropHook(Oid classId, Oid objectId, int subId,
+				  int dropflags)
+{
+	ObjectAccessDrop	drop_arg;
+
+	/* XXX - should be checked at caller side */
+	Assert(object_access_hook != NULL);
+
+	memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
+	drop_arg.dropflags = dropflags;
+
+	(*object_access_hook)(OAT_DROP,
+						  classId, objectId, subId,
+						  (void *) &drop_arg);
+}
diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c
index 6020d16..0c25554 100644
--- a/src/backend/catalog/pg_collation.c
+++ b/src/backend/catalog/pg_collation.c
@@ -136,8 +136,7 @@ CollationCreate(const char *collname, Oid collnamespace,
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new collation */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   CollationRelationId, oid, 0, NULL);
+	InvokeObjectPostCreateHook(CollationRelationId, oid, 0);
 
 	heap_freetuple(tup);
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 5e8c6da..1e6d947 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -367,8 +367,7 @@ CreateConstraintEntry(const char *constraintName,
 	}
 
 	/* Post creation hook for new constraint */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ConstraintRelationId, conOid, 0, NULL);
+	InvokeObjectPostCreateHook(ConstraintRelationId, conOid, 0);
 
 	return conOid;
 }
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index 68f1aa7..caef609 100644
--- a/src/backend/catalog/pg_conversion.c
+++ b/src/backend/catalog/pg_conversion.c
@@ -136,8 +136,7 @@ ConversionCreate(const char *conname, Oid connamespace,
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new conversion */
-	InvokeObjectAccessHook(OAT_POST_CREATE, ConversionRelationId,
-						   HeapTupleGetOid(tup), 0, NULL);
+	InvokeObjectPostCreateHook(ConversionRelationId, HeapTupleGetOid(tup), 0);
 
 	heap_freetuple(tup);
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c
index 098df22..b322ff6 100644
--- a/src/backend/catalog/pg_namespace.c
+++ b/src/backend/catalog/pg_namespace.c
@@ -96,8 +96,7 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
 		recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new schema */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   NamespaceRelationId, nspoid, 0, NULL);
+	InvokeObjectPostCreateHook(NamespaceRelationId, nspoid, 0);
 
 	return nspoid;
 }
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 88af345..bd44333 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -275,8 +275,7 @@ OperatorShellMake(const char *operatorName,
 	heap_freetuple(tup);
 
 	/* Post creation hook for new shell operator */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorRelationId, operatorObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
 
 	/*
 	 * Make sure the tuple is visible for subsequent lookups/updates.
@@ -544,8 +543,7 @@ OperatorCreate(const char *operatorName,
 	makeOperatorDependencies(tup);
 
 	/* Post creation hook for new operator */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorRelationId, operatorObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
 
 	heap_close(pg_operator_desc, RowExclusiveLock);
 
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index ba73264..444ee78 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -661,8 +661,7 @@ ProcedureCreate(const char *procedureName,
 	heap_freetuple(tup);
 
 	/* Post creation hook for new function */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ProcedureRelationId, retval, 0, NULL);
+	InvokeObjectPostCreateHook(ProcedureRelationId, retval, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 49133ee..cf0ebcc 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -163,8 +163,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
 								 false);
 
 	/* Post creation hook for new shell type */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TypeRelationId, typoid, 0, NULL);
+	InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
 
 	/*
 	 * clean up and return the type-oid
@@ -476,8 +475,7 @@ TypeCreate(Oid newTypeOid,
 								 rebuildDeps);
 
 	/* Post creation hook for new type */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TypeRelationId, typeObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
 
 	/*
 	 * finish up
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 3c13c47..09c06ed 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -520,8 +520,7 @@ createdb(const CreatedbStmt *stmt)
 	copyTemplateDependencies(src_dboid, dboid);
 
 	/* Post creation hook for new database */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   DatabaseRelationId, dboid, 0, NULL);
+	InvokeObjectPostCreateHook(DatabaseRelationId, dboid, 0);
 
 	/*
 	 * Force a checkpoint before starting the copy. This will force dirty
@@ -784,14 +783,7 @@ dropdb(const char *dbname, bool missing_ok)
 					   dbname);
 
 	/* DROP hook for the database being removed */
-	if (object_access_hook)
-	{
-		ObjectAccessDrop drop_arg;
-
-		memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
-		InvokeObjectAccessHook(OAT_DROP,
-							   DatabaseRelationId, db_id, 0, &drop_arg);
-	}
+	InvokeObjectDropHook(DatabaseRelationId, db_id, 0);
 
 	/*
 	 * Disallow dropping a DB that is marked istemplate.  This is just to
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 2e24e0d..97dde84 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -307,8 +307,7 @@ insert_event_trigger_tuple(char *trigname, char *eventname, Oid evtOwner,
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new operator family */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   EventTriggerRelationId, trigoid, 0, NULL);
+	InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
 
 	/* Close pg_event_trigger. */
 	heap_close(tgrel, RowExclusiveLock);
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 47631be..e45de83 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1560,8 +1560,7 @@ InsertExtensionTuple(const char *extName, Oid extOwner,
 		recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
 	}
 	/* Post creation hook for new extension */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ExtensionRelationId, extensionOid, 0, NULL);
+	InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
 
 	return extensionOid;
 }
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 2d73d2d..e2f86d2 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -589,8 +589,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new foreign data wrapper */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ForeignDataWrapperRelationId, fdwId, 0, NULL);
+	InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
@@ -886,8 +885,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new foreign server */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ForeignServerRelationId, srvId, 0, NULL);
+	InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
@@ -1127,8 +1125,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new user mapping */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   UserMappingRelationId, umId, 0, NULL);
+	InvokeObjectPostCreateHook(UserMappingRelationId, umId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index cf0613f..26a806b 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1610,8 +1610,7 @@ CreateCast(CreateCastStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new cast */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   CastRelationId, castid, 0, NULL);
+	InvokeObjectPostCreateHook(CastRelationId, castid, 0);
 
 	heap_freetuple(tuple);
 
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 044ddd3..c8e0e75 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -309,8 +309,7 @@ CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new operator family */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorFamilyRelationId, opfamilyoid, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
@@ -710,8 +709,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new operator class */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorClassRelationId, opclassoid, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 6526b7e..2e446b5 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -429,8 +429,7 @@ create_proc_lang(const char *languageName, bool replace,
 	}
 
 	/* Post creation hook for new procedural language */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   LanguageRelationId, myself.objectId, 0, NULL);
+	InvokeObjectPostCreateHook(LanguageRelationId, myself.objectId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 4065740..d516e2a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4462,8 +4462,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	heap_freetuple(reltup);
 
 	/* Post creation hook for new attribute */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   RelationRelationId, myrelid, newattnum, NULL);
+	InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
 
 	heap_close(pgclass, RowExclusiveLock);
 
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index d80b3a6..e794ecf 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -331,8 +331,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
 	recordDependencyOnOwner(TableSpaceRelationId, tablespaceoid, ownerId);
 
 	/* Post creation hook for new tablespace */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TableSpaceRelationId, tablespaceoid, 0, NULL);
+	InvokeObjectPostCreateHook(TableSpaceRelationId, tablespaceoid, 0);
 
 	create_tablespace_directories(location, tablespaceoid);
 
@@ -437,14 +436,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
 					   tablespacename);
 
 	/* DROP hook for the tablespace being removed */
-	if (object_access_hook)
-	{
-		ObjectAccessDrop drop_arg;
-
-		memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
-		InvokeObjectAccessHook(OAT_DROP, TableSpaceRelationId,
-							   tablespaceoid, 0, &drop_arg);
-	}
+	InvokeObjectDropHook(TableSpaceRelationId, tablespaceoid, 0);
 
 	/*
 	 * Remove the pg_tablespace tuple (this will roll back if we fail below)
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 91ef779..4a369a4 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -741,8 +741,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 							   DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new trigger */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TriggerRelationId, trigoid, 0, NULL);
+	InvokeObjectPostCreateHook(TriggerRelationId, trigoid, 0);
 
 	/* Keep lock on target rel until end of xact */
 	heap_close(rel, NoLock);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 9dbfa0c..64e9885 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -272,8 +272,7 @@ DefineTSParser(List *names, List *parameters)
 	makeParserDependencies(tup);
 
 	/* Post creation hook for new text search parser */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSParserRelationId, prsOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSParserRelationId, prsOid, 0);
 
 	heap_freetuple(tup);
 
@@ -477,8 +476,7 @@ DefineTSDictionary(List *names, List *parameters)
 	makeDictionaryDependencies(tup);
 
 	/* Post creation hook for new text search dictionary */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSDictionaryRelationId, dictOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSDictionaryRelationId, dictOid, 0);
 
 	heap_freetuple(tup);
 
@@ -790,8 +788,7 @@ DefineTSTemplate(List *names, List *parameters)
 	makeTSTemplateDependencies(tup);
 
 	/* Post creation hook for new text search template */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSTemplateRelationId, dictOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSTemplateRelationId, dictOid, 0);
 
 	heap_freetuple(tup);
 
@@ -1084,8 +1081,7 @@ DefineTSConfiguration(List *names, List *parameters)
 	makeConfigurationDependencies(tup, false, mapRel);
 
 	/* Post creation hook for new text search configuration */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSConfigRelationId, cfgOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSConfigRelationId, cfgOid, 0);
 
 	heap_freetuple(tup);
 
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index f178167..c1b7b93 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -426,8 +426,7 @@ CreateRole(CreateRoleStmt *stmt)
 				GetUserId(), false);
 
 	/* Post creation hook for new role */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   AuthIdRelationId, roleid, 0, NULL);
+	InvokeObjectPostCreateHook(AuthIdRelationId, roleid, 0);
 
 	/*
 	 * Close pg_authid, but keep lock till commit.
@@ -935,14 +934,7 @@ DropRole(DropRoleStmt *stmt)
 					 errmsg("must be superuser to drop superusers")));
 
 		/* DROP hook for the role being removed */
-		if (object_access_hook)
-		{
-			ObjectAccessDrop drop_arg;
-
-			memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
-			InvokeObjectAccessHook(OAT_DROP,
-								   AuthIdRelationId, roleid, 0, &drop_arg);
-		}
+		InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
 
 		/*
 		 * Lock the role, so nobody can add dependencies to her while we drop
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 55b0fed..17e3513 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -179,8 +179,7 @@ InsertRule(char *rulname,
 	}
 
 	/* Post creation hook for new rule */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   RewriteRelationId, rewriteObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(RewriteRelationId, rewriteObjectId, 0);
 
 	heap_close(pg_rewrite_desc, RowExclusiveLock);
 
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index ad8424b..b2c8781 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -218,8 +218,7 @@ inv_create(Oid lobjId)
 							lobjId_new, GetUserId());
 
 	/* Post creation hook for new large object */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   LargeObjectRelationId, lobjId_new, 0, NULL);
+	InvokeObjectPostCreateHook(LargeObjectRelationId, lobjId_new, 0);
 
 	/*
 	 * Advance command counter to make new tuple visible to later operations.
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 8dd2b4b..536d308 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -18,7 +18,6 @@
  */
 #include "postgres.h"
 
-#include "catalog/objectaccess.h"
 #include "libpq/pqcomm.h"
 #include "miscadmin.h"
 #include "storage/backendid.h"
@@ -125,9 +124,3 @@ int			VacuumCostBalance = 0;		/* working state for vacuum */
 bool		VacuumCostActive = false;
 
 int			GinFuzzySearchLimit = 0;
-
-/*
- * Hook on object accesses.  This is intended as infrastructure for security
- * and logging plugins.
- */
-object_access_hook_type object_access_hook = NULL;
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index b4b84a6..3e080ba 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -66,11 +66,27 @@ typedef void (*object_access_hook_type) (ObjectAccessType access,
 
 extern PGDLLIMPORT object_access_hook_type object_access_hook;
 
-#define InvokeObjectAccessHook(access,classId,objectId,subId,arg)	\
+extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
+									bool is_internal);
+extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
+							  int dropflags);
+
+#define InvokeObjectPostCreateHook(classId,objectId,subId)			\
+	InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
+#define InvokeObjectPostCreateHookArg(classId,objectId,subId,is_internal) \
+	do {															\
+		if (object_access_hook)										\
+			RunObjectPostCreateHook((classId),(objectId),(subId),	\
+									(is_internal));					\
+	} while(0)
+
+#define InvokeObjectDropHook(classId,objectId,subId)				\
+	InvokeObjectDropHookArg((classId),(objectId),(subId),0)
+#define InvokeObjectDropHookArg(classId,objectId,subId,dropflags)	\
 	do {															\
 		if (object_access_hook)										\
-			(*object_access_hook)((access),(classId),				\
-								  (objectId),(subId),(arg));		\
+			RunObjectDropHook((classId),(objectId),(subId),			\
+							  (dropflags));							\
 	} while(0)
 
 #endif   /* OBJECTACCESS_H */
#13Robert Haas
robertmhaas@gmail.com
In reply to: Kohei KaiGai (#11)
Re: [v9.3] OAT_POST_ALTER object access hooks

On Mon, Dec 3, 2012 at 9:59 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

As we discussed before, it is hard to determine which attributes shall
be informed to extension via object_access_hook, so the proposed
post-alter hook (that allows to compare older and newer versions)
works fine on 99% cases.
However, I'm inclined to handle SET TABLESPACE as an exception
of this scenario. For example, an idea is to define OAT_PREP_ALTER
event additionally, but only invoked very limited cases that takes
unignorable side-effects until system catalog updates.
For consistency of hook, OAT_POST_ALTER event may also ought
to be invoked just after catalog updates of pg_class->reltablespace,
but is_internal=true.

How about your opinion?

I don't really like it - I think POST should mean POST. You can
define some other hook that gets called somewhere else, but after
means after. There are other plausible uses of these hooks besides
sepgsql; for example, logging the completion time of an action.
Putting the hooks in the "wrong" places because that happens to be
more convenient for sepgsql is going to render them useless for any
other purpose. Maybe nobody else will use them anyway, but I'd rather
not render it impossible before we get off the ground.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#14Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Robert Haas (#13)
Re: [v9.3] OAT_POST_ALTER object access hooks

2012/12/11 Robert Haas <robertmhaas@gmail.com>:

On Mon, Dec 3, 2012 at 9:59 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

As we discussed before, it is hard to determine which attributes shall
be informed to extension via object_access_hook, so the proposed
post-alter hook (that allows to compare older and newer versions)
works fine on 99% cases.
However, I'm inclined to handle SET TABLESPACE as an exception
of this scenario. For example, an idea is to define OAT_PREP_ALTER
event additionally, but only invoked very limited cases that takes
unignorable side-effects until system catalog updates.
For consistency of hook, OAT_POST_ALTER event may also ought
to be invoked just after catalog updates of pg_class->reltablespace,
but is_internal=true.

How about your opinion?

I don't really like it - I think POST should mean POST. You can
define some other hook that gets called somewhere else, but after
means after. There are other plausible uses of these hooks besides
sepgsql; for example, logging the completion time of an action.
Putting the hooks in the "wrong" places because that happens to be
more convenient for sepgsql is going to render them useless for any
other purpose. Maybe nobody else will use them anyway, but I'd rather
not render it impossible before we get off the ground.

I have to admit "PREP" hook is problematic to determine which information
should be delivered, and which should not, as we had discussed before.
Yes, a hook convenient for sepgsql, might be unconvenient for others.

So, which alternatives do we have? I can list up a few ideas.

1) Putting POST_ALTER hook after existing whole table rewrite.
good: no need to have significant code change
bad: it takes heavy i/o prior to hook invocation

2) Updating reltablespace of pg_class prior to whole table rewrite,
and put POST_ALTER hook just after catalog update.
good: well fit with assumption of POST hook.
bad: it takes significant code changes on table rewriting

3) Using ProcessUtility_hook to track AKTER TABLE ... SET
TABLESPACE as an exception.
good: no need to have significant code change
bad: sepgsql also have to have analyzer of ALTER TABLE
commands.

I think (2) is the best way, if feasible. I need to investigate whether
the relevant code allows to implement catalog updates prior to
whole table rewriting.
However, (1) is also not so bad in a short term, as a first step towards
the idea (2) that takes additional code updates.
Of course, I can implement with (3), but not inclined with this idea.

Is there other idea?

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#15Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Kohei KaiGai (#14)
2 attachment(s)
Re: [v9.3] OAT_POST_ALTER object access hooks

2012/12/11 Kohei KaiGai <kaigai@kaigai.gr.jp>:

2012/12/11 Robert Haas <robertmhaas@gmail.com>:

On Mon, Dec 3, 2012 at 9:59 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

As we discussed before, it is hard to determine which attributes shall
be informed to extension via object_access_hook, so the proposed
post-alter hook (that allows to compare older and newer versions)
works fine on 99% cases.
However, I'm inclined to handle SET TABLESPACE as an exception
of this scenario. For example, an idea is to define OAT_PREP_ALTER
event additionally, but only invoked very limited cases that takes
unignorable side-effects until system catalog updates.
For consistency of hook, OAT_POST_ALTER event may also ought
to be invoked just after catalog updates of pg_class->reltablespace,
but is_internal=true.

How about your opinion?

I don't really like it - I think POST should mean POST. You can
define some other hook that gets called somewhere else, but after
means after. There are other plausible uses of these hooks besides
sepgsql; for example, logging the completion time of an action.
Putting the hooks in the "wrong" places because that happens to be
more convenient for sepgsql is going to render them useless for any
other purpose. Maybe nobody else will use them anyway, but I'd rather
not render it impossible before we get off the ground.

I have to admit "PREP" hook is problematic to determine which information
should be delivered, and which should not, as we had discussed before.
Yes, a hook convenient for sepgsql, might be unconvenient for others.

So, which alternatives do we have? I can list up a few ideas.

1) Putting POST_ALTER hook after existing whole table rewrite.
good: no need to have significant code change
bad: it takes heavy i/o prior to hook invocation

2) Updating reltablespace of pg_class prior to whole table rewrite,
and put POST_ALTER hook just after catalog update.
good: well fit with assumption of POST hook.
bad: it takes significant code changes on table rewriting

3) Using ProcessUtility_hook to track AKTER TABLE ... SET
TABLESPACE as an exception.
good: no need to have significant code change
bad: sepgsql also have to have analyzer of ALTER TABLE
commands.

I think (2) is the best way, if feasible. I need to investigate whether
the relevant code allows to implement catalog updates prior to
whole table rewriting.
However, (1) is also not so bad in a short term, as a first step towards
the idea (2) that takes additional code updates.
Of course, I can implement with (3), but not inclined with this idea.

Is there other idea?

I tried to adjust my patch based on the idea (1).

It does not do anything special on SET TABLESPACE, thus it follows
the manner of "POST_ALTER" command, but it also means permission
checks are applied after (possible) heavy i/o workload.

I'd like to revise the logic of whole table rewrite to move catalog update
prior to actual i/o works, however, it is not scope of this patch.

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

sepgsql-v9.3-post-alter-support.v5.part-2.patchapplication/octet-stream; name=sepgsql-v9.3-post-alter-support.v5.part-2.patchDownload
 contrib/sepgsql/database.c               |   27 +++++
 contrib/sepgsql/expected/alter.out       |  192 ++++++++++++++++++++++++++++++
 contrib/sepgsql/expected/ddl.out         |    9 ++
 contrib/sepgsql/hooks.c                  |   48 ++++++++
 contrib/sepgsql/proc.c                   |   90 +++++++++++++-
 contrib/sepgsql/relation.c               |   91 ++++++++++++--
 contrib/sepgsql/schema.c                 |   51 ++++++++
 contrib/sepgsql/sepgsql.h                |    7 ++
 contrib/sepgsql/sql/alter.sql            |  136 +++++++++++++++++++++
 contrib/sepgsql/sql/ddl.sql              |    6 +
 contrib/sepgsql/test_sepgsql             |    2 +-
 doc/src/sgml/sepgsql.sgml                |   21 +++-
 src/backend/catalog/aclchk.c             |    9 ++
 src/backend/catalog/heap.c               |   41 +++++--
 src/backend/catalog/index.c              |   12 +-
 src/backend/catalog/objectaccess.c       |   23 ++++
 src/backend/catalog/pg_constraint.c      |   11 +-
 src/backend/catalog/pg_db_role_setting.c |    5 +-
 src/backend/catalog/pg_type.c            |    3 +
 src/backend/commands/alter.c             |    9 ++
 src/backend/commands/cluster.c           |   30 ++++-
 src/backend/commands/collationcmds.c     |    1 +
 src/backend/commands/dbcommands.c        |   13 ++
 src/backend/commands/event_trigger.c     |    3 +
 src/backend/commands/extension.c         |    8 ++
 src/backend/commands/foreigncmds.c       |   11 ++
 src/backend/commands/functioncmds.c      |    2 +-
 src/backend/commands/opclasscmds.c       |    6 +
 src/backend/commands/schemacmds.c        |    7 +-
 src/backend/commands/sequence.c          |    4 +
 src/backend/commands/tablecmds.c         |   99 ++++++++++++---
 src/backend/commands/tablespace.c        |    3 +
 src/backend/commands/trigger.c           |   13 +-
 src/backend/commands/tsearchcmds.c       |    5 +
 src/backend/commands/typecmds.c          |   28 ++++-
 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       |   41 +++++++
 src/include/catalog/pg_constraint.h      |    3 +-
 src/include/commands/cluster.h           |    3 +-
 src/include/commands/tablecmds.h         |    2 +-
 43 files changed, 1024 insertions(+), 67 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..ef9abb3
--- /dev/null
+++ b/contrib/sepgsql/expected/alter.out
@@ -0,0 +1,192 @@
+--
+-- 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
+--
+-- XXX: It should take db_xxx:{setattr} permission checks even if
+--      owner is not actually changed.
+--
+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 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 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 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 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 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 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
+ALTER TABLE regtest_table SET TABLESPACE pg_default;
+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 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..22afca7 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
@@ -529,6 +559,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 +590,66 @@ 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);
+
+	/*
+	 * XXX - In the future version, db_tuple:{use} of system catalog entry
+	 * shall be checked, if tablespace configuration is changed.
 	 */
 
 	/*
 	 * 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..4bded7e
--- /dev/null
+++ b/contrib/sepgsql/sql/alter.sql
@@ -0,0 +1,136 @@
+--
+-- 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
+--
+-- XXX: It should take db_xxx:{setattr} permission checks even if
+--      owner is not actually changed.
+--
+ALTER DATABASE regtest_sepgsql_test_database_1 OWNER TO regtest_sepgsql_test_user;
+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 SCHEMA regtest_schema_1 OWNER TO regtest_sepgsql_test_user;
+ALTER TABLE regtest_table_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 SEQUENCE regtest_seq_1 OWNER TO regtest_sepgsql_test_user;
+ALTER VIEW regtest_view_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 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
+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 d82c8ce..2da9f55 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,14 @@ SetDefaultACL(InternalDefaultACL *iacls)
 							  iacls->roleid,
 							  noldmembers, oldmembers,
 							  nnewmembers, newmembers);
+
+		/* Post create or alter hook of this default ACL */
+		if (isNew)
+			InvokeObjectPostCreateHook(DefaultAclRelationId,
+									   HeapTupleGetOid(newtuple), 0);
+		else
+			InvokeObjectPostAlterHook(DefaultAclRelationId,
+									  HeapTupleGetOid(newtuple), 0);
 	}
 
 	if (HeapTupleIsValid(tuple))
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 54de9a7..f482656 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -95,8 +95,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);
@@ -1286,7 +1287,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
@@ -1799,7 +1800,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;
@@ -1891,6 +1893,17 @@ 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.
+	 */
+	InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
+								  RelationGetRelid(rel), attnum, is_internal);
 }
 
 /*
@@ -1902,7 +1915,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;
@@ -1986,7 +1999,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);
@@ -2001,7 +2015,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;
@@ -2023,11 +2037,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:
@@ -2053,6 +2068,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.
@@ -2070,7 +2086,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;
@@ -2133,7 +2150,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;
@@ -2259,7 +2276,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 b1091ac..bc20725 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -932,7 +932,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
 		{
@@ -1106,6 +1107,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,
@@ -1118,7 +1120,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,
@@ -1183,7 +1186,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.
@@ -1292,6 +1296,8 @@ index_constraint_create(Relation heapRelation,
 		{
 			simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
 			CatalogUpdateIndexes(pg_index, indexTuple);
+			InvokeObjectPostAlterHookArg(IndexRelationId, indexRelationId, 0,
+										 InvalidOid, is_internal);
 		}
 
 		heap_freetuple(indexTuple);
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
index 79c1136..0e6844c 100644
--- a/src/backend/catalog/objectaccess.c
+++ b/src/backend/catalog/objectaccess.c
@@ -61,3 +61,26 @@ RunObjectDropHook(Oid classId, Oid objectId, int subId,
 						  classId, objectId, subId,
 						  (void *) &drop_arg);
 }
+
+/*
+ * RunObjectPostAlterHook
+ *
+ * It is entrypoint of OAT_POST_ALTER event
+ */
+void
+RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
+					   Oid auxiliaryId, bool is_internal)
+{
+	ObjectAccessPostAlter	pa_arg;
+
+	/* XXX - should be checked at caller side */
+	Assert(object_access_hook != NULL);
+
+	memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
+	pa_arg.auxiliary_id = auxiliaryId;
+	pa_arg.is_internal = is_internal;
+
+	(*object_access_hook)(OAT_POST_ALTER,
+						  classId, objectId, subId,
+						  (void *) &pa_arg);
+}
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 1e6d947..de5bc81 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,7 +368,8 @@ CreateConstraintEntry(const char *constraintName,
 	}
 
 	/* Post creation hook for new constraint */
-	InvokeObjectPostCreateHook(ConstraintRelationId, conOid, 0);
+	InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0,
+								  is_internal);
 
 	return conOid;
 }
@@ -665,6 +667,9 @@ RenameConstraintById(Oid conId, const char *newname)
 	/* update the system catalog indexes */
 	CatalogUpdateIndexes(conDesc, tuple);
 
+	/* Post alter hook for this constraint */
+	InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0);
+
 	heap_freetuple(tuple);
 	heap_close(conDesc, RowExclusiveLock);
 }
@@ -736,6 +741,8 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 			 * changeDependencyFor().
 			 */
 		}
+		/* Post alter hook for the constraint */
+		InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0);
 
 		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..9a0ead7 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,9 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
 		/* Update indexes */
 		CatalogUpdateIndexes(rel, newtuple);
 	}
-
+	/* Post alter hook for this database-role-settings */
+	InvokeObjectPostAlterHookArg(DbRoleSettingRelationId,
+								 databaseid, 0, roleid, false);
 	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 cf0ebcc..8c756eb 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -712,6 +712,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 */
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	heap_freetuple(tuple);
 	heap_close(pg_type_desc, RowExclusiveLock);
 
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 6f08210..5b257ff 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"
@@ -177,6 +178,9 @@ AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
 	simple_heap_update(rel, &oldtup->t_self, newtup);
 	CatalogUpdateIndexes(rel, newtup);
 
+	/* Post alter hook of the object */
+	InvokeObjectPostAlterHook(classId, objectId, 0);
+
 	/* Release memory */
 	pfree(values);
 	pfree(nulls);
@@ -560,6 +564,9 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
 	changeDependencyFor(classId, objid,
 						NamespaceRelationId, oldNspOid, nspOid);
 
+	/* Post alter hook for the object */
+	InvokeObjectPostAlterHook(classId, objid, 0);
+
 	return oldNspOid;
 }
 
@@ -837,4 +844,6 @@ AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
 		pfree(nulls);
 		pfree(replaces);
 	}
+	/* Post alter hook for the object */
+	InvokeObjectPostAlterHook(classId, objectId, 0);
 }
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index c3deb56..58f062b 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -26,6 +26,7 @@
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
 #include "catalog/toasting.h"
 #include "commands/cluster.h"
 #include "commands/tablecmds.h"
@@ -465,7 +466,7 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMOD
  * otherwise concurrent executions of RelationGetIndexList could miss indexes.
  */
 void
-mark_index_clustered(Relation rel, Oid indexOid)
+mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
 {
 	HeapTuple	indexTuple;
 	Form_pg_index indexForm;
@@ -525,6 +526,9 @@ mark_index_clustered(Relation rel, Oid indexOid)
 			simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
 			CatalogUpdateIndexes(pg_index, indexTuple);
 		}
+		/* Post object alter hook of this index */
+		InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
+									 InvalidOid, is_internal);
 		heap_freetuple(indexTuple);
 	}
 
@@ -552,7 +556,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid,
 
 	/* Mark the correct index as clustered */
 	if (OidIsValid(indexOid))
-		mark_index_clustered(OldHeap, indexOid);
+		mark_index_clustered(OldHeap, indexOid, true);
 
 	/* Remember if it's a system catalog */
 	is_system_catalog = IsSystemRelation(OldHeap);
@@ -573,7 +577,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid,
 	 * rebuild the target's indexes and throw away the transient table.
 	 */
 	finish_heap_swap(tableOid, OIDNewHeap, is_system_catalog,
-					 swap_toast_by_content, false, frozenXid);
+					 swap_toast_by_content, false, true, frozenXid);
 }
 
 
@@ -1096,6 +1100,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
 static void
 swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 					bool swap_toast_by_content,
+					bool is_internal,
 					TransactionId frozenXid,
 					Oid *mapped_tables)
 {
@@ -1248,6 +1253,15 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 		CatalogIndexInsert(indstate, reltup1);
 		CatalogIndexInsert(indstate, reltup2);
 		CatalogCloseIndexes(indstate);
+
+		/*
+		 * Post alter hook of these relations, but r2 is always internal
+		 * stuff, and r1 is also depending on the invocation context.
+		 */
+		InvokeObjectPostAlterHookArg(RelationRelationId, r1, 0,
+									 InvalidOid, is_internal);
+		InvokeObjectPostAlterHookArg(RelationRelationId, r2, 0,
+									 InvalidOid, true);
 	}
 	else
 	{
@@ -1271,6 +1285,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 									relform2->reltoastrelid,
 									target_is_pg_class,
 									swap_toast_by_content,
+									is_internal,
 									frozenXid,
 									mapped_tables);
 			}
@@ -1360,6 +1375,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 							relform2->reltoastidxid,
 							target_is_pg_class,
 							swap_toast_by_content,
+							is_internal,
 							InvalidTransactionId,
 							mapped_tables);
 
@@ -1398,6 +1414,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 				 bool is_system_catalog,
 				 bool swap_toast_by_content,
 				 bool check_constraints,
+				 bool is_internal,
 				 TransactionId frozenXid)
 {
 	ObjectAddress object;
@@ -1414,7 +1431,8 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 	 */
 	swap_relation_files(OIDOldHeap, OIDNewHeap,
 						(OIDOldHeap == RelationRelationId),
-						swap_toast_by_content, frozenXid, mapped_tables);
+						swap_toast_by_content, is_internal,
+						frozenXid, mapped_tables);
 
 	/*
 	 * If it's a system catalog, queue an sinval message to flush all
@@ -1495,13 +1513,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 458b573..9eecd2b 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"
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 09c06ed..8695a52 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -965,6 +965,9 @@ RenameDatabase(const char *oldname, const char *newname)
 	simple_heap_update(rel, &newtup->t_self, newtup);
 	CatalogUpdateIndexes(rel, newtup);
 
+	/* Post alter hook for this database */
+	InvokeObjectPostAlterHook(DatabaseRelationId, db_id, 0);
+
 	/*
 	 * Close pg_database, but keep lock till commit.
 	 */
@@ -1200,6 +1203,10 @@ movedb(const char *dbname, const char *tblspcname)
 		/* Update indexes */
 		CatalogUpdateIndexes(pgdbrel, newtuple);
 
+		/* Post alter hook for this database */
+		InvokeObjectPostAlterHook(DatabaseRelationId,
+								  HeapTupleGetOid(newtuple), 0);
+
 		systable_endscan(sysscan);
 
 		/*
@@ -1394,6 +1401,10 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
 	/* Update indexes */
 	CatalogUpdateIndexes(rel, newtuple);
 
+	/* Post alter hook for this database */
+	InvokeObjectPostAlterHook(DatabaseRelationId,
+							  HeapTupleGetOid(newtuple), 0);
+
 	systable_endscan(scan);
 
 	/* Close pg_database, but keep lock till commit */
@@ -1526,6 +1537,8 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
 		changeDependencyOnOwner(DatabaseRelationId, HeapTupleGetOid(tuple),
 								newOwnerId);
 	}
+	/* Post alter hook for the database */
+	InvokeObjectPostAlterHook(DatabaseRelationId, HeapTupleGetOid(tuple), 0);
 
 	systable_endscan(scan);
 
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 2de2edb..228001d 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -491,6 +491,9 @@ AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 	changeDependencyOnOwner(EventTriggerRelationId,
 							HeapTupleGetOid(tup),
 							newOwnerId);
+	/* Post alter hook for the event trigger */
+	InvokeObjectPostAlterHook(EventTriggerRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index e45de83..d067fec 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2360,6 +2360,9 @@ 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 */
+	InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
 }
 
 /*
@@ -2640,6 +2643,9 @@ ApplyExtensionUpdates(Oid extensionOid,
 			recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
 		}
 
+		/* Post alter hook for this extension */
+		InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
+
 		/*
 		 * Finally, execute the update script file
 		 */
@@ -2745,6 +2751,8 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 											DEPENDENCY_EXTENSION) != 1)
 			elog(ERROR, "unexpected number of extension dependency records");
 	}
+	/* Post alter hook of this extension */
+	InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
 
 	/*
 	 * 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 e2f86d2..5cb6c2f 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -241,6 +241,9 @@ AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerI
 								HeapTupleGetOid(tup),
 								newOwnerId);
 	}
+	/* Post alter hook for the FDW */
+	InvokeObjectPostAlterHook(ForeignDataWrapperRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
@@ -344,6 +347,9 @@ AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 		changeDependencyOnOwner(ForeignServerRelationId, HeapTupleGetOid(tup),
 								newOwnerId);
 	}
+	/* Post alter hook for the foreign server */
+	InvokeObjectPostAlterHook(ForeignServerRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
@@ -751,6 +757,8 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
 	}
+	/* Post alter hook of this FDW */
+	InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
@@ -978,6 +986,9 @@ AlterForeignServer(AlterForeignServerStmt *stmt)
 	simple_heap_update(rel, &tp->t_self, tp);
 	CatalogUpdateIndexes(rel, tp);
 
+	/* Post alter hook of this foreign server */
+	InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);
+
 	heap_freetuple(tp);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 26a806b..91f9fdc 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1222,7 +1222,7 @@ AlterFunction(AlterFunctionStmt *stmt)
 	/* Do the update */
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
-
+	InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 }
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index c8e0e75..35f10b5 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -1370,6 +1370,9 @@ storeOperators(List *opfamilyname, Oid amoid,
 			referenced.objectSubId = 0;
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
+		/* Post create hook of this access method operator */
+		InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
+								   entryoid, 0);
 	}
 
 	heap_close(rel, RowExclusiveLock);
@@ -1469,6 +1472,9 @@ storeProcedures(List *opfamilyname, Oid amoid,
 			referenced.objectSubId = 0;
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 		}
+		/* Post create hook of access method procedure */
+		InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
+								   entryoid, 0);
 	}
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index e69c86b..9d4d75e 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,8 @@ RenameSchema(const char *oldname, const char *newname)
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
 
+	InvokeObjectPostAlterHook(NamespaceRelationId, HeapTupleGetOid(tup), 0);
+
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 }
@@ -363,5 +366,7 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
 		changeDependencyOnOwner(NamespaceRelationId, HeapTupleGetOid(tup),
 								newOwnerId);
 	}
-
+	/* Post alter hook for the namespace */
+	InvokeObjectPostAlterHook(NamespaceRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 634ce3f..3829003 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,9 @@ AlterSequence(AlterSeqStmt *stmt)
 	if (owned_by)
 		process_owned_by(seqrel, owned_by);
 
+	/* Post alter hook of this sequence */
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
+
 	relation_close(seqrel, NoLock);
 }
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index d516e2a..20eb0a5 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
@@ -1955,6 +1955,11 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
 
 	recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL);
 
+	/* Post creation hook of this inheritance */
+	InvokeObjectPostAlterHookArg(InheritsRelationId,
+								 relationId, 0,
+								 parentOid, false);
+
 	/*
 	 * Mark the parent as having subclasses.
 	 */
@@ -2213,6 +2218,9 @@ renameatt_internal(Oid myrelid,
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, atttup);
 
+	/* Post alter hook for this attribute */
+	InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
+
 	heap_freetuple(atttup);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -2357,7 +2365,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);
 
@@ -2433,7 +2441,7 @@ RenameRelation(RenameStmt *stmt)
 	}
 
 	/* Do the work */
-	RenameRelationInternal(relid, stmt->newname);
+	RenameRelationInternal(relid, stmt->newname, false);
 }
 
 /*
@@ -2446,7 +2454,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 */
@@ -2488,6 +2496,10 @@ RenameRelationInternal(Oid myrelid, const char *newrelname)
 	/* keep the system catalog indexes current */
 	CatalogUpdateIndexes(relrelation, reltup);
 
+	/* Post alter hook for this relation */
+	InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
+								 InvalidOid, is_internal);
+
 	heap_freetuple(reltup);
 	heap_close(relrelation, RowExclusiveLock);
 
@@ -3309,7 +3321,6 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			 */
 			break;
 		case AT_SetTableSpace:	/* SET TABLESPACE */
-
 			/*
 			 * Nothing to do here; Phase 3 does the work
 			 */
@@ -3500,7 +3511,9 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
 			 * interest in letting this code work on system catalogs.
 			 */
 			finish_heap_swap(tab->relid, OIDNewHeap,
-							 false, false, true, RecentXmin);
+							 false, false, true,
+							 !OidIsValid(tab->newTableSpace),
+							 RecentXmin);
 		}
 		else
 		{
@@ -4489,7 +4502,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();
@@ -4826,6 +4840,8 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
 		/* keep the system catalog indexes current */
 		CatalogUpdateIndexes(attr_rel, tuple);
 	}
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
 
 	heap_close(attr_rel, RowExclusiveLock);
 }
@@ -4878,6 +4894,8 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
 		/* Tell Phase 3 it needs to test the constraint */
 		tab->new_notnull = true;
 	}
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
 
 	heap_close(attr_rel, RowExclusiveLock);
 }
@@ -4933,7 +4951,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, true, false);
 	}
 }
 
@@ -5017,6 +5036,9 @@ ATExecSetStatistics(Relation rel, const char *colName, Node *newValue, LOCKMODE
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, tuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(tuple);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -5074,13 +5096,17 @@ 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);
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(newtuple);
 
+	ReleaseSysCache(tuple);
+
 	heap_close(attrelation, RowExclusiveLock);
 }
 
@@ -5150,6 +5176,9 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, tuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(tuple);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -5464,7 +5493,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 */
@@ -5488,7 +5517,8 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
 							stmt->primary,
 							true, /* update pg_index */
 							true, /* remove old dependencies */
-							allowSystemTableMods);
+							allowSystemTableMods,
+							false);	/* is_internal */
 
 	index_close(indexRel, NoLock);
 }
@@ -5600,7 +5630,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)
@@ -6050,7 +6081,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.
@@ -6232,6 +6264,8 @@ ATExecValidateConstraint(Relation rel, char *constrName, bool recurse,
 		copy_con->convalidated = true;
 		simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
 		CatalogUpdateIndexes(conrel, copyTuple);
+		InvokeObjectPostAlterHook(ConstraintRelationId,
+								  HeapTupleGetOid(tuple), 0);
 		heap_freetuple(copyTuple);
 	}
 
@@ -7659,6 +7693,10 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 	 */
 	RemoveStatistics(RelationGetRelid(rel), attnum);
 
+	/* Post alter hook of this column */
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
+
 	/*
 	 * Update the default, if present, by brute force --- remove and re-add
 	 * the default.  Probably unsafe to take shortcuts, since the new version
@@ -7678,7 +7716,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 		RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
 						  true);
 
-		StoreAttrDefault(rel, attnum, defaultexpr);
+		StoreAttrDefault(rel, attnum, defaultexpr, true);
 	}
 
 	/* Cleanup */
@@ -7769,10 +7807,13 @@ 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);
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  atttableform->attnum);
+	ReleaseSysCache(tuple);
 
 	heap_close(attrel, RowExclusiveLock);
 
@@ -8244,6 +8285,8 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 			change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
 		}
 	}
+	/* Post alter hook of this relation */
+	InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
 
 	ReleaseSysCache(tuple);
 	heap_close(class_rel, RowExclusiveLock);
@@ -8406,7 +8449,7 @@ ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
 	check_index_is_clusterable(rel, indexOid, false, lockmode);
 
 	/* And do the work */
-	mark_index_clustered(rel, indexOid);
+	mark_index_clustered(rel, indexOid, false);
 }
 
 /*
@@ -8418,7 +8461,7 @@ ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
 static void
 ATExecDropCluster(Relation rel, LOCKMODE lockmode)
 {
-	mark_index_clustered(rel, InvalidOid);
+	mark_index_clustered(rel, InvalidOid, false);
 }
 
 /*
@@ -8538,6 +8581,8 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 
 	CatalogUpdateIndexes(pgclass, newtuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
+
 	heap_freetuple(newtuple);
 
 	ReleaseSysCache(tuple);
@@ -8595,6 +8640,10 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 
 		CatalogUpdateIndexes(pgclass, newtuple);
 
+		InvokeObjectPostAlterHookArg(RelationRelationId,
+									 RelationGetRelid(toastrel), 0,
+									 InvalidOid, true);
+
 		heap_freetuple(newtuple);
 
 		ReleaseSysCache(tuple);
@@ -8636,6 +8685,8 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	if (newTableSpace == oldTableSpace ||
 		(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
 	{
+		InvokeObjectPostAlterHook(RelationRelationId,
+								  RelationGetRelid(rel), 0);
 		relation_close(rel, NoLock);
 		return;
 	}
@@ -8732,6 +8783,7 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	rd_rel->relfilenode = newrelfilenode;
 	simple_heap_update(pg_class, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(pg_class, tuple);
+	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
 
 	heap_freetuple(tuple);
 
@@ -9421,6 +9473,11 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
 						   RelationRelationId,
 						   RelationGetRelid(parent_rel));
 
+	/* Post alter hook of this inherits */
+	InvokeObjectPostAlterHookArg(InheritsRelationId,
+								 RelationGetRelid(rel), 0,
+								 RelationGetRelid(parent_rel), false);
+
 	/* keep our lock on the parent relation until commit */
 	heap_close(parent_rel, NoLock);
 }
@@ -9603,6 +9660,7 @@ 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);
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
 	heap_freetuple(classtuple);
 	heap_close(relationRelation, RowExclusiveLock);
 
@@ -9643,6 +9701,7 @@ ATExecDropOf(Relation rel, LOCKMODE lockmode)
 	((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
 	simple_heap_update(relationRelation, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(relationRelation, tuple);
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
 	heap_freetuple(tuple);
 	heap_close(relationRelation, RowExclusiveLock);
 }
@@ -9712,6 +9771,9 @@ ATExecGenericOptions(Relation rel, List *options)
 	simple_heap_update(ftrel, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(ftrel, tuple);
 
+	InvokeObjectPostAlterHook(ForeignTableRelationId,
+							  RelationGetRelid(rel), 0);
+
 	heap_close(ftrel, RowExclusiveLock);
 
 	heap_freetuple(tuple);
@@ -9865,6 +9927,9 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
 				 NameStr(classForm->relname));
 
 		add_exact_object_address(&thisobj, objsMoved);
+
+		/* Post alter hook for this relation */
+		InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
 	}
 
 	heap_freetuple(classTup);
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index e794ecf..ade5d75 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -862,6 +862,8 @@ RenameTableSpace(const char *oldname, const char *newname)
 	/* OK, update the entry */
 	AlterObjectRename_internal(rel, tableSpaceId, newname);
 
+	InvokeObjectPostAlterHook(TableSpaceRelationId, tableSpaceId, 0);
+
 	heap_close(rel, NoLock);
 }
 
@@ -925,6 +927,7 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
 	/* Update system catalog. */
 	simple_heap_update(rel, &newtuple->t_self, newtuple);
 	CatalogUpdateIndexes(rel, newtuple);
+	InvokeObjectPostAlterHook(TableSpaceRelationId, HeapTupleGetOid(tup), 0);
 	heap_freetuple(newtuple);
 
 	/* Conclude heap scan. */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 4a369a4..311edef 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,7 +742,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 							   DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new trigger */
-	InvokeObjectPostCreateHook(TriggerRelationId, trigoid, 0);
+	InvokeObjectPostCreateHookArg(TriggerRelationId, trigoid, 0,
+								  isInternal);
 
 	/* Keep lock on target rel until end of xact */
 	heap_close(rel, NoLock);
@@ -1273,6 +1275,10 @@ renametrig(RenameStmt *stmt)
 		/* keep system catalog indexes current */
 		CatalogUpdateIndexes(tgrel, tuple);
 
+		/* Post alter hook for this trigger */
+		InvokeObjectPostAlterHook(TriggerRelationId,
+								  HeapTupleGetOid(tuple), 0);
+
 		/*
 		 * Invalidate relation's relcache entry so that other backends (and
 		 * this one too!) are sent SI message to make them rebuild relcache
@@ -1386,6 +1392,9 @@ EnableDisableTrigger(Relation rel, const char *tgname,
 
 			changed = true;
 		}
+		/* Post alter hook for this trigger */
+		InvokeObjectPostAlterHook(TriggerRelationId,
+								  HeapTupleGetOid(tuple), 0);
 	}
 
 	systable_endscan(tgscan);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 64e9885..61342d2 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -608,6 +608,8 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
 
 	CatalogUpdateIndexes(rel, newtup);
 
+	InvokeObjectPostAlterHook(TSDictionaryRelationId, dictId, 0);
+
 	/*
 	 * NOTE: because we only support altering the options, not the template,
 	 * there is no need to update dependencies.  This might have to change if
@@ -1171,6 +1173,9 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
 	/* Update dependencies */
 	makeConfigurationDependencies(tup, true, relMap);
 
+	InvokeObjectPostAlterHook(TSConfigMapRelationId,
+							  HeapTupleGetOid(tup), 0);
+
 	heap_close(relMap, RowExclusiveLock);
 
 	ReleaseSysCache(tup);
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 36de6d7..b9fff13 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"
@@ -1210,6 +1211,9 @@ AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
 				 stmt->newValNeighbor, stmt->newValIsAfter,
 				 stmt->skipIfExists);
 
+	/* Post alter hook of this enum type */
+	InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
+
 	ReleaseSysCache(tup);
 }
 
@@ -2183,7 +2187,8 @@ AlterDomainDefault(List *names, Node *defaultRaw)
 							 typTup->typcollation,
 							 defaultExpr,
 							 true);		/* Rebuild is true */
-
+	/* Post alter hook of this domain */
+	InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
 	/* Clean up */
 	heap_close(rel, NoLock);
 	heap_freetuple(newtuple);
@@ -2280,6 +2285,9 @@ AlterDomainNotNull(List *names, bool notNull)
 
 	CatalogUpdateIndexes(typrel, tup);
 
+	/* Post alter hook of this domain */
+	InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
+
 	/* Clean up */
 	heap_freetuple(tup);
 	heap_close(typrel, RowExclusiveLock);
@@ -2561,6 +2569,8 @@ AlterDomainValidateConstraint(List *names, char *constrName)
 	copy_con->convalidated = true;
 	simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
 	CatalogUpdateIndexes(conrel, copyTuple);
+	InvokeObjectPostAlterHook(ConstraintRelationId,
+							  HeapTupleGetOid(copyTuple), 0);
 	heap_freetuple(copyTuple);
 
 	systable_endscan(scan);
@@ -2959,7 +2969,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
@@ -3154,7 +3165,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);
@@ -3275,6 +3286,9 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
 			/* Update owner dependency reference */
 			changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
 
+			/* Post alter hook of this type */
+			InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 			/* If it has an array type, update that too */
 			if (OidIsValid(typTup->typarray))
 				AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
@@ -3295,6 +3309,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,
@@ -3328,6 +3344,9 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
 	if (OidIsValid(typTup->typarray))
 		AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
 
+	/* Post alter hook for the type */
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	/* Clean up */
 	heap_close(rel, RowExclusiveLock);
 }
@@ -3513,6 +3532,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 */
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	heap_freetuple(tup);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index c1b7b93..2b17675 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -775,6 +775,9 @@ AlterRole(AlterRoleStmt *stmt)
 	/* Update indexes */
 	CatalogUpdateIndexes(pg_authid_rel, new_tuple);
 
+	/* Post alter hook of this role */
+	InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
+
 	ReleaseSysCache(tuple);
 	heap_freetuple(new_tuple);
 
@@ -1128,6 +1131,8 @@ RenameRole(const char *oldname, const char *newname)
 
 	CatalogUpdateIndexes(rel, newtuple);
 
+	InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
+
 	ReleaseSysCache(oldtuple);
 
 	/*
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 17e3513..6f7e87d 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -733,6 +733,8 @@ EnableDisableRule(Relation rel, const char *rulename,
 
 		changed = true;
 	}
+	InvokeObjectPostAlterHook(RewriteRelationId,
+							  HeapTupleGetOid(ruletup), 0);
 
 	heap_freetuple(ruletup);
 	heap_close(pg_rewrite_desc, RowExclusiveLock);
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 b96099f..225ee73 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -72,7 +72,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 3e080ba..be7fd9c 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,
@@ -70,6 +98,8 @@ extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
 									bool is_internal);
 extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
 							  int dropflags);
+extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
+								   Oid auxiliaryId, bool is_internal);
 
 #define InvokeObjectPostCreateHook(classId,objectId,subId)			\
 	InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
@@ -89,4 +119,15 @@ extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
 							  (dropflags));							\
 	} while(0)
 
+#define InvokeObjectPostAlterHook(classId,objectId,subId)			\
+	InvokeObjectPostAlterHookArg((classId),(objectId),(subId),		\
+								 InvalidOid,false)
+#define InvokeObjectPostAlterHookArg(classId,objectId,subId,		\
+									 auxiliaryId,is_internal)		\
+	do {															\
+		if (object_access_hook)										\
+			RunObjectPostAlterHook((classId),(objectId),(subId),	\
+								   (auxiliaryId),(is_internal));	\
+	} while(0)
+
 #endif   /* OBJECTACCESS_H */
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/cluster.h b/src/include/commands/cluster.h
index 21b2a58..1b4bd22 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -23,13 +23,14 @@ extern void cluster_rel(Oid tableOid, Oid indexOid, bool recheck,
 			bool verbose, int freeze_min_age, int freeze_table_age);
 extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
 						   bool recheck, LOCKMODE lockmode);
-extern void mark_index_clustered(Relation rel, Oid indexOid);
+extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
 
 extern Oid	make_new_heap(Oid OIDOldHeap, Oid NewTableSpace);
 extern void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 				 bool is_system_catalog,
 				 bool swap_toast_by_content,
 				 bool check_constraints,
+				 bool is_internal,
 				 TransactionId frozenXid);
 
 #endif   /* CLUSTER_H */
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,
sepgsql-v9.3-post-alter-support.v5.part-1.patchapplication/octet-stream; name=sepgsql-v9.3-post-alter-support.v5.part-1.patchDownload
 src/backend/catalog/Makefile               |    3 +-
 src/backend/catalog/dependency.c           |   10 +----
 src/backend/catalog/heap.c                 |   10 +----
 src/backend/catalog/index.c                |   11 +----
 src/backend/catalog/objectaccess.c         |   63 ++++++++++++++++++++++++++++
 src/backend/catalog/pg_collation.c         |    3 +-
 src/backend/catalog/pg_constraint.c        |    3 +-
 src/backend/catalog/pg_conversion.c        |    3 +-
 src/backend/catalog/pg_namespace.c         |    3 +-
 src/backend/catalog/pg_operator.c          |    6 +--
 src/backend/catalog/pg_proc.c              |    3 +-
 src/backend/catalog/pg_type.c              |    6 +--
 src/backend/commands/dbcommands.c          |   12 +-----
 src/backend/commands/event_trigger.c       |    3 +-
 src/backend/commands/extension.c           |    3 +-
 src/backend/commands/foreigncmds.c         |    9 ++--
 src/backend/commands/functioncmds.c        |    3 +-
 src/backend/commands/opclasscmds.c         |    6 +--
 src/backend/commands/proclang.c            |    3 +-
 src/backend/commands/tablecmds.c           |    3 +-
 src/backend/commands/tablespace.c          |   12 +-----
 src/backend/commands/trigger.c             |    3 +-
 src/backend/commands/tsearchcmds.c         |   12 ++----
 src/backend/commands/user.c                |   12 +-----
 src/backend/rewrite/rewriteDefine.c        |    3 +-
 src/backend/storage/large_object/inv_api.c |    3 +-
 src/backend/utils/init/globals.c           |    7 ----
 src/include/catalog/objectaccess.h         |   22 ++++++++--
 28 files changed, 121 insertions(+), 119 deletions(-)

diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index df6da1f..c4d3f3c 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -11,7 +11,8 @@ top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
 OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
-       objectaddress.o pg_aggregate.o pg_collation.o pg_constraint.o pg_conversion.o \
+       objectaccess.o objectaddress.o pg_aggregate.o pg_collation.o \
+       pg_constraint.o pg_conversion.o \
        pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \
        pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \
        pg_type.o storage.o toasting.o
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 192b421..958b251 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -997,14 +997,8 @@ deleteOneObject(const ObjectAddress *object, Relation *depRel, int flags)
 	HeapTuple	tup;
 
 	/* DROP hook of the objects being removed */
-	if (object_access_hook)
-	{
-		ObjectAccessDrop drop_arg;
-
-		drop_arg.dropflags = flags;
-		InvokeObjectAccessHook(OAT_DROP, object->classId, object->objectId,
-							   object->objectSubId, &drop_arg);
-	}
+	InvokeObjectDropHookArg(object->classId, object->objectId,
+							object->objectSubId, flags);
 
 	/*
 	 * Close depRel if we are doing a drop concurrently.  The object deletion
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index d93d273..54de9a7 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1277,15 +1277,7 @@ heap_create_with_catalog(const char *relname,
 	}
 
 	/* Post creation hook for new relation */
-	if (object_access_hook)
-	{
-		ObjectAccessPostCreate	post_create_args;
-
-		memset(&post_create_args, 0, sizeof(ObjectAccessPostCreate));
-		post_create_args.is_internal = is_internal;
-		(*object_access_hook)(OAT_POST_CREATE, RelationRelationId,
-							  relid, 0, &post_create_args);
-    }
+	InvokeObjectPostCreateHookArg(RelationRelationId, relid, 0, is_internal);
 
 	/*
 	 * Store any supplied constraints and defaults.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 66012ac..b1091ac 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1027,15 +1027,8 @@ index_create(Relation heapRelation,
 	}
 
 	/* Post creation hook for new index */
-	if (object_access_hook)
-	{
-		ObjectAccessPostCreate	post_create_args;
-
-		memset(&post_create_args, 0, sizeof(ObjectAccessPostCreate));
-		post_create_args.is_internal = is_internal;
-		(*object_access_hook)(OAT_POST_CREATE, RelationRelationId,
-							  indexRelationId, 0, &post_create_args);
-	}
+	InvokeObjectPostCreateHookArg(RelationRelationId,
+								  indexRelationId, 0, is_internal);
 
 	/*
 	 * Advance the command counter so that we can see the newly-entered
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
new file mode 100644
index 0000000..79c1136
--- /dev/null
+++ b/src/backend/catalog/objectaccess.c
@@ -0,0 +1,63 @@
+/* -------------------------------------------------------------------------
+ *
+ * objectaccess.c
+ *		functions for object_access_hook on various events
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "catalog/objectaccess.h"
+
+/*
+ * Hook on object accesses.  This is intended as infrastructure for security
+ * and logging plugins.
+ */
+object_access_hook_type object_access_hook = NULL;
+
+/*
+ * RunObjectPostCreateHook
+ *
+ * It is entrypoint of OAT_POST_CREATE event
+ */
+void
+RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
+						bool is_internal)
+{
+	ObjectAccessPostCreate	pc_arg;
+
+	/* XXX - should be checked at caller side */
+	Assert(object_access_hook != NULL);
+
+	memset(&pc_arg, 0, sizeof(ObjectAccessPostCreate));
+	pc_arg.is_internal = is_internal;
+
+	(*object_access_hook)(OAT_POST_CREATE,
+						  classId, objectId, subId,
+						  (void *) &pc_arg);
+}
+
+/*
+ * RunObjectDropHook
+ *
+ * It is entrypoint of OAT_DROP event
+ */
+void
+RunObjectDropHook(Oid classId, Oid objectId, int subId,
+				  int dropflags)
+{
+	ObjectAccessDrop	drop_arg;
+
+	/* XXX - should be checked at caller side */
+	Assert(object_access_hook != NULL);
+
+	memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
+	drop_arg.dropflags = dropflags;
+
+	(*object_access_hook)(OAT_DROP,
+						  classId, objectId, subId,
+						  (void *) &drop_arg);
+}
diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c
index 6020d16..0c25554 100644
--- a/src/backend/catalog/pg_collation.c
+++ b/src/backend/catalog/pg_collation.c
@@ -136,8 +136,7 @@ CollationCreate(const char *collname, Oid collnamespace,
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new collation */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   CollationRelationId, oid, 0, NULL);
+	InvokeObjectPostCreateHook(CollationRelationId, oid, 0);
 
 	heap_freetuple(tup);
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 5e8c6da..1e6d947 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -367,8 +367,7 @@ CreateConstraintEntry(const char *constraintName,
 	}
 
 	/* Post creation hook for new constraint */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ConstraintRelationId, conOid, 0, NULL);
+	InvokeObjectPostCreateHook(ConstraintRelationId, conOid, 0);
 
 	return conOid;
 }
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index 68f1aa7..caef609 100644
--- a/src/backend/catalog/pg_conversion.c
+++ b/src/backend/catalog/pg_conversion.c
@@ -136,8 +136,7 @@ ConversionCreate(const char *conname, Oid connamespace,
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new conversion */
-	InvokeObjectAccessHook(OAT_POST_CREATE, ConversionRelationId,
-						   HeapTupleGetOid(tup), 0, NULL);
+	InvokeObjectPostCreateHook(ConversionRelationId, HeapTupleGetOid(tup), 0);
 
 	heap_freetuple(tup);
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c
index 098df22..b322ff6 100644
--- a/src/backend/catalog/pg_namespace.c
+++ b/src/backend/catalog/pg_namespace.c
@@ -96,8 +96,7 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
 		recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new schema */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   NamespaceRelationId, nspoid, 0, NULL);
+	InvokeObjectPostCreateHook(NamespaceRelationId, nspoid, 0);
 
 	return nspoid;
 }
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 88af345..bd44333 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -275,8 +275,7 @@ OperatorShellMake(const char *operatorName,
 	heap_freetuple(tup);
 
 	/* Post creation hook for new shell operator */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorRelationId, operatorObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
 
 	/*
 	 * Make sure the tuple is visible for subsequent lookups/updates.
@@ -544,8 +543,7 @@ OperatorCreate(const char *operatorName,
 	makeOperatorDependencies(tup);
 
 	/* Post creation hook for new operator */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorRelationId, operatorObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
 
 	heap_close(pg_operator_desc, RowExclusiveLock);
 
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index ba73264..444ee78 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -661,8 +661,7 @@ ProcedureCreate(const char *procedureName,
 	heap_freetuple(tup);
 
 	/* Post creation hook for new function */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ProcedureRelationId, retval, 0, NULL);
+	InvokeObjectPostCreateHook(ProcedureRelationId, retval, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 49133ee..cf0ebcc 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -163,8 +163,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
 								 false);
 
 	/* Post creation hook for new shell type */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TypeRelationId, typoid, 0, NULL);
+	InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
 
 	/*
 	 * clean up and return the type-oid
@@ -476,8 +475,7 @@ TypeCreate(Oid newTypeOid,
 								 rebuildDeps);
 
 	/* Post creation hook for new type */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TypeRelationId, typeObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
 
 	/*
 	 * finish up
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 3c13c47..09c06ed 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -520,8 +520,7 @@ createdb(const CreatedbStmt *stmt)
 	copyTemplateDependencies(src_dboid, dboid);
 
 	/* Post creation hook for new database */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   DatabaseRelationId, dboid, 0, NULL);
+	InvokeObjectPostCreateHook(DatabaseRelationId, dboid, 0);
 
 	/*
 	 * Force a checkpoint before starting the copy. This will force dirty
@@ -784,14 +783,7 @@ dropdb(const char *dbname, bool missing_ok)
 					   dbname);
 
 	/* DROP hook for the database being removed */
-	if (object_access_hook)
-	{
-		ObjectAccessDrop drop_arg;
-
-		memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
-		InvokeObjectAccessHook(OAT_DROP,
-							   DatabaseRelationId, db_id, 0, &drop_arg);
-	}
+	InvokeObjectDropHook(DatabaseRelationId, db_id, 0);
 
 	/*
 	 * Disallow dropping a DB that is marked istemplate.  This is just to
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index a126f32..2de2edb 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -307,8 +307,7 @@ insert_event_trigger_tuple(char *trigname, char *eventname, Oid evtOwner,
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new operator family */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   EventTriggerRelationId, trigoid, 0, NULL);
+	InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
 
 	/* Close pg_event_trigger. */
 	heap_close(tgrel, RowExclusiveLock);
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 47631be..e45de83 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1560,8 +1560,7 @@ InsertExtensionTuple(const char *extName, Oid extOwner,
 		recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
 	}
 	/* Post creation hook for new extension */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ExtensionRelationId, extensionOid, 0, NULL);
+	InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
 
 	return extensionOid;
 }
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 2d73d2d..e2f86d2 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -589,8 +589,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new foreign data wrapper */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ForeignDataWrapperRelationId, fdwId, 0, NULL);
+	InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
@@ -886,8 +885,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new foreign server */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ForeignServerRelationId, srvId, 0, NULL);
+	InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
@@ -1127,8 +1125,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new user mapping */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   UserMappingRelationId, umId, 0, NULL);
+	InvokeObjectPostCreateHook(UserMappingRelationId, umId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index cf0613f..26a806b 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1610,8 +1610,7 @@ CreateCast(CreateCastStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new cast */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   CastRelationId, castid, 0, NULL);
+	InvokeObjectPostCreateHook(CastRelationId, castid, 0);
 
 	heap_freetuple(tuple);
 
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 044ddd3..c8e0e75 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -309,8 +309,7 @@ CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new operator family */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorFamilyRelationId, opfamilyoid, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
@@ -710,8 +709,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new operator class */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorClassRelationId, opclassoid, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 6526b7e..2e446b5 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -429,8 +429,7 @@ create_proc_lang(const char *languageName, bool replace,
 	}
 
 	/* Post creation hook for new procedural language */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   LanguageRelationId, myself.objectId, 0, NULL);
+	InvokeObjectPostCreateHook(LanguageRelationId, myself.objectId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 }
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 4065740..d516e2a 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4462,8 +4462,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	heap_freetuple(reltup);
 
 	/* Post creation hook for new attribute */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   RelationRelationId, myrelid, newattnum, NULL);
+	InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
 
 	heap_close(pgclass, RowExclusiveLock);
 
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index d80b3a6..e794ecf 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -331,8 +331,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
 	recordDependencyOnOwner(TableSpaceRelationId, tablespaceoid, ownerId);
 
 	/* Post creation hook for new tablespace */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TableSpaceRelationId, tablespaceoid, 0, NULL);
+	InvokeObjectPostCreateHook(TableSpaceRelationId, tablespaceoid, 0);
 
 	create_tablespace_directories(location, tablespaceoid);
 
@@ -437,14 +436,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
 					   tablespacename);
 
 	/* DROP hook for the tablespace being removed */
-	if (object_access_hook)
-	{
-		ObjectAccessDrop drop_arg;
-
-		memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
-		InvokeObjectAccessHook(OAT_DROP, TableSpaceRelationId,
-							   tablespaceoid, 0, &drop_arg);
-	}
+	InvokeObjectDropHook(TableSpaceRelationId, tablespaceoid, 0);
 
 	/*
 	 * Remove the pg_tablespace tuple (this will roll back if we fail below)
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 91ef779..4a369a4 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -741,8 +741,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 							   DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new trigger */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TriggerRelationId, trigoid, 0, NULL);
+	InvokeObjectPostCreateHook(TriggerRelationId, trigoid, 0);
 
 	/* Keep lock on target rel until end of xact */
 	heap_close(rel, NoLock);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 9dbfa0c..64e9885 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -272,8 +272,7 @@ DefineTSParser(List *names, List *parameters)
 	makeParserDependencies(tup);
 
 	/* Post creation hook for new text search parser */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSParserRelationId, prsOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSParserRelationId, prsOid, 0);
 
 	heap_freetuple(tup);
 
@@ -477,8 +476,7 @@ DefineTSDictionary(List *names, List *parameters)
 	makeDictionaryDependencies(tup);
 
 	/* Post creation hook for new text search dictionary */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSDictionaryRelationId, dictOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSDictionaryRelationId, dictOid, 0);
 
 	heap_freetuple(tup);
 
@@ -790,8 +788,7 @@ DefineTSTemplate(List *names, List *parameters)
 	makeTSTemplateDependencies(tup);
 
 	/* Post creation hook for new text search template */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSTemplateRelationId, dictOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSTemplateRelationId, dictOid, 0);
 
 	heap_freetuple(tup);
 
@@ -1084,8 +1081,7 @@ DefineTSConfiguration(List *names, List *parameters)
 	makeConfigurationDependencies(tup, false, mapRel);
 
 	/* Post creation hook for new text search configuration */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSConfigRelationId, cfgOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSConfigRelationId, cfgOid, 0);
 
 	heap_freetuple(tup);
 
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index f178167..c1b7b93 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -426,8 +426,7 @@ CreateRole(CreateRoleStmt *stmt)
 				GetUserId(), false);
 
 	/* Post creation hook for new role */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   AuthIdRelationId, roleid, 0, NULL);
+	InvokeObjectPostCreateHook(AuthIdRelationId, roleid, 0);
 
 	/*
 	 * Close pg_authid, but keep lock till commit.
@@ -935,14 +934,7 @@ DropRole(DropRoleStmt *stmt)
 					 errmsg("must be superuser to drop superusers")));
 
 		/* DROP hook for the role being removed */
-		if (object_access_hook)
-		{
-			ObjectAccessDrop drop_arg;
-
-			memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
-			InvokeObjectAccessHook(OAT_DROP,
-								   AuthIdRelationId, roleid, 0, &drop_arg);
-		}
+		InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
 
 		/*
 		 * Lock the role, so nobody can add dependencies to her while we drop
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 55b0fed..17e3513 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -179,8 +179,7 @@ InsertRule(char *rulname,
 	}
 
 	/* Post creation hook for new rule */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   RewriteRelationId, rewriteObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(RewriteRelationId, rewriteObjectId, 0);
 
 	heap_close(pg_rewrite_desc, RowExclusiveLock);
 
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index ad8424b..b2c8781 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -218,8 +218,7 @@ inv_create(Oid lobjId)
 							lobjId_new, GetUserId());
 
 	/* Post creation hook for new large object */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   LargeObjectRelationId, lobjId_new, 0, NULL);
+	InvokeObjectPostCreateHook(LargeObjectRelationId, lobjId_new, 0);
 
 	/*
 	 * Advance command counter to make new tuple visible to later operations.
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index 8dd2b4b..536d308 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -18,7 +18,6 @@
  */
 #include "postgres.h"
 
-#include "catalog/objectaccess.h"
 #include "libpq/pqcomm.h"
 #include "miscadmin.h"
 #include "storage/backendid.h"
@@ -125,9 +124,3 @@ int			VacuumCostBalance = 0;		/* working state for vacuum */
 bool		VacuumCostActive = false;
 
 int			GinFuzzySearchLimit = 0;
-
-/*
- * Hook on object accesses.  This is intended as infrastructure for security
- * and logging plugins.
- */
-object_access_hook_type object_access_hook = NULL;
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index b4b84a6..3e080ba 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -66,11 +66,27 @@ typedef void (*object_access_hook_type) (ObjectAccessType access,
 
 extern PGDLLIMPORT object_access_hook_type object_access_hook;
 
-#define InvokeObjectAccessHook(access,classId,objectId,subId,arg)	\
+extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
+									bool is_internal);
+extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
+							  int dropflags);
+
+#define InvokeObjectPostCreateHook(classId,objectId,subId)			\
+	InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
+#define InvokeObjectPostCreateHookArg(classId,objectId,subId,is_internal) \
+	do {															\
+		if (object_access_hook)										\
+			RunObjectPostCreateHook((classId),(objectId),(subId),	\
+									(is_internal));					\
+	} while(0)
+
+#define InvokeObjectDropHook(classId,objectId,subId)				\
+	InvokeObjectDropHookArg((classId),(objectId),(subId),0)
+#define InvokeObjectDropHookArg(classId,objectId,subId,dropflags)	\
 	do {															\
 		if (object_access_hook)										\
-			(*object_access_hook)((access),(classId),				\
-								  (objectId),(subId),(arg));		\
+			RunObjectDropHook((classId),(objectId),(subId),			\
+							  (dropflags));							\
 	} while(0)
 
 #endif   /* OBJECTACCESS_H */
#16Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Kohei KaiGai (#15)
2 attachment(s)
Re: [v9.3] OAT_POST_ALTER object access hooks

I rebased the patch towards the latest master branch, but here is no
functionality changes.

The part-1 patch adds catalog/objectaccess.c to have entrypoints of
object_access_hook, instead of simple macro definition, to simplify
invocations with arguments. It is just a replacement of existing
OAT_POST_CREATE and OAT_DROP invocation with new style,

The part-2 patch adds new OAT_POST_ALTER event type, and
its relevant permission checks on contrib/sepgsql.

I hope part-1 patch at least being committed earlier, because it performs
prerequisite of other two simple patches to add permission checks to
sepgsql, even though I can understand part-2 takes a bit more power
of concentration for reviewing.

Thanks,

2012/12/13 Kohei KaiGai <kaigai@kaigai.gr.jp>:

2012/12/11 Kohei KaiGai <kaigai@kaigai.gr.jp>:

2012/12/11 Robert Haas <robertmhaas@gmail.com>:

On Mon, Dec 3, 2012 at 9:59 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

As we discussed before, it is hard to determine which attributes shall
be informed to extension via object_access_hook, so the proposed
post-alter hook (that allows to compare older and newer versions)
works fine on 99% cases.
However, I'm inclined to handle SET TABLESPACE as an exception
of this scenario. For example, an idea is to define OAT_PREP_ALTER
event additionally, but only invoked very limited cases that takes
unignorable side-effects until system catalog updates.
For consistency of hook, OAT_POST_ALTER event may also ought
to be invoked just after catalog updates of pg_class->reltablespace,
but is_internal=true.

How about your opinion?

I don't really like it - I think POST should mean POST. You can
define some other hook that gets called somewhere else, but after
means after. There are other plausible uses of these hooks besides
sepgsql; for example, logging the completion time of an action.
Putting the hooks in the "wrong" places because that happens to be
more convenient for sepgsql is going to render them useless for any
other purpose. Maybe nobody else will use them anyway, but I'd rather
not render it impossible before we get off the ground.

I have to admit "PREP" hook is problematic to determine which information
should be delivered, and which should not, as we had discussed before.
Yes, a hook convenient for sepgsql, might be unconvenient for others.

So, which alternatives do we have? I can list up a few ideas.

1) Putting POST_ALTER hook after existing whole table rewrite.
good: no need to have significant code change
bad: it takes heavy i/o prior to hook invocation

2) Updating reltablespace of pg_class prior to whole table rewrite,
and put POST_ALTER hook just after catalog update.
good: well fit with assumption of POST hook.
bad: it takes significant code changes on table rewriting

3) Using ProcessUtility_hook to track AKTER TABLE ... SET
TABLESPACE as an exception.
good: no need to have significant code change
bad: sepgsql also have to have analyzer of ALTER TABLE
commands.

I think (2) is the best way, if feasible. I need to investigate whether
the relevant code allows to implement catalog updates prior to
whole table rewriting.
However, (1) is also not so bad in a short term, as a first step towards
the idea (2) that takes additional code updates.
Of course, I can implement with (3), but not inclined with this idea.

Is there other idea?

I tried to adjust my patch based on the idea (1).

It does not do anything special on SET TABLESPACE, thus it follows
the manner of "POST_ALTER" command, but it also means permission
checks are applied after (possible) heavy i/o workload.

I'd like to revise the logic of whole table rewrite to move catalog update
prior to actual i/o works, however, it is not scope of this patch.

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

sepgsql-v9.3-post-alter-support.v6.part-2.patchapplication/octet-stream; name=sepgsql-v9.3-post-alter-support.v6.part-2.patchDownload
 contrib/sepgsql/database.c               |  27 +++++
 contrib/sepgsql/expected/alter.out       | 192 +++++++++++++++++++++++++++++++
 contrib/sepgsql/expected/ddl.out         |   9 ++
 contrib/sepgsql/hooks.c                  |  48 ++++++++
 contrib/sepgsql/proc.c                   |  90 ++++++++++++++-
 contrib/sepgsql/relation.c               |  91 +++++++++++++--
 contrib/sepgsql/schema.c                 |  51 ++++++++
 contrib/sepgsql/sepgsql.h                |   7 ++
 contrib/sepgsql/sql/alter.sql            | 136 ++++++++++++++++++++++
 contrib/sepgsql/sql/ddl.sql              |   6 +
 contrib/sepgsql/test_sepgsql             |   2 +-
 doc/src/sgml/sepgsql.sgml                |  19 ++-
 src/backend/catalog/aclchk.c             |   9 ++
 src/backend/catalog/heap.c               |  41 +++++--
 src/backend/catalog/index.c              |  12 +-
 src/backend/catalog/objectaccess.c       |  23 ++++
 src/backend/catalog/pg_constraint.c      |  11 +-
 src/backend/catalog/pg_db_role_setting.c |   5 +-
 src/backend/catalog/pg_type.c            |   3 +
 src/backend/commands/alter.c             |   9 ++
 src/backend/commands/cluster.c           |  32 ++++--
 src/backend/commands/collationcmds.c     |   1 +
 src/backend/commands/dbcommands.c        |  13 +++
 src/backend/commands/event_trigger.c     |   3 +
 src/backend/commands/extension.c         |   8 ++
 src/backend/commands/foreigncmds.c       |  11 ++
 src/backend/commands/functioncmds.c      |   2 +-
 src/backend/commands/opclasscmds.c       |   6 +
 src/backend/commands/schemacmds.c        |   7 +-
 src/backend/commands/sequence.c          |   4 +
 src/backend/commands/tablecmds.c         |  99 +++++++++++++---
 src/backend/commands/tablespace.c        |   3 +
 src/backend/commands/trigger.c           |  13 ++-
 src/backend/commands/tsearchcmds.c       |   5 +
 src/backend/commands/typecmds.c          |  28 ++++-
 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       |  40 +++++++
 src/include/catalog/pg_constraint.h      |   3 +-
 src/include/commands/cluster.h           |   3 +-
 src/include/commands/tablecmds.h         |   2 +-
 43 files changed, 1023 insertions(+), 67 deletions(-)

diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c
index 975c1d4..64d37a3 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..ef9abb3
--- /dev/null
+++ b/contrib/sepgsql/expected/alter.out
@@ -0,0 +1,192 @@
+--
+-- 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
+--
+-- XXX: It should take db_xxx:{setattr} permission checks even if
+--      owner is not actually changed.
+--
+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 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 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 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 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 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 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
+ALTER TABLE regtest_table SET TABLESPACE pg_default;
+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 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 7ec72a0..2cb3aed 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 b47c880..53b941d 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 a277fab..8bcaa41 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
@@ -529,6 +559,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 +590,66 @@ 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);
+
+	/*
+	 * XXX - In the future version, db_tuple:{use} of system catalog entry
+	 * shall be checked, if tablespace configuration is changed.
 	 */
 
 	/*
 	 * 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 75b2826..ecdfd73 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 5ae5146..d4ee94b 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..4bded7e
--- /dev/null
+++ b/contrib/sepgsql/sql/alter.sql
@@ -0,0 +1,136 @@
+--
+-- 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
+--
+-- XXX: It should take db_xxx:{setattr} permission checks even if
+--      owner is not actually changed.
+--
+ALTER DATABASE regtest_sepgsql_test_database_1 OWNER TO regtest_sepgsql_test_user;
+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 SCHEMA regtest_schema_1 OWNER TO regtest_sepgsql_test_user;
+ALTER TABLE regtest_table_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 SEQUENCE regtest_seq_1 OWNER TO regtest_sepgsql_test_user;
+ALTER VIEW regtest_view_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 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
+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 e7ce8b5..bc4b6a9 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -438,6 +438,9 @@ 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>
@@ -450,9 +453,21 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
    </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 0bf5356..a329239 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,14 @@ SetDefaultACL(InternalDefaultACL *iacls)
 							  iacls->roleid,
 							  noldmembers, oldmembers,
 							  nnewmembers, newmembers);
+
+		/* Post create or alter hook of this default ACL */
+		if (isNew)
+			InvokeObjectPostCreateHook(DefaultAclRelationId,
+									   HeapTupleGetOid(newtuple), 0);
+		else
+			InvokeObjectPostAlterHook(DefaultAclRelationId,
+									  HeapTupleGetOid(newtuple), 0);
 	}
 
 	if (HeapTupleIsValid(tuple))
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 8685d11..c9d4188 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -96,8 +96,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);
@@ -1298,7 +1299,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
@@ -1811,7 +1812,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;
@@ -1903,6 +1905,17 @@ 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.
+	 */
+	InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
+								  RelationGetRelid(rel), attnum, is_internal);
 }
 
 /*
@@ -1914,7 +1927,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;
@@ -1998,7 +2011,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);
@@ -2013,7 +2027,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;
@@ -2035,11 +2049,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:
@@ -2065,6 +2080,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.
@@ -2082,7 +2098,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;
@@ -2145,7 +2162,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;
@@ -2271,7 +2288,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 33a1803..64af1d7 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -933,7 +933,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.
@@ -1293,6 +1297,8 @@ index_constraint_create(Relation heapRelation,
 		{
 			simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
 			CatalogUpdateIndexes(pg_index, indexTuple);
+			InvokeObjectPostAlterHookArg(IndexRelationId, indexRelationId, 0,
+										 InvalidOid, is_internal);
 		}
 
 		heap_freetuple(indexTuple);
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
index 79c1136..0e6844c 100644
--- a/src/backend/catalog/objectaccess.c
+++ b/src/backend/catalog/objectaccess.c
@@ -61,3 +61,26 @@ RunObjectDropHook(Oid classId, Oid objectId, int subId,
 						  classId, objectId, subId,
 						  (void *) &drop_arg);
 }
+
+/*
+ * RunObjectPostAlterHook
+ *
+ * It is entrypoint of OAT_POST_ALTER event
+ */
+void
+RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
+					   Oid auxiliaryId, bool is_internal)
+{
+	ObjectAccessPostAlter	pa_arg;
+
+	/* XXX - should be checked at caller side */
+	Assert(object_access_hook != NULL);
+
+	memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
+	pa_arg.auxiliary_id = auxiliaryId;
+	pa_arg.is_internal = is_internal;
+
+	(*object_access_hook)(OAT_POST_ALTER,
+						  classId, objectId, subId,
+						  (void *) &pa_arg);
+}
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 547c7ee..a27da2d 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,7 +368,8 @@ CreateConstraintEntry(const char *constraintName,
 	}
 
 	/* Post creation hook for new constraint */
-	InvokeObjectPostCreateHook(ConstraintRelationId, conOid, 0);
+	InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0,
+								  is_internal);
 
 	return conOid;
 }
@@ -665,6 +667,9 @@ RenameConstraintById(Oid conId, const char *newname)
 	/* update the system catalog indexes */
 	CatalogUpdateIndexes(conDesc, tuple);
 
+	/* Post alter hook for this constraint */
+	InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0);
+
 	heap_freetuple(tuple);
 	heap_close(conDesc, RowExclusiveLock);
 }
@@ -736,6 +741,8 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 			 * changeDependencyFor().
 			 */
 		}
+		/* Post alter hook for the constraint */
+		InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0);
 
 		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 337ccdd..db0a686 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,9 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
 		/* Update indexes */
 		CatalogUpdateIndexes(rel, newtuple);
 	}
-
+	/* Post alter hook for this database-role-settings */
+	InvokeObjectPostAlterHookArg(DbRoleSettingRelationId,
+								 databaseid, 0, roleid, false);
 	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 b044400..3b3aa30 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -712,6 +712,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 */
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	heap_freetuple(tuple);
 	heap_close(pg_type_desc, RowExclusiveLock);
 
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index c2d4bb3..a5f6aca 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_collation.h"
 #include "catalog/pg_conversion.h"
 #include "catalog/pg_event_trigger.h"
@@ -280,6 +281,9 @@ AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
 	simple_heap_update(rel, &oldtup->t_self, newtup);
 	CatalogUpdateIndexes(rel, newtup);
 
+	/* Post alter hook of the object */
+	InvokeObjectPostAlterHook(classId, objectId, 0);
+
 	/* Release memory */
 	pfree(values);
 	pfree(nulls);
@@ -650,6 +654,9 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
 	changeDependencyFor(classId, objid,
 						NamespaceRelationId, oldNspOid, nspOid);
 
+	/* Post alter hook for the object */
+	InvokeObjectPostAlterHook(classId, objid, 0);
+
 	return oldNspOid;
 }
 
@@ -927,4 +934,6 @@ AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
 		pfree(nulls);
 		pfree(replaces);
 	}
+	/* Post alter hook for the object */
+	InvokeObjectPostAlterHook(classId, objectId, 0);
 }
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index c0cb2f6..d5dc230 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -27,6 +27,7 @@
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
 #include "catalog/toasting.h"
 #include "commands/cluster.h"
 #include "commands/tablecmds.h"
@@ -467,7 +468,7 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMOD
  * otherwise concurrent executions of RelationGetIndexList could miss indexes.
  */
 void
-mark_index_clustered(Relation rel, Oid indexOid)
+mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
 {
 	HeapTuple	indexTuple;
 	Form_pg_index indexForm;
@@ -527,6 +528,9 @@ mark_index_clustered(Relation rel, Oid indexOid)
 			simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
 			CatalogUpdateIndexes(pg_index, indexTuple);
 		}
+		/* Post object alter hook of this index */
+		InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
+									 InvalidOid, is_internal);
 		heap_freetuple(indexTuple);
 	}
 
@@ -555,7 +559,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid,
 
 	/* Mark the correct index as clustered */
 	if (OidIsValid(indexOid))
-		mark_index_clustered(OldHeap, indexOid);
+		mark_index_clustered(OldHeap, indexOid, true);
 
 	/* Remember if it's a system catalog */
 	is_system_catalog = IsSystemRelation(OldHeap);
@@ -576,7 +580,8 @@ rebuild_relation(Relation OldHeap, Oid indexOid,
 	 * rebuild the target's indexes and throw away the transient table.
 	 */
 	finish_heap_swap(tableOid, OIDNewHeap, is_system_catalog,
-					 swap_toast_by_content, false, frozenXid, frozenMulti);
+					 swap_toast_by_content, false, true,
+					 frozenXid, frozenMulti);
 }
 
 
@@ -1102,6 +1107,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
 static void
 swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 					bool swap_toast_by_content,
+					bool is_internal,
 					TransactionId frozenXid,
 					MultiXactId frozenMulti,
 					Oid *mapped_tables)
@@ -1257,6 +1263,15 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 		CatalogIndexInsert(indstate, reltup1);
 		CatalogIndexInsert(indstate, reltup2);
 		CatalogCloseIndexes(indstate);
+
+		/*
+		 * Post alter hook of these relations, but r2 is always internal
+		 * stuff, and r1 is also depending on the invocation context.
+		 */
+		InvokeObjectPostAlterHookArg(RelationRelationId, r1, 0,
+									 InvalidOid, is_internal);
+		InvokeObjectPostAlterHookArg(RelationRelationId, r2, 0,
+									 InvalidOid, true);
 	}
 	else
 	{
@@ -1280,6 +1295,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 									relform2->reltoastrelid,
 									target_is_pg_class,
 									swap_toast_by_content,
+									is_internal,
 									frozenXid,
 									frozenMulti,
 									mapped_tables);
@@ -1370,6 +1386,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 							relform2->reltoastidxid,
 							target_is_pg_class,
 							swap_toast_by_content,
+							is_internal,
 							InvalidTransactionId,
 							InvalidMultiXactId,
 							mapped_tables);
@@ -1409,6 +1426,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 				 bool is_system_catalog,
 				 bool swap_toast_by_content,
 				 bool check_constraints,
+				 bool is_internal,
 				 TransactionId frozenXid,
 				 MultiXactId frozenMulti)
 {
@@ -1426,8 +1444,8 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 	 */
 	swap_relation_files(OIDOldHeap, OIDNewHeap,
 						(OIDOldHeap == RelationRelationId),
-						swap_toast_by_content, frozenXid, frozenMulti,
-						mapped_tables);
+						swap_toast_by_content, is_internal,
+						frozenXid, frozenMulti, mapped_tables);
 
 	/*
 	 * If it's a system catalog, queue an sinval message to flush all
@@ -1508,13 +1526,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 8326cd0..cdf086f 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"
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 76ef23a..ac63b03 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -997,6 +997,9 @@ RenameDatabase(const char *oldname, const char *newname)
 	simple_heap_update(rel, &newtup->t_self, newtup);
 	CatalogUpdateIndexes(rel, newtup);
 
+	/* Post alter hook for this database */
+	InvokeObjectPostAlterHook(DatabaseRelationId, db_id, 0);
+
 	/*
 	 * Close pg_database, but keep lock till commit.
 	 */
@@ -1234,6 +1237,10 @@ movedb(const char *dbname, const char *tblspcname)
 		/* Update indexes */
 		CatalogUpdateIndexes(pgdbrel, newtuple);
 
+		/* Post alter hook for this database */
+		InvokeObjectPostAlterHook(DatabaseRelationId,
+								  HeapTupleGetOid(newtuple), 0);
+
 		systable_endscan(sysscan);
 
 		/*
@@ -1431,6 +1438,10 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
 	/* Update indexes */
 	CatalogUpdateIndexes(rel, newtuple);
 
+	/* Post alter hook for this database */
+	InvokeObjectPostAlterHook(DatabaseRelationId,
+							  HeapTupleGetOid(newtuple), 0);
+
 	systable_endscan(scan);
 
 	/* Close pg_database, but keep lock till commit */
@@ -1569,6 +1580,8 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
 		changeDependencyOnOwner(DatabaseRelationId, HeapTupleGetOid(tuple),
 								newOwnerId);
 	}
+	/* Post alter hook for the database */
+	InvokeObjectPostAlterHook(DatabaseRelationId, HeapTupleGetOid(tuple), 0);
 
 	systable_endscan(scan);
 
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index bedeb6a..a0cf903 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -505,6 +505,9 @@ AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 	changeDependencyOnOwner(EventTriggerRelationId,
 							HeapTupleGetOid(tup),
 							newOwnerId);
+	/* Post alter hook for the event trigger */
+	InvokeObjectPostAlterHook(EventTriggerRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 6b7cb5b..866d674 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2573,6 +2573,9 @@ AlterExtensionNamespace(List *names, const char *newschema)
 	changeDependencyFor(ExtensionRelationId, extensionOid,
 						NamespaceRelationId, oldNspOid, nspOid);
 
+	/* Post alter hook for the extension */
+	InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
+
 	return extensionOid;
 }
 
@@ -2856,6 +2859,9 @@ ApplyExtensionUpdates(Oid extensionOid,
 			recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
 		}
 
+		/* Post alter hook for this extension */
+		InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
+
 		/*
 		 * Finally, execute the update script file
 		 */
@@ -2968,6 +2974,8 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 		if (object.classId == RelationRelationId)
 			extension_config_remove(extension.objectId, object.objectId);
 	}
+	/* Post alter hook of this extension */
+	InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
 
 	/*
 	 * 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 83cdf9e..6e06c0c 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -241,6 +241,9 @@ AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerI
 								HeapTupleGetOid(tup),
 								newOwnerId);
 	}
+	/* Post alter hook for the FDW */
+	InvokeObjectPostAlterHook(ForeignDataWrapperRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
@@ -349,6 +352,9 @@ AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 		changeDependencyOnOwner(ForeignServerRelationId, HeapTupleGetOid(tup),
 								newOwnerId);
 	}
+	/* Post alter hook for the foreign server */
+	InvokeObjectPostAlterHook(ForeignServerRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
@@ -763,6 +769,8 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
 	}
+	/* Post alter hook of this FDW */
+	InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
@@ -994,6 +1002,9 @@ AlterForeignServer(AlterForeignServerStmt *stmt)
 	simple_heap_update(rel, &tp->t_self, tp);
 	CatalogUpdateIndexes(rel, tp);
 
+	/* Post alter hook of this foreign server */
+	InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);
+
 	heap_freetuple(tp);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index fda379a..58958fe 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1168,7 +1168,7 @@ AlterFunction(AlterFunctionStmt *stmt)
 	/* Do the update */
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
-
+	InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index fc38c2a..e28424a 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -1374,6 +1374,9 @@ storeOperators(List *opfamilyname, Oid amoid,
 			referenced.objectSubId = 0;
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
+		/* Post create hook of this access method operator */
+		InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
+								   entryoid, 0);
 	}
 
 	heap_close(rel, RowExclusiveLock);
@@ -1473,6 +1476,9 @@ storeProcedures(List *opfamilyname, Oid amoid,
 			referenced.objectSubId = 0;
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 		}
+		/* Post create hook of access method procedure */
+		InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
+								   entryoid, 0);
 	}
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 1e857d9..d7b47a3 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"
@@ -240,6 +241,8 @@ RenameSchema(const char *oldname, const char *newname)
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
 
+	InvokeObjectPostAlterHook(NamespaceRelationId, HeapTupleGetOid(tup), 0);
+
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 
@@ -375,5 +378,7 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
 		changeDependencyOnOwner(NamespaceRelationId, HeapTupleGetOid(tup),
 								newOwnerId);
 	}
-
+	/* Post alter hook for the namespace */
+	InvokeObjectPostAlterHook(NamespaceRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index de41c8a..b50f343 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -20,6 +20,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"
@@ -487,6 +488,9 @@ AlterSequence(AlterSeqStmt *stmt)
 	if (owned_by)
 		process_owned_by(seqrel, owned_by);
 
+	/* Post alter hook of this sequence */
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
+
 	relation_close(seqrel, NoLock);
 
 	return relid;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index b0309be..8d24dd5 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -665,7 +665,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
@@ -1967,6 +1967,11 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
 
 	recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL);
 
+	/* Post creation hook of this inheritance */
+	InvokeObjectPostAlterHookArg(InheritsRelationId,
+								 relationId, 0,
+								 parentOid, false);
+
 	/*
 	 * Mark the parent as having subclasses.
 	 */
@@ -2225,6 +2230,9 @@ renameatt_internal(Oid myrelid,
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, atttup);
 
+	/* Post alter hook for this attribute */
+	InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
+
 	heap_freetuple(atttup);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -2372,7 +2380,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);
 
@@ -2452,7 +2460,7 @@ RenameRelation(RenameStmt *stmt)
 	}
 
 	/* Do the work */
-	RenameRelationInternal(relid, stmt->newname);
+	RenameRelationInternal(relid, stmt->newname, false);
 
 	return relid;
 }
@@ -2467,7 +2475,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 */
@@ -2509,6 +2517,10 @@ RenameRelationInternal(Oid myrelid, const char *newrelname)
 	/* keep the system catalog indexes current */
 	CatalogUpdateIndexes(relrelation, reltup);
 
+	/* Post alter hook for this relation */
+	InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
+								 InvalidOid, is_internal);
+
 	heap_freetuple(reltup);
 	heap_close(relrelation, RowExclusiveLock);
 
@@ -3330,7 +3342,6 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			 */
 			break;
 		case AT_SetTableSpace:	/* SET TABLESPACE */
-
 			/*
 			 * Nothing to do here; Phase 3 does the work
 			 */
@@ -3521,7 +3532,9 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
 			 * interest in letting this code work on system catalogs.
 			 */
 			finish_heap_swap(tab->relid, OIDNewHeap,
-							 false, false, true, RecentXmin,
+							 false, false, true,
+							 !OidIsValid(tab->newTableSpace),
+							 RecentXmin,
 							 ReadNextMultiXactId());
 		}
 		else
@@ -4511,7 +4524,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();
@@ -4848,6 +4862,8 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
 		/* keep the system catalog indexes current */
 		CatalogUpdateIndexes(attr_rel, tuple);
 	}
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
 
 	heap_close(attr_rel, RowExclusiveLock);
 }
@@ -4900,6 +4916,8 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
 		/* Tell Phase 3 it needs to test the constraint */
 		tab->new_notnull = true;
 	}
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
 
 	heap_close(attr_rel, RowExclusiveLock);
 }
@@ -4955,7 +4973,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, true, false);
 	}
 }
 
@@ -5039,6 +5058,9 @@ ATExecSetStatistics(Relation rel, const char *colName, Node *newValue, LOCKMODE
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, tuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(tuple);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -5096,13 +5118,17 @@ 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);
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(newtuple);
 
+	ReleaseSysCache(tuple);
+
 	heap_close(attrelation, RowExclusiveLock);
 }
 
@@ -5172,6 +5198,9 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, tuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(tuple);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -5486,7 +5515,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 */
@@ -5510,7 +5539,8 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
 							stmt->primary,
 							true, /* update pg_index */
 							true, /* remove old dependencies */
-							allowSystemTableMods);
+							allowSystemTableMods,
+							false);	/* is_internal */
 
 	index_close(indexRel, NoLock);
 }
@@ -5622,7 +5652,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)
@@ -6076,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.
@@ -6258,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);
+		InvokeObjectPostAlterHook(ConstraintRelationId,
+								  HeapTupleGetOid(tuple), 0);
 		heap_freetuple(copyTuple);
 	}
 
@@ -7685,6 +7719,10 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 	 */
 	RemoveStatistics(RelationGetRelid(rel), attnum);
 
+	/* Post alter hook of this column */
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
+
 	/*
 	 * Update the default, if present, by brute force --- remove and re-add
 	 * the default.  Probably unsafe to take shortcuts, since the new version
@@ -7704,7 +7742,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 		RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
 						  true);
 
-		StoreAttrDefault(rel, attnum, defaultexpr);
+		StoreAttrDefault(rel, attnum, defaultexpr, true);
 	}
 
 	/* Cleanup */
@@ -7795,10 +7833,13 @@ 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);
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  atttableform->attnum);
+	ReleaseSysCache(tuple);
 
 	heap_close(attrel, RowExclusiveLock);
 
@@ -8270,6 +8311,8 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 			change_owner_recurse_to_sequences(relationOid, newOwnerId, lockmode);
 		}
 	}
+	/* Post alter hook of this relation */
+	InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
 
 	ReleaseSysCache(tuple);
 	heap_close(class_rel, RowExclusiveLock);
@@ -8432,7 +8475,7 @@ ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
 	check_index_is_clusterable(rel, indexOid, false, lockmode);
 
 	/* And do the work */
-	mark_index_clustered(rel, indexOid);
+	mark_index_clustered(rel, indexOid, false);
 }
 
 /*
@@ -8444,7 +8487,7 @@ ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
 static void
 ATExecDropCluster(Relation rel, LOCKMODE lockmode)
 {
-	mark_index_clustered(rel, InvalidOid);
+	mark_index_clustered(rel, InvalidOid, false);
 }
 
 /*
@@ -8564,6 +8607,8 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 
 	CatalogUpdateIndexes(pgclass, newtuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
+
 	heap_freetuple(newtuple);
 
 	ReleaseSysCache(tuple);
@@ -8621,6 +8666,10 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 
 		CatalogUpdateIndexes(pgclass, newtuple);
 
+		InvokeObjectPostAlterHookArg(RelationRelationId,
+									 RelationGetRelid(toastrel), 0,
+									 InvalidOid, true);
+
 		heap_freetuple(newtuple);
 
 		ReleaseSysCache(tuple);
@@ -8662,6 +8711,8 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	if (newTableSpace == oldTableSpace ||
 		(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
 	{
+		InvokeObjectPostAlterHook(RelationRelationId,
+								  RelationGetRelid(rel), 0);
 		relation_close(rel, NoLock);
 		return;
 	}
@@ -8758,6 +8809,7 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	rd_rel->relfilenode = newrelfilenode;
 	simple_heap_update(pg_class, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(pg_class, tuple);
+	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
 
 	heap_freetuple(tuple);
 
@@ -9461,6 +9513,11 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
 						   RelationRelationId,
 						   RelationGetRelid(parent_rel));
 
+	/* Post alter hook of this inherits */
+	InvokeObjectPostAlterHookArg(InheritsRelationId,
+								 RelationGetRelid(rel), 0,
+								 RelationGetRelid(parent_rel), false);
+
 	/* keep our lock on the parent relation until commit */
 	heap_close(parent_rel, NoLock);
 }
@@ -9643,6 +9700,7 @@ 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);
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
 	heap_freetuple(classtuple);
 	heap_close(relationRelation, RowExclusiveLock);
 
@@ -9683,6 +9741,7 @@ ATExecDropOf(Relation rel, LOCKMODE lockmode)
 	((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
 	simple_heap_update(relationRelation, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(relationRelation, tuple);
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
 	heap_freetuple(tuple);
 	heap_close(relationRelation, RowExclusiveLock);
 }
@@ -9752,6 +9811,9 @@ ATExecGenericOptions(Relation rel, List *options)
 	simple_heap_update(ftrel, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(ftrel, tuple);
 
+	InvokeObjectPostAlterHook(ForeignTableRelationId,
+							  RelationGetRelid(rel), 0);
+
 	heap_close(ftrel, RowExclusiveLock);
 
 	heap_freetuple(tuple);
@@ -9907,6 +9969,9 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
 				 NameStr(classForm->relname));
 
 		add_exact_object_address(&thisobj, objsMoved);
+
+		/* Post alter hook for this relation */
+		InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
 	}
 
 	heap_freetuple(classTup);
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index f1da26a..420ae52 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -876,6 +876,8 @@ RenameTableSpace(const char *oldname, const char *newname)
 	simple_heap_update(rel, &newtuple->t_self, newtuple);
 	CatalogUpdateIndexes(rel, newtuple);
 
+	InvokeObjectPostAlterHook(TableSpaceRelationId, tspId, 0);
+
 	heap_close(rel, NoLock);
 
 	return tspId;
@@ -944,6 +946,7 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
 	/* Update system catalog. */
 	simple_heap_update(rel, &newtuple->t_self, newtuple);
 	CatalogUpdateIndexes(rel, newtuple);
+	InvokeObjectPostAlterHook(TableSpaceRelationId, HeapTupleGetOid(tup), 0);
 	heap_freetuple(newtuple);
 
 	/* Conclude heap scan. */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index ff9ddce..cd9d2a9 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -446,7 +446,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 											  NULL,
 											  true,		/* islocal */
 											  0,		/* inhcount */
-											  true);	/* isnoinherit */
+											  true,		/* isnoinherit */
+											  isInternal);	/* is_internal */
 	}
 
 	/*
@@ -742,7 +743,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 							   DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new trigger */
-	InvokeObjectPostCreateHook(TriggerRelationId, trigoid, 0);
+	InvokeObjectPostCreateHookArg(TriggerRelationId, trigoid, 0,
+								  isInternal);
 
 	/* Keep lock on target rel until end of xact */
 	heap_close(rel, NoLock);
@@ -1276,6 +1278,10 @@ renametrig(RenameStmt *stmt)
 		/* keep system catalog indexes current */
 		CatalogUpdateIndexes(tgrel, tuple);
 
+		/* Post alter hook for this trigger */
+		InvokeObjectPostAlterHook(TriggerRelationId,
+								  HeapTupleGetOid(tuple), 0);
+
 		/*
 		 * Invalidate relation's relcache entry so that other backends (and
 		 * this one too!) are sent SI message to make them rebuild relcache
@@ -1391,6 +1397,9 @@ EnableDisableTrigger(Relation rel, const char *tgname,
 
 			changed = true;
 		}
+		/* Post alter hook for this trigger */
+		InvokeObjectPostAlterHook(TriggerRelationId,
+								  HeapTupleGetOid(tuple), 0);
 	}
 
 	systable_endscan(tgscan);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 821fdc6..57b69f8 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -612,6 +612,8 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
 
 	CatalogUpdateIndexes(rel, newtup);
 
+	InvokeObjectPostAlterHook(TSDictionaryRelationId, dictId, 0);
+
 	/*
 	 * NOTE: because we only support altering the options, not the template,
 	 * there is no need to update dependencies.  This might have to change if
@@ -1184,6 +1186,9 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
 	/* Update dependencies */
 	makeConfigurationDependencies(tup, true, relMap);
 
+	InvokeObjectPostAlterHook(TSConfigMapRelationId,
+							  HeapTupleGetOid(tup), 0);
+
 	heap_close(relMap, RowExclusiveLock);
 
 	ReleaseSysCache(tup);
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 7a72416..9a48421 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"
@@ -1214,6 +1215,9 @@ AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
 				 stmt->newValNeighbor, stmt->newValIsAfter,
 				 stmt->skipIfExists);
 
+	/* Post alter hook of this enum type */
+	InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
+
 	ReleaseSysCache(tup);
 
 	return enum_type_oid;
@@ -2189,7 +2193,8 @@ AlterDomainDefault(List *names, Node *defaultRaw)
 							 typTup->typcollation,
 							 defaultExpr,
 							 true);		/* Rebuild is true */
-
+	/* Post alter hook of this domain */
+	InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
 	/* Clean up */
 	heap_close(rel, NoLock);
 	heap_freetuple(newtuple);
@@ -2288,6 +2293,9 @@ AlterDomainNotNull(List *names, bool notNull)
 
 	CatalogUpdateIndexes(typrel, tup);
 
+	/* Post alter hook of this domain */
+	InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
+
 	/* Clean up */
 	heap_freetuple(tup);
 	heap_close(typrel, RowExclusiveLock);
@@ -2575,6 +2583,8 @@ AlterDomainValidateConstraint(List *names, char *constrName)
 	copy_con->convalidated = true;
 	simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
 	CatalogUpdateIndexes(conrel, copyTuple);
+	InvokeObjectPostAlterHook(ConstraintRelationId,
+							  HeapTupleGetOid(copyTuple), 0);
 	heap_freetuple(copyTuple);
 
 	systable_endscan(scan);
@@ -2970,7 +2980,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
@@ -3165,7 +3176,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);
@@ -3288,6 +3299,9 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
 			/* Update owner dependency reference */
 			changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
 
+			/* Post alter hook of this type */
+			InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 			/* If it has an array type, update that too */
 			if (OidIsValid(typTup->typarray))
 				AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
@@ -3310,6 +3324,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,
@@ -3343,6 +3359,9 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
 	if (OidIsValid(typTup->typarray))
 		AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
 
+	/* Post alter hook for the type */
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	/* Clean up */
 	heap_close(rel, RowExclusiveLock);
 }
@@ -3530,6 +3549,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 */
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	heap_freetuple(tup);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 2b23473..8f34ce2 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -777,6 +777,9 @@ AlterRole(AlterRoleStmt *stmt)
 	/* Update indexes */
 	CatalogUpdateIndexes(pg_authid_rel, new_tuple);
 
+	/* Post alter hook of this role */
+	InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
+
 	ReleaseSysCache(tuple);
 	heap_freetuple(new_tuple);
 
@@ -1137,6 +1140,8 @@ RenameRole(const char *oldname, const char *newname)
 
 	CatalogUpdateIndexes(rel, newtuple);
 
+	InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
+
 	ReleaseSysCache(oldtuple);
 
 	/*
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 887f42f..e4f44a1 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -736,6 +736,8 @@ EnableDisableRule(Relation rel, const char *rulename,
 
 		changed = true;
 	}
+	InvokeObjectPostAlterHook(RewriteRelationId,
+							  HeapTupleGetOid(ruletup), 0);
 
 	heap_freetuple(ruletup);
 	heap_close(pg_rewrite_desc, RowExclusiveLock);
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index 3a1788d..6b60d55 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 fb323f7..e697275 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -72,7 +72,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 b9bb1bc..1359368 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -22,6 +22,11 @@
  * 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
@@ -57,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,
@@ -71,6 +98,8 @@ extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
 									bool is_internal);
 extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
 							  int dropflags);
+extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
+								   Oid auxiliaryId, bool is_internal);
 
 #define InvokeObjectPostCreateHook(classId,objectId,subId)			\
 	InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
@@ -90,4 +119,15 @@ extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
 							  (dropflags));							\
 	} while(0)
 
+#define InvokeObjectPostAlterHook(classId,objectId,subId)			\
+	InvokeObjectPostAlterHookArg((classId),(objectId),(subId),		\
+								 InvalidOid,false)
+#define InvokeObjectPostAlterHookArg(classId,objectId,subId,		\
+									 auxiliaryId,is_internal)		\
+	do {															\
+		if (object_access_hook)										\
+			RunObjectPostAlterHook((classId),(objectId),(subId),	\
+								   (auxiliaryId),(is_internal));	\
+	} while(0)
+
 #endif   /* OBJECTACCESS_H */
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index 29f71f1..4a6a18f 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/cluster.h b/src/include/commands/cluster.h
index 73c701f..aa6d332 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -23,13 +23,14 @@ extern void cluster_rel(Oid tableOid, Oid indexOid, bool recheck,
 			bool verbose, int freeze_min_age, int freeze_table_age);
 extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
 						   bool recheck, LOCKMODE lockmode);
-extern void mark_index_clustered(Relation rel, Oid indexOid);
+extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
 
 extern Oid	make_new_heap(Oid OIDOldHeap, Oid NewTableSpace);
 extern void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 				 bool is_system_catalog,
 				 bool swap_toast_by_content,
 				 bool check_constraints,
+				 bool is_internal,
 				 TransactionId frozenXid,
 				 MultiXactId frozenMulti);
 
diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h
index 27dc5e8..c07603b 100644
--- a/src/include/commands/tablecmds.h
+++ b/src/include/commands/tablecmds.h
@@ -58,7 +58,7 @@ extern Oid RenameConstraint(RenameStmt *stmt);
 extern Oid 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,
sepgsql-v9.3-post-alter-support.v6.part-1.patchapplication/octet-stream; name=sepgsql-v9.3-post-alter-support.v6.part-1.patchDownload
 src/backend/catalog/Makefile               |  3 +-
 src/backend/catalog/dependency.c           | 10 +----
 src/backend/catalog/heap.c                 | 10 +----
 src/backend/catalog/index.c                | 11 +-----
 src/backend/catalog/objectaccess.c         | 63 ++++++++++++++++++++++++++++++
 src/backend/catalog/pg_collation.c         |  3 +-
 src/backend/catalog/pg_constraint.c        |  3 +-
 src/backend/catalog/pg_conversion.c        |  3 +-
 src/backend/catalog/pg_namespace.c         |  3 +-
 src/backend/catalog/pg_operator.c          |  6 +--
 src/backend/catalog/pg_proc.c              |  3 +-
 src/backend/catalog/pg_type.c              |  6 +--
 src/backend/commands/aggregatecmds.c       |  1 +
 src/backend/commands/dbcommands.c          | 12 +-----
 src/backend/commands/event_trigger.c       |  3 +-
 src/backend/commands/extension.c           |  3 +-
 src/backend/commands/foreigncmds.c         |  9 ++---
 src/backend/commands/functioncmds.c        |  3 +-
 src/backend/commands/opclasscmds.c         |  6 +--
 src/backend/commands/proclang.c            |  3 +-
 src/backend/commands/tablecmds.c           |  3 +-
 src/backend/commands/tablespace.c          | 12 +-----
 src/backend/commands/trigger.c             |  3 +-
 src/backend/commands/tsearchcmds.c         | 12 ++----
 src/backend/commands/user.c                | 12 +-----
 src/backend/rewrite/rewriteDefine.c        |  3 +-
 src/backend/storage/large_object/inv_api.c |  3 +-
 src/backend/utils/init/globals.c           |  7 ----
 src/include/catalog/objectaccess.h         | 23 +++++++++--
 29 files changed, 123 insertions(+), 119 deletions(-)

diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index df6da1f..c4d3f3c 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -11,7 +11,8 @@ top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
 OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \
-       objectaddress.o pg_aggregate.o pg_collation.o pg_constraint.o pg_conversion.o \
+       objectaccess.o objectaddress.o pg_aggregate.o pg_collation.o \
+       pg_constraint.o pg_conversion.o \
        pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \
        pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \
        pg_type.o storage.o toasting.o
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index d203725..5314044 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -997,14 +997,8 @@ deleteOneObject(const ObjectAddress *object, Relation *depRel, int flags)
 	HeapTuple	tup;
 
 	/* DROP hook of the objects being removed */
-	if (object_access_hook)
-	{
-		ObjectAccessDrop drop_arg;
-
-		drop_arg.dropflags = flags;
-		InvokeObjectAccessHook(OAT_DROP, object->classId, object->objectId,
-							   object->objectSubId, &drop_arg);
-	}
+	InvokeObjectDropHookArg(object->classId, object->objectId,
+							object->objectSubId, flags);
 
 	/*
 	 * Close depRel if we are doing a drop concurrently.  The object deletion
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index db51e0b..8685d11 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -1289,15 +1289,7 @@ heap_create_with_catalog(const char *relname,
 	}
 
 	/* Post creation hook for new relation */
-	if (object_access_hook)
-	{
-		ObjectAccessPostCreate	post_create_args;
-
-		memset(&post_create_args, 0, sizeof(ObjectAccessPostCreate));
-		post_create_args.is_internal = is_internal;
-		(*object_access_hook)(OAT_POST_CREATE, RelationRelationId,
-							  relid, 0, &post_create_args);
-    }
+	InvokeObjectPostCreateHookArg(RelationRelationId, relid, 0, is_internal);
 
 	/*
 	 * Store any supplied constraints and defaults.
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 9b33929..33a1803 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -1028,15 +1028,8 @@ index_create(Relation heapRelation,
 	}
 
 	/* Post creation hook for new index */
-	if (object_access_hook)
-	{
-		ObjectAccessPostCreate	post_create_args;
-
-		memset(&post_create_args, 0, sizeof(ObjectAccessPostCreate));
-		post_create_args.is_internal = is_internal;
-		(*object_access_hook)(OAT_POST_CREATE, RelationRelationId,
-							  indexRelationId, 0, &post_create_args);
-	}
+	InvokeObjectPostCreateHookArg(RelationRelationId,
+								  indexRelationId, 0, is_internal);
 
 	/*
 	 * Advance the command counter so that we can see the newly-entered
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
new file mode 100644
index 0000000..79c1136
--- /dev/null
+++ b/src/backend/catalog/objectaccess.c
@@ -0,0 +1,63 @@
+/* -------------------------------------------------------------------------
+ *
+ * objectaccess.c
+ *		functions for object_access_hook on various events
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "catalog/objectaccess.h"
+
+/*
+ * Hook on object accesses.  This is intended as infrastructure for security
+ * and logging plugins.
+ */
+object_access_hook_type object_access_hook = NULL;
+
+/*
+ * RunObjectPostCreateHook
+ *
+ * It is entrypoint of OAT_POST_CREATE event
+ */
+void
+RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
+						bool is_internal)
+{
+	ObjectAccessPostCreate	pc_arg;
+
+	/* XXX - should be checked at caller side */
+	Assert(object_access_hook != NULL);
+
+	memset(&pc_arg, 0, sizeof(ObjectAccessPostCreate));
+	pc_arg.is_internal = is_internal;
+
+	(*object_access_hook)(OAT_POST_CREATE,
+						  classId, objectId, subId,
+						  (void *) &pc_arg);
+}
+
+/*
+ * RunObjectDropHook
+ *
+ * It is entrypoint of OAT_DROP event
+ */
+void
+RunObjectDropHook(Oid classId, Oid objectId, int subId,
+				  int dropflags)
+{
+	ObjectAccessDrop	drop_arg;
+
+	/* XXX - should be checked at caller side */
+	Assert(object_access_hook != NULL);
+
+	memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
+	drop_arg.dropflags = dropflags;
+
+	(*object_access_hook)(OAT_DROP,
+						  classId, objectId, subId,
+						  (void *) &drop_arg);
+}
diff --git a/src/backend/catalog/pg_collation.c b/src/backend/catalog/pg_collation.c
index 46d6e27..dd00502 100644
--- a/src/backend/catalog/pg_collation.c
+++ b/src/backend/catalog/pg_collation.c
@@ -136,8 +136,7 @@ CollationCreate(const char *collname, Oid collnamespace,
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new collation */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   CollationRelationId, oid, 0, NULL);
+	InvokeObjectPostCreateHook(CollationRelationId, oid, 0);
 
 	heap_freetuple(tup);
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 7179fa9..547c7ee 100644
--- a/src/backend/catalog/pg_constraint.c
+++ b/src/backend/catalog/pg_constraint.c
@@ -367,8 +367,7 @@ CreateConstraintEntry(const char *constraintName,
 	}
 
 	/* Post creation hook for new constraint */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ConstraintRelationId, conOid, 0, NULL);
+	InvokeObjectPostCreateHook(ConstraintRelationId, conOid, 0);
 
 	return conOid;
 }
diff --git a/src/backend/catalog/pg_conversion.c b/src/backend/catalog/pg_conversion.c
index 75eafd4..45d8e62 100644
--- a/src/backend/catalog/pg_conversion.c
+++ b/src/backend/catalog/pg_conversion.c
@@ -136,8 +136,7 @@ ConversionCreate(const char *conname, Oid connamespace,
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new conversion */
-	InvokeObjectAccessHook(OAT_POST_CREATE, ConversionRelationId,
-						   HeapTupleGetOid(tup), 0, NULL);
+	InvokeObjectPostCreateHook(ConversionRelationId, HeapTupleGetOid(tup), 0);
 
 	heap_freetuple(tup);
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/catalog/pg_namespace.c b/src/backend/catalog/pg_namespace.c
index 2948c64..8be0558 100644
--- a/src/backend/catalog/pg_namespace.c
+++ b/src/backend/catalog/pg_namespace.c
@@ -96,8 +96,7 @@ NamespaceCreate(const char *nspName, Oid ownerId, bool isTemp)
 		recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new schema */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   NamespaceRelationId, nspoid, 0, NULL);
+	InvokeObjectPostCreateHook(NamespaceRelationId, nspoid, 0);
 
 	return nspoid;
 }
diff --git a/src/backend/catalog/pg_operator.c b/src/backend/catalog/pg_operator.c
index 7a91488..f8d6bb0 100644
--- a/src/backend/catalog/pg_operator.c
+++ b/src/backend/catalog/pg_operator.c
@@ -275,8 +275,7 @@ OperatorShellMake(const char *operatorName,
 	heap_freetuple(tup);
 
 	/* Post creation hook for new shell operator */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorRelationId, operatorObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
 
 	/*
 	 * Make sure the tuple is visible for subsequent lookups/updates.
@@ -544,8 +543,7 @@ OperatorCreate(const char *operatorName,
 	makeOperatorDependencies(tup);
 
 	/* Post creation hook for new operator */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorRelationId, operatorObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorRelationId, operatorObjectId, 0);
 
 	heap_close(pg_operator_desc, RowExclusiveLock);
 
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 3570240..0b70adc 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -661,8 +661,7 @@ ProcedureCreate(const char *procedureName,
 	heap_freetuple(tup);
 
 	/* Post creation hook for new function */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ProcedureRelationId, retval, 0, NULL);
+	InvokeObjectPostCreateHook(ProcedureRelationId, retval, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c
index 591714f..b044400 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -163,8 +163,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
 								 false);
 
 	/* Post creation hook for new shell type */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TypeRelationId, typoid, 0, NULL);
+	InvokeObjectPostCreateHook(TypeRelationId, typoid, 0);
 
 	/*
 	 * clean up and return the type-oid
@@ -476,8 +475,7 @@ TypeCreate(Oid newTypeOid,
 								 rebuildDeps);
 
 	/* Post creation hook for new type */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TypeRelationId, typeObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(TypeRelationId, typeObjectId, 0);
 
 	/*
 	 * finish up
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index e251081..d34a102 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -29,6 +29,7 @@
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
+#include "commands/alter.h"
 #include "commands/defrem.h"
 #include "miscadmin.h"
 #include "parser/parse_func.h"
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 5b06af2..76ef23a 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -524,8 +524,7 @@ createdb(const CreatedbStmt *stmt)
 	copyTemplateDependencies(src_dboid, dboid);
 
 	/* Post creation hook for new database */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   DatabaseRelationId, dboid, 0, NULL);
+	InvokeObjectPostCreateHook(DatabaseRelationId, dboid, 0);
 
 	/*
 	 * Force a checkpoint before starting the copy. This will force dirty
@@ -816,14 +815,7 @@ dropdb(const char *dbname, bool missing_ok)
 					   dbname);
 
 	/* DROP hook for the database being removed */
-	if (object_access_hook)
-	{
-		ObjectAccessDrop drop_arg;
-
-		memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
-		InvokeObjectAccessHook(OAT_DROP,
-							   DatabaseRelationId, db_id, 0, &drop_arg);
-	}
+	InvokeObjectDropHook(DatabaseRelationId, db_id, 0);
 
 	/*
 	 * Disallow dropping a DB that is marked istemplate.  This is just to
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 18b3753..bedeb6a 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -308,8 +308,7 @@ insert_event_trigger_tuple(char *trigname, char *eventname, Oid evtOwner,
 	recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new operator family */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   EventTriggerRelationId, trigoid, 0, NULL);
+	InvokeObjectPostCreateHook(EventTriggerRelationId, trigoid, 0);
 
 	/* Close pg_event_trigger. */
 	heap_close(tgrel, RowExclusiveLock);
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index c02101f..6b7cb5b 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1562,8 +1562,7 @@ InsertExtensionTuple(const char *extName, Oid extOwner,
 		recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
 	}
 	/* Post creation hook for new extension */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ExtensionRelationId, extensionOid, 0, NULL);
+	InvokeObjectPostCreateHook(ExtensionRelationId, extensionOid, 0);
 
 	return extensionOid;
 }
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 7700e91..83cdf9e 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -599,8 +599,7 @@ CreateForeignDataWrapper(CreateFdwStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new foreign data wrapper */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ForeignDataWrapperRelationId, fdwId, 0, NULL);
+	InvokeObjectPostCreateHook(ForeignDataWrapperRelationId, fdwId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
@@ -900,8 +899,7 @@ CreateForeignServer(CreateForeignServerStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new foreign server */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   ForeignServerRelationId, srvId, 0, NULL);
+	InvokeObjectPostCreateHook(ForeignServerRelationId, srvId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
@@ -1145,8 +1143,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new user mapping */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   UserMappingRelationId, umId, 0, NULL);
+	InvokeObjectPostCreateHook(UserMappingRelationId, umId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 7b91233..fda379a 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1558,8 +1558,7 @@ CreateCast(CreateCastStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new cast */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   CastRelationId, castid, 0, NULL);
+	InvokeObjectPostCreateHook(CastRelationId, castid, 0);
 
 	heap_freetuple(tuple);
 
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index 2cfd89a..fc38c2a 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -309,8 +309,7 @@ CreateOpFamily(char *amname, char *opfname, Oid namespaceoid, Oid amoid)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new operator family */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorFamilyRelationId, opfamilyoid, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorFamilyRelationId, opfamilyoid, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
@@ -710,8 +709,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
 	recordDependencyOnCurrentExtension(&myself, false);
 
 	/* Post creation hook for new operator class */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   OperatorClassRelationId, opclassoid, 0, NULL);
+	InvokeObjectPostCreateHook(OperatorClassRelationId, opclassoid, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index e6c6d4e..1c98c32 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -429,8 +429,7 @@ create_proc_lang(const char *languageName, bool replace,
 	}
 
 	/* Post creation hook for new procedural language */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   LanguageRelationId, myself.objectId, 0, NULL);
+	InvokeObjectPostCreateHook(LanguageRelationId, myself.objectId, 0);
 
 	heap_close(rel, RowExclusiveLock);
 
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 6bc056b..b0309be 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4484,8 +4484,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	heap_freetuple(reltup);
 
 	/* Post creation hook for new attribute */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   RelationRelationId, myrelid, newattnum, NULL);
+	InvokeObjectPostCreateHook(RelationRelationId, myrelid, newattnum);
 
 	heap_close(pgclass, RowExclusiveLock);
 
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 9bba75b..f1da26a 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -330,8 +330,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
 	recordDependencyOnOwner(TableSpaceRelationId, tablespaceoid, ownerId);
 
 	/* Post creation hook for new tablespace */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TableSpaceRelationId, tablespaceoid, 0, NULL);
+	InvokeObjectPostCreateHook(TableSpaceRelationId, tablespaceoid, 0);
 
 	create_tablespace_directories(location, tablespaceoid);
 
@@ -438,14 +437,7 @@ DropTableSpace(DropTableSpaceStmt *stmt)
 					   tablespacename);
 
 	/* DROP hook for the tablespace being removed */
-	if (object_access_hook)
-	{
-		ObjectAccessDrop drop_arg;
-
-		memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
-		InvokeObjectAccessHook(OAT_DROP, TableSpaceRelationId,
-							   tablespaceoid, 0, &drop_arg);
-	}
+	InvokeObjectDropHook(TableSpaceRelationId, tablespaceoid, 0);
 
 	/*
 	 * Remove the pg_tablespace tuple (this will roll back if we fail below)
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index f11a8ec..ff9ddce 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -742,8 +742,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 							   DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new trigger */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TriggerRelationId, trigoid, 0, NULL);
+	InvokeObjectPostCreateHook(TriggerRelationId, trigoid, 0);
 
 	/* Keep lock on target rel until end of xact */
 	heap_close(rel, NoLock);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 95377ac..821fdc6 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -272,8 +272,7 @@ DefineTSParser(List *names, List *parameters)
 	makeParserDependencies(tup);
 
 	/* Post creation hook for new text search parser */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSParserRelationId, prsOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSParserRelationId, prsOid, 0);
 
 	heap_freetuple(tup);
 
@@ -479,8 +478,7 @@ DefineTSDictionary(List *names, List *parameters)
 	makeDictionaryDependencies(tup);
 
 	/* Post creation hook for new text search dictionary */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSDictionaryRelationId, dictOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSDictionaryRelationId, dictOid, 0);
 
 	heap_freetuple(tup);
 
@@ -796,8 +794,7 @@ DefineTSTemplate(List *names, List *parameters)
 	makeTSTemplateDependencies(tup);
 
 	/* Post creation hook for new text search template */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSTemplateRelationId, tmplOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSTemplateRelationId, tmplOid, 0);
 
 	heap_freetuple(tup);
 
@@ -1092,8 +1089,7 @@ DefineTSConfiguration(List *names, List *parameters)
 	makeConfigurationDependencies(tup, false, mapRel);
 
 	/* Post creation hook for new text search configuration */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   TSConfigRelationId, cfgOid, 0, NULL);
+	InvokeObjectPostCreateHook(TSConfigRelationId, cfgOid, 0);
 
 	heap_freetuple(tup);
 
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 3ba877d..2b23473 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -426,8 +426,7 @@ CreateRole(CreateRoleStmt *stmt)
 				GetUserId(), false);
 
 	/* Post creation hook for new role */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   AuthIdRelationId, roleid, 0, NULL);
+	InvokeObjectPostCreateHook(AuthIdRelationId, roleid, 0);
 
 	/*
 	 * Close pg_authid, but keep lock till commit.
@@ -944,14 +943,7 @@ DropRole(DropRoleStmt *stmt)
 					 errmsg("must be superuser to drop superusers")));
 
 		/* DROP hook for the role being removed */
-		if (object_access_hook)
-		{
-			ObjectAccessDrop drop_arg;
-
-			memset(&drop_arg, 0, sizeof(ObjectAccessDrop));
-			InvokeObjectAccessHook(OAT_DROP,
-								   AuthIdRelationId, roleid, 0, &drop_arg);
-		}
+		InvokeObjectDropHook(AuthIdRelationId, roleid, 0);
 
 		/*
 		 * Lock the role, so nobody can add dependencies to her while we drop
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index ac724c3..887f42f 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -179,8 +179,7 @@ InsertRule(char *rulname,
 	}
 
 	/* Post creation hook for new rule */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   RewriteRelationId, rewriteObjectId, 0, NULL);
+	InvokeObjectPostCreateHook(RewriteRelationId, rewriteObjectId, 0);
 
 	heap_close(pg_rewrite_desc, RowExclusiveLock);
 
diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c
index 9e4377d..b98110c 100644
--- a/src/backend/storage/large_object/inv_api.c
+++ b/src/backend/storage/large_object/inv_api.c
@@ -218,8 +218,7 @@ inv_create(Oid lobjId)
 							lobjId_new, GetUserId());
 
 	/* Post creation hook for new large object */
-	InvokeObjectAccessHook(OAT_POST_CREATE,
-						   LargeObjectRelationId, lobjId_new, 0, NULL);
+	InvokeObjectPostCreateHook(LargeObjectRelationId, lobjId_new, 0);
 
 	/*
 	 * Advance command counter to make new tuple visible to later operations.
diff --git a/src/backend/utils/init/globals.c b/src/backend/utils/init/globals.c
index f1f8b17..9f51929 100644
--- a/src/backend/utils/init/globals.c
+++ b/src/backend/utils/init/globals.c
@@ -18,7 +18,6 @@
  */
 #include "postgres.h"
 
-#include "catalog/objectaccess.h"
 #include "libpq/pqcomm.h"
 #include "miscadmin.h"
 #include "storage/backendid.h"
@@ -126,9 +125,3 @@ int			VacuumCostBalance = 0;		/* working state for vacuum */
 bool		VacuumCostActive = false;
 
 int			GinFuzzySearchLimit = 0;
-
-/*
- * Hook on object accesses.  This is intended as infrastructure for security
- * and logging plugins.
- */
-object_access_hook_type object_access_hook = NULL;
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index 67c8c1b..b9bb1bc 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -28,6 +28,7 @@ typedef enum ObjectAccessType
 {
 	OAT_POST_CREATE,
 	OAT_DROP,
+	OAT_POST_ALTER,
 } ObjectAccessType;
 
 /*
@@ -66,11 +67,27 @@ typedef void (*object_access_hook_type) (ObjectAccessType access,
 
 extern PGDLLIMPORT object_access_hook_type object_access_hook;
 
-#define InvokeObjectAccessHook(access,classId,objectId,subId,arg)	\
+extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
+									bool is_internal);
+extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
+							  int dropflags);
+
+#define InvokeObjectPostCreateHook(classId,objectId,subId)			\
+	InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
+#define InvokeObjectPostCreateHookArg(classId,objectId,subId,is_internal) \
+	do {															\
+		if (object_access_hook)										\
+			RunObjectPostCreateHook((classId),(objectId),(subId),	\
+									(is_internal));					\
+	} while(0)
+
+#define InvokeObjectDropHook(classId,objectId,subId)				\
+	InvokeObjectDropHookArg((classId),(objectId),(subId),0)
+#define InvokeObjectDropHookArg(classId,objectId,subId,dropflags)	\
 	do {															\
 		if (object_access_hook)										\
-			(*object_access_hook)((access),(classId),				\
-								  (objectId),(subId),(arg));		\
+			RunObjectDropHook((classId),(objectId),(subId),			\
+							  (dropflags));							\
 	} while(0)
 
 #endif   /* OBJECTACCESS_H */
#17Robert Haas
robertmhaas@gmail.com
In reply to: Kohei KaiGai (#16)
Re: [v9.3] OAT_POST_ALTER object access hooks

On Sun, Jan 27, 2013 at 1:55 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

The part-1 patch adds catalog/objectaccess.c to have entrypoints of
object_access_hook, instead of simple macro definition, to simplify
invocations with arguments. It is just a replacement of existing
OAT_POST_CREATE and OAT_DROP invocation with new style,

Looks good. Committed.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#18Robert Haas
robertmhaas@gmail.com
In reply to: Kohei KaiGai (#16)
Re: [v9.3] OAT_POST_ALTER object access hooks

On Sun, Jan 27, 2013 at 1:55 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

The part-2 patch adds new OAT_POST_ALTER event type, and
its relevant permission checks on contrib/sepgsql.

This documentation hunk is unclear:

+    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.

Based on previous experience reading your patches, I'm guessing that
what you actually mean is that both things are checked, but the
wording doesn't make that clear. Also, if permissions are now checked
on functions, doesn't the previous sentence need an update?

+    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.

Suggest: In addition, <literal>remove_name</> and <literal>add_name</>
will be checked on the old and new schemas, respectively, when an
object is moved to a new schema.

+ A few additional checks are applied depending on object types.

For certain object types, additional checks are performed.

+    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.

This is a near-duplicate of the previous hunk and suffers from the
same awkwardness.

+ * is_internal: TRUE if constraint is constructed unless user's intention

I dunno what this means. What's the difference between an internal
constraint and a non-internal constraint, and why do we need that
distinction? This seems to percolate to a lot of places; I'd rather
not do that without a real good reason.

+ /* XXX - should be checked at caller side */

XXX should be used only for things that really ought to be revisited
and changed. See the wording I used in the just-committed part 1
patch.

+#include "catalog/objectaccess.h"

This is the only hunk in collationcmds.c, hence presumably not needed.

+               /* Post create hook of this access method operator */
+               InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
+                                                                  entryoid, 0);

I suggest uniformly adding a blank line before each of these hunks,
rather than adding it for some and not others. I think, though, that
we could probably ditch the comments throughout. They don't add
anything, really.

@@ -3330,7 +3342,6 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab,
Relation rel,
*/
break;
case AT_SetTableSpace: /* SET TABLESPACE */
-
/*
* Nothing to do here; Phase 3 does the work
*/

Spurious whitespace hunk.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#19Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Robert Haas (#18)
Re: [v9.3] OAT_POST_ALTER object access hooks

Thanks for your reviewing.

2013/3/7 Robert Haas <robertmhaas@gmail.com>:

On Sun, Jan 27, 2013 at 1:55 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

The part-2 patch adds new OAT_POST_ALTER event type, and
its relevant permission checks on contrib/sepgsql.

This documentation hunk is unclear:

+    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.

Based on previous experience reading your patches, I'm guessing that
what you actually mean is that both things are checked, but the
wording doesn't make that clear. Also, if permissions are now checked
on functions, doesn't the previous sentence need an update?

Your guess is right. When user defines a function with leakproof attribute,
sepgsql checks both of "create" and "install" permissions on the new
function being labeled according to the default security labeling rules.

The previous section introduces the common behavior when user create
a database object, not particular object class. So, it mention about "create"
permission only on creation of object.
On the other hand, the later session introduces special checks depending
on object classes, such as schema objects.
This section says as below on top of the secsion:
| A few additional checks are applied depending on object types.

And, the sentence says "not only <literal>create</>".

Please give me idea to make the sentence not misleading.

+    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.

Suggest: In addition, <literal>remove_name</> and <literal>add_name</>
will be checked on the old and new schemas, respectively, when an
object is moved to a new schema.

+ A few additional checks are applied depending on object types.

For certain object types, additional checks are performed.

Thanks, I applied it.

+    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.

This is a near-duplicate of the previous hunk and suffers from the
same awkwardness.

The above section introduces about behavior when user create an object
of particular object classes. Do I revise it to introduce the behavior

+ * is_internal: TRUE if constraint is constructed unless user's intention

I dunno what this means. What's the difference between an internal
constraint and a non-internal constraint, and why do we need that
distinction? This seems to percolate to a lot of places; I'd rather
not do that without a real good reason.

"is_internal" is not a property of constraint itself, but reflects the nature
of its invocation context. Unfortunately, some invocation path requires
to handle the event when a constraint is created or altered as internal
one.
For example, make_new_heap() that also calls heap_create_with_catalog()
is called to construct a clone empty relation to rewrite whole table on
some ALTER TABLE command and others. This table creation is purely
internal stuff (in other words, object was constructed because of just
implementation reason). The heap_create_with_catalog() also calls
StoreConstraints() that adds a new constraint with hook invocation.
It is a situation that extension wants to distinct an internal one from
non-internal one.
Otherwise, in case when AT_ReAddConstraint command tries to add
a constraint, it is constructed due to data type changes in primary
ALTER TABLE command, even existing one is internally dropped.

So, it is a reason why I had to add is_internal flag for constraint.

+ /* XXX - should be checked at caller side */

XXX should be used only for things that really ought to be revisited
and changed. See the wording I used in the just-committed part 1
patch.

OK, I'll fix it.

+#include "catalog/objectaccess.h"

This is the only hunk in collationcmds.c, hence presumably not needed.

+               /* Post create hook of this access method operator */
+               InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
+                                                                  entryoid, 0);

I suggest uniformly adding a blank line before each of these hunks,
rather than adding it for some and not others. I think, though, that
we could probably ditch the comments throughout. They don't add
anything, really.

OK, I'll follow the manner. The comment about hook might make sense
in the previous version, but these comments does not introduce something
more than function-name.

@@ -3330,7 +3342,6 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab,
Relation rel,
*/
break;
case AT_SetTableSpace: /* SET TABLESPACE */
-
/*
* Nothing to do here; Phase 3 does the work
*/

Spurious whitespace hunk.

Sorry, fixed it.

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#20Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Kohei KaiGai (#19)
1 attachment(s)
Re: [v9.3] OAT_POST_ALTER object access hooks

The attached patch is rebased one towards the latest master.
It newly added a hook being missed in the previous revision at ALTER
EVENT TRIGGER ENABLE / DISABLE, and adjusted argument of
finish_heap_swap() on REFRESH MATERIALIZED VIEW to handle
it as internal operations.

2013/3/8 Kohei KaiGai <kaigai@kaigai.gr.jp>:

Thanks for your reviewing.

2013/3/7 Robert Haas <robertmhaas@gmail.com>:

On Sun, Jan 27, 2013 at 1:55 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

The part-2 patch adds new OAT_POST_ALTER event type, and
its relevant permission checks on contrib/sepgsql.

This documentation hunk is unclear:

+    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.

Based on previous experience reading your patches, I'm guessing that
what you actually mean is that both things are checked, but the
wording doesn't make that clear. Also, if permissions are now checked
on functions, doesn't the previous sentence need an update?

Your guess is right. When user defines a function with leakproof attribute,
sepgsql checks both of "create" and "install" permissions on the new
function being labeled according to the default security labeling rules.

The previous section introduces the common behavior when user create
a database object, not particular object class. So, it mention about "create"
permission only on creation of object.
On the other hand, the later session introduces special checks depending
on object classes, such as schema objects.
This section says as below on top of the secsion:
| A few additional checks are applied depending on object types.

And, the sentence says "not only <literal>create</>".

Please give me idea to make the sentence not misleading.

I tried to revise the sentence as below:

+    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. This permission will be also
+    checked when user tries to turn on <literal>leakproof</> attribute
+    using <xref linkend="sql-alterfunction"> command, with
+    <literal>setattr</> permission on the function being altered.

It eliminates same explanation around ALTER command.
But I'm not sure whether it gives an impression that only "install"
permission will be checked on leakproof functions, instead of
"create" permission, incorrectly.

+ * is_internal: TRUE if constraint is constructed unless user's intention

I dunno what this means. What's the difference between an internal
constraint and a non-internal constraint, and why do we need that
distinction? This seems to percolate to a lot of places; I'd rather
not do that without a real good reason.

"is_internal" is not a property of constraint itself, but reflects the nature
of its invocation context. Unfortunately, some invocation path requires
to handle the event when a constraint is created or altered as internal
one.
For example, make_new_heap() that also calls heap_create_with_catalog()
is called to construct a clone empty relation to rewrite whole table on
some ALTER TABLE command and others. This table creation is purely
internal stuff (in other words, object was constructed because of just
implementation reason). The heap_create_with_catalog() also calls
StoreConstraints() that adds a new constraint with hook invocation.
It is a situation that extension wants to distinct an internal one from
non-internal one.
Otherwise, in case when AT_ReAddConstraint command tries to add
a constraint, it is constructed due to data type changes in primary
ALTER TABLE command, even existing one is internally dropped.

So, it is a reason why I had to add is_internal flag for constraint.

Right now, I don't touch this portion.

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

sepgsql-v9.3-post-alter-support.v7.patchapplication/octet-stream; name=sepgsql-v9.3-post-alter-support.v7.patchDownload
 contrib/sepgsql/database.c               |  27 +++++
 contrib/sepgsql/expected/alter.out       | 192 +++++++++++++++++++++++++++++++
 contrib/sepgsql/expected/ddl.out         |   9 ++
 contrib/sepgsql/hooks.c                  |  48 ++++++++
 contrib/sepgsql/proc.c                   |  90 ++++++++++++++-
 contrib/sepgsql/relation.c               |  91 +++++++++++++--
 contrib/sepgsql/schema.c                 |  51 ++++++++
 contrib/sepgsql/sepgsql.h                |   7 ++
 contrib/sepgsql/sql/alter.sql            | 136 ++++++++++++++++++++++
 contrib/sepgsql/sql/ddl.sql              |   6 +
 contrib/sepgsql/test_sepgsql             |  27 ++++-
 doc/src/sgml/sepgsql.sgml                |  22 +++-
 src/backend/catalog/aclchk.c             |   8 ++
 src/backend/catalog/heap.c               |  41 +++++--
 src/backend/catalog/index.c              |  13 ++-
 src/backend/catalog/objectaccess.c       |  23 ++++
 src/backend/catalog/pg_constraint.c      |  10 +-
 src/backend/catalog/pg_db_role_setting.c |   4 +
 src/backend/catalog/pg_type.c            |   2 +
 src/backend/commands/alter.c             |   7 ++
 src/backend/commands/cluster.c           |  33 ++++--
 src/backend/commands/dbcommands.c        |  10 ++
 src/backend/commands/event_trigger.c     |   6 +
 src/backend/commands/extension.c         |   6 +
 src/backend/commands/foreigncmds.c       |  10 ++
 src/backend/commands/functioncmds.c      |   2 +
 src/backend/commands/matview.c           |   4 +-
 src/backend/commands/opclasscmds.c       |   6 +
 src/backend/commands/schemacmds.c        |   5 +
 src/backend/commands/sequence.c          |   3 +
 src/backend/commands/tablecmds.c         | 116 ++++++++++++++++---
 src/backend/commands/tablespace.c        |   5 +
 src/backend/commands/trigger.c           |  12 +-
 src/backend/commands/tsearchcmds.c       |   5 +
 src/backend/commands/typecmds.c          |  24 +++-
 src/backend/commands/user.c              |   4 +
 src/backend/rewrite/rewriteDefine.c      |   3 +
 src/include/catalog/heap.h               |   6 +-
 src/include/catalog/index.h              |   3 +-
 src/include/catalog/objectaccess.h       |  40 +++++++
 src/include/catalog/pg_constraint.h      |   3 +-
 src/include/commands/cluster.h           |   3 +-
 src/include/commands/tablecmds.h         |   2 +-
 43 files changed, 1060 insertions(+), 65 deletions(-)

diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c
index 975c1d4..64d37a3 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..ef9abb3
--- /dev/null
+++ b/contrib/sepgsql/expected/alter.out
@@ -0,0 +1,192 @@
+--
+-- 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
+--
+-- XXX: It should take db_xxx:{setattr} permission checks even if
+--      owner is not actually changed.
+--
+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 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 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 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 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 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 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
+ALTER TABLE regtest_table SET TABLESPACE pg_default;
+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 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 7ec72a0..0715aa8 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->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 b47c880..53b941d 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 a277fab..8bcaa41 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
@@ -529,6 +559,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 +590,66 @@ 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);
+
+	/*
+	 * XXX - In the future version, db_tuple:{use} of system catalog entry
+	 * shall be checked, if tablespace configuration is changed.
 	 */
 
 	/*
 	 * 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 75b2826..ecdfd73 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 5ae5146..d4ee94b 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..4bded7e
--- /dev/null
+++ b/contrib/sepgsql/sql/alter.sql
@@ -0,0 +1,136 @@
+--
+-- 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
+--
+-- XXX: It should take db_xxx:{setattr} permission checks even if
+--      owner is not actually changed.
+--
+ALTER DATABASE regtest_sepgsql_test_database_1 OWNER TO regtest_sepgsql_test_user;
+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 SCHEMA regtest_schema_1 OWNER TO regtest_sepgsql_test_user;
+ALTER TABLE regtest_table_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 SEQUENCE regtest_seq_1 OWNER TO regtest_sepgsql_test_user;
+ALTER VIEW regtest_view_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 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
+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..8d1a35c 100755
--- a/contrib/sepgsql/test_sepgsql
+++ b/contrib/sepgsql/test_sepgsql
@@ -162,6 +162,31 @@ if [ "${POLICY_STATUS}" != on ]; then
     echo ""
     exit 1
 fi
+POLICY_STATUS=`getsebool sepgsql_enable_users_ddl | awk '{print $3}'`
+echo ${POLICY_STATUS:-failed}
+if [ "${POLICY_STATUS}" != on ]; then
+    echo ""
+    echo "The SELinux boolean 'sepgsql_enable_users_ddl' must be"
+    echo "turned on in order to enable the rules necessary to run"
+    echo "the regression tests."
+    echo ""
+    if [ "${POLICY_STATUS}" = "" ]; then
+        echo "We attempted to determine the state of this Boolean using"
+        echo "'getsebool', but that command did not produce the expected"
+        echo "output.  Please verify that getsebool is available and in"
+        echo "your PATH."
+    else
+        echo "You can turn on this variable using the following commands:"
+        echo ""
+        echo "  \$ sudo setsebool sepgsql_enable_users_ddl on"
+        echo ""
+        echo "For security reasons, it is suggested that you turn off this"
+        echo "variable when regression testing is complete, unless you"
+        echo "don't want to allow unprivileged users DDL commands."
+    fi
+    echo ""
+    exit 1
+fi
 
 # 'psql' command must be executable from test domain
 echo -n "checking whether we can run psql    ... "
@@ -259,6 +284,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 e7ce8b5..5ee08e1 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -438,6 +438,12 @@ 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. This permission will be also
+    checked when user tries to turn on <literal>leakproof</> attribute
+    using <xref linkend="sql-alterfunction"> command, with
+    <literal>setattr</> permission on the function being altered.
    </para>
 
    <para>
@@ -450,9 +456,19 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
    </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.
+    When <literal>ALTER</> command is executed, <literal>setattr</> will be
+    checked on the object being modified for each object types. 
+    In addition, <literal>remove_name</> and <literal>add_name</>
+    will be checked on the old and new schemas, respectively, when an
+    object is moved to a new schema.
+    For certain object types, additional checks are performed.
+   </para>
+
+   <para>
+    When objects that are subsidiary of other objects (such as a table's
+    indexes 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 340350f..976f2d2 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"
@@ -1290,6 +1291,13 @@ SetDefaultACL(InternalDefaultACL *iacls)
 							  iacls->roleid,
 							  noldmembers, oldmembers,
 							  nnewmembers, newmembers);
+
+		if (isNew)
+			InvokeObjectPostCreateHook(DefaultAclRelationId,
+									   HeapTupleGetOid(newtuple), 0);
+		else
+			InvokeObjectPostAlterHook(DefaultAclRelationId,
+									  HeapTupleGetOid(newtuple), 0);
 	}
 
 	if (HeapTupleIsValid(tuple))
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index 04a927d..638376f 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -96,8 +96,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);
@@ -1302,7 +1303,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
@@ -1836,7 +1837,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;
@@ -1928,6 +1930,17 @@ 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
+	 *
+	 * 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.
+	 */
+	InvokeObjectPostCreateHookArg(AttrDefaultRelationId,
+								  RelationGetRelid(rel), attnum, is_internal);
 }
 
 /*
@@ -1939,7 +1952,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;
@@ -2023,7 +2036,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);
@@ -2038,7 +2052,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;
@@ -2060,11 +2074,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:
@@ -2090,6 +2105,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.
@@ -2107,7 +2123,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;
@@ -2170,7 +2187,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;
@@ -2296,7 +2313,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 33a1803..7966558 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -933,7 +933,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.
@@ -1293,6 +1297,9 @@ index_constraint_create(Relation heapRelation,
 		{
 			simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
 			CatalogUpdateIndexes(pg_index, indexTuple);
+
+			InvokeObjectPostAlterHookArg(IndexRelationId, indexRelationId, 0,
+										 InvalidOid, is_internal);
 		}
 
 		heap_freetuple(indexTuple);
diff --git a/src/backend/catalog/objectaccess.c b/src/backend/catalog/objectaccess.c
index 09f9db5..bc565eb 100644
--- a/src/backend/catalog/objectaccess.c
+++ b/src/backend/catalog/objectaccess.c
@@ -61,3 +61,26 @@ RunObjectDropHook(Oid classId, Oid objectId, int subId,
 						  classId, objectId, subId,
 						  (void *) &drop_arg);
 }
+
+/*
+ * RunObjectPostAlterHook
+ *
+ * It is entrypoint of OAT_POST_ALTER event
+ */
+void
+RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
+					   Oid auxiliaryId, bool is_internal)
+{
+	ObjectAccessPostAlter	pa_arg;
+
+	/* caller should check, but just in case... */
+	Assert(object_access_hook != NULL);
+
+	memset(&pa_arg, 0, sizeof(ObjectAccessPostAlter));
+	pa_arg.auxiliary_id = auxiliaryId;
+	pa_arg.is_internal = is_internal;
+
+	(*object_access_hook)(OAT_POST_ALTER,
+						  classId, objectId, subId,
+						  (void *) &pa_arg);
+}
diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c
index 547c7ee..7ddadcc 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,7 +368,8 @@ CreateConstraintEntry(const char *constraintName,
 	}
 
 	/* Post creation hook for new constraint */
-	InvokeObjectPostCreateHook(ConstraintRelationId, conOid, 0);
+	InvokeObjectPostCreateHookArg(ConstraintRelationId, conOid, 0,
+								  is_internal);
 
 	return conOid;
 }
@@ -665,6 +667,8 @@ RenameConstraintById(Oid conId, const char *newname)
 	/* update the system catalog indexes */
 	CatalogUpdateIndexes(conDesc, tuple);
 
+	InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0);
+
 	heap_freetuple(tuple);
 	heap_close(conDesc, RowExclusiveLock);
 }
@@ -737,6 +741,8 @@ AlterConstraintNamespaces(Oid ownerId, Oid oldNspId,
 			 */
 		}
 
+		InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0);
+
 		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 337ccdd..4594912 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"
@@ -160,6 +161,9 @@ AlterSetting(Oid databaseid, Oid roleid, VariableSetStmt *setstmt)
 		CatalogUpdateIndexes(rel, newtuple);
 	}
 
+	InvokeObjectPostAlterHookArg(DbRoleSettingRelationId,
+								 databaseid, 0, roleid, false);
+
 	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 b044400..23ac3dd 100644
--- a/src/backend/catalog/pg_type.c
+++ b/src/backend/catalog/pg_type.c
@@ -712,6 +712,8 @@ RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace)
 	/* update the system catalog indexes */
 	CatalogUpdateIndexes(pg_type_desc, tuple);
 
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	heap_freetuple(tuple);
 	heap_close(pg_type_desc, RowExclusiveLock);
 
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 416a068..2d2ab1b 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_collation.h"
 #include "catalog/pg_conversion.h"
 #include "catalog/pg_event_trigger.h"
@@ -281,6 +282,8 @@ AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name)
 	simple_heap_update(rel, &oldtup->t_self, newtup);
 	CatalogUpdateIndexes(rel, newtup);
 
+	InvokeObjectPostAlterHook(classId, objectId, 0);
+
 	/* Release memory */
 	pfree(values);
 	pfree(nulls);
@@ -657,6 +660,8 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
 	changeDependencyFor(classId, objid,
 						NamespaceRelationId, oldNspOid, nspOid);
 
+	InvokeObjectPostAlterHook(classId, objid, 0);
+
 	return oldNspOid;
 }
 
@@ -934,4 +939,6 @@ AlterObjectOwner_internal(Relation rel, Oid objectId, Oid new_ownerId)
 		pfree(nulls);
 		pfree(replaces);
 	}
+
+	InvokeObjectPostAlterHook(classId, objectId, 0);
 }
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 8ab8c17..ea936a7 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -27,6 +27,7 @@
 #include "catalog/heap.h"
 #include "catalog/index.h"
 #include "catalog/namespace.h"
+#include "catalog/objectaccess.h"
 #include "catalog/toasting.h"
 #include "commands/cluster.h"
 #include "commands/matview.h"
@@ -481,7 +482,7 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid, bool recheck, LOCKMOD
  * otherwise concurrent executions of RelationGetIndexList could miss indexes.
  */
 void
-mark_index_clustered(Relation rel, Oid indexOid)
+mark_index_clustered(Relation rel, Oid indexOid, bool is_internal)
 {
 	HeapTuple	indexTuple;
 	Form_pg_index indexForm;
@@ -541,6 +542,10 @@ mark_index_clustered(Relation rel, Oid indexOid)
 			simple_heap_update(pg_index, &indexTuple->t_self, indexTuple);
 			CatalogUpdateIndexes(pg_index, indexTuple);
 		}
+
+		InvokeObjectPostAlterHookArg(IndexRelationId, thisIndexOid, 0,
+									 InvalidOid, is_internal);
+
 		heap_freetuple(indexTuple);
 	}
 
@@ -569,7 +574,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid,
 
 	/* Mark the correct index as clustered */
 	if (OidIsValid(indexOid))
-		mark_index_clustered(OldHeap, indexOid);
+		mark_index_clustered(OldHeap, indexOid, true);
 
 	/* Remember if it's a system catalog */
 	is_system_catalog = IsSystemRelation(OldHeap);
@@ -590,7 +595,8 @@ rebuild_relation(Relation OldHeap, Oid indexOid,
 	 * rebuild the target's indexes and throw away the transient table.
 	 */
 	finish_heap_swap(tableOid, OIDNewHeap, is_system_catalog,
-					 swap_toast_by_content, false, frozenXid, frozenMulti);
+					 swap_toast_by_content, false, true,
+					 frozenXid, frozenMulti);
 }
 
 
@@ -1120,6 +1126,7 @@ copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
 static void
 swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 					bool swap_toast_by_content,
+					bool is_internal,
 					TransactionId frozenXid,
 					MultiXactId frozenMulti,
 					Oid *mapped_tables)
@@ -1275,6 +1282,15 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 		CatalogIndexInsert(indstate, reltup1);
 		CatalogIndexInsert(indstate, reltup2);
 		CatalogCloseIndexes(indstate);
+
+		/*
+		 * Post alter hook of these relations. The relation r2 is always
+		 * internal stuff, but r1 depends on the invocation context.
+		 */
+		InvokeObjectPostAlterHookArg(RelationRelationId, r1, 0,
+									 InvalidOid, is_internal);
+		InvokeObjectPostAlterHookArg(RelationRelationId, r2, 0,
+									 InvalidOid, true);
 	}
 	else
 	{
@@ -1298,6 +1314,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 									relform2->reltoastrelid,
 									target_is_pg_class,
 									swap_toast_by_content,
+									is_internal,
 									frozenXid,
 									frozenMulti,
 									mapped_tables);
@@ -1388,6 +1405,7 @@ swap_relation_files(Oid r1, Oid r2, bool target_is_pg_class,
 							relform2->reltoastidxid,
 							target_is_pg_class,
 							swap_toast_by_content,
+							is_internal,
 							InvalidTransactionId,
 							InvalidMultiXactId,
 							mapped_tables);
@@ -1427,6 +1445,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 				 bool is_system_catalog,
 				 bool swap_toast_by_content,
 				 bool check_constraints,
+				 bool is_internal,
 				 TransactionId frozenXid,
 				 MultiXactId frozenMulti)
 {
@@ -1444,8 +1463,8 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 	 */
 	swap_relation_files(OIDOldHeap, OIDNewHeap,
 						(OIDOldHeap == RelationRelationId),
-						swap_toast_by_content, frozenXid, frozenMulti,
-						mapped_tables);
+						swap_toast_by_content, is_internal,
+						frozenXid, frozenMulti, mapped_tables);
 
 	/*
 	 * If it's a system catalog, queue an sinval message to flush all
@@ -1526,13 +1545,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/dbcommands.c b/src/backend/commands/dbcommands.c
index 76ef23a..b3911bf 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -997,6 +997,8 @@ RenameDatabase(const char *oldname, const char *newname)
 	simple_heap_update(rel, &newtup->t_self, newtup);
 	CatalogUpdateIndexes(rel, newtup);
 
+	InvokeObjectPostAlterHook(DatabaseRelationId, db_id, 0);
+
 	/*
 	 * Close pg_database, but keep lock till commit.
 	 */
@@ -1234,6 +1236,9 @@ movedb(const char *dbname, const char *tblspcname)
 		/* Update indexes */
 		CatalogUpdateIndexes(pgdbrel, newtuple);
 
+		InvokeObjectPostAlterHook(DatabaseRelationId,
+								  HeapTupleGetOid(newtuple), 0);
+
 		systable_endscan(sysscan);
 
 		/*
@@ -1431,6 +1436,9 @@ AlterDatabase(AlterDatabaseStmt *stmt, bool isTopLevel)
 	/* Update indexes */
 	CatalogUpdateIndexes(rel, newtuple);
 
+	InvokeObjectPostAlterHook(DatabaseRelationId,
+							  HeapTupleGetOid(newtuple), 0);
+
 	systable_endscan(scan);
 
 	/* Close pg_database, but keep lock till commit */
@@ -1570,6 +1578,8 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
 								newOwnerId);
 	}
 
+	InvokeObjectPostAlterHook(DatabaseRelationId, HeapTupleGetOid(tuple), 0);
+
 	systable_endscan(scan);
 
 	/* Close pg_database, but keep lock till commit */
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
index 2c3b6bf..fbe8f49 100644
--- a/src/backend/commands/event_trigger.c
+++ b/src/backend/commands/event_trigger.c
@@ -412,6 +412,9 @@ AlterEventTrigger(AlterEventTrigStmt *stmt)
 	simple_heap_update(tgrel, &tup->t_self, tup);
 	CatalogUpdateIndexes(tgrel, tup);
 
+	InvokeObjectPostAlterHook(EventTriggerRelationId,
+							  trigoid, 0);
+
 	/* clean up */
 	heap_freetuple(tup);
 	heap_close(tgrel, RowExclusiveLock);
@@ -507,6 +510,9 @@ AlterEventTriggerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 	changeDependencyOnOwner(EventTriggerRelationId,
 							HeapTupleGetOid(tup),
 							newOwnerId);
+
+	InvokeObjectPostAlterHook(EventTriggerRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 6b7cb5b..36df8bd 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -2573,6 +2573,8 @@ AlterExtensionNamespace(List *names, const char *newschema)
 	changeDependencyFor(ExtensionRelationId, extensionOid,
 						NamespaceRelationId, oldNspOid, nspOid);
 
+	InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
+
 	return extensionOid;
 }
 
@@ -2856,6 +2858,8 @@ ApplyExtensionUpdates(Oid extensionOid,
 			recordDependencyOn(&myself, &otherext, DEPENDENCY_NORMAL);
 		}
 
+		InvokeObjectPostAlterHook(ExtensionRelationId, extensionOid, 0);
+
 		/*
 		 * Finally, execute the update script file
 		 */
@@ -2969,6 +2973,8 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt)
 			extension_config_remove(extension.objectId, object.objectId);
 	}
 
+	InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
+
 	/*
 	 * If get_object_address() opened the relation for us, we close it to keep
 	 * the reference count correct - but we retain any locks acquired by
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index 83cdf9e..fb31118 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -241,6 +241,9 @@ AlterForeignDataWrapperOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerI
 								HeapTupleGetOid(tup),
 								newOwnerId);
 	}
+
+	InvokeObjectPostAlterHook(ForeignDataWrapperRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
@@ -349,6 +352,9 @@ AlterForeignServerOwner_internal(Relation rel, HeapTuple tup, Oid newOwnerId)
 		changeDependencyOnOwner(ForeignServerRelationId, HeapTupleGetOid(tup),
 								newOwnerId);
 	}
+
+	InvokeObjectPostAlterHook(ForeignServerRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
 
 /*
@@ -764,6 +770,8 @@ AlterForeignDataWrapper(AlterFdwStmt *stmt)
 		}
 	}
 
+	InvokeObjectPostAlterHook(ForeignDataWrapperRelationId, fdwId, 0);
+
 	heap_close(rel, RowExclusiveLock);
 
 	return fdwId;
@@ -994,6 +1002,8 @@ AlterForeignServer(AlterForeignServerStmt *stmt)
 	simple_heap_update(rel, &tp->t_self, tp);
 	CatalogUpdateIndexes(rel, tp);
 
+	InvokeObjectPostAlterHook(ForeignServerRelationId, srvId, 0);
+
 	heap_freetuple(tp);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index fda379a..9f0ac9b 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -1169,6 +1169,8 @@ AlterFunction(AlterFunctionStmt *stmt)
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
 
+	InvokeObjectPostAlterHook(ProcedureRelationId, funcOid, 0);
+
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 
diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c
index 6a06438..e20feda 100644
--- a/src/backend/commands/matview.c
+++ b/src/backend/commands/matview.c
@@ -198,8 +198,8 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
 	 * Swap the physical files of the target and transient tables, then
 	 * rebuild the target's indexes and throw away the transient table.
 	 */
-	finish_heap_swap(matviewOid, OIDNewHeap, false, false, true, RecentXmin,
-					 ReadNextMultiXactId());
+	finish_heap_swap(matviewOid, OIDNewHeap, false, false, true, true,
+					 RecentXmin, ReadNextMultiXactId());
 
 	RelationCacheInvalidateEntry(matviewOid);
 }
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index e9563fb..68ec57a 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -1374,6 +1374,9 @@ storeOperators(List *opfamilyname, Oid amoid,
 			referenced.objectSubId = 0;
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
 		}
+		/* Post create hook of this access method operator */
+		InvokeObjectPostCreateHook(AccessMethodOperatorRelationId,
+								   entryoid, 0);
 	}
 
 	heap_close(rel, RowExclusiveLock);
@@ -1473,6 +1476,9 @@ storeProcedures(List *opfamilyname, Oid amoid,
 			referenced.objectSubId = 0;
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
 		}
+		/* Post create hook of access method procedure */
+		InvokeObjectPostCreateHook(AccessMethodProcedureRelationId,
+								   entryoid, 0);
 	}
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 1e857d9..21d7e60 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"
@@ -240,6 +241,8 @@ RenameSchema(const char *oldname, const char *newname)
 	simple_heap_update(rel, &tup->t_self, tup);
 	CatalogUpdateIndexes(rel, tup);
 
+	InvokeObjectPostAlterHook(NamespaceRelationId, HeapTupleGetOid(tup), 0);
+
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 
@@ -376,4 +379,6 @@ AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
 								newOwnerId);
 	}
 
+	InvokeObjectPostAlterHook(NamespaceRelationId,
+							  HeapTupleGetOid(tup), 0);
 }
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index de41c8a..225edd9 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -20,6 +20,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"
@@ -487,6 +488,8 @@ AlterSequence(AlterSeqStmt *stmt)
 	if (owned_by)
 		process_owned_by(seqrel, owned_by);
 
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
+
 	relation_close(seqrel, NoLock);
 
 	return relid;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 47b6233..87a53cc 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -674,7 +674,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
@@ -1981,6 +1981,15 @@ StoreCatalogInheritance1(Oid relationId, Oid parentOid,
 	recordDependencyOn(&childobject, &parentobject, DEPENDENCY_NORMAL);
 
 	/*
+	 * Post creation hook of this inheritance. Since object_access_hook
+	 * doesn't take multiple object identifiers, we put oid of parent
+	 * relation using auxiliary_id argument.
+	 */
+	InvokeObjectPostAlterHookArg(InheritsRelationId,
+								 relationId, 0,
+								 parentOid, false);
+
+	/*
 	 * Mark the parent as having subclasses.
 	 */
 	SetRelationHasSubclass(parentOid, true);
@@ -2239,6 +2248,8 @@ renameatt_internal(Oid myrelid,
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, atttup);
 
+	InvokeObjectPostAlterHook(RelationRelationId, myrelid, attnum);
+
 	heap_freetuple(atttup);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -2386,7 +2397,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);
 
@@ -2466,7 +2477,7 @@ RenameRelation(RenameStmt *stmt)
 	}
 
 	/* Do the work */
-	RenameRelationInternal(relid, stmt->newname);
+	RenameRelationInternal(relid, stmt->newname, false);
 
 	return relid;
 }
@@ -2481,7 +2492,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 */
@@ -2523,6 +2534,9 @@ RenameRelationInternal(Oid myrelid, const char *newrelname)
 	/* keep the system catalog indexes current */
 	CatalogUpdateIndexes(relrelation, reltup);
 
+	InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0,
+								 InvalidOid, is_internal);
+
 	heap_freetuple(reltup);
 	heap_close(relrelation, RowExclusiveLock);
 
@@ -3536,7 +3550,9 @@ ATRewriteTables(List **wqueue, LOCKMODE lockmode)
 			 * interest in letting this code work on system catalogs.
 			 */
 			finish_heap_swap(tab->relid, OIDNewHeap,
-							 false, false, true, RecentXmin,
+							 false, false, true,
+							 !OidIsValid(tab->newTableSpace),
+							 RecentXmin,
 							 ReadNextMultiXactId());
 		}
 		else
@@ -4541,7 +4557,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();
@@ -4879,6 +4896,9 @@ ATExecDropNotNull(Relation rel, const char *colName, LOCKMODE lockmode)
 		CatalogUpdateIndexes(attr_rel, tuple);
 	}
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
+
 	heap_close(attr_rel, RowExclusiveLock);
 }
 
@@ -4931,6 +4951,9 @@ ATExecSetNotNull(AlteredTableInfo *tab, Relation rel,
 		tab->new_notnull = true;
 	}
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
+
 	heap_close(attr_rel, RowExclusiveLock);
 }
 
@@ -4985,7 +5008,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, true, false);
 	}
 }
 
@@ -5070,6 +5094,9 @@ ATExecSetStatistics(Relation rel, const char *colName, Node *newValue, LOCKMODE
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, tuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(tuple);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -5127,13 +5154,18 @@ 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);
+
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
 	heap_freetuple(newtuple);
 
+	ReleaseSysCache(tuple);
+
 	heap_close(attrelation, RowExclusiveLock);
 }
 
@@ -5203,6 +5235,10 @@ ATExecSetStorage(Relation rel, const char *colName, Node *newValue, LOCKMODE loc
 	/* keep system catalog indexes current */
 	CatalogUpdateIndexes(attrelation, tuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  attrtuple->attnum);
+
 	heap_freetuple(tuple);
 
 	heap_close(attrelation, RowExclusiveLock);
@@ -5517,7 +5553,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 */
@@ -5541,7 +5577,8 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel,
 							stmt->primary,
 							true, /* update pg_index */
 							true, /* remove old dependencies */
-							allowSystemTableMods);
+							allowSystemTableMods,
+							false);	/* is_internal */
 
 	index_close(indexRel, NoLock);
 }
@@ -5653,7 +5690,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)
@@ -6107,7 +6145,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.
@@ -6289,6 +6328,10 @@ ATExecValidateConstraint(Relation rel, char *constrName, bool recurse,
 		copy_con->convalidated = true;
 		simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
 		CatalogUpdateIndexes(conrel, copyTuple);
+
+		InvokeObjectPostAlterHook(ConstraintRelationId,
+								  HeapTupleGetOid(tuple), 0);
+
 		heap_freetuple(copyTuple);
 	}
 
@@ -7717,6 +7760,9 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 	 */
 	RemoveStatistics(RelationGetRelid(rel), attnum);
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel), attnum);
+
 	/*
 	 * Update the default, if present, by brute force --- remove and re-add
 	 * the default.  Probably unsafe to take shortcuts, since the new version
@@ -7736,7 +7782,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
 		RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true,
 						  true);
 
-		StoreAttrDefault(rel, attnum, defaultexpr);
+		StoreAttrDefault(rel, attnum, defaultexpr, true);
 	}
 
 	/* Cleanup */
@@ -7827,11 +7873,16 @@ 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);
 
+	InvokeObjectPostAlterHook(RelationRelationId,
+							  RelationGetRelid(rel),
+							  atttableform->attnum);
+
+	ReleaseSysCache(tuple);
+
 	heap_close(attrel, RowExclusiveLock);
 
 	heap_freetuple(newtuple);
@@ -8306,6 +8357,8 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId, bool recursing, LOCKMODE lock
 		}
 	}
 
+	InvokeObjectPostAlterHook(RelationRelationId, relationOid, 0);
+
 	ReleaseSysCache(tuple);
 	heap_close(class_rel, RowExclusiveLock);
 	relation_close(target_rel, NoLock);
@@ -8467,7 +8520,7 @@ ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
 	check_index_is_clusterable(rel, indexOid, false, lockmode);
 
 	/* And do the work */
-	mark_index_clustered(rel, indexOid);
+	mark_index_clustered(rel, indexOid, false);
 }
 
 /*
@@ -8479,7 +8532,7 @@ ATExecClusterOn(Relation rel, const char *indexName, LOCKMODE lockmode)
 static void
 ATExecDropCluster(Relation rel, LOCKMODE lockmode)
 {
-	mark_index_clustered(rel, InvalidOid);
+	mark_index_clustered(rel, InvalidOid, false);
 }
 
 /*
@@ -8600,6 +8653,8 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 
 	CatalogUpdateIndexes(pgclass, newtuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
+
 	heap_freetuple(newtuple);
 
 	ReleaseSysCache(tuple);
@@ -8657,6 +8712,10 @@ ATExecSetRelOptions(Relation rel, List *defList, AlterTableType operation,
 
 		CatalogUpdateIndexes(pgclass, newtuple);
 
+		InvokeObjectPostAlterHookArg(RelationRelationId,
+									 RelationGetRelid(toastrel), 0,
+									 InvalidOid, true);
+
 		heap_freetuple(newtuple);
 
 		ReleaseSysCache(tuple);
@@ -8698,6 +8757,9 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	if (newTableSpace == oldTableSpace ||
 		(newTableSpace == MyDatabaseTableSpace && oldTableSpace == 0))
 	{
+		InvokeObjectPostAlterHook(RelationRelationId,
+								  RelationGetRelid(rel), 0);
+
 		relation_close(rel, NoLock);
 		return;
 	}
@@ -8795,6 +8857,8 @@ ATExecSetTableSpace(Oid tableOid, Oid newTableSpace, LOCKMODE lockmode)
 	simple_heap_update(pg_class, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(pg_class, tuple);
 
+	InvokeObjectPostAlterHook(RelationRelationId, RelationGetRelid(rel), 0);
+
 	heap_freetuple(tuple);
 
 	heap_close(pg_class, RowExclusiveLock);
@@ -9497,6 +9561,15 @@ ATExecDropInherit(Relation rel, RangeVar *parent, LOCKMODE lockmode)
 						   RelationRelationId,
 						   RelationGetRelid(parent_rel));
 
+	/*
+	 * Post alter hook of this inherits. Since object_access_hook doesn't
+	 * take multiple object identifiers, we put oid of parent relation
+	 * using auxiliary_id argument.
+	 */
+	InvokeObjectPostAlterHookArg(InheritsRelationId,
+								 RelationGetRelid(rel), 0,
+								 RelationGetRelid(parent_rel), false);
+
 	/* keep our lock on the parent relation until commit */
 	heap_close(parent_rel, NoLock);
 }
@@ -9679,6 +9752,9 @@ 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);
+
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
+
 	heap_freetuple(classtuple);
 	heap_close(relationRelation, RowExclusiveLock);
 
@@ -9719,6 +9795,9 @@ ATExecDropOf(Relation rel, LOCKMODE lockmode)
 	((Form_pg_class) GETSTRUCT(tuple))->reloftype = InvalidOid;
 	simple_heap_update(relationRelation, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(relationRelation, tuple);
+
+	InvokeObjectPostAlterHook(RelationRelationId, relid, 0);
+
 	heap_freetuple(tuple);
 	heap_close(relationRelation, RowExclusiveLock);
 }
@@ -9788,6 +9867,9 @@ ATExecGenericOptions(Relation rel, List *options)
 	simple_heap_update(ftrel, &tuple->t_self, tuple);
 	CatalogUpdateIndexes(ftrel, tuple);
 
+	InvokeObjectPostAlterHook(ForeignTableRelationId,
+							  RelationGetRelid(rel), 0);
+
 	heap_close(ftrel, RowExclusiveLock);
 
 	heap_freetuple(tuple);
@@ -9945,6 +10027,8 @@ AlterRelationNamespaceInternal(Relation classRel, Oid relOid,
 				 NameStr(classForm->relname));
 
 		add_exact_object_address(&thisobj, objsMoved);
+
+		InvokeObjectPostAlterHook(RelationRelationId, relOid, 0);
 	}
 
 	heap_freetuple(classTup);
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index dfcc829..8589512 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -877,6 +877,8 @@ RenameTableSpace(const char *oldname, const char *newname)
 	simple_heap_update(rel, &newtuple->t_self, newtuple);
 	CatalogUpdateIndexes(rel, newtuple);
 
+	InvokeObjectPostAlterHook(TableSpaceRelationId, tspId, 0);
+
 	heap_close(rel, NoLock);
 
 	return tspId;
@@ -945,6 +947,9 @@ AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt)
 	/* Update system catalog. */
 	simple_heap_update(rel, &newtuple->t_self, newtuple);
 	CatalogUpdateIndexes(rel, newtuple);
+
+	InvokeObjectPostAlterHook(TableSpaceRelationId, HeapTupleGetOid(tup), 0);
+
 	heap_freetuple(newtuple);
 
 	/* Conclude heap scan. */
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index f79cef5..bebb551 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -446,7 +446,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 											  NULL,
 											  true,		/* islocal */
 											  0,		/* inhcount */
-											  true);	/* isnoinherit */
+											  true,		/* isnoinherit */
+											  isInternal);	/* is_internal */
 	}
 
 	/*
@@ -742,7 +743,8 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 							   DEPENDENCY_NORMAL);
 
 	/* Post creation hook for new trigger */
-	InvokeObjectPostCreateHook(TriggerRelationId, trigoid, 0);
+	InvokeObjectPostCreateHookArg(TriggerRelationId, trigoid, 0,
+								  isInternal);
 
 	/* Keep lock on target rel until end of xact */
 	heap_close(rel, NoLock);
@@ -1276,6 +1278,9 @@ renametrig(RenameStmt *stmt)
 		/* keep system catalog indexes current */
 		CatalogUpdateIndexes(tgrel, tuple);
 
+		InvokeObjectPostAlterHook(TriggerRelationId,
+								  HeapTupleGetOid(tuple), 0);
+
 		/*
 		 * Invalidate relation's relcache entry so that other backends (and
 		 * this one too!) are sent SI message to make them rebuild relcache
@@ -1391,6 +1396,9 @@ EnableDisableTrigger(Relation rel, const char *tgname,
 
 			changed = true;
 		}
+
+		InvokeObjectPostAlterHook(TriggerRelationId,
+								  HeapTupleGetOid(tuple), 0);
 	}
 
 	systable_endscan(tgscan);
diff --git a/src/backend/commands/tsearchcmds.c b/src/backend/commands/tsearchcmds.c
index 821fdc6..57b69f8 100644
--- a/src/backend/commands/tsearchcmds.c
+++ b/src/backend/commands/tsearchcmds.c
@@ -612,6 +612,8 @@ AlterTSDictionary(AlterTSDictionaryStmt *stmt)
 
 	CatalogUpdateIndexes(rel, newtup);
 
+	InvokeObjectPostAlterHook(TSDictionaryRelationId, dictId, 0);
+
 	/*
 	 * NOTE: because we only support altering the options, not the template,
 	 * there is no need to update dependencies.  This might have to change if
@@ -1184,6 +1186,9 @@ AlterTSConfiguration(AlterTSConfigurationStmt *stmt)
 	/* Update dependencies */
 	makeConfigurationDependencies(tup, true, relMap);
 
+	InvokeObjectPostAlterHook(TSConfigMapRelationId,
+							  HeapTupleGetOid(tup), 0);
+
 	heap_close(relMap, RowExclusiveLock);
 
 	ReleaseSysCache(tup);
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 1ba6d5e..2c4c6cb 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"
@@ -1214,6 +1215,8 @@ AlterEnum(AlterEnumStmt *stmt, bool isTopLevel)
 				 stmt->newValNeighbor, stmt->newValIsAfter,
 				 stmt->skipIfExists);
 
+	InvokeObjectPostAlterHook(TypeRelationId, enum_type_oid, 0);
+
 	ReleaseSysCache(tup);
 
 	return enum_type_oid;
@@ -2190,6 +2193,8 @@ AlterDomainDefault(List *names, Node *defaultRaw)
 							 defaultExpr,
 							 true);		/* Rebuild is true */
 
+	InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
+
 	/* Clean up */
 	heap_close(rel, NoLock);
 	heap_freetuple(newtuple);
@@ -2299,6 +2304,8 @@ AlterDomainNotNull(List *names, bool notNull)
 
 	CatalogUpdateIndexes(typrel, tup);
 
+	InvokeObjectPostAlterHook(TypeRelationId, domainoid, 0);
+
 	/* Clean up */
 	heap_freetuple(tup);
 	heap_close(typrel, RowExclusiveLock);
@@ -2586,6 +2593,10 @@ AlterDomainValidateConstraint(List *names, char *constrName)
 	copy_con->convalidated = true;
 	simple_heap_update(conrel, &copyTuple->t_self, copyTuple);
 	CatalogUpdateIndexes(conrel, copyTuple);
+
+	InvokeObjectPostAlterHook(ConstraintRelationId,
+							  HeapTupleGetOid(copyTuple), 0);
+
 	heap_freetuple(copyTuple);
 
 	systable_endscan(scan);
@@ -2993,7 +3004,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
@@ -3188,7 +3200,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);
@@ -3311,6 +3323,8 @@ AlterTypeOwner(List *names, Oid newOwnerId, ObjectType objecttype)
 			/* Update owner dependency reference */
 			changeDependencyOnOwner(TypeRelationId, typeOid, newOwnerId);
 
+			InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 			/* If it has an array type, update that too */
 			if (OidIsValid(typTup->typarray))
 				AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
@@ -3333,6 +3347,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,
@@ -3366,6 +3382,8 @@ AlterTypeOwnerInternal(Oid typeOid, Oid newOwnerId,
 	if (OidIsValid(typTup->typarray))
 		AlterTypeOwnerInternal(typTup->typarray, newOwnerId, false);
 
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	/* Clean up */
 	heap_close(rel, RowExclusiveLock);
 }
@@ -3553,6 +3571,8 @@ AlterTypeNamespaceInternal(Oid typeOid, Oid nspOid,
 			elog(ERROR, "failed to change schema dependency for type %s",
 				 format_type_be(typeOid));
 
+	InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0);
+
 	heap_freetuple(tup);
 
 	heap_close(rel, RowExclusiveLock);
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 9302416..c7886ed 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -777,6 +777,8 @@ AlterRole(AlterRoleStmt *stmt)
 	/* Update indexes */
 	CatalogUpdateIndexes(pg_authid_rel, new_tuple);
 
+	InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
+
 	ReleaseSysCache(tuple);
 	heap_freetuple(new_tuple);
 
@@ -1161,6 +1163,8 @@ RenameRole(const char *oldname, const char *newname)
 
 	CatalogUpdateIndexes(rel, newtuple);
 
+	InvokeObjectPostAlterHook(AuthIdRelationId, roleid, 0);
+
 	ReleaseSysCache(oldtuple);
 
 	/*
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index 0e265db..3bc13b1 100644
--- a/src/backend/rewrite/rewriteDefine.c
+++ b/src/backend/rewrite/rewriteDefine.c
@@ -816,6 +816,9 @@ EnableDisableRule(Relation rel, const char *rulename,
 		changed = true;
 	}
 
+	InvokeObjectPostAlterHook(RewriteRelationId,
+							  HeapTupleGetOid(ruletup), 0);
+
 	heap_freetuple(ruletup);
 	heap_close(pg_rewrite_desc, RowExclusiveLock);
 
diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h
index 989089a..97d507e 100644
--- a/src/include/catalog/heap.h
+++ b/src/include/catalog/heap.h
@@ -96,9 +96,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 fb323f7..e697275 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -72,7 +72,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 b9bb1bc..1359368 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -22,6 +22,11 @@
  * 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
@@ -57,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,
@@ -71,6 +98,8 @@ extern void RunObjectPostCreateHook(Oid classId, Oid objectId, int subId,
 									bool is_internal);
 extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
 							  int dropflags);
+extern void RunObjectPostAlterHook(Oid classId, Oid objectId, int subId,
+								   Oid auxiliaryId, bool is_internal);
 
 #define InvokeObjectPostCreateHook(classId,objectId,subId)			\
 	InvokeObjectPostCreateHookArg((classId),(objectId),(subId),false)
@@ -90,4 +119,15 @@ extern void RunObjectDropHook(Oid classId, Oid objectId, int subId,
 							  (dropflags));							\
 	} while(0)
 
+#define InvokeObjectPostAlterHook(classId,objectId,subId)			\
+	InvokeObjectPostAlterHookArg((classId),(objectId),(subId),		\
+								 InvalidOid,false)
+#define InvokeObjectPostAlterHookArg(classId,objectId,subId,		\
+									 auxiliaryId,is_internal)		\
+	do {															\
+		if (object_access_hook)										\
+			RunObjectPostAlterHook((classId),(objectId),(subId),	\
+								   (auxiliaryId),(is_internal));	\
+	} while(0)
+
 #endif   /* OBJECTACCESS_H */
diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h
index 29f71f1..4a6a18f 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/cluster.h b/src/include/commands/cluster.h
index 73c701f..aa6d332 100644
--- a/src/include/commands/cluster.h
+++ b/src/include/commands/cluster.h
@@ -23,13 +23,14 @@ extern void cluster_rel(Oid tableOid, Oid indexOid, bool recheck,
 			bool verbose, int freeze_min_age, int freeze_table_age);
 extern void check_index_is_clusterable(Relation OldHeap, Oid indexOid,
 						   bool recheck, LOCKMODE lockmode);
-extern void mark_index_clustered(Relation rel, Oid indexOid);
+extern void mark_index_clustered(Relation rel, Oid indexOid, bool is_internal);
 
 extern Oid	make_new_heap(Oid OIDOldHeap, Oid NewTableSpace);
 extern void finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 				 bool is_system_catalog,
 				 bool swap_toast_by_content,
 				 bool check_constraints,
+				 bool is_internal,
 				 TransactionId frozenXid,
 				 MultiXactId frozenMulti);
 
diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h
index 031c77c..7b86c44 100644
--- a/src/include/commands/tablecmds.h
+++ b/src/include/commands/tablecmds.h
@@ -58,7 +58,7 @@ extern Oid RenameConstraint(RenameStmt *stmt);
 extern Oid 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,
#21Robert Haas
robertmhaas@gmail.com
In reply to: Kohei KaiGai (#20)
Re: [v9.3] OAT_POST_ALTER object access hooks

On Tue, Mar 12, 2013 at 11:53 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

The attached patch is rebased one towards the latest master.
It newly added a hook being missed in the previous revision at ALTER
EVENT TRIGGER ENABLE / DISABLE, and adjusted argument of
finish_heap_swap() on REFRESH MATERIALIZED VIEW to handle
it as internal operations.

Thanks. I committed the backend portions of this, but not the sepgsql
and related documentation changes yet. I made some improvements to
the comments along the way. I am not entirely happy with the grotty
hack around ALTER COLUMN SET/DROP DEFAULT. Is there a better
alternative? Do we really need a hook there at all?

The one non-cosmetic change I made was to adjust slightly the firing
point in swap_relation_files. It doesn't make any sense to me to
exclude pg_class here, rather arbitrarily, out of all objects in the
system. This does to some degree raise the question more broadly: is
the point just after CatalogUpdateIndexes() the right rule for where
to put this hook? But I've left it the way you have it for now. Part
of me thinks that what you really want here is a pre-alter hook rather
than a post-alter hook...

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

#22Kohei KaiGai
kaigai@kaigai.gr.jp
In reply to: Robert Haas (#21)
1 attachment(s)
Re: [v9.3] OAT_POST_ALTER object access hooks

2013/3/18 Robert Haas <robertmhaas@gmail.com>:

On Tue, Mar 12, 2013 at 11:53 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

The attached patch is rebased one towards the latest master.
It newly added a hook being missed in the previous revision at ALTER
EVENT TRIGGER ENABLE / DISABLE, and adjusted argument of
finish_heap_swap() on REFRESH MATERIALIZED VIEW to handle
it as internal operations.

Thanks. I committed the backend portions of this, but not the sepgsql
and related documentation changes yet. I made some improvements to
the comments along the way. I am not entirely happy with the grotty
hack around ALTER COLUMN SET/DROP DEFAULT. Is there a better
alternative? Do we really need a hook there at all?

Here is no code point to update system catalog around ALTER COLUMN
SET/DROP DEFAULT, except for StoreAttrDefault(). In addition, it is not
easy job for extensions to know that column defaults were modified
without hook towards AttrDefaultRelationId.

ATExecColumnDefault() tries to drop an existing default at first, then
invokes AddRelationNewConstraints() that also invokes StoreAttrDefault().
Isn't it feasible to call RemoveAttrDefault() only when new expression
was given and StoreAttrDefault() insert or update a new expression
depending on existing entry. Of course, relevant entries on pg_depend
has to be managed by itself because we cannot use dependency
mechanism here.
My alternative might not be graceful. :-(

The one non-cosmetic change I made was to adjust slightly the firing
point in swap_relation_files. It doesn't make any sense to me to
exclude pg_class here, rather arbitrarily, out of all objects in the
system. This does to some degree raise the question more broadly: is
the point just after CatalogUpdateIndexes() the right rule for where
to put this hook?

We have put OAT_POST_CREATE/_ALTER hook after
CatalogUpdateIndexes() or recordDependencyOn() that should be
usually called after CatalogUpdateIndexes().
Does it make a problem when extension tries to search a newer
version of catalog using SnapshotSelf, without CatalogUpdateIndexes()
doesn't it?

I agree with your adjustment around swap_relation_files().

But I've left it the way you have it for now. Part
of me thinks that what you really want here is a pre-alter hook rather
than a post-alter hook...

Yes. It is the reason why I wanted to put a pre-alter hook for this
code path exceptionally.

The attached patch is rebased version of contrib/sepgsql patch.
Even though I added nothing from the previous one, it might make
sense to add checks for the cases when user altered external
properties of tables (such as triggers, attribute-default, ...).
How about your opinion? It is middle of March now.

Thanks,
--
KaiGai Kohei <kaigai@kaigai.gr.jp>

Attachments:

sepgsql-v9.3-post-alter-support.v8.patchapplication/octet-stream; name=sepgsql-v9.3-post-alter-support.v8.patchDownload
 contrib/sepgsql/database.c         |  27 ++++++
 contrib/sepgsql/expected/alter.out | 192 +++++++++++++++++++++++++++++++++++++
 contrib/sepgsql/expected/ddl.out   |   9 ++
 contrib/sepgsql/hooks.c            |  48 ++++++++++
 contrib/sepgsql/proc.c             |  90 ++++++++++++++++-
 contrib/sepgsql/relation.c         |  91 ++++++++++++++++--
 contrib/sepgsql/schema.c           |  51 ++++++++++
 contrib/sepgsql/sepgsql.h          |   7 ++
 contrib/sepgsql/sql/alter.sql      | 136 ++++++++++++++++++++++++++
 contrib/sepgsql/sql/ddl.sql        |   6 ++
 contrib/sepgsql/test_sepgsql       |  27 +++++-
 doc/src/sgml/sepgsql.sgml          |  22 ++++-
 12 files changed, 693 insertions(+), 13 deletions(-)

diff --git a/contrib/sepgsql/database.c b/contrib/sepgsql/database.c
index 975c1d4..64d37a3 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..ef9abb3
--- /dev/null
+++ b/contrib/sepgsql/expected/alter.out
@@ -0,0 +1,192 @@
+--
+-- 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
+--
+-- XXX: It should take db_xxx:{setattr} permission checks even if
+--      owner is not actually changed.
+--
+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 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 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 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 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 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 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
+ALTER TABLE regtest_table SET TABLESPACE pg_default;
+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 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 7ec72a0..0715aa8 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->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 b47c880..53b941d 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 a277fab..8bcaa41 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
@@ -529,6 +559,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 +590,66 @@ 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);
+
+	/*
+	 * XXX - In the future version, db_tuple:{use} of system catalog entry
+	 * shall be checked, if tablespace configuration is changed.
 	 */
 
 	/*
 	 * 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 75b2826..ecdfd73 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 5ae5146..d4ee94b 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..4bded7e
--- /dev/null
+++ b/contrib/sepgsql/sql/alter.sql
@@ -0,0 +1,136 @@
+--
+-- 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
+--
+-- XXX: It should take db_xxx:{setattr} permission checks even if
+--      owner is not actually changed.
+--
+ALTER DATABASE regtest_sepgsql_test_database_1 OWNER TO regtest_sepgsql_test_user;
+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 SCHEMA regtest_schema_1 OWNER TO regtest_sepgsql_test_user;
+ALTER TABLE regtest_table_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 SEQUENCE regtest_seq_1 OWNER TO regtest_sepgsql_test_user;
+ALTER VIEW regtest_view_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 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
+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..8d1a35c 100755
--- a/contrib/sepgsql/test_sepgsql
+++ b/contrib/sepgsql/test_sepgsql
@@ -162,6 +162,31 @@ if [ "${POLICY_STATUS}" != on ]; then
     echo ""
     exit 1
 fi
+POLICY_STATUS=`getsebool sepgsql_enable_users_ddl | awk '{print $3}'`
+echo ${POLICY_STATUS:-failed}
+if [ "${POLICY_STATUS}" != on ]; then
+    echo ""
+    echo "The SELinux boolean 'sepgsql_enable_users_ddl' must be"
+    echo "turned on in order to enable the rules necessary to run"
+    echo "the regression tests."
+    echo ""
+    if [ "${POLICY_STATUS}" = "" ]; then
+        echo "We attempted to determine the state of this Boolean using"
+        echo "'getsebool', but that command did not produce the expected"
+        echo "output.  Please verify that getsebool is available and in"
+        echo "your PATH."
+    else
+        echo "You can turn on this variable using the following commands:"
+        echo ""
+        echo "  \$ sudo setsebool sepgsql_enable_users_ddl on"
+        echo ""
+        echo "For security reasons, it is suggested that you turn off this"
+        echo "variable when regression testing is complete, unless you"
+        echo "don't want to allow unprivileged users DDL commands."
+    fi
+    echo ""
+    exit 1
+fi
 
 # 'psql' command must be executable from test domain
 echo -n "checking whether we can run psql    ... "
@@ -259,6 +284,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 e7ce8b5..5ee08e1 100644
--- a/doc/src/sgml/sepgsql.sgml
+++ b/doc/src/sgml/sepgsql.sgml
@@ -438,6 +438,12 @@ 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. This permission will be also
+    checked when user tries to turn on <literal>leakproof</> attribute
+    using <xref linkend="sql-alterfunction"> command, with
+    <literal>setattr</> permission on the function being altered.
    </para>
 
    <para>
@@ -450,9 +456,19 @@ UPDATE t1 SET x = 2, y = md5sum(y) WHERE z = 100;
    </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.
+    When <literal>ALTER</> command is executed, <literal>setattr</> will be
+    checked on the object being modified for each object types. 
+    In addition, <literal>remove_name</> and <literal>add_name</>
+    will be checked on the old and new schemas, respectively, when an
+    object is moved to a new schema.
+    For certain object types, additional checks are performed.
+   </para>
+
+   <para>
+    When objects that are subsidiary of other objects (such as a table's
+    indexes 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>
#23Robert Haas
robertmhaas@gmail.com
In reply to: Kohei KaiGai (#22)
Re: [v9.3] OAT_POST_ALTER object access hooks

On Tue, Mar 19, 2013 at 9:28 AM, Kohei KaiGai <kaigai@kaigai.gr.jp> wrote:

But I've left it the way you have it for now. Part
of me thinks that what you really want here is a pre-alter hook rather
than a post-alter hook...

Yes. It is the reason why I wanted to put a pre-alter hook for this
code path exceptionally.

The attached patch is rebased version of contrib/sepgsql patch.
Even though I added nothing from the previous one, it might make
sense to add checks for the cases when user altered external
properties of tables (such as triggers, attribute-default, ...).
How about your opinion? It is middle of March now.

It might make sense to rework this further in a future release, but I
don't think we can do that now.

Anyhow, I've committed the rest of this patch. Sorry that took so long.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers