aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/aclchk.c436
-rw-r--r--src/backend/commands/extension.c21
-rw-r--r--src/include/utils/acl.h4
-rw-r--r--src/test/modules/test_pg_dump/expected/test_pg_dump.out100
-rw-r--r--src/test/modules/test_pg_dump/sql/test_pg_dump.sql108
-rw-r--r--src/test/modules/test_pg_dump/t/001_base.pl92
6 files changed, 732 insertions, 29 deletions
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index a585c3ad19a..066b7fdb740 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -27,7 +27,10 @@
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/objectaccess.h"
+#include "catalog/pg_aggregate.h"
+#include "catalog/pg_am.h"
#include "catalog/pg_authid.h"
+#include "catalog/pg_cast.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
@@ -49,6 +52,9 @@
#include "catalog/pg_type.h"
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_dict.h"
+#include "catalog/pg_ts_parser.h"
+#include "catalog/pg_ts_template.h"
+#include "catalog/pg_transform.h"
#include "commands/dbcommands.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
@@ -130,6 +136,8 @@ static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnu
Oid roleid, AclMode mask, AclMaskHow how);
static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
Acl *new_acl);
+static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
+ Acl *new_acl);
#ifdef ACLDEBUG
@@ -5222,10 +5230,367 @@ get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
}
/*
- * Record initial ACL for an extension object
+ * Record initial privileges for the top-level object passed in.
*
- * This will perform a wholesale replacement of the entire ACL for the object
- * passed in, therefore be sure to pass in the complete new ACL to use.
+ * For the object passed in, this will record its ACL (if any) and the ACLs of
+ * any sub-objects (eg: columns) into pg_init_privs.
+ *
+ * Any new kinds of objects which have ACLs associated with them and can be
+ * added to an extension should be added to the if-else tree below.
+ */
+void
+recordExtObjInitPriv(Oid objoid, Oid classoid)
+{
+ /*
+ * pg_class / pg_attribute
+ *
+ * If this is a relation then we need to see if there are any sub-objects
+ * (eg: columns) for it and, if so, be sure to call
+ * recordExtensionInitPrivWorker() for each one.
+ */
+ if (classoid == RelationRelationId)
+ {
+ Form_pg_class pg_class_tuple;
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", objoid);
+ pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
+
+ /* Indexes don't have permissions */
+ if (pg_class_tuple->relkind == RELKIND_INDEX)
+ return;
+
+ /* Composite types don't have permissions either */
+ if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
+ return;
+
+ /*
+ * If this isn't a sequence, index, or composite type then it's
+ * possibly going to have columns associated with it that might have
+ * ACLs.
+ */
+ if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
+ {
+ AttrNumber curr_att;
+ AttrNumber nattrs = pg_class_tuple->relnatts;
+
+ for (curr_att = 1; curr_att <= nattrs; curr_att++)
+ {
+ HeapTuple attTuple;
+ Datum attaclDatum;
+
+ attTuple = SearchSysCache2(ATTNUM,
+ ObjectIdGetDatum(objoid),
+ Int16GetDatum(curr_att));
+
+ if (!HeapTupleIsValid(attTuple))
+ continue;
+
+ /* ignore dropped columns */
+ if (((Form_pg_attribute) GETSTRUCT(attTuple))->attisdropped)
+ {
+ ReleaseSysCache(attTuple);
+ continue;
+ }
+
+ attaclDatum = SysCacheGetAttr(ATTNUM, attTuple,
+ Anum_pg_attribute_attacl,
+ &isNull);
+
+ /* no need to do anything for a NULL ACL */
+ if (isNull)
+ {
+ ReleaseSysCache(attTuple);
+ continue;
+ }
+
+ recordExtensionInitPrivWorker(objoid, classoid, curr_att,
+ DatumGetAclP(attaclDatum));
+
+ ReleaseSysCache(attTuple);
+ }
+ }
+
+ aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl,
+ &isNull);
+
+ /* Add the record, if any, for the top-level object */
+ if (!isNull)
+ recordExtensionInitPrivWorker(objoid, classoid, 0,
+ DatumGetAclP(aclDatum));
+
+ ReleaseSysCache(tuple);
+ }
+ /* pg_foreign_data_wrapper */
+ else if (classoid == ForeignDataWrapperRelationId)
+ {
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(FOREIGNDATAWRAPPEROID,
+ ObjectIdGetDatum(objoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for foreign data wrapper %u",
+ objoid);
+
+ aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
+ Anum_pg_foreign_data_wrapper_fdwacl,
+ &isNull);
+
+ /* Add the record, if any, for the top-level object */
+ if (!isNull)
+ recordExtensionInitPrivWorker(objoid, classoid, 0,
+ DatumGetAclP(aclDatum));
+
+ ReleaseSysCache(tuple);
+ }
+ /* pg_foreign_server */
+ else if (classoid == ForeignServerRelationId)
+ {
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(FOREIGNSERVEROID, ObjectIdGetDatum(objoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for foreign data wrapper %u",
+ objoid);
+
+ aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
+ Anum_pg_foreign_server_srvacl,
+ &isNull);
+
+ /* Add the record, if any, for the top-level object */
+ if (!isNull)
+ recordExtensionInitPrivWorker(objoid, classoid, 0,
+ DatumGetAclP(aclDatum));
+
+ ReleaseSysCache(tuple);
+ }
+ /* pg_language */
+ else if (classoid == LanguageRelationId)
+ {
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(LANGOID, ObjectIdGetDatum(objoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for language %u", objoid);
+
+ aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
+ &isNull);
+
+ /* Add the record, if any, for the top-level object */
+ if (!isNull)
+ recordExtensionInitPrivWorker(objoid, classoid, 0,
+ DatumGetAclP(aclDatum));
+
+ ReleaseSysCache(tuple);
+ }
+ /* pg_largeobject_metadata */
+ else if (classoid == LargeObjectMetadataRelationId)
+ {
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple tuple;
+ ScanKeyData entry[1];
+ SysScanDesc scan;
+ Relation relation;
+
+ relation = heap_open(LargeObjectMetadataRelationId, RowExclusiveLock);
+
+ /* There's no syscache for pg_largeobject_metadata */
+ ScanKeyInit(&entry[0],
+ ObjectIdAttributeNumber,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(objoid));
+
+ scan = systable_beginscan(relation,
+ LargeObjectMetadataOidIndexId, true,
+ NULL, 1, entry);
+
+ tuple = systable_getnext(scan);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for large object %u", objoid);
+
+ aclDatum = heap_getattr(tuple,
+ Anum_pg_largeobject_metadata_lomacl,
+ RelationGetDescr(relation), &isNull);
+
+ /* Add the record, if any, for the top-level object */
+ if (!isNull)
+ recordExtensionInitPrivWorker(objoid, classoid, 0,
+ DatumGetAclP(aclDatum));
+
+ systable_endscan(scan);
+ }
+ /* pg_namespace */
+ else if (classoid == NamespaceRelationId)
+ {
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(objoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for function %u", objoid);
+
+ aclDatum = SysCacheGetAttr(NAMESPACEOID, tuple,
+ Anum_pg_namespace_nspacl, &isNull);
+
+ /* Add the record, if any, for the top-level object */
+ if (!isNull)
+ recordExtensionInitPrivWorker(objoid, classoid, 0,
+ DatumGetAclP(aclDatum));
+
+ ReleaseSysCache(tuple);
+ }
+ /* pg_proc */
+ else if (classoid == ProcedureRelationId)
+ {
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(objoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for function %u", objoid);
+
+ aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
+ &isNull);
+
+ /* Add the record, if any, for the top-level object */
+ if (!isNull)
+ recordExtensionInitPrivWorker(objoid, classoid, 0,
+ DatumGetAclP(aclDatum));
+
+ ReleaseSysCache(tuple);
+ }
+ /* pg_type */
+ else if (classoid == TypeRelationId)
+ {
+ Datum aclDatum;
+ bool isNull;
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(objoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for function %u", objoid);
+
+ aclDatum = SysCacheGetAttr(TYPEOID, tuple, Anum_pg_type_typacl,
+ &isNull);
+
+ /* Add the record, if any, for the top-level object */
+ if (!isNull)
+ recordExtensionInitPrivWorker(objoid, classoid, 0,
+ DatumGetAclP(aclDatum));
+
+ ReleaseSysCache(tuple);
+ }
+ else if (classoid == AccessMethodRelationId ||
+ classoid == AggregateRelationId ||
+ classoid == CastRelationId ||
+ classoid == CollationRelationId ||
+ classoid == ConversionRelationId ||
+ classoid == EventTriggerRelationId ||
+ classoid == OperatorRelationId ||
+ classoid == OperatorClassRelationId ||
+ classoid == OperatorFamilyRelationId ||
+ classoid == NamespaceRelationId ||
+ classoid == TSConfigRelationId ||
+ classoid == TSDictionaryRelationId ||
+ classoid == TSParserRelationId ||
+ classoid == TSTemplateRelationId ||
+ classoid == TransformRelationId
+ )
+ {
+ /* no ACL for these object types, so do nothing. */
+ }
+
+ /*
+ * complain if we are given a class OID for a class that extensions don't
+ * support or that we don't recognize.
+ */
+ else
+ {
+ elog(ERROR, "unrecognized or unsupported class OID: %u", classoid);
+ }
+}
+
+/*
+ * For the object passed in, remove its ACL and the ACLs of any object subIds
+ * from pg_init_privs (via recordExtensionInitPrivWorker()).
+ */
+void
+removeExtObjInitPriv(Oid objoid, Oid classoid)
+{
+ /*
+ * If this is a relation then we need to see if there are any sub-objects
+ * (eg: columns) for it and, if so, be sure to call
+ * recordExtensionInitPrivWorker() for each one.
+ */
+ if (classoid == RelationRelationId)
+ {
+ Form_pg_class pg_class_tuple;
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(objoid));
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", objoid);
+ pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
+
+ /* Indexes don't have permissions */
+ if (pg_class_tuple->relkind == RELKIND_INDEX)
+ return;
+
+ /* Composite types don't have permissions either */
+ if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE)
+ return;
+
+ /*
+ * If this isn't a sequence, index, or composite type then it's
+ * possibly going to have columns associated with it that might have
+ * ACLs.
+ */
+ if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
+ {
+ AttrNumber curr_att;
+ AttrNumber nattrs = pg_class_tuple->relnatts;
+
+ for (curr_att = 1; curr_att <= nattrs; curr_att++)
+ {
+ HeapTuple attTuple;
+
+ attTuple = SearchSysCache2(ATTNUM,
+ ObjectIdGetDatum(objoid),
+ Int16GetDatum(curr_att));
+
+ if (!HeapTupleIsValid(attTuple))
+ continue;
+
+ /* when removing, remove all entires, even dropped columns */
+
+ recordExtensionInitPrivWorker(objoid, classoid, curr_att, NULL);
+
+ ReleaseSysCache(attTuple);
+ }
+ }
+
+ ReleaseSysCache(tuple);
+ }
+
+ /* Remove the record, if any, for the top-level object */
+ recordExtensionInitPrivWorker(objoid, classoid, 0, NULL);
+}
+
+/*
+ * Record initial ACL for an extension object
*
* Can be called at any time, we check if 'creating_extension' is set and, if
* not, exit immediately.
@@ -5244,12 +5609,6 @@ get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
static void
recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
{
- Relation relation;
- ScanKeyData key[3];
- SysScanDesc scan;
- HeapTuple tuple;
- HeapTuple oldtuple;
-
/*
* Generally, we only record the initial privileges when an extension is
* being created, but because we don't actually use CREATE EXTENSION
@@ -5261,6 +5620,30 @@ recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
if (!creating_extension && !binary_upgrade_record_init_privs)
return;
+ recordExtensionInitPrivWorker(objoid, classoid, objsubid, new_acl);
+}
+
+/*
+ * Record initial ACL for an extension object, worker.
+ *
+ * This will perform a wholesale replacement of the entire ACL for the object
+ * passed in, therefore be sure to pass in the complete new ACL to use.
+ *
+ * Generally speaking, do *not* use this function directly but instead use
+ * recordExtensionInitPriv(), which checks if 'creating_extension' is set.
+ * This function does *not* check if 'creating_extension' is set as it is also
+ * used when an object is added to or removed from an extension via ALTER
+ * EXTENSION ... ADD/DROP.
+ */
+static void
+recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
+{
+ Relation relation;
+ ScanKeyData key[3];
+ SysScanDesc scan;
+ HeapTuple tuple;
+ HeapTuple oldtuple;
+
relation = heap_open(InitPrivsRelationId, RowExclusiveLock);
ScanKeyInit(&key[0],
@@ -5313,28 +5696,37 @@ recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl)
}
else
{
- /* No entry found, so add it. */
Datum values[Natts_pg_init_privs];
bool nulls[Natts_pg_init_privs];
- MemSet(nulls, false, sizeof(nulls));
+ /*
+ * Only add a new entry if the new ACL is non-NULL.
+ *
+ * If we are passed in a NULL ACL and no entry exists, we can just
+ * fall through and do nothing.
+ */
+ if (new_acl)
+ {
+ /* No entry found, so add it. */
+ MemSet(nulls, false, sizeof(nulls));
- values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
- values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
- values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
+ values[Anum_pg_init_privs_objoid - 1] = ObjectIdGetDatum(objoid);
+ values[Anum_pg_init_privs_classoid - 1] = ObjectIdGetDatum(classoid);
+ values[Anum_pg_init_privs_objsubid - 1] = Int32GetDatum(objsubid);
- /* This function only handles initial privileges of extensions */
- values[Anum_pg_init_privs_privtype - 1] =
- CharGetDatum(INITPRIVS_EXTENSION);
+ /* This function only handles initial privileges of extensions */
+ values[Anum_pg_init_privs_privtype - 1] =
+ CharGetDatum(INITPRIVS_EXTENSION);
- values[Anum_pg_init_privs_privs - 1] = PointerGetDatum(new_acl);
+ values[Anum_pg_init_privs_privs - 1] = PointerGetDatum(new_acl);
- tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
+ tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls);
- simple_heap_insert(relation, tuple);
+ simple_heap_insert(relation, tuple);
- /* keep the catalog indexes up to date */
- CatalogUpdateIndexes(relation, tuple);
+ /* keep the catalog indexes up to date */
+ CatalogUpdateIndexes(relation, tuple);
+ }
}
systable_endscan(scan);
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 518fefcf09b..33b0de0a765 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -52,6 +52,7 @@
#include "nodes/makefuncs.h"
#include "storage/fd.h"
#include "tcop/utility.h"
+#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
@@ -3046,6 +3047,16 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
* OK, add the dependency.
*/
recordDependencyOn(&object, &extension, DEPENDENCY_EXTENSION);
+
+ /*
+ * Also record the initial ACL on the object, if any.
+ *
+ * Note that this will handle the object's ACLs, as well as any ACLs
+ * on object subIds. (In other words, when the object is a table,
+ * this will record the table's ACL and the ACLs for the columns on
+ * the table, if any).
+ */
+ recordExtObjInitPriv(object.objectId, object.classId);
}
else
{
@@ -3073,6 +3084,16 @@ ExecAlterExtensionContentsStmt(AlterExtensionContentsStmt *stmt,
*/
if (object.classId == RelationRelationId)
extension_config_remove(extension.objectId, object.objectId);
+
+ /*
+ * Remove all the initial ACLs, if any.
+ *
+ * Note that this will remove the object's ACLs, as well as any ACLs
+ * on object subIds. (In other words, when the object is a table,
+ * this will remove the table's ACL and the ACLs for the columns on
+ * the table, if any).
+ */
+ removeExtObjInitPriv(object.objectId, object.classId);
}
InvokeObjectPostAlterHook(ExtensionRelationId, extension.objectId, 0);
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 4cc49f0c0c2..5a4f1714f31 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -311,6 +311,10 @@ extern void aclcheck_error_col(AclResult aclerr, AclObjectKind objectkind,
extern void aclcheck_error_type(AclResult aclerr, Oid typeOid);
+extern void recordExtObjInitPriv(Oid objoid, Oid classoid);
+extern void removeExtObjInitPriv(Oid objoid, Oid classoid);
+
+
/* ownercheck routines just return true (owner) or false (not) */
extern bool pg_class_ownercheck(Oid class_oid, Oid roleid);
extern bool pg_type_ownercheck(Oid type_oid, Oid roleid);
diff --git a/src/test/modules/test_pg_dump/expected/test_pg_dump.out b/src/test/modules/test_pg_dump/expected/test_pg_dump.out
index 360caa2cb30..c9bc6f76258 100644
--- a/src/test/modules/test_pg_dump/expected/test_pg_dump.out
+++ b/src/test/modules/test_pg_dump/expected/test_pg_dump.out
@@ -1,6 +1,94 @@
-SELECT 1;
- ?column?
-----------
- 1
-(1 row)
-
+CREATE ROLE regress_dump_test_role;
+CREATE EXTENSION test_pg_dump;
+ALTER EXTENSION test_pg_dump ADD DATABASE postgres; -- error
+ERROR: syntax error at or near "DATABASE"
+LINE 1: ALTER EXTENSION test_pg_dump ADD DATABASE postgres;
+ ^
+CREATE TABLE test_pg_dump_t1 (c1 int);
+CREATE VIEW test_pg_dump_v1 AS SELECT * FROM test_pg_dump_t1;
+CREATE MATERIALIZED VIEW test_pg_dump_mv1 AS SELECT * FROM test_pg_dump_t1;
+CREATE SCHEMA test_pg_dump_s1;
+CREATE TYPE test_pg_dump_e1 AS ENUM ('abc', 'def');
+CREATE AGGREGATE newavg (
+ sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+ finalfunc = int8_avg,
+ initcond1 = '{0,0}'
+);
+CREATE FUNCTION test_pg_dump(int) RETURNS int AS $$
+BEGIN
+RETURN abs($1);
+END
+$$ LANGUAGE plpgsql IMMUTABLE;
+CREATE OPERATOR ==== (
+ LEFTARG = int,
+ RIGHTARG = int,
+ PROCEDURE = int4eq,
+ COMMUTATOR = ====
+);
+CREATE ACCESS METHOD gist2 TYPE INDEX HANDLER gisthandler;
+CREATE TYPE casttesttype;
+CREATE FUNCTION casttesttype_in(cstring)
+ RETURNS casttesttype
+ AS 'textin'
+ LANGUAGE internal STRICT IMMUTABLE;
+NOTICE: return type casttesttype is only a shell
+CREATE FUNCTION casttesttype_out(casttesttype)
+ RETURNS cstring
+ AS 'textout'
+ LANGUAGE internal STRICT IMMUTABLE;
+NOTICE: argument type casttesttype is only a shell
+CREATE TYPE casttesttype (
+ internallength = variable,
+ input = casttesttype_in,
+ output = casttesttype_out,
+ alignment = int4
+);
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+CREATE FOREIGN DATA WRAPPER dummy;
+CREATE SERVER s0 FOREIGN DATA WRAPPER dummy;
+CREATE FOREIGN TABLE ft1 (
+ c1 integer OPTIONS ("param 1" 'val1') NOT NULL,
+ c2 text OPTIONS (param2 'val2', param3 'val3') CHECK (c2 <> ''),
+ c3 date,
+ CHECK (c3 BETWEEN '1994-01-01'::date AND '1994-01-31'::date)
+) SERVER s0 OPTIONS (delimiter ',', quote '"', "be quoted" 'value');
+REVOKE EXECUTE ON FUNCTION test_pg_dump(int) FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION test_pg_dump(int) TO regress_dump_test_role;
+GRANT SELECT (c1) ON test_pg_dump_t1 TO regress_dump_test_role;
+GRANT SELECT ON test_pg_dump_v1 TO regress_dump_test_role;
+GRANT USAGE ON FOREIGN DATA WRAPPER dummy TO regress_dump_test_role;
+GRANT USAGE ON FOREIGN SERVER s0 TO regress_dump_test_role;
+GRANT SELECT (c1) ON ft1 TO regress_dump_test_role;
+GRANT SELECT ON ft1 TO regress_dump_test_role;
+GRANT UPDATE ON test_pg_dump_mv1 TO regress_dump_test_role;
+GRANT USAGE ON SCHEMA test_pg_dump_s1 TO regress_dump_test_role;
+GRANT USAGE ON TYPE test_pg_dump_e1 TO regress_dump_test_role;
+ALTER EXTENSION test_pg_dump ADD ACCESS METHOD gist2;
+ALTER EXTENSION test_pg_dump ADD AGGREGATE newavg(int4);
+ALTER EXTENSION test_pg_dump ADD CAST (text AS casttesttype);
+ALTER EXTENSION test_pg_dump ADD FOREIGN DATA WRAPPER dummy;
+ALTER EXTENSION test_pg_dump ADD FOREIGN TABLE ft1;
+ALTER EXTENSION test_pg_dump ADD MATERIALIZED VIEW test_pg_dump_mv1;
+ALTER EXTENSION test_pg_dump ADD OPERATOR ==== (int, int);
+ALTER EXTENSION test_pg_dump ADD SCHEMA test_pg_dump_s1;
+ALTER EXTENSION test_pg_dump ADD SERVER s0;
+ALTER EXTENSION test_pg_dump ADD FUNCTION test_pg_dump(int);
+ALTER EXTENSION test_pg_dump ADD TABLE test_pg_dump_t1;
+ALTER EXTENSION test_pg_dump ADD TYPE test_pg_dump_e1;
+ALTER EXTENSION test_pg_dump ADD VIEW test_pg_dump_v1;
+REVOKE SELECT (c1) ON test_pg_dump_t1 FROM regress_dump_test_role;
+REVOKE SELECT ON test_pg_dump_v1 FROM regress_dump_test_role;
+REVOKE USAGE ON FOREIGN DATA WRAPPER dummy FROM regress_dump_test_role;
+ALTER EXTENSION test_pg_dump DROP ACCESS METHOD gist2;
+ALTER EXTENSION test_pg_dump DROP AGGREGATE newavg(int4);
+ALTER EXTENSION test_pg_dump DROP CAST (text AS casttesttype);
+ALTER EXTENSION test_pg_dump DROP FOREIGN DATA WRAPPER dummy;
+ALTER EXTENSION test_pg_dump DROP FOREIGN TABLE ft1;
+ALTER EXTENSION test_pg_dump DROP FUNCTION test_pg_dump(int);
+ALTER EXTENSION test_pg_dump DROP MATERIALIZED VIEW test_pg_dump_mv1;
+ALTER EXTENSION test_pg_dump DROP OPERATOR ==== (int, int);
+ALTER EXTENSION test_pg_dump DROP SCHEMA test_pg_dump_s1;
+ALTER EXTENSION test_pg_dump DROP SERVER s0;
+ALTER EXTENSION test_pg_dump DROP TABLE test_pg_dump_t1;
+ALTER EXTENSION test_pg_dump DROP TYPE test_pg_dump_e1;
+ALTER EXTENSION test_pg_dump DROP VIEW test_pg_dump_v1;
diff --git a/src/test/modules/test_pg_dump/sql/test_pg_dump.sql b/src/test/modules/test_pg_dump/sql/test_pg_dump.sql
index e0ac49d1ecf..e463dec4040 100644
--- a/src/test/modules/test_pg_dump/sql/test_pg_dump.sql
+++ b/src/test/modules/test_pg_dump/sql/test_pg_dump.sql
@@ -1 +1,107 @@
-SELECT 1;
+CREATE ROLE regress_dump_test_role;
+CREATE EXTENSION test_pg_dump;
+
+ALTER EXTENSION test_pg_dump ADD DATABASE postgres; -- error
+
+CREATE TABLE test_pg_dump_t1 (c1 int);
+CREATE VIEW test_pg_dump_v1 AS SELECT * FROM test_pg_dump_t1;
+CREATE MATERIALIZED VIEW test_pg_dump_mv1 AS SELECT * FROM test_pg_dump_t1;
+CREATE SCHEMA test_pg_dump_s1;
+CREATE TYPE test_pg_dump_e1 AS ENUM ('abc', 'def');
+
+CREATE AGGREGATE newavg (
+ sfunc = int4_avg_accum, basetype = int4, stype = _int8,
+ finalfunc = int8_avg,
+ initcond1 = '{0,0}'
+);
+
+CREATE FUNCTION test_pg_dump(int) RETURNS int AS $$
+BEGIN
+RETURN abs($1);
+END
+$$ LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OPERATOR ==== (
+ LEFTARG = int,
+ RIGHTARG = int,
+ PROCEDURE = int4eq,
+ COMMUTATOR = ====
+);
+
+CREATE ACCESS METHOD gist2 TYPE INDEX HANDLER gisthandler;
+
+CREATE TYPE casttesttype;
+
+CREATE FUNCTION casttesttype_in(cstring)
+ RETURNS casttesttype
+ AS 'textin'
+ LANGUAGE internal STRICT IMMUTABLE;
+CREATE FUNCTION casttesttype_out(casttesttype)
+ RETURNS cstring
+ AS 'textout'
+ LANGUAGE internal STRICT IMMUTABLE;
+
+CREATE TYPE casttesttype (
+ internallength = variable,
+ input = casttesttype_in,
+ output = casttesttype_out,
+ alignment = int4
+);
+
+CREATE CAST (text AS casttesttype) WITHOUT FUNCTION;
+
+CREATE FOREIGN DATA WRAPPER dummy;
+
+CREATE SERVER s0 FOREIGN DATA WRAPPER dummy;
+
+CREATE FOREIGN TABLE ft1 (
+ c1 integer OPTIONS ("param 1" 'val1') NOT NULL,
+ c2 text OPTIONS (param2 'val2', param3 'val3') CHECK (c2 <> ''),
+ c3 date,
+ CHECK (c3 BETWEEN '1994-01-01'::date AND '1994-01-31'::date)
+) SERVER s0 OPTIONS (delimiter ',', quote '"', "be quoted" 'value');
+
+REVOKE EXECUTE ON FUNCTION test_pg_dump(int) FROM PUBLIC;
+GRANT EXECUTE ON FUNCTION test_pg_dump(int) TO regress_dump_test_role;
+
+GRANT SELECT (c1) ON test_pg_dump_t1 TO regress_dump_test_role;
+GRANT SELECT ON test_pg_dump_v1 TO regress_dump_test_role;
+GRANT USAGE ON FOREIGN DATA WRAPPER dummy TO regress_dump_test_role;
+GRANT USAGE ON FOREIGN SERVER s0 TO regress_dump_test_role;
+GRANT SELECT (c1) ON ft1 TO regress_dump_test_role;
+GRANT SELECT ON ft1 TO regress_dump_test_role;
+GRANT UPDATE ON test_pg_dump_mv1 TO regress_dump_test_role;
+GRANT USAGE ON SCHEMA test_pg_dump_s1 TO regress_dump_test_role;
+GRANT USAGE ON TYPE test_pg_dump_e1 TO regress_dump_test_role;
+
+ALTER EXTENSION test_pg_dump ADD ACCESS METHOD gist2;
+ALTER EXTENSION test_pg_dump ADD AGGREGATE newavg(int4);
+ALTER EXTENSION test_pg_dump ADD CAST (text AS casttesttype);
+ALTER EXTENSION test_pg_dump ADD FOREIGN DATA WRAPPER dummy;
+ALTER EXTENSION test_pg_dump ADD FOREIGN TABLE ft1;
+ALTER EXTENSION test_pg_dump ADD MATERIALIZED VIEW test_pg_dump_mv1;
+ALTER EXTENSION test_pg_dump ADD OPERATOR ==== (int, int);
+ALTER EXTENSION test_pg_dump ADD SCHEMA test_pg_dump_s1;
+ALTER EXTENSION test_pg_dump ADD SERVER s0;
+ALTER EXTENSION test_pg_dump ADD FUNCTION test_pg_dump(int);
+ALTER EXTENSION test_pg_dump ADD TABLE test_pg_dump_t1;
+ALTER EXTENSION test_pg_dump ADD TYPE test_pg_dump_e1;
+ALTER EXTENSION test_pg_dump ADD VIEW test_pg_dump_v1;
+
+REVOKE SELECT (c1) ON test_pg_dump_t1 FROM regress_dump_test_role;
+REVOKE SELECT ON test_pg_dump_v1 FROM regress_dump_test_role;
+REVOKE USAGE ON FOREIGN DATA WRAPPER dummy FROM regress_dump_test_role;
+
+ALTER EXTENSION test_pg_dump DROP ACCESS METHOD gist2;
+ALTER EXTENSION test_pg_dump DROP AGGREGATE newavg(int4);
+ALTER EXTENSION test_pg_dump DROP CAST (text AS casttesttype);
+ALTER EXTENSION test_pg_dump DROP FOREIGN DATA WRAPPER dummy;
+ALTER EXTENSION test_pg_dump DROP FOREIGN TABLE ft1;
+ALTER EXTENSION test_pg_dump DROP FUNCTION test_pg_dump(int);
+ALTER EXTENSION test_pg_dump DROP MATERIALIZED VIEW test_pg_dump_mv1;
+ALTER EXTENSION test_pg_dump DROP OPERATOR ==== (int, int);
+ALTER EXTENSION test_pg_dump DROP SCHEMA test_pg_dump_s1;
+ALTER EXTENSION test_pg_dump DROP SERVER s0;
+ALTER EXTENSION test_pg_dump DROP TABLE test_pg_dump_t1;
+ALTER EXTENSION test_pg_dump DROP TYPE test_pg_dump_e1;
+ALTER EXTENSION test_pg_dump DROP VIEW test_pg_dump_v1;
diff --git a/src/test/modules/test_pg_dump/t/001_base.pl b/src/test/modules/test_pg_dump/t/001_base.pl
index 156bd3d1723..c8e8d4a94ce 100644
--- a/src/test/modules/test_pg_dump/t/001_base.pl
+++ b/src/test/modules/test_pg_dump/t/001_base.pl
@@ -236,6 +236,30 @@ my %pgdump_runs = (
# as the regexps are used for each run the test applies to.
my %tests = (
+ 'ALTER EXTENSION test_pg_dump' => {
+ create_order => 9,
+ create_sql => 'ALTER EXTENSION test_pg_dump ADD TABLE regress_pg_dump_table_added;',
+ regexp => qr/^
+ \QCREATE TABLE regress_pg_dump_table_added (\E
+ \n\s+\Qcol1 integer NOT NULL,\E
+ \n\s+\Qcol2 integer\E
+ \n\);\n/xm,
+ like => {
+ binary_upgrade => 1,
+ },
+ unlike => {
+ clean => 1,
+ clean_if_exists => 1,
+ createdb => 1,
+ defaults => 1,
+ no_privs => 1,
+ no_owner => 1,
+ pg_dumpall_globals => 1,
+ schema_only => 1,
+ section_pre_data => 1,
+ section_post_data => 1,
+ }, },
+
'CREATE EXTENSION test_pg_dump' => {
create_order => 2,
create_sql => 'CREATE EXTENSION test_pg_dump;',
@@ -303,6 +327,30 @@ my %tests = (
section_post_data => 1,
}, },
+ 'CREATE TABLE regress_pg_dump_table_added' => {
+ create_order => 7,
+ create_sql => 'CREATE TABLE regress_pg_dump_table_added (col1 int not null, col2 int);',
+ regexp => qr/^
+ \QCREATE TABLE regress_pg_dump_table_added (\E
+ \n\s+\Qcol1 integer NOT NULL,\E
+ \n\s+\Qcol2 integer\E
+ \n\);\n/xm,
+ like => {
+ binary_upgrade => 1,
+ },
+ unlike => {
+ clean => 1,
+ clean_if_exists => 1,
+ createdb => 1,
+ defaults => 1,
+ no_privs => 1,
+ no_owner => 1,
+ pg_dumpall_globals => 1,
+ schema_only => 1,
+ section_pre_data => 1,
+ section_post_data => 1,
+ }, },
+
'CREATE SEQUENCE regress_pg_dump_seq' => {
regexp => qr/^
\QCREATE SEQUENCE regress_pg_dump_seq\E
@@ -413,6 +461,50 @@ my %tests = (
section_post_data => 1,
}, },
+ 'GRANT SELECT regress_pg_dump_table_added pre-ALTER EXTENSION' => {
+ create_order => 8,
+ create_sql => 'GRANT SELECT ON regress_pg_dump_table_added TO regress_dump_test_role;',
+ regexp => qr/^
+ \QGRANT SELECT ON TABLE regress_pg_dump_table_added TO regress_dump_test_role;\E
+ \n/xm,
+ like => {
+ binary_upgrade => 1,
+ },
+ unlike => {
+ clean => 1,
+ clean_if_exists => 1,
+ createdb => 1,
+ defaults => 1,
+ no_privs => 1,
+ no_owner => 1,
+ pg_dumpall_globals => 1,
+ schema_only => 1,
+ section_pre_data => 1,
+ section_post_data => 1,
+ }, },
+
+ 'REVOKE SELECT regress_pg_dump_table_added post-ALTER EXTENSION' => {
+ create_order => 10,
+ create_sql => 'REVOKE SELECT ON regress_pg_dump_table_added FROM regress_dump_test_role;',
+ regexp => qr/^
+ \QREVOKE SELECT ON TABLE regress_pg_dump_table_added FROM regress_dump_test_role;\E
+ \n/xm,
+ like => {
+ binary_upgrade => 1,
+ clean => 1,
+ clean_if_exists => 1,
+ createdb => 1,
+ defaults => 1,
+ no_owner => 1,
+ schema_only => 1,
+ section_pre_data => 1,
+ },
+ unlike => {
+ no_privs => 1,
+ pg_dumpall_globals => 1,
+ section_post_data => 1,
+ }, },
+
'GRANT SELECT ON TABLE regress_pg_dump_table' => {
regexp => qr/^
\QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n