diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 725bacee5d..d6b60db074 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -178,6 +178,11 @@ table inheritance hierarchy + + pg_init_privs + object initial privileges + + pg_language languages for writing functions @@ -3785,6 +3790,109 @@ + + <structname>pg_init_privs</structname> + + + pg_init_privs + + + + The catalog pg_init_privs records information about + the initial privileges of objects in the system. There is one entry + for each object in the database which has a non-default (non-NULL) + initial set of privileges. + + + + Objects can have initial privileges either by having those privileges set + when the system is initialized (by initdb) or when the + object is created during a CREATE EXTENSION and the + extension script sets initial privileges using the GRANT + system. Note that the system will automatically handle recording of the + privileges during the extension script and that extension authors need + only use the GRANT and REVOKE + statements in their script to have the privileges recorded. The + privtype column indicates if the initial privilege was + set by initdb or during a + CREATE EXTENSION command. + + + + Objects which have initial privileges set by initdb will + have entries where privtype is + 'i', while objects which have initial privileges set + by CREATE EXTENSION will have entries where + privtype is 'e'. + + + + <structname>pg_inherits</> Columns + + + + + Name + Type + References + Description + + + + + + objoid + oid + any OID column + The OID of the specific object + + + + classoid + oid + pg_class.oid + The OID of the system catalog the object is in + + + + objsubid + int4 + + + For a table column, this is the column number (the + objoid and classoid refer to the + table itself). For all other object types, this column is + zero. + + + + + privtype + char + + + A code defining the type of initial privilege of this object; see text + + + + + initprivs + aclitem[] + + + The initial access privileges; see + and + + for details + + + + + +
+ +
+ <structname>pg_language</structname> diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index 25130ecf12..1ce7610049 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -40,7 +40,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\ pg_ts_parser.h pg_ts_template.h pg_extension.h \ pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \ pg_foreign_table.h pg_policy.h pg_replication_origin.h \ - pg_default_acl.h pg_seclabel.h pg_shseclabel.h \ + pg_default_acl.h pg_init_privs.h pg_seclabel.h pg_shseclabel.h \ pg_collation.h pg_range.h pg_transform.h \ toasting.h indexing.h \ ) diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 0f3bc074e1..ffb6678c6a 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -35,6 +35,7 @@ #include "catalog/pg_extension.h" #include "catalog/pg_foreign_data_wrapper.h" #include "catalog/pg_foreign_server.h" +#include "catalog/pg_init_privs.h" #include "catalog/pg_language.h" #include "catalog/pg_largeobject.h" #include "catalog/pg_largeobject_metadata.h" @@ -49,6 +50,7 @@ #include "catalog/pg_ts_dict.h" #include "commands/dbcommands.h" #include "commands/event_trigger.h" +#include "commands/extension.h" #include "commands/proclang.h" #include "commands/tablespace.h" #include "foreign/foreign.h" @@ -119,6 +121,8 @@ static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions, AttrNumber att_number, const char *colname); static AclMode pg_aclmask(AclObjectKind objkind, Oid table_oid, AttrNumber attnum, Oid roleid, AclMode mask, AclMaskHow how); +static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, + Acl *new_acl); #ifdef ACLDEBUG @@ -1678,6 +1682,10 @@ ExecGrant_Attribute(InternalGrant *istmt, Oid relOid, const char *relname, /* keep the catalog indexes up to date */ CatalogUpdateIndexes(attRelation, newtuple); + /* Update initial privileges for extensions */ + recordExtensionInitPriv(relOid, RelationRelationId, attnum, + ACL_NUM(new_acl) > 0 ? new_acl : NULL); + /* Update the shared dependency ACL info */ updateAclDependencies(RelationRelationId, relOid, attnum, ownerId, @@ -1939,6 +1947,9 @@ ExecGrant_Relation(InternalGrant *istmt) /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); + /* Update initial privileges for extensions */ + recordExtensionInitPriv(relOid, RelationRelationId, 0, new_acl); + /* Update the shared dependency ACL info */ updateAclDependencies(RelationRelationId, relOid, 0, ownerId, @@ -2254,6 +2265,10 @@ ExecGrant_Fdw(InternalGrant *istmt) /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); + /* Update initial privileges for extensions */ + recordExtensionInitPriv(fdwid, ForeignDataWrapperRelationId, 0, + new_acl); + /* Update the shared dependency ACL info */ updateAclDependencies(ForeignDataWrapperRelationId, HeapTupleGetOid(tuple), 0, @@ -2379,6 +2394,9 @@ ExecGrant_ForeignServer(InternalGrant *istmt) /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); + /* Update initial privileges for extensions */ + recordExtensionInitPriv(srvid, ForeignServerRelationId, 0, new_acl); + /* Update the shared dependency ACL info */ updateAclDependencies(ForeignServerRelationId, HeapTupleGetOid(tuple), 0, @@ -2503,6 +2521,9 @@ ExecGrant_Function(InternalGrant *istmt) /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); + /* Update initial privileges for extensions */ + recordExtensionInitPriv(funcId, ProcedureRelationId, 0, new_acl); + /* Update the shared dependency ACL info */ updateAclDependencies(ProcedureRelationId, funcId, 0, ownerId, @@ -2633,6 +2654,9 @@ ExecGrant_Language(InternalGrant *istmt) /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); + /* Update initial privileges for extensions */ + recordExtensionInitPriv(langId, LanguageRelationId, 0, new_acl); + /* Update the shared dependency ACL info */ updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple), 0, ownerId, @@ -2772,6 +2796,9 @@ ExecGrant_Largeobject(InternalGrant *istmt) /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); + /* Update initial privileges for extensions */ + recordExtensionInitPriv(loid, LargeObjectRelationId, 0, new_acl); + /* Update the shared dependency ACL info */ updateAclDependencies(LargeObjectRelationId, HeapTupleGetOid(tuple), 0, @@ -2897,6 +2924,9 @@ ExecGrant_Namespace(InternalGrant *istmt) /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); + /* Update initial privileges for extensions */ + recordExtensionInitPriv(nspid, NamespaceRelationId, 0, new_acl); + /* Update the shared dependency ACL info */ updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple), 0, ownerId, @@ -3158,6 +3188,9 @@ ExecGrant_Type(InternalGrant *istmt) /* keep the catalog indexes up to date */ CatalogUpdateIndexes(relation, newtuple); + /* Update initial privileges for extensions */ + recordExtensionInitPriv(typId, TypeRelationId, 0, new_acl); + /* Update the shared dependency ACL info */ updateAclDependencies(TypeRelationId, typId, 0, ownerId, @@ -5174,3 +5207,119 @@ get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid) return result; } + +/* + * Record initial ACL for an extension object + * + * 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. + * + * Can be called at any time, we check if 'creating_extension' is set and, if + * not, exit immediately. + * + * Pass in the object OID, the OID of the class (the OID of the table which + * the object is defined in) and the 'sub' id of the object (objsubid), if + * any. If there is no 'sub' id (they are currently only used for columns of + * tables) then pass in '0'. Finally, pass in the complete ACL to store. + * + * If an ACL already exists for this object/sub-object then we will replace + * it with what is passed in. + * + * Passing in NULL for 'new_acl' will result in the entry for the object being + * removed, if one is found. + */ +static void +recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid, Acl *new_acl) +{ + Relation relation; + ScanKeyData key[3]; + SysScanDesc scan; + HeapTuple tuple; + HeapTuple oldtuple; + + if (!creating_extension) + return; + + relation = heap_open(InitPrivsRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_init_privs_objoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(objoid)); + ScanKeyInit(&key[1], + Anum_pg_init_privs_classoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(classoid)); + ScanKeyInit(&key[2], + Anum_pg_init_privs_objsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(objsubid)); + + scan = systable_beginscan(relation, InitPrivsObjIndexId, true, + NULL, 3, key); + + /* There should exist only one entry or none. */ + oldtuple = systable_getnext(scan); + + systable_endscan(scan); + + /* If we find an entry, update it with the latest ACL. */ + if (HeapTupleIsValid(oldtuple)) + { + Datum values[Natts_pg_init_privs]; + bool nulls[Natts_pg_init_privs]; + bool replace[Natts_pg_init_privs]; + + /* If we have a new ACL to set, then update the row with it. */ + if (new_acl) + { + MemSet(values, 0, sizeof(values)); + MemSet(nulls, false, sizeof(nulls)); + MemSet(replace, false, sizeof(replace)); + + values[Anum_pg_init_privs_privs - 1] = PointerGetDatum(new_acl); + replace[Anum_pg_init_privs_privs - 1] = true; + + oldtuple = heap_modify_tuple(oldtuple, RelationGetDescr(relation), + values, nulls, replace); + + simple_heap_update(relation, &oldtuple->t_self, oldtuple); + + /* keep the catalog indexes up to date */ + CatalogUpdateIndexes(relation, oldtuple); + } + else + /* new_acl is NULL, so delete the entry we found. */ + simple_heap_delete(relation, &oldtuple->t_self); + } + else + { + /* No entry found, so add it. */ + Datum values[Natts_pg_init_privs]; + bool nulls[Natts_pg_init_privs]; + + 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); + + /* 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); + + tuple = heap_form_tuple(RelationGetDescr(relation), values, nulls); + + simple_heap_insert(relation, tuple); + + /* keep the catalog indexes up to date */ + CatalogUpdateIndexes(relation, tuple); + } + + /* prevent error when processing objects multiple times */ + CommandCounterIncrement(); + + heap_close(relation, RowExclusiveLock); +} diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index 79595a9d23..a6180a64f2 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -39,6 +39,7 @@ #include "catalog/pg_extension.h" #include "catalog/pg_foreign_data_wrapper.h" #include "catalog/pg_foreign_server.h" +#include "catalog/pg_init_privs.h" #include "catalog/pg_language.h" #include "catalog/pg_largeobject.h" #include "catalog/pg_namespace.h" @@ -196,6 +197,7 @@ static bool object_address_present_add_flags(const ObjectAddress *object, static bool stack_address_present_add_flags(const ObjectAddress *object, int flags, ObjectAddressStack *stack); +static void DeleteInitPrivs(const ObjectAddress *object); /* @@ -1106,12 +1108,13 @@ deleteOneObject(const ObjectAddress *object, Relation *depRel, int flags) /* - * Delete any comments or security labels associated with this object. - * (This is a convenient place to do these things, rather than having - * every object type know to do it.) + * Delete any comments, security labels, or initial privileges associated + * with this object. (This is a convenient place to do these things, + * rather than having every object type know to do it.) */ DeleteComments(object->objectId, object->classId, object->objectSubId); DeleteSecurityLabel(object); + DeleteInitPrivs(object); /* * CommandCounterIncrement here to ensure that preceding changes are all @@ -2432,3 +2435,40 @@ getObjectClass(const ObjectAddress *object) elog(ERROR, "unrecognized object class: %u", object->classId); return OCLASS_CLASS; /* keep compiler quiet */ } + +/* + * delete initial ACL for extension objects + */ +static void +DeleteInitPrivs(const ObjectAddress *object) +{ + Relation relation; + ScanKeyData key[3]; + SysScanDesc scan; + HeapTuple oldtuple; + + relation = heap_open(InitPrivsRelationId, RowExclusiveLock); + + ScanKeyInit(&key[0], + Anum_pg_init_privs_objoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + ScanKeyInit(&key[1], + Anum_pg_init_privs_classoid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->classId)); + ScanKeyInit(&key[2], + Anum_pg_init_privs_objsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(object->objectSubId)); + + scan = systable_beginscan(relation, InitPrivsObjIndexId, true, + NULL, 3, key); + + while (HeapTupleIsValid(oldtuple = systable_getnext(scan))) + simple_heap_delete(relation, &oldtuple->t_self); + + systable_endscan(scan); + + heap_close(relation, RowExclusiveLock); +} diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c index ed3ba7b624..858667b394 100644 --- a/src/bin/initdb/initdb.c +++ b/src/bin/initdb/initdb.c @@ -1989,6 +1989,11 @@ setup_dictionary(FILE *cmdfd) * Some objects may require different permissions by default, so we * make sure we don't overwrite privilege sets that have already been * set (NOT NULL). + * + * Also populate pg_init_privs to save what the privileges are at init + * time. This is used by pg_dump to allow users to change privileges + * on catalog objects and to have those privilege changes preserved + * across dump/reload and pg_upgrade. */ static void setup_privileges(FILE *cmdfd) @@ -2002,6 +2007,144 @@ setup_privileges(FILE *cmdfd) "GRANT USAGE ON SCHEMA pg_catalog TO PUBLIC;\n\n", "GRANT CREATE, USAGE ON SCHEMA public TO PUBLIC;\n\n", "REVOKE ALL ON pg_largeobject FROM PUBLIC;\n\n", + "INSERT INTO pg_init_privs " + " (objoid, classoid, objsubid, initprivs, privtype)" + " SELECT" + " oid," + " (SELECT oid FROM pg_class WHERE relname = 'pg_class')," + " 0," + " relacl," + " 'i'" + " FROM" + " pg_class" + " WHERE" + " relacl IS NOT NULL" + " AND relkind IN ('r', 'v', 'm', 'S');", + "INSERT INTO pg_init_privs " + " (objoid, classoid, objsubid, initprivs, privtype)" + " SELECT" + " pg_class.oid," + " (SELECT oid FROM pg_class WHERE relname = 'pg_class')," + " pg_attribute.attnum," + " pg_attribute.attacl," + " 'i'" + " FROM" + " pg_class" + " JOIN pg_attribute ON (pg_class.oid = pg_attribute.attrelid)" + " WHERE" + " pg_attribute.attacl IS NOT NULL" + " AND pg_class.relkind IN ('r', 'v', 'm', 'S');", + "INSERT INTO pg_init_privs " + " (objoid, classoid, objsubid, initprivs, privtype)" + " SELECT" + " oid," + " (SELECT oid FROM pg_class WHERE relname = 'pg_proc')," + " 0," + " proacl," + " 'i'" + " FROM" + " pg_proc" + " WHERE" + " proacl IS NOT NULL;", + "INSERT INTO pg_init_privs " + " (objoid, classoid, objsubid, initprivs, privtype)" + " SELECT" + " oid," + " (SELECT oid FROM pg_class WHERE relname = 'pg_type')," + " 0," + " typacl," + " 'i'" + " FROM" + " pg_type" + " WHERE" + " typacl IS NOT NULL;", + "INSERT INTO pg_init_privs " + " (objoid, classoid, objsubid, initprivs, privtype)" + " SELECT" + " oid," + " (SELECT oid FROM pg_class WHERE relname = 'pg_language')," + " 0," + " lanacl," + " 'i'" + " FROM" + " pg_language" + " WHERE" + " lanacl IS NOT NULL;", + "INSERT INTO pg_init_privs " + " (objoid, classoid, objsubid, initprivs, privtype)" + " SELECT" + " oid," + " (SELECT oid FROM pg_class WHERE " + " relname = 'pg_largeobject_metadata')," + " 0," + " lomacl," + " 'i'" + " FROM" + " pg_largeobject_metadata" + " WHERE" + " lomacl IS NOT NULL;", + "INSERT INTO pg_init_privs " + " (objoid, classoid, objsubid, initprivs, privtype)" + " SELECT" + " oid," + " (SELECT oid FROM pg_class WHERE relname = 'pg_namespace')," + " 0," + " nspacl," + " 'i'" + " FROM" + " pg_namespace" + " WHERE" + " nspacl IS NOT NULL;", + "INSERT INTO pg_init_privs " + " (objoid, classoid, objsubid, initprivs, privtype)" + " SELECT" + " oid," + " (SELECT oid FROM pg_class WHERE relname = 'pg_database')," + " 0," + " datacl," + " 'i'" + " FROM" + " pg_database" + " WHERE" + " datacl IS NOT NULL;", + "INSERT INTO pg_init_privs " + " (objoid, classoid, objsubid, initprivs, privtype)" + " SELECT" + " oid," + " (SELECT oid FROM pg_class WHERE relname = 'pg_tablespace')," + " 0," + " spcacl," + " 'i'" + " FROM" + " pg_tablespace" + " WHERE" + " spcacl IS NOT NULL;", + "INSERT INTO pg_init_privs " + " (objoid, classoid, objsubid, initprivs, privtype)" + " SELECT" + " oid," + " (SELECT oid FROM pg_class WHERE " + " relname = 'pg_foreign_data_wrapper')," + " 0," + " fdwacl," + " 'i'" + " FROM" + " pg_foreign_data_wrapper" + " WHERE" + " fdwacl IS NOT NULL;", + "INSERT INTO pg_init_privs " + " (objoid, classoid, objsubid, initprivs, privtype)" + " SELECT" + " oid," + " (SELECT oid FROM pg_class " + " WHERE relname = 'pg_foreign_server')," + " 0," + " srvacl," + " 'i'" + " FROM" + " pg_foreign_server" + " WHERE" + " srvacl IS NOT NULL;", NULL }; diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index ab2c1a8e68..ca5eb3d417 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -162,6 +162,9 @@ DECLARE_UNIQUE_INDEX(pg_inherits_relid_seqno_index, 2680, on pg_inherits using b DECLARE_INDEX(pg_inherits_parent_index, 2187, on pg_inherits using btree(inhparent oid_ops)); #define InheritsParentIndexId 2187 +DECLARE_UNIQUE_INDEX(pg_init_privs_o_c_o_index, 3395, on pg_init_privs using btree(objoid oid_ops, classoid oid_ops, objsubid int4_ops)); +#define InitPrivsObjIndexId 3395 + DECLARE_UNIQUE_INDEX(pg_language_name_index, 2681, on pg_language using btree(lanname name_ops)); #define LanguageNameIndexId 2681 DECLARE_UNIQUE_INDEX(pg_language_oid_index, 2682, on pg_language using btree(oid oid_ops)); diff --git a/src/include/catalog/pg_init_privs.h b/src/include/catalog/pg_init_privs.h new file mode 100644 index 0000000000..e13edd3ff5 --- /dev/null +++ b/src/include/catalog/pg_init_privs.h @@ -0,0 +1,101 @@ +/*------------------------------------------------------------------------- + * + * pg_init_privs.h + * definition of the system "initial privileges" relation (pg_init_privs) + * + * NOTE: an object is identified by the OID of the row that primarily + * defines the object, plus the OID of the table that that row appears in. + * For example, a function is identified by the OID of its pg_proc row + * plus the pg_class OID of table pg_proc. This allows unique identification + * of objects without assuming that OIDs are unique across tables. + * + * Since attributes don't have OIDs of their own, we identify an attribute + * privilege by the objoid+classoid of its parent table, plus an "objsubid" + * giving the attribute column number. "objsubid" must be zero in a privilege + * for a table itself, so that it is distinct from any column privilege. + * Currently, objsubid is unused and zero for all other kinds of objects. + * + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/catalog/pg_init_privs.h + * + * NOTES + * the genbki.pl script reads this file and generates .bki + * information from the DATA() statements. + * + * XXX do NOT break up DATA() statements into multiple lines! + * the scripts are not as smart as you might think... + * + *------------------------------------------------------------------------- + */ +#ifndef PG_INIT_PRIVS_H +#define PG_INIT_PRIVS_H + +#include "catalog/genbki.h" + +/* ---------------- + * pg_init_privs definition. cpp turns this into + * typedef struct FormData_pg_init_privs + * ---------------- + */ +#define InitPrivsRelationId 3394 + +CATALOG(pg_init_privs,3394) BKI_WITHOUT_OIDS +{ + Oid objoid; /* OID of object itself */ + Oid classoid; /* OID of table containing object */ + int32 objsubid; /* column number, or 0 if not used */ + char privtype; /* from initdb or extension? */ + +#ifdef CATALOG_VARLEN /* variable-length fields start here */ + aclitem initprivs[1] BKI_FORCE_NOT_NULL; /* initial privs on + * object */ +#endif +} FormData_pg_init_privs; + +/* ---------------- + * Form_pg_init_privs corresponds to a pointer to a tuple with + * the format of pg_init_privs relation. + * ---------------- + */ +typedef FormData_pg_init_privs *Form_pg_init_privs; + +/* ---------------- + * compiler constants for pg_init_privs + * ---------------- + */ +#define Natts_pg_init_privs 5 +#define Anum_pg_init_privs_objoid 1 +#define Anum_pg_init_privs_classoid 2 +#define Anum_pg_init_privs_objsubid 3 +#define Anum_pg_init_privs_privtype 4 +#define Anum_pg_init_privs_privs 5 + +/* + * It is important to know if the initial privileges are from initdb or from an + * extension. This enum is used to provide that differentiation and the two + * places which populate this table (initdb and during CREATE EXTENSION, see + * recordExtensionInitPriv()) know to use the correct values. + */ + +typedef enum InitPrivsType +{ + INITPRIVS_INITDB = 'i', + INITPRIVS_EXTENSION = 'e' +} InitPrivsType; + +/* ---------------- + * initial contents of pg_init_privs + * ---------------- + */ + +/* + * Because the contents of this table depend on what is done with the other + * objects in the system (and, in particular, may change due to changes is + * system_views.sql), there is no initialization here. + * + * The initial contents are loaded near the end of initdb. + */ + +#endif /* PG_INIT_PRIVS_H */ diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index 2c5be4bae4..4d81ba7dac 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -110,6 +110,7 @@ pg_foreign_server|t pg_foreign_table|t pg_index|t pg_inherits|t +pg_init_privs|t pg_language|t pg_largeobject|t pg_largeobject_metadata|t