pgsql-seclabel.5.patch

application/octect-stream

Filename: pgsql-seclabel.5.patch
Type: application/octect-stream
Part: 0
Message: Re: security label support, revised

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: context
File+
contrib/dummy_esp/dummy_esp.c 56 0
contrib/dummy_esp/Makefile 14 0
contrib/Makefile 1 0
doc/src/sgml/catalogs.sgml 89 0
doc/src/sgml/user-manag.sgml 31 0
src/backend/catalog/system_views.sql 109 0
src/bin/pg_dump/pg_dumpall.c 7 0
src/bin/pg_dump/pg_dump.c 336 0
src/test/regress/expected/rules.out 4 0
src/test/regress/GNUmakefile 8 0
src/test/regress/input/security_label.source 66 0
src/test/regress/output/security_label.source 66 0
src/test/regress/parallel_schedule 1 0
src/test/regress/serial_schedule 1 0
*** a/contrib/Makefile
--- b/contrib/Makefile
***************
*** 15,20 **** SUBDIRS = \
--- 15,21 ----
  		dblink		\
  		dict_int	\
  		dict_xsyn	\
+ 		dummy_esp	\
  		earthdistance	\
  		fuzzystrmatch	\
  		hstore		\
*** /dev/null
--- b/contrib/dummy_esp/Makefile
***************
*** 0 ****
--- 1,14 ----
+ # contrib/dummy_esp/Makefile
+ 
+ MODULES = dummy_esp
+ 
+ ifdef USE_PGXS
+ PG_CONFIG = pg_config
+ PGXS := $(shell $(PG_CONFIG) --pgxs)
+ include $(PGXS)
+ else
+ subdir = contrib/dummy_esp
+ top_builddir = ../..
+ include $(top_builddir)/src/Makefile.global
+ include $(top_srcdir)/contrib/contrib-global.mk
+ endif
*** /dev/null
--- b/contrib/dummy_esp/dummy_esp.c
***************
*** 0 ****
--- 1,56 ----
+ /*
+  * dummy_esp.c
+  *
+  * A dummy plugin of external security provider with security label.
+  *
+  * This module does not provide something worthful from security perspective,
+  * but being used to regression test independent from the platform specific
+  * features like SELinux.
+  *
+  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+  * Portions Copyright (c) 1994, Regents of the University of California
+  */
+ #include "postgres.h"
+ 
+ #include "commands/seclabel.h"
+ 
+ PG_MODULE_MAGIC;
+ 
+ /* Entrypoint of the module */
+ void _PG_init(void);
+ 
+ /*
+  * dummy_object_relabel
+  *
+  * It shall be invoked when user tries to assign security label of
+  * the database object.
+  */
+ void
+ dummy_object_relabel(const ObjectAddress *object, const char *seclabel)
+ {
+ 	if (strcmp(seclabel, "unclassified") == 0 ||
+ 		strcmp(seclabel, "classified") == 0)
+ 		return;
+ 
+ 	if (strcmp(seclabel, "secret") == 0 ||
+ 		strcmp(seclabel, "top secret") == 0)
+ 	{
+ 		if (!superuser())
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 					 errmsg("only superuser can set '%s' label", seclabel)));
+ 		return;
+ 	}
+ 	ereport(ERROR,
+ 			(errcode(ERRCODE_INVALID_NAME),
+ 			 errmsg("'%s' is not a valid security label", seclabel)));
+ }
+ 
+ /*
+  * Entrypoint of the module
+  */
+ void
+ _PG_init(void)
+ {
+ 	register_label_provider("dummy", dummy_object_relabel);
+ }
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
***************
*** 5964,5969 ****
--- 5964,5974 ----
       </row>
  
       <row>
+       <entry><link linkend="view-pg-seclabels"><structname>pg_seclabels</structname></link></entry>
+       <entry>security labels</entry>
+      </row>
+ 
+      <row>
        <entry><link linkend="view-pg-settings"><structname>pg_settings</structname></link></entry>
        <entry>parameter settings</entry>
       </row>
***************
*** 6870,6876 ****
--- 6875,6965 ----
    </para>
  
   </sect1>
+  <sect1 id="view-pg-seclabels">
+   <title><structname>pg_seclabels</structname></title>
+ 
+   <indexterm zone="view-pg-seclabels">
+    <primary>pg_seclabels</primary>
+   </indexterm>
+ 
+   <para>
+    The view <structname>pg_seclabels</structname> provides references to
+    security label of database objects with their text identifiers.
+   </para>
+ 
+   <table>
+    <title><structname>pg_seclabels</> Columns</title>
  
+    <tgroup cols="4">
+     <thead>
+      <row>
+       <entry>Name</entry>
+       <entry>Type</entry>
+       <entry>References</entry>
+       <entry>Description</entry>
+      </row>
+     </thead>
+     <tbody>
+      <row>
+       <entry><structfield>objoid</structfield></entry>
+       <entry><type>oid</type></entry>
+       <entry>any OID column</entry>
+       <entry>The OID of the object this security label assigned on</entry>
+      </row>
+      <row>
+       <entry><structfield>classoid</structfield></entry>
+       <entry><type>oid</type></entry>
+       <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
+       <entry>The OID of the system catalog this object appears in</entry>
+      </row>
+      <row>
+       <entry><structfield>objsubid</structfield></entry>
+       <entry><type>int4</type></entry>
+       <entry></entry>
+       <entry>
+        For a security label on a table column, this is the column number (the
+        <structfield>objoid</> and <structfield>classoid</> refer to
+        the table itself).  For all other object types, this column is
+        zero.
+       </entry>
+      </row>
+      <row>
+       <entry><structfield>objtype</structfield></entry>
+       <entry><type>text</type></entry>
+       <entry></entry>
+       <entry>text identifier of the object type</entry>
+      </row>
+      <row>
+       <entry><structfield>objnamespace</structfield></entry>
+       <entry><type>oid</type></entry>
+       <entry><literal><link linkend="catalog-pg-namespace"><structname>pg_namespace</structname></link>.oid</literal></entry>
+       <entry>
+        The OID of the namespace that contains this object.
+        Maybe <literal>NULL</literal>, if object does not have its namespace.
+       </entry>
+      </row>
+      <row>
+       <entry><structfield>objname</structfield></entry>
+       <entry><type>text</type></entry>
+       <entry></entry>
+       <entry>The name of the object this security label assigned on</entry>
+      </row>
+      <row>
+       <entry><structfield>provider</structfield></entry>
+       <entry><type>text</type></entry>
+       <entry><literal><link linkend="catalog-pg-seclabel"><structname>pg_seclabel</structname></link>.provider</literal></entry>
+       <entry>The label provider associated with this label.</entry>
+      </row>
+      <row>
+       <entry><structfield>label</structfield></entry>
+       <entry><type>text</type></entry>
+       <entry><literal><link linkend="catalog-pg-seclabel"><structname>pg_seclabel</structname></link>.label</literal></entry>
+       <entry>The security label applied to this object.</entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+  </sect1>
   <sect1 id="view-pg-settings">
    <title><structname>pg_settings</structname></title>
  
*** a/doc/src/sgml/user-manag.sgml
--- b/doc/src/sgml/user-manag.sgml
***************
*** 502,505 **** DROP ROLE <replaceable>name</replaceable>;
--- 502,536 ----
    </para>
   </sect1>
  
+  <sect1 id="external-security-providers">
+   <title>External Security Providers</title>
+ 
+   <para>
+    <productname>PostgreSQL</productname> allows third party plugins to
+    make their access control decision in addition to the default database
+    privilege mechanism. We call these plugins external security providers.
+    The version <literal>9.1.0</literal> or later provide various kind of
+    security hooks on strategic points of code paths, then the external
+    security providers shall be invoked via the hooks.
+   </para>
+   <para>
+    The major purpose to support external security providers is porting
+    mandatory access control (MAC) features;
+    such as <productname>SELinux</productname>.
+    Unlike the default database privilege mechanism, it makes access
+    control decision using a security label of database objects being
+    referenced and a centralized security policy.
+    <productname>PostgreSQL</productname> provides a set of facilities
+    to manage security labels of database objects as built-in feature.
+    The <link linkend="catalog-pg-seclabel"><structname>pg_seclabel
+    </structname></link> system catalog enables to assign security labels
+    on database objects, <xref linkend="sql-security-label"> command
+    allows us to manage security labels, and some of security hooks allows
+    to label database objects on its creation time.
+   </para>
+   <para>
+    We don't mention about detail of the individual security module here,
+    so please reference their own documentation to see any more information.
+   </para>
+  </sect1>
  </chapter>
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
***************
*** 160,165 **** CREATE VIEW pg_prepared_xacts AS
--- 160,274 ----
  CREATE VIEW pg_prepared_statements AS
      SELECT * FROM pg_prepared_statement() AS P;
  
+ CREATE VIEW pg_seclabels AS
+ SELECT
+ 	l.objoid, l.classoid, l.objsubid,
+ 	CASE WHEN rel.relkind = 'r' THEN 'table'::text
+ 	     WHEN rel.relkind = 'v' THEN 'view'::text
+ 	     WHEN rel.relkind = 'S' THEN 'sequence'::text END AS objtype,
+ 	rel.relnamespace AS objnamespace,
+ 	CASE WHEN pg_table_is_visible(rel.oid)
+ 	     THEN quote_ident(rel.relname)
+ 	     ELSE quote_ident(nsp.nspname) || '.' || quote_ident(rel.relname)
+ 	     END AS objname,
+ 	l.provider, l.label
+ FROM
+ 	pg_seclabel l
+ 	JOIN pg_class rel ON l.classoid = rel.tableoid AND l.objoid = rel.oid
+ 	JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
+ WHERE
+ 	l.objsubid = 0
+ UNION ALL
+ SELECT
+ 	l.objoid, l.classoid, l.objsubid,
+ 	'column'::text AS objtype,
+ 	rel.relnamespace AS objnamespace,
+ 	CASE WHEN pg_table_is_visible(rel.oid)
+ 	     THEN quote_ident(rel.relname)
+ 	     ELSE quote_ident(nsp.nspname) || '.' || quote_ident(rel.relname)
+ 	     END || '.' || att.attname AS objname,
+ 	l.provider, l.label
+ FROM
+ 	pg_seclabel l
+ 	JOIN pg_class rel ON l.classoid = rel.tableoid AND l.objoid = rel.oid
+ 	JOIN pg_attribute att
+ 	     ON rel.oid = att.attrelid AND l.objsubid = att.attnum
+ 	JOIN pg_namespace nsp ON rel.relnamespace = nsp.oid
+ WHERE
+ 	l.objsubid != 0
+ UNION ALL
+ SELECT
+ 	l.objoid, l.classoid, l.objsubid,
+ 	CASE WHEN pro.proisagg = true THEN 'aggregate'::text
+ 	     WHEN pro.proisagg = false THEN 'function'::text
+ 	END AS objtype,
+ 	pro.pronamespace AS objnamespace,
+ 	CASE WHEN pg_function_is_visible(pro.oid)
+ 	     THEN quote_ident(pro.proname)
+ 	     ELSE quote_ident(nsp.nspname) || '.' || quote_ident(pro.proname)
+ 	END || '(' || pg_catalog.pg_get_function_arguments(pro.oid) || ')' AS objname,
+ 	l.provider, l.label
+ FROM
+ 	pg_seclabel l
+ 	JOIN pg_proc pro ON l.classoid = pro.tableoid AND l.objoid = pro.oid
+ 	JOIN pg_namespace nsp ON pro.pronamespace = nsp.oid
+ WHERE
+ 	l.objsubid = 0
+ UNION ALL
+ SELECT
+ 	l.objoid, l.classoid, l.objsubid,
+ 	CASE WHEN typ.typtype = 'd' THEN 'domain'::text
+ 	ELSE 'type'::text END AS objtype,
+ 	typ.typnamespace AS objnamespace,
+ 	CASE WHEN pg_type_is_visible(typ.oid)
+ 	THEN quote_ident(typ.typname)
+ 	ELSE quote_ident(nsp.nspname) || '.' || quote_ident(typ.typname)
+ 	END AS objname,
+ 	l.provider, l.label
+ FROM
+ 	pg_seclabel l
+ 	JOIN pg_type typ ON l.classoid = typ.tableoid AND l.objoid = typ.oid
+ 	JOIN pg_namespace nsp ON typ.typnamespace = nsp.oid
+ WHERE
+ 	l.objsubid = 0
+ UNION ALL
+ SELECT
+ 	l.objoid, l.classoid, l.objsubid,
+ 	'large object'::text AS objtype,
+ 	NULL::oid AS objnamespace,
+ 	l.objoid::text AS objname,
+ 	l.provider, l.label
+ FROM
+ 	pg_seclabel l
+ 	JOIN pg_largeobject_metadata lom ON l.objoid = lom.oid
+ WHERE
+ 	l.classoid = 'pg_catalog.pg_largeobject'::regclass AND l.objsubid = 0
+ UNION ALL
+ SELECT
+ 	l.objoid, l.classoid, l.objsubid,
+ 	'language'::text AS objtype,
+ 	NULL::oid AS objnamespace,
+ 	quote_ident(lan.lanname) AS objname,
+ 	l.provider, l.label
+ FROM
+ 	pg_seclabel l
+ 	JOIN pg_language lan ON l.classoid = lan.tableoid AND l.objoid = lan.oid
+ WHERE
+ 	l.objsubid = 0
+ UNION ALL
+ SELECT
+ 	l.objoid, l.classoid, l.objsubid,
+ 	'schema'::text AS objtype,
+ 	nsp.oid AS objnamespace,
+ 	quote_ident(nsp.nspname) AS objname,
+ 	l.provider, l.label
+ FROM
+ 	pg_seclabel l
+ 	JOIN pg_namespace nsp ON l.classoid = nsp.tableoid AND l.objoid = nsp.oid
+ WHERE
+ 	l.objsubid = 0
+ ;
+ 
  CREATE VIEW pg_settings AS 
      SELECT * FROM pg_show_all_settings() AS A; 
  
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
***************
*** 70,75 **** typedef struct
--- 70,83 ----
  	int			objsubid;		/* subobject (table column #) */
  } CommentItem;
  
+ typedef struct
+ {
+ 	const char *provider;		/* label provider of this security label */
+ 	const char *label;			/* security label for an object */
+ 	Oid			classoid;		/* object class (catalog OID) */
+ 	Oid			objoid;			/* object OID */
+ 	int			objsubid;		/* subobject (table column #) */
+ } SecLabelItem;
  
  /* global decls */
  bool		g_verbose;			/* User wants verbose narration of our
***************
*** 125,131 **** static int	binary_upgrade = 0;
  static int	disable_dollar_quoting = 0;
  static int	dump_inserts = 0;
  static int	column_inserts = 0;
! static int	security_label = 0;
  
  
  static void help(const char *progname);
--- 133,139 ----
  static int	disable_dollar_quoting = 0;
  static int	dump_inserts = 0;
  static int	column_inserts = 0;
! static int	no_security_label = 0;
  
  
  static void help(const char *progname);
***************
*** 142,147 **** static void dumpComment(Archive *fout, const char *target,
--- 150,161 ----
  static int findComments(Archive *fout, Oid classoid, Oid objoid,
  			 CommentItem **items);
  static int	collectComments(Archive *fout, CommentItem **items);
+ static void	dumpSecLabel(Archive *fout, const char *target,
+ 						 const char *namespace, const char *owner,
+ 						 CatalogId catalogId, int subid, DumpId dumpId);
+ static int	findSecLabels(Archive *fout, Oid classoid, Oid objoid,
+ 						  SecLabelItem **items);
+ static int	collectSecLabels(Archive *fout, SecLabelItem **items);
  static void dumpDumpableObject(Archive *fout, DumpableObject *dobj);
  static void dumpNamespace(Archive *fout, NamespaceInfo *nspinfo);
  static void dumpType(Archive *fout, TypeInfo *tyinfo);
***************
*** 184,193 **** static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
  		const char *tag, const char *nspname, const char *owner,
  		const char *acls);
  
- static void dumpSecLabel(Archive *fout, CatalogId objCatId, DumpId objDumpId,
- 			 const char *type, const char *target, const char *nspname,
- 			 const char *owner);
- 
  static void getDependencies(void);
  static void getDomainConstraints(TypeInfo *tyinfo);
  static void getTableData(TableInfo *tblinfo, int numTables, bool oids);
--- 198,203 ----
***************
*** 305,311 **** main(int argc, char **argv)
  		{"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
  		{"role", required_argument, NULL, 3},
  		{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
! 		{"security-label", no_argument, &security_label, 1},
  
  		{NULL, 0, NULL, 0}
  	};
--- 315,321 ----
  		{"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
  		{"role", required_argument, NULL, 3},
  		{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
! 		{"no-security-label", no_argument, &no_security_label, 1},
  
  		{NULL, 0, NULL, 0}
  	};
***************
*** 454,461 **** main(int argc, char **argv)
  					outputNoTablespaces = 1;
  				else if (strcmp(optarg, "use-set-session-authorization") == 0)
  					use_setsessauth = 1;
! 				else if (strcmp(optarg, "security-label") == 0)
! 					security_label = 1;
  				else
  				{
  					fprintf(stderr,
--- 464,471 ----
  					outputNoTablespaces = 1;
  				else if (strcmp(optarg, "use-set-session-authorization") == 0)
  					use_setsessauth = 1;
! 				else if (strcmp(optarg, "no-security-label") == 0)
! 					no_security_label = 1;
  				else
  				{
  					fprintf(stderr,
***************
*** 653,663 **** main(int argc, char **argv)
  	/*
  	 * Disables security label support if server version < v9.1.x
  	 */
! 	if (security_label && g_fout->remoteVersion < 90100)
! 	{
! 		write_msg(NULL, "Server does not support security labels\n");
! 		security_label = 0;
! 	}
  
  	/*
  	 * Start serializable transaction to dump consistent data.
--- 663,670 ----
  	/*
  	 * Disables security label support if server version < v9.1.x
  	 */
! 	if (!no_security_label && g_fout->remoteVersion < 90100)
! 		no_security_label = 1;
  
  	/*
  	 * Start serializable transaction to dump consistent data.
***************
*** 856,862 **** help(const char *progname)
  	printf(_("  --no-tablespaces            do not dump tablespace assignments\n"));
  	printf(_("  --quote-all-identifiers     quote all identifiers, even if not keywords\n"));
  	printf(_("  --role=ROLENAME             do SET ROLE before dump\n"));
! 	printf(_("  --security-label            also dump security labels\n"));
  	printf(_("  --use-set-session-authorization\n"
  			 "                              use SET SESSION AUTHORIZATION commands instead of\n"
  	"                              ALTER OWNER commands to set ownership\n"));
--- 863,869 ----
  	printf(_("  --no-tablespaces            do not dump tablespace assignments\n"));
  	printf(_("  --quote-all-identifiers     quote all identifiers, even if not keywords\n"));
  	printf(_("  --role=ROLENAME             do SET ROLE before dump\n"));
! 	printf(_("  --no-security-label         do not dump security label assignments\n"));
  	printf(_("  --use-set-session-authorization\n"
  			 "                              use SET SESSION AUTHORIZATION commands instead of\n"
  	"                              ALTER OWNER commands to set ownership\n"));
***************
*** 2076,2081 **** dumpBlob(Archive *AH, BlobInfo *binfo)
--- 2083,2093 ----
  				NULL, binfo->rolname,
  				binfo->dobj.catId, 0, binfo->dobj.dumpId);
  
+ 	/* Dump security label if any */
+ 	dumpSecLabel(AH, cquery->data,
+ 				 NULL, binfo->rolname,
+ 				 binfo->dobj.catId, 0, binfo->dobj.dumpId);
+ 
  	/* Dump ACL if any */
  	if (binfo->blobacl)
  		dumpACL(AH, binfo->dobj.catId, binfo->dobj.dumpId, "LARGE OBJECT",
***************
*** 6587,6598 **** dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
  				 nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
  				 NULL, NULL);
  
! 	/* Dump Schema Comments */
  	resetPQExpBuffer(q);
  	appendPQExpBuffer(q, "SCHEMA %s", qnspname);
  	dumpComment(fout, q->data,
  				NULL, nspinfo->rolname,
  				nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
  
  	dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
  			qnspname, NULL, nspinfo->dobj.name, NULL,
--- 6599,6613 ----
  				 nspinfo->dobj.dependencies, nspinfo->dobj.nDeps,
  				 NULL, NULL);
  
! 	/* Dump Schema Comments and Security Labels */
  	resetPQExpBuffer(q);
  	appendPQExpBuffer(q, "SCHEMA %s", qnspname);
  	dumpComment(fout, q->data,
  				NULL, nspinfo->rolname,
  				nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
+ 	dumpSecLabel(fout, q->data,
+ 				 NULL, nspinfo->rolname,
+ 				 nspinfo->dobj.catId, 0, nspinfo->dobj.dumpId);
  
  	dumpACL(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, "SCHEMA",
  			qnspname, NULL, nspinfo->dobj.name, NULL,
***************
*** 6717,6729 **** dumpEnumType(Archive *fout, TypeInfo *tyinfo)
  				 tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
  				 NULL, NULL);
  
! 	/* Dump Type Comments */
  	resetPQExpBuffer(q);
  
  	appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
  	dumpComment(fout, q->data,
  				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  
  	PQclear(res);
  	destroyPQExpBuffer(q);
--- 6732,6747 ----
  				 tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
  				 NULL, NULL);
  
! 	/* Dump Type Comments and Security Labels */
  	resetPQExpBuffer(q);
  
  	appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
  	dumpComment(fout, q->data,
  				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ 	dumpSecLabel(fout, q->data,
+ 				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+ 				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  
  	PQclear(res);
  	destroyPQExpBuffer(q);
***************
*** 7093,7105 **** dumpBaseType(Archive *fout, TypeInfo *tyinfo)
  				 tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
  				 NULL, NULL);
  
! 	/* Dump Type Comments */
  	resetPQExpBuffer(q);
  
  	appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
  	dumpComment(fout, q->data,
  				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  
  	PQclear(res);
  	destroyPQExpBuffer(q);
--- 7111,7126 ----
  				 tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
  				 NULL, NULL);
  
! 	/* Dump Type Comments and Security Labels */
  	resetPQExpBuffer(q);
  
  	appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
  	dumpComment(fout, q->data,
  				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ 	dumpSecLabel(fout, q->data,
+ 				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+ 				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  
  	PQclear(res);
  	destroyPQExpBuffer(q);
***************
*** 7217,7229 **** dumpDomain(Archive *fout, TypeInfo *tyinfo)
  				 tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
  				 NULL, NULL);
  
! 	/* Dump Domain Comments */
  	resetPQExpBuffer(q);
  
  	appendPQExpBuffer(q, "DOMAIN %s", fmtId(tyinfo->dobj.name));
  	dumpComment(fout, q->data,
  				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  
  	destroyPQExpBuffer(q);
  	destroyPQExpBuffer(delq);
--- 7238,7253 ----
  				 tyinfo->dobj.dependencies, tyinfo->dobj.nDeps,
  				 NULL, NULL);
  
! 	/* Dump Domain Comments and Security Labels */
  	resetPQExpBuffer(q);
  
  	appendPQExpBuffer(q, "DOMAIN %s", fmtId(tyinfo->dobj.name));
  	dumpComment(fout, q->data,
  				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ 	dumpSecLabel(fout, q->data,
+ 				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+ 				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  
  	destroyPQExpBuffer(q);
  	destroyPQExpBuffer(delq);
***************
*** 7323,7335 **** dumpCompositeType(Archive *fout, TypeInfo *tyinfo)
  				 NULL, NULL);
  
  
! 	/* Dump Type Comments */
  	resetPQExpBuffer(q);
  
  	appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
  	dumpComment(fout, q->data,
  				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  
  	PQclear(res);
  	destroyPQExpBuffer(q);
--- 7347,7362 ----
  				 NULL, NULL);
  
  
! 	/* Dump Type Comments and Security Labels */
  	resetPQExpBuffer(q);
  
  	appendPQExpBuffer(q, "TYPE %s", fmtId(tyinfo->dobj.name));
  	dumpComment(fout, q->data,
  				tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
  				tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
+ 	dumpSecLabel(fout, q->data,
+ 				 tyinfo->dobj.namespace->dobj.name, tyinfo->rolname,
+ 				 tyinfo->dobj.catId, 0, tyinfo->dobj.dumpId);
  
  	PQclear(res);
  	destroyPQExpBuffer(q);
***************
*** 7647,7658 **** dumpProcLang(Archive *fout, ProcLangInfo *plang)
  				 plang->dobj.dependencies, plang->dobj.nDeps,
  				 NULL, NULL);
  
! 	/* Dump Proc Lang Comments */
  	resetPQExpBuffer(defqry);
  	appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
  	dumpComment(fout, defqry->data,
  				NULL, "",
  				plang->dobj.catId, 0, plang->dobj.dumpId);
  
  	if (plang->lanpltrusted)
  		dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
--- 7674,7688 ----
  				 plang->dobj.dependencies, plang->dobj.nDeps,
  				 NULL, NULL);
  
! 	/* Dump Proc Lang Comments and Security Labels */
  	resetPQExpBuffer(defqry);
  	appendPQExpBuffer(defqry, "LANGUAGE %s", qlanname);
  	dumpComment(fout, defqry->data,
  				NULL, "",
  				plang->dobj.catId, 0, plang->dobj.dumpId);
+ 	dumpSecLabel(fout, defqry->data,
+ 				 NULL, "",
+ 				 plang->dobj.catId, 0, plang->dobj.dumpId);
  
  	if (plang->lanpltrusted)
  		dumpACL(fout, plang->dobj.catId, plang->dobj.dumpId, "LANGUAGE",
***************
*** 8208,8219 **** dumpFunc(Archive *fout, FuncInfo *finfo)
  				 finfo->dobj.dependencies, finfo->dobj.nDeps,
  				 NULL, NULL);
  
! 	/* Dump Function Comments */
  	resetPQExpBuffer(q);
  	appendPQExpBuffer(q, "FUNCTION %s", funcsig);
  	dumpComment(fout, q->data,
  				finfo->dobj.namespace->dobj.name, finfo->rolname,
  				finfo->dobj.catId, 0, finfo->dobj.dumpId);
  
  	dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
  			funcsig, NULL, funcsig_tag,
--- 8238,8252 ----
  				 finfo->dobj.dependencies, finfo->dobj.nDeps,
  				 NULL, NULL);
  
! 	/* Dump Function Comments and Security Labels */
  	resetPQExpBuffer(q);
  	appendPQExpBuffer(q, "FUNCTION %s", funcsig);
  	dumpComment(fout, q->data,
  				finfo->dobj.namespace->dobj.name, finfo->rolname,
  				finfo->dobj.catId, 0, finfo->dobj.dumpId);
+ 	dumpSecLabel(fout, q->data,
+ 				 finfo->dobj.namespace->dobj.name, finfo->rolname,
+ 				 finfo->dobj.catId, 0, finfo->dobj.dumpId);
  
  	dumpACL(fout, finfo->dobj.catId, finfo->dobj.dumpId, "FUNCTION",
  			funcsig, NULL, funcsig_tag,
***************
*** 9711,9716 **** dumpAgg(Archive *fout, AggInfo *agginfo)
--- 9744,9752 ----
  	dumpComment(fout, q->data,
  			agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
  				agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
+ 	dumpSecLabel(fout, q->data,
+ 			agginfo->aggfn.dobj.namespace->dobj.name, agginfo->aggfn.rolname,
+ 				 agginfo->aggfn.dobj.catId, 0, agginfo->aggfn.dobj.dumpId);
  
  	/*
  	 * Since there is no GRANT ON AGGREGATE syntax, we have to make the ACL
***************
*** 10461,10566 **** dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
  /*
   * dumpSecLabel 
   *
!  * It dumps any security labels associated with the object handed
!  * to this routine. The routine takes a constant character string
!  * for the target part of the security-label command, plus the
!  * namespace and owner of the object (for labeling the ArchiveEntry),
!  * plus catalogId which is lookup key for pg_seclabel, and dumpId
!  * for the object.
   * If a matching pg_seclabel entry is found, it is dumped.
   */
  static void
! dumpSecLabel(Archive *fout, CatalogId objCatId, DumpId objDumpId,
! 			 const char *type, const char *target,
! 			 const char *nspname, const char *owner)
  {
! 	PGresult	   *res;
! 	PQExpBuffer		lquery;
! 	PQExpBuffer		cquery;
! 	PQExpBuffer		tgbuf;
! 	int				i_attname;
! 	int				i_provider;
! 	int				i_label;
! 	int				i, ntups;
  
! 	/* do nothing, if security label dump is not enabled */
! 	if (!security_label)
! 		return;
! 
! 	/* --data-only skips security labels *except* large object */
! 	if (dataOnly && strcmp(type, "LARGE OBJECT") != 0)
  		return;
  
! 	/*
! 	 * Fetch security labels associated with the object
! 	 */
! 	lquery = createPQExpBuffer();
! 	cquery = createPQExpBuffer();
! 	tgbuf = createPQExpBuffer();
! 
! 	appendPQExpBuffer(lquery,
! 					  "SELECT a.attname, s.provider, s.label"
! 					  "  FROM pg_catalog.pg_seclabel s"
! 					  "       LEFT OUTER JOIN"
! 					  "       pg_catalog.pg_attribute a"
! 					  "       ON s.objoid = a.attrelid AND"
! 					  "          s.objsubid = a.attnum"
! 					  "  WHERE classoid = %u AND objoid = %u",
! 					  objCatId.tableoid, objCatId.oid);
! 
! 	res = PQexec(g_conn, lquery->data);
! 	check_sql_result(res, g_conn, lquery->data, PGRES_TUPLES_OK);
  
! 	i_attname = PQfnumber(res, "attname");
! 	i_provider = PQfnumber(res, "provider");
! 	i_label	= PQfnumber(res, "label");
  
! 	ntups = PQntuples(res);
  
! 	for (i = 0; i < ntups; i++)
  	{
- 		if (strcmp(type, "TABLE") == 0 &&
- 			!PQgetisnull(res, i, i_attname))
- 		{
- 			appendPQExpBuffer(cquery,
- 							  "SECURITY LABEL FOR '%s'"
- 							  " ON COLUMN %s.%s IS '%s';\n",
- 							  PQgetvalue(res, i, i_provider),
- 							  target,
- 							  fmtId(PQgetvalue(res, i, i_attname)),
- 							  PQgetvalue(res, i, i_label));
- 			continue;
- 		}
- 
  		/*
! 		 * a.attname can be available only when type = "TABLE",
! 		 * so we expect it will be always NULL. Elsewhere, we assume
! 		 * it as a data corruption, so simply ignored.
  		 */
! 		if (!PQgetisnull(res, i, i_attname))
  			continue;
  
! 		appendPQExpBuffer(cquery,
! 						  "SECURITY LABEL FOR '%s' ON %s %s IS '%s';\n",
! 						  PQgetvalue(res, i, i_provider),
! 						  type, target,
! 						  PQgetvalue(res, i, i_label));
  	}
- 	PQclear(res);
  
! 	if (cquery->len > 0)
  	{
- 		appendPQExpBuffer(tgbuf, "%s %s", type, target);
  		ArchiveEntry(fout, nilCatalogId, createDumpId(),
! 					 tgbuf->data, nspname, NULL, owner,
  					 false, "SECURITY LABEL", SECTION_NONE,
! 					 cquery->data, "", NULL,
! 					 &(objDumpId), 1,
  					 NULL, NULL);
  	}
! 	destroyPQExpBuffer(lquery);
! 	destroyPQExpBuffer(cquery);
! 	destroyPQExpBuffer(tgbuf);
  }
  
  /*
--- 10497,10796 ----
  /*
   * dumpSecLabel 
   *
!  * This routine is used to dump any security labels associated with the
!  * object handed to this routine. The routine takes a constant character
!  * string for the target part of the security-label command, plus
!  * the namespace and owner of the object (for labeling the ArchiveEntry),
!  * plus catalog ID and subid which are the lookup key for pg_seclabel,
!  * plus the dump ID for the object (for setting a dependency).
   * If a matching pg_seclabel entry is found, it is dumped.
+  *
+  * Note: although this routine takes a dumpId for dependency purposes,
+  * that purpose is just to mark the dependency in the emitted dump file
+  * for possible future use by pg_restore.  We do NOT use it for determining
+  * ordering of the label in the dump file, because this routine is called
+  * after dependency sorting occurs.  This routine should be called just after
+  * calling ArchiveEntry() for the specified object.
   */
  static void
! dumpSecLabel(Archive *fout, const char *target,
! 			 const char *namespace, const char *owner,
! 			 CatalogId catalogId, int subid, DumpId dumpId)
  {
! 	SecLabelItem   *labels;
! 	int				nlabels;
! 	int				i;
! 	PQExpBuffer		query;
  
! 	/* do nothing, if --no-security-label is supplied */
! 	if (no_security_label)
  		return;
  
! 	/* Comments are schema not data ... except blob comments are data */
! 	if (strncmp(target, "LARGE OBJECT ", 13) != 0)
! 	{
! 		if (dataOnly)
! 			return;
! 	}
! 	else
! 	{
! 		if (schemaOnly)
! 			return;
! 	}
  
! 	/* Search for security labels associated with catalogId, using table */
! 	nlabels = findSecLabels(fout, catalogId.tableoid, catalogId.oid, &labels);
  
! 	query = createPQExpBuffer();
  
! 	for (i = 0; i < nlabels; i++)
  	{
  		/*
! 		 * Ignore label entries which does not match with the supplied subid.
! 		 * However, only relations have objsubid except for zero, and we dump
! 		 * security labels of relations at dumpTableSecLabel(), so it might
! 		 * be a bug if labels[i].objsubid has any values except for zero.
  		 */
! 		if (labels[i].objsubid != subid)
  			continue;
  
! 		appendPQExpBuffer(query,
! 						  "SECURITY LABEL FOR '%s' ON %s IS ",
! 						  labels[i].provider, target);
! 		appendStringLiteralAH(query, labels[i].label, fout);
! 		appendPQExpBuffer(query, ";\n");
  	}
  
! 	if (query->len > 0)
  	{
  		ArchiveEntry(fout, nilCatalogId, createDumpId(),
! 					 target, namespace, NULL, owner,
  					 false, "SECURITY LABEL", SECTION_NONE,
! 					 query->data, "", NULL,
! 					 &(dumpId), 1,
  					 NULL, NULL);
  	}
! 	destroyPQExpBuffer(query);
! }
! 
! /*
!  * dumpTableSecLabel
!  *
!  * As above, but dump security label for both the specified table (or view)
!  * and its columns.
!  */
! static void
! dumpTableSecLabel(Archive *fout, TableInfo *tbinfo, const char *reltypename)
! {
! 	SecLabelItem   *labels;
! 	int				nlabels;
! 	int				i;
! 	PQExpBuffer		query;
!     PQExpBuffer		target;
! 
! 	/* do nothing, if --no-security-label is supplied */
! 	if (no_security_label)
! 		return;
! 
! 	/* SecLabel are SCHEMA not data */
! 	if (dataOnly)
! 		return;
! 
! 	/* Search for comments associated with relation, using table */
! 	nlabels = findSecLabels(fout,
! 							tbinfo->dobj.catId.tableoid,
! 							tbinfo->dobj.catId.oid,
! 							&labels);
! 
! 	/* If comments exist, build SECURITY LABEL statements */
! 	if (nlabels <= 0)
! 		return;
! 
! 	query = createPQExpBuffer();
! 	target = createPQExpBuffer();
! 
! 	for (i = 0; i < nlabels; i++)
! 	{
! 		const char *colname;
! 		const char *provider	= labels[i].provider;
! 		const char *label		= labels[i].label;
! 		int			objsubid	= labels[i].objsubid;
! 
! 		resetPQExpBuffer(target);
! 		if (objsubid == 0)
! 		{
! 			appendPQExpBuffer(target, "%s %s", reltypename,
! 							  fmtId(tbinfo->dobj.name));
! 		}
! 		else
! 		{
! 			colname = getAttrName(objsubid, tbinfo);
! 			appendPQExpBuffer(target, "COLUMN %s.%s",
! 							  fmtId(tbinfo->dobj.name),
! 							  fmtId(colname));
! 		}
! 		appendPQExpBuffer(query, "SECURITY LABEL FOR %s ON %s IS ",
! 						  provider, target->data);
! 		appendStringLiteralAH(query, label, fout);
! 		appendPQExpBuffer(query, ";\n");
! 	}
! 	if (query->len > 0)
! 	{
! 		resetPQExpBuffer(target);
! 		appendPQExpBuffer(target, "%s %s", reltypename,
! 						  fmtId(tbinfo->dobj.name));
! 		ArchiveEntry(fout, nilCatalogId, createDumpId(),
! 					 target->data,
! 					 tbinfo->dobj.namespace->dobj.name,
! 					 NULL, tbinfo->rolname,
! 					 false, "SECURITY LABEL", SECTION_NONE,
! 					 query->data, "", NULL,
! 					 &(tbinfo->dobj.dumpId), 1,
! 					 NULL, NULL);
! 	}
! 	destroyPQExpBuffer(query);
! 	destroyPQExpBuffer(target);
! }
! 
! /*
!  * findSecLabels
!  *
!  * Find the security label(s), if any, associated with the given object.
!  * All the objsubid values associated with the given classoid/objoid are
!  * found with one search.
!  */
! static int
! findSecLabels(Archive *fout, Oid classoid, Oid objoid, SecLabelItem **items)
! {
! 	/* static storage for table of security labels */
! 	static SecLabelItem *labels = NULL;
! 	static int			 nlabels = -1;
! 
! 	SecLabelItem		*middle = NULL;
! 	SecLabelItem		*low;
! 	SecLabelItem		*high;
! 	int					 nmatch;
! 
! 	/* Get security labels if we didn't already */
! 	if (nlabels < 0)
! 		nlabels = collectSecLabels(fout, &labels);
! 
! 	/*
! 	 * Do binary search to find some item matching the object.
! 	 */
! 	low = &labels[0];
! 	high = &labels[nlabels - 1];
! 	while (low <= high)
! 	{
! 		middle = low + (high - low) / 2;
! 
! 		if (classoid < middle->classoid)
! 			high = middle - 1;
! 		else if (classoid > middle->classoid)
! 			low = middle + 1;
! 		else if (objoid < middle->objoid)
! 			high = middle - 1;
! 		else if (objoid > middle->objoid)
! 			low = middle + 1;
! 		else
! 			break;			/* found a match */
! 	}
! 
! 	if (low > high)			/* no matches */
! 	{
! 		*items = NULL;
! 		return 0;
! 	}
! 
! 	/*
! 	 * Now determine how many items match the object.  The search loop
! 	 * invariant still holds: only items between low and high inclusive could
! 	 * match.
! 	 */
! 	nmatch = 1;
! 	while (middle > low)
! 	{
! 		if (classoid != middle[-1].classoid ||
! 			objoid != middle[-1].objoid)
! 			break;
! 		middle--;
! 		nmatch++;
! 	}
! 
! 	*items = middle;
! 
! 	middle += nmatch;
! 	while (middle <= high)
! 	{
! 		if (classoid != middle->classoid ||
! 			objoid != middle->objoid)
! 			break;
! 		middle++;
! 		nmatch++;
! 	}
! 
! 	return nmatch;
! }
! 
! /*
!  * collectSecLabels
!  *
!  * Construct a table of all security labels available for database objects.
!  * We used to do per-object queries for the comments, but it's much faster
!  * to pull them all over at once, and on most databases the memory cost
!  * isn't high.
!  *
!  * The table is sorted by classoid/objid/objsubid for speed in lookup.
!  */
! static int
! collectSecLabels(Archive *fout, SecLabelItem **items)
! {
! 	PGresult	   *res;
! 	PQExpBuffer		query;
! 	int				i_label;
! 	int				i_provider;
! 	int				i_classoid;
! 	int				i_objoid;
! 	int				i_objsubid;
! 	int				ntups;
! 	int				i;
! 	SecLabelItem   *labels;
! 
! 	query = createPQExpBuffer();
! 
! 	appendPQExpBuffer(query,
! 					  "SELECT label, provider, classoid, objoid, objsubid "
! 					  "FROM pg_catalog.pg_seclabel "
! 					  "ORDER BY classoid, objoid, objsubid");
! 
! 	res = PQexec(g_conn, query->data);
! 	check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
! 
! 	/* Construct lookup table containing OIDs in numeric form */
! 	i_label		= PQfnumber(res, "label");
! 	i_provider	= PQfnumber(res, "provider");
! 	i_classoid	= PQfnumber(res, "classoid");
! 	i_objoid	= PQfnumber(res, "objoid");
! 	i_objsubid	= PQfnumber(res, "objsubid");
! 
! 	ntups = PQntuples(res);
! 
! 	labels = (SecLabelItem *) malloc(ntups * sizeof(SecLabelItem));
! 
! 	for (i = 0; i < ntups; i++)
! 	{
! 		labels[i].label		= PQgetvalue(res, i, i_label);
! 		labels[i].provider	= PQgetvalue(res, i, i_provider);
! 		labels[i].classoid = atooid(PQgetvalue(res, i, i_classoid));
! 		labels[i].objoid = atooid(PQgetvalue(res, i, i_objoid));
! 		labels[i].objsubid = atoi(PQgetvalue(res, i, i_objsubid));
! 	}
! 
! 	/* Do NOT free the PGresult since we are keeping pointers into it */
!     destroyPQExpBuffer(query);
! 
! 	*items = labels;
! 	return ntups;
  }
  
  /*
***************
*** 10587,10599 **** dumpTable(Archive *fout, TableInfo *tbinfo)
  				tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
  				tbinfo->relacl);
  
- 		/* Handle the security label here */
- 		dumpSecLabel(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
- 					 (tbinfo->relkind == RELKIND_SEQUENCE ? "SEQUENCE" :
- 					  (tbinfo->relkind == RELKIND_VIEW ? "VIEW" : "TABLE")),
- 					 namecopy,
- 					 tbinfo->dobj.namespace->dobj.name,
- 					 tbinfo->rolname);
  		/*
  		 * Handle column ACLs, if any.	Note: we pull these with a separate
  		 * query rather than trying to fetch them during getTableAttrs, so
--- 10817,10822 ----
***************
*** 11086,11091 **** dumpTableSchema(Archive *fout, TableInfo *tbinfo)
--- 11309,11317 ----
  	/* Dump Table Comments */
  	dumpTableComment(fout, tbinfo, reltypename);
  
+ 	/* Dump Table Security Labels */
+ 	dumpTableSecLabel(fout, tbinfo, reltypename);
+ 
  	/* Dump comments on inlined table constraints */
  	for (j = 0; j < tbinfo->ncheck; j++)
  	{
***************
*** 11799,11810 **** dumpSequence(Archive *fout, TableInfo *tbinfo)
  			}
  		}
  
! 		/* Dump Sequence Comments */
  		resetPQExpBuffer(query);
  		appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
  		dumpComment(fout, query->data,
  					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
  					tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
  	}
  
  	if (!schemaOnly)
--- 12025,12039 ----
  			}
  		}
  
! 		/* Dump Sequence Comments and Security Labels */
  		resetPQExpBuffer(query);
  		appendPQExpBuffer(query, "SEQUENCE %s", fmtId(tbinfo->dobj.name));
  		dumpComment(fout, query->data,
  					tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
  					tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
+ 		dumpSecLabel(fout, query->data,
+ 					 tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
+ 					 tbinfo->dobj.catId, 0, tbinfo->dobj.dumpId);
  	}
  
  	if (!schemaOnly)
*** a/src/bin/pg_dump/pg_dumpall.c
--- b/src/bin/pg_dump/pg_dumpall.c
***************
*** 69,75 **** static int	disable_triggers = 0;
  static int	inserts = 0;
  static int	no_tablespaces = 0;
  static int	use_setsessauth = 0;
! static int	security_label = 0;
  static int	server_version;
  
  static FILE *OPF;
--- 69,75 ----
  static int	inserts = 0;
  static int	no_tablespaces = 0;
  static int	use_setsessauth = 0;
! static int	no_security_label = 0;
  static int	server_version;
  
  static FILE *OPF;
***************
*** 134,140 **** main(int argc, char *argv[])
  		{"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
  		{"role", required_argument, NULL, 3},
  		{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
! 		{"security-label", no_argument, &security_label, 1},
  
  		{NULL, 0, NULL, 0}
  	};
--- 134,140 ----
  		{"quote-all-identifiers", no_argument, &quote_all_identifiers, 1},
  		{"role", required_argument, NULL, 3},
  		{"use-set-session-authorization", no_argument, &use_setsessauth, 1},
! 		{"no-security-label", no_argument, &no_security_label, 1},
  
  		{NULL, 0, NULL, 0}
  	};
***************
*** 288,295 **** main(int argc, char *argv[])
  					no_tablespaces = 1;
  				else if (strcmp(optarg, "use-set-session-authorization") == 0)
  					use_setsessauth = 1;
! 				else if (strcmp(optarg, "security-label") == 0)
! 					security_label = 1;
  				else
  				{
  					fprintf(stderr,
--- 288,295 ----
  					no_tablespaces = 1;
  				else if (strcmp(optarg, "use-set-session-authorization") == 0)
  					use_setsessauth = 1;
! 				else if (strcmp(optarg, "no-security-label") == 0)
! 					no_security_label = 1;
  				else
  				{
  					fprintf(stderr,
***************
*** 375,382 **** main(int argc, char *argv[])
  		appendPQExpBuffer(pgdumpopts, " --quote-all-identifiers");
  	if (use_setsessauth)
  		appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization");
! 	if (security_label)
! 		appendPQExpBuffer(pgdumpopts, " --security-label");
  
  	/*
  	 * If there was a database specified on the command line, use that,
--- 375,382 ----
  		appendPQExpBuffer(pgdumpopts, " --quote-all-identifiers");
  	if (use_setsessauth)
  		appendPQExpBuffer(pgdumpopts, " --use-set-session-authorization");
! 	if (no_security_label)
! 		appendPQExpBuffer(pgdumpopts, " --no-security-label");
  
  	/*
  	 * If there was a database specified on the command line, use that,
***************
*** 573,579 **** help(void)
  	printf(_("  --no-tablespaces            do not dump tablespace assignments\n"));
  	printf(_("  --quote-all-identifiers     quote all identifiers, even if not keywords\n"));
  	printf(_("  --role=ROLENAME             do SET ROLE before dump\n"));
! 	printf(_("  --security-label            also dump security labels\n"));
  	printf(_("  --use-set-session-authorization\n"
  			 "                              use SET SESSION AUTHORIZATION commands instead of\n"
  	"                              ALTER OWNER commands to set ownership\n"));
--- 573,579 ----
  	printf(_("  --no-tablespaces            do not dump tablespace assignments\n"));
  	printf(_("  --quote-all-identifiers     quote all identifiers, even if not keywords\n"));
  	printf(_("  --role=ROLENAME             do SET ROLE before dump\n"));
! 	printf(_("  --no-security-label         do not dump security label assignments\n"));
  	printf(_("  --use-set-session-authorization\n"
  			 "                              use SET SESSION AUTHORIZATION commands instead of\n"
  	"                              ALTER OWNER commands to set ownership\n"));
*** a/src/test/regress/GNUmakefile
--- b/src/test/regress/GNUmakefile
***************
*** 109,115 **** installdirs-tests: installdirs
  
  # Get some extra C modules from contrib/spi...
  
! all: refint$(DLSUFFIX) autoinc$(DLSUFFIX)
  
  refint$(DLSUFFIX): $(top_builddir)/contrib/spi/refint$(DLSUFFIX)
  	cp $< $@
--- 109,115 ----
  
  # Get some extra C modules from contrib/spi...
  
! all: refint$(DLSUFFIX) autoinc$(DLSUFFIX) dummy_esp$(DLSUFFIX)
  
  refint$(DLSUFFIX): $(top_builddir)/contrib/spi/refint$(DLSUFFIX)
  	cp $< $@
***************
*** 117,128 **** refint$(DLSUFFIX): $(top_builddir)/contrib/spi/refint$(DLSUFFIX)
--- 117,133 ----
  autoinc$(DLSUFFIX): $(top_builddir)/contrib/spi/autoinc$(DLSUFFIX)
  	cp $< $@
  
+ dummy_esp$(DLSUFFIX): $(top_builddir)/contrib/dummy_esp/dummy_esp$(DLSUFFIX)
+ 	cp $< $@
+ 
  $(top_builddir)/contrib/spi/refint$(DLSUFFIX): $(top_srcdir)/contrib/spi/refint.c
  	$(MAKE) -C $(top_builddir)/contrib/spi refint$(DLSUFFIX)
  
  $(top_builddir)/contrib/spi/autoinc$(DLSUFFIX): $(top_srcdir)/contrib/spi/autoinc.c
  	$(MAKE) -C $(top_builddir)/contrib/spi autoinc$(DLSUFFIX)
  
+ $(top_builddir)/contrib/dummy_esp/dummy_esp$(DLSUFFIX): $(top_builddir)/contrib/dummy_esp/dummy_esp.c
+ 	$(MAKE) -C $(top_builddir)/contrib/dummy_esp dummy_esp$(DLSUFFIX)
  
  # Tablespace setup
  
***************
*** 171,177 **** bigcheck: all
  
  clean distclean maintainer-clean: clean-lib
  # things built by `all' target
! 	rm -f $(OBJS) refint$(DLSUFFIX) autoinc$(DLSUFFIX) pg_regress_main.o pg_regress.o pg_regress$(X)
  # things created by various check targets
  	rm -f $(output_files) $(input_files)
  	rm -rf testtablespace
--- 176,183 ----
  
  clean distclean maintainer-clean: clean-lib
  # things built by `all' target
! 	rm -f $(OBJS) refint$(DLSUFFIX) autoinc$(DLSUFFIX) dummy_esp$(DLSUFFIX)
! 	rm -f pg_regress_main.o pg_regress.o pg_regress$(X)
  # things created by various check targets
  	rm -f $(output_files) $(input_files)
  	rm -rf testtablespace
*** a/src/test/regress/expected/rules.out
--- b/src/test/regress/expected/rules.out
***************
*** 1276,1283 **** drop table cchild;
  -- Check that ruleutils are working
  --
  SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
!           viewname           |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            definition                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            
! -----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   iexit                       | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
   pg_cursors                  | SELECT c.name, c.statement, c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time);
   pg_group                    | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
--- 1276,1283 ----
  -- Check that ruleutils are working
  --
  SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schema' ORDER BY viewname;
!           viewname           |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         definition                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
! -----------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
   iexit                       | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
   pg_cursors                  | SELECT c.name, c.statement, c.is_holdable, c.is_binary, c.is_scrollable, c.creation_time FROM pg_cursor() c(name, statement, is_holdable, is_binary, is_scrollable, creation_time);
   pg_group                    | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
***************
*** 1287,1292 **** SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
--- 1287,1293 ----
   pg_prepared_xacts           | SELECT p.transaction, p.gid, p.prepared, u.rolname AS owner, d.datname AS database FROM ((pg_prepared_xact() p(transaction, gid, prepared, ownerid, dbid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid)));
   pg_roles                    | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, pg_authid.rolconnlimit, '********'::text AS rolpassword, pg_authid.rolvaliduntil, s.setconfig AS rolconfig, pg_authid.oid FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid))));
   pg_rules                    | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
+  pg_seclabels                | (((((SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (rel.relkind = 'r'::"char") THEN 'table'::text WHEN (rel.relkind = 'v'::"char") THEN 'view'::text WHEN (rel.relkind = 'S'::"char") THEN 'sequence'::text ELSE NULL::text END AS objtype, rel.relnamespace AS objnamespace, CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid = 0) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'column'::text AS objtype, rel.relnamespace AS objnamespace, ((CASE WHEN pg_table_is_visible(rel.oid) THEN quote_ident((rel.relname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((rel.relname)::text)) END || '.'::text) || (att.attname)::text) AS objname, l.provider, l.label FROM (((pg_seclabel l JOIN pg_class rel ON (((l.classoid = rel.tableoid) AND (l.objoid = rel.oid)))) JOIN pg_attribute att ON (((rel.oid = att.attrelid) AND (l.objsubid = att.attnum)))) JOIN pg_namespace nsp ON ((rel.relnamespace = nsp.oid))) WHERE (l.objsubid <> 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (pro.proisagg = true) THEN 'aggregate'::text WHEN (pro.proisagg = false) THEN 'function'::text ELSE NULL::text END AS objtype, pro.pronamespace AS objnamespace, (((CASE WHEN pg_function_is_visible(pro.oid) THEN quote_ident((pro.proname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((pro.proname)::text)) END || '('::text) || pg_get_function_arguments(pro.oid)) || ')'::text) AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_proc pro ON (((l.classoid = pro.tableoid) AND (l.objoid = pro.oid)))) JOIN pg_namespace nsp ON ((pro.pronamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, CASE WHEN (typ.typtype = 'd'::"char") THEN 'domain'::text ELSE 'type'::text END AS objtype, typ.typnamespace AS objnamespace, CASE WHEN pg_type_is_visible(typ.oid) THEN quote_ident((typ.typname)::text) ELSE ((quote_ident((nsp.nspname)::text) || '.'::text) || quote_ident((typ.typname)::text)) END AS objname, l.provider, l.label FROM ((pg_seclabel l JOIN pg_type typ ON (((l.classoid = typ.tableoid) AND (l.objoid = typ.oid)))) JOIN pg_namespace nsp ON ((typ.typnamespace = nsp.oid))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'large object'::text AS objtype, NULL::oid AS objnamespace, (l.objoid)::text AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_largeobject_metadata lom ON ((l.objoid = lom.oid))) WHERE ((l.classoid = (SELECT pg_class.oid FROM pg_class WHERE ((pg_class.relname = 'pg_largeobject'::name) AND (pg_class.relnamespace = (SELECT pg_namespace.oid FROM pg_namespace WHERE (pg_namespace.nspname = 'pg_catalog'::name)))))) AND (l.objsubid = 0))) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'language'::text AS objtype, NULL::oid AS objnamespace, quote_ident((lan.lanname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_language lan ON (((l.classoid = lan.tableoid) AND (l.objoid = lan.oid)))) WHERE (l.objsubid = 0)) UNION ALL SELECT l.objoid, l.classoid, l.objsubid, 'schema'::text AS objtype, nsp.oid AS objnamespace, quote_ident((nsp.nspname)::text) AS objname, l.provider, l.label FROM (pg_seclabel l JOIN pg_namespace nsp ON (((l.classoid = nsp.tableoid) AND (l.objoid = nsp.oid)))) WHERE (l.objsubid = 0);
   pg_settings                 | SELECT a.name, a.setting, a.unit, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val, a.enumvals, a.boot_val, a.reset_val, a.sourcefile, a.sourceline FROM pg_show_all_settings() a(name, setting, unit, category, short_desc, extra_desc, context, vartype, source, min_val, max_val, enumvals, boot_val, reset_val, sourcefile, sourceline);
   pg_shadow                   | SELECT pg_authid.rolname AS usename, pg_authid.oid AS usesysid, pg_authid.rolcreatedb AS usecreatedb, pg_authid.rolsuper AS usesuper, pg_authid.rolcatupdate AS usecatupd, pg_authid.rolpassword AS passwd, (pg_authid.rolvaliduntil)::abstime AS valuntil, s.setconfig AS useconfig FROM (pg_authid LEFT JOIN pg_db_role_setting s ON (((pg_authid.oid = s.setrole) AND (s.setdatabase = (0)::oid)))) WHERE pg_authid.rolcanlogin;
   pg_stat_activity            | SELECT s.datid, d.datname, s.procpid, s.usesysid, u.rolname AS usename, s.application_name, s.client_addr, s.client_port, s.backend_start, s.xact_start, s.query_start, s.waiting, s.current_query FROM pg_database d, pg_stat_get_activity(NULL::integer) s(datid, procpid, usesysid, application_name, current_query, waiting, xact_start, query_start, backend_start, client_addr, client_port), pg_authid u WHERE ((s.datid = d.oid) AND (s.usesysid = u.oid));
***************
*** 1333,1339 **** SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
   shoelace_obsolete           | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
   street                      | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
   toyemp                      | SELECT emp.name, emp.age, emp.location, (12 * emp.salary) AS annualsal FROM emp;
! (55 rows)
  
  SELECT tablename, rulename, definition FROM pg_rules 
  	ORDER BY tablename, rulename;
--- 1334,1340 ----
   shoelace_obsolete           | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
   street                      | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
   toyemp                      | SELECT emp.name, emp.age, emp.location, (12 * emp.salary) AS annualsal FROM emp;
! (56 rows)
  
  SELECT tablename, rulename, definition FROM pg_rules 
  	ORDER BY tablename, rulename;
*** /dev/null
--- b/src/test/regress/input/security_label.source
***************
*** 0 ****
--- 1,66 ----
+ --
+ -- Test for facilities of security label
+ --
+ 
+ -- initial setups
+ SET client_min_messages TO 'warning';
+ 
+ DROP ROLE IF EXISTS esp_user1;
+ DROP ROLE IF EXISTS esp_user2;
+ 
+ DROP TABLE IF EXISTS esp_tbl1;
+ DROP TABLE IF EXISTS esp_tbl2;
+ DROP TABLE IF EXISTS esp_tbl3;
+ 
+ CREATE USER esp_user1;
+ CREATE USER esp_user2;
+ 
+ CREATE TABLE esp_tbl1 (a int, b text);
+ CREATE TABLE esp_tbl2 (x int, y text);
+ 
+ ALTER TABLE esp_tbl1 OWNER TO esp_user1;
+ ALTER TABLE esp_tbl2 OWNER TO esp_user2;
+ 
+ RESET client_min_messages;
+ 
+ --
+ -- Test of SECURITY LABEL statement without a plugin
+ --
+ SECURITY LABEL ON TABLE esp_tbl1 IS 'classified';			-- fail
+ SECURITY LABEL FOR 'dummy' ON TABLE esp_tbl1 IS 'classified';		-- fail
+ SECURITY LABEL ON TABLE esp_tbl1 IS '...invalid label...';		-- fail
+ SECURITY LABEL ON TABLE esp_tbl3 IS 'unclassified';			-- fail
+ 
+ -- Load dummy external security provider
+ LOAD '@abs_builddir@/dummy_esp';
+ 
+ --
+ -- Test of SECURITY LABEL statement with a plugin
+ --
+ SET SESSION AUTHORIZATION esp_user1;
+ 
+ SECURITY LABEL ON TABLE esp_tbl1 IS 'classified';			-- OK
+ SECURITY LABEL ON COLUMN esp_tbl1.a IS 'unclassified';			-- OK
+ SECURITY LABEL ON TABLE esp_tbl1 IS '...invalid label...';		-- fail
+ SECURITY LABEL FOR 'dummy' ON TABLE esp_tbl1 IS 'unclassified';		-- OK
+ SECURITY LABEL FOR 'unknown_esp' ON TABLE esp_tbl1 IS 'classified';	-- fail
+ SECURITY LABEL ON TABLE esp_tbl2 IS 'unclassified';			-- fail (not owner)
+ SECURITY LABEL ON TABLE esp_tbl1 IS 'secret';				-- fail (not superuser)
+ SECURITY LABEL ON TABLE esp_tbl3 IS 'unclassified';			-- fail (not found)
+ 
+ SET SESSION AUTHORIZATION esp_user2;
+ SECURITY LABEL ON TABLE esp_tbl1 IS 'unclassified';			-- fail
+ SECURITY LABEL ON TABLE esp_tbl2 IS 'classified';			-- OK
+ 
+ RESET SESSION AUTHORIZATION;
+ 
+ SECURITY LABEL ON TABLE esp_tbl1 IS 'top secret';			-- OK
+ 
+ SELECT objtype, objname, provider, label FROM pg_seclabels
+ 	WHERE objname in ('esp_tbl1', 'esp_tbl2');
+ 
+ -- clean up objects
+ DROP TABLE esp_tbl1;
+ DROP TABLE esp_tbl2;
+ DROP USER esp_user1;
+ DROP USER esp_user2;
*** /dev/null
--- b/src/test/regress/output/security_label.source
***************
*** 0 ****
--- 1,66 ----
+ --
+ -- Test for facilities of security label
+ --
+ -- initial setups
+ SET client_min_messages TO 'warning';
+ DROP ROLE IF EXISTS esp_user1;
+ DROP ROLE IF EXISTS esp_user2;
+ DROP TABLE IF EXISTS esp_tbl1;
+ DROP TABLE IF EXISTS esp_tbl2;
+ DROP TABLE IF EXISTS esp_tbl3;
+ CREATE USER esp_user1;
+ CREATE USER esp_user2;
+ CREATE TABLE esp_tbl1 (a int, b text);
+ CREATE TABLE esp_tbl2 (x int, y text);
+ ALTER TABLE esp_tbl1 OWNER TO esp_user1;
+ ALTER TABLE esp_tbl2 OWNER TO esp_user2;
+ RESET client_min_messages;
+ --
+ -- Test of SECURITY LABEL statement without a plugin
+ --
+ SECURITY LABEL ON TABLE esp_tbl1 IS 'classified';			-- fail
+ ERROR:  security label providers have been loaded
+ SECURITY LABEL FOR 'dummy' ON TABLE esp_tbl1 IS 'classified';		-- fail
+ ERROR:  security label provider "dummy" is not loaded
+ SECURITY LABEL ON TABLE esp_tbl1 IS '...invalid label...';		-- fail
+ ERROR:  security label providers have been loaded
+ SECURITY LABEL ON TABLE esp_tbl3 IS 'unclassified';			-- fail
+ ERROR:  security label providers have been loaded
+ -- Load dummy external security provider
+ LOAD '@abs_builddir@/dummy_esp';
+ --
+ -- Test of SECURITY LABEL statement with a plugin
+ --
+ SET SESSION AUTHORIZATION esp_user1;
+ SECURITY LABEL ON TABLE esp_tbl1 IS 'classified';			-- OK
+ SECURITY LABEL ON COLUMN esp_tbl1.a IS 'unclassified';			-- OK
+ SECURITY LABEL ON TABLE esp_tbl1 IS '...invalid label...';		-- fail
+ ERROR:  '...invalid label...' is not a valid security label
+ SECURITY LABEL FOR 'dummy' ON TABLE esp_tbl1 IS 'unclassified';		-- OK
+ SECURITY LABEL FOR 'unknown_esp' ON TABLE esp_tbl1 IS 'classified';	-- fail
+ ERROR:  security label provider "unknown_esp" is not loaded
+ SECURITY LABEL ON TABLE esp_tbl2 IS 'unclassified';			-- fail (not owner)
+ ERROR:  must be owner of relation esp_tbl2
+ SECURITY LABEL ON TABLE esp_tbl1 IS 'secret';				-- fail (not superuser)
+ ERROR:  only superuser can set 'secret' label
+ SECURITY LABEL ON TABLE esp_tbl3 IS 'unclassified';			-- fail (not found)
+ ERROR:  relation "esp_tbl3" does not exist
+ SET SESSION AUTHORIZATION esp_user2;
+ SECURITY LABEL ON TABLE esp_tbl1 IS 'unclassified';			-- fail
+ ERROR:  must be owner of relation esp_tbl1
+ SECURITY LABEL ON TABLE esp_tbl2 IS 'classified';			-- OK
+ RESET SESSION AUTHORIZATION;
+ SECURITY LABEL ON TABLE esp_tbl1 IS 'top secret';			-- OK
+ SELECT objtype, objname, provider, label FROM pg_seclabels
+ 	WHERE objname in ('esp_tbl1', 'esp_tbl2');
+  objtype | objname  | provider |   label    
+ ---------+----------+----------+------------
+  table   | esp_tbl1 | dummy    | top secret
+  table   | esp_tbl2 | dummy    | classified
+ (2 rows)
+ 
+ -- clean up objects
+ DROP TABLE esp_tbl1;
+ DROP TABLE esp_tbl2;
+ DROP USER esp_user1;
+ DROP USER esp_user2;
*** a/src/test/regress/parallel_schedule
--- b/src/test/regress/parallel_schedule
***************
*** 76,82 **** ignore: random
  # ----------
  test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts delete
  
! test: privileges
  test: misc
  # rules cannot run concurrently with any test that creates a view
  test: rules
--- 76,82 ----
  # ----------
  test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts delete
  
! test: privileges security_label
  test: misc
  # rules cannot run concurrently with any test that creates a view
  test: rules
*** a/src/test/regress/serial_schedule
--- b/src/test/regress/serial_schedule
***************
*** 88,93 **** test: delete
--- 88,94 ----
  test: namespace
  test: prepared_xacts
  test: privileges
+ test: security_label
  test: misc
  test: rules
  test: select_views