*** 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 ----
+ pg_seclabels
+ security labels
+
+
+ pg_settingsparameter settings
***************
*** 6870,6876 ****
--- 6875,6965 ----
+
+ pg_seclabels
+
+
+ pg_seclabels
+
+
+
+ The view pg_seclabels provides references to
+ security label of database objects with their text identifiers.
+
+
+
+ pg_seclabels> Columns
+
+
+
+ Name
+ Type
+ References
+ Description
+
+
+
+
+ objoid
+ oid
+ any OID column
+ The OID of the object this security label assigned on
+
+
+ classoid
+ oid
+ pg_class.oid
+ The OID of the system catalog this object appears in
+
+
+ objsubid
+ int4
+
+
+ For a security label on 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.
+
+
+
+ objtype
+ text
+
+ text identifier of the object type
+
+
+ objnamespace
+ oid
+ pg_namespace.oid
+
+ The OID of the namespace that contains this object.
+ Maybe NULL, if object does not have its namespace.
+
+
+
+ objname
+ text
+
+ The name of the object this security label assigned on
+
+
+ provider
+ text
+ pg_seclabel.provider
+ The label provider associated with this label.
+
+
+ label
+ text
+ pg_seclabel.label
+ The security label applied to this object.
+
+
+
+
+ pg_settings
*** a/doc/src/sgml/user-manag.sgml
--- b/doc/src/sgml/user-manag.sgml
***************
*** 502,505 **** DROP ROLE name;
--- 502,536 ----
+
+ External Security Providers
+
+
+ PostgreSQL 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 9.1.0 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.
+
+
+ The major purpose to support external security providers is porting
+ mandatory access control (MAC) features;
+ such as SELinux.
+ 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.
+ PostgreSQL provides a set of facilities
+ to manage security labels of database objects as built-in feature.
+ The pg_seclabel
+ system catalog enables to assign security labels
+ on database objects, command
+ allows us to manage security labels, and some of security hooks allows
+ to label database objects on its creation time.
+
+
+ We don't mention about detail of the individual security module here,
+ so please reference their own documentation to see any more information.
+
+
*** 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, "e_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, "e_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, "e_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, "e_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