diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index d2710db..e19cad6 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -209,6 +209,11 @@
      </row>
 
      <row>
+      <entry><link linkend="catalog-pg-seclabel"><structname>pg_seclabel</structname></link></entry>
+      <entry>security labels on local database objects</entry>
+     </row>
+
+     <row>
       <entry><link linkend="catalog-pg-shdepend"><structname>pg_shdepend</structname></link></entry>
       <entry>dependencies on shared objects</entry>
      </row>
@@ -4204,6 +4209,91 @@
   </table>
  </sect1>
 
+ <sect1 id="catalog-pg-seclabel">
+  <title><structname>pg_seclabel</structname></title>
+
+  <indexterm zone="catalog-pg-seclabel">
+   <primary>pg_seclabel</primary>
+  </indexterm>
+
+  <para>
+   The catalog <structname>pg_seclabel</structname> stores the security
+   label of database objects. This information allows external security
+   providers to apply label based mandatory access controls.
+  </para>
+
+  <para>
+   When external security providers with label based mandatory access
+   control are installed, its security label shall be assigned on
+   creation of database obejcts.
+   (Please note that only relations are supported right now.)
+  </para>
+  <para>
+   The security labels shall be automatically cleaned up when the database
+   object being labeled is dropped.
+  </para>
+  <para>
+   See also <link linkend="sql-security-label"><command>SECURITY LABEL</command></link>,
+   which provides a functionality to relabel a certain database object,
+   as long as user has enough privileges.
+  </para>
+
+  <table>
+   <title><structname>pg_seclabel</structname> 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>reloid</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>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>subid</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</structfield> and <structfield>classoid</structfield>
+       refer to the table itself).  For all other object types, this column is
+       zero
+      </entry>
+     </row>
+
+     <row>
+      <entry><structfield>tag</structfield></entry>
+      <entry><type>text</type></entry>
+      <entry></entry>
+      <entry>identifier of external security provider</entry>
+     </row>
+
+     <row>
+      <entry><structfield>label</structfield></entry>
+      <entry><type>text</type></entry>
+      <entry></entry>
+      <entry>security label in text format</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+ </sect1>
 
  <sect1 id="catalog-pg-shdepend">
   <title><structname>pg_shdepend</structname></title>
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index 82f761d..362b153 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -37,7 +37,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
 	pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
 	pg_ts_parser.h pg_ts_template.h \
 	pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
-	pg_default_acl.h \
+	pg_default_acl.h pg_seclabel.h \
 	toasting.h indexing.h \
     )
 
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 12b5d85..b171f01 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -57,6 +57,7 @@
 #include "commands/defrem.h"
 #include "commands/proclang.h"
 #include "commands/schemacmds.h"
+#include "commands/seclabel.h"
 #include "commands/tablespace.h"
 #include "commands/trigger.h"
 #include "commands/typecmds.h"
@@ -1010,6 +1011,13 @@ deleteOneObject(const ObjectAddress *object, Relation depRel)
 	DeleteComments(object->objectId, object->classId, object->objectSubId);
 
 	/*
+	 * Delete any security labels associated with this object. (This is also
+	 * a convenient place to do it instead of having every object type know
+	 * to do it.)
+	 */
+	DeleteSecurityLabel(object);
+
+	/*
 	 * CommandCounterIncrement here to ensure that preceding changes are all
 	 * visible to the next deletion step.
 	 */
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index a2cc786..17ce32b 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -17,7 +17,7 @@ OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o  \
 	dbcommands.o define.o discard.o explain.o foreigncmds.o functioncmds.o \
 	indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
 	portalcmds.o prepare.o proclang.o \
-	schemacmds.o sequence.o tablecmds.o tablespace.o trigger.o \
+	schemacmds.o seclabel.o sequence.o tablecmds.o tablespace.o trigger.o \
 	tsearchcmds.o typecmds.o user.o vacuum.o vacuumlazy.o \
 	variable.o view.o
 
diff --git a/src/backend/commands/seclabel.c b/src/backend/commands/seclabel.c
new file mode 100644
index 0000000..5f914fa
--- /dev/null
+++ b/src/backend/commands/seclabel.c
@@ -0,0 +1,271 @@
+/* -------------------------------------------------------------------------
+ *
+ * seclabel.c
+ *    routines to support security label feature.
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "catalog/catalog.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_seclabel.h"
+#include "commands/seclabel.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/rel.h"
+#include "utils/tqual.h"
+
+/*
+ * GetLocalSecLabel
+ *
+ * It tries to look up a security label entry for the given OID of the
+ * relation, object itself and sub identifier (if needed) from the
+ * pg_seclabel system catalog.
+ * It returns NULL, if no valid entry. Elsewhere, it returns a security
+ * label of the specified object.
+ */
+static char *
+GetLocalSecLabel(const ObjectAddress *object, const char *tag)
+{
+	Relation	pg_seclabel;
+	ScanKeyData	keys[4];
+	SysScanDesc	scan;
+	HeapTuple	tuple;
+	Datum		datum;
+	bool		isnull;
+	char	   *seclabel = NULL;
+
+	ScanKeyInit(&keys[0],
+				Anum_pg_seclabel_reloid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(object->classId));
+	ScanKeyInit(&keys[1],
+				Anum_pg_seclabel_objoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(object->objectId));
+	ScanKeyInit(&keys[2],
+				Anum_pg_seclabel_subid,
+				BTEqualStrategyNumber, F_INT4EQ,
+				Int32GetDatum(object->objectSubId));
+	ScanKeyInit(&keys[3],
+				Anum_pg_seclabel_tag,
+				BTEqualStrategyNumber, F_TEXTEQ,
+				CStringGetTextDatum(tag));
+
+	pg_seclabel = heap_open(SecLabelRelationId, AccessShareLock);
+
+	scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
+							  SnapshotNow, 4, keys);
+
+	tuple = systable_getnext(scan);
+	if (HeapTupleIsValid(tuple))
+	{
+		datum = heap_getattr(tuple, Anum_pg_seclabel_label,
+							 RelationGetDescr(pg_seclabel), &isnull);
+		if (!isnull)
+			seclabel = TextDatumGetCString(datum);
+	}
+	systable_endscan(scan);
+
+	heap_close(pg_seclabel, AccessShareLock);
+
+	return seclabel;
+}
+
+/*
+ * SetLocalSecLabel
+ *
+ * It tries to insert/update/delete a security label for the given OID
+ * of the relation, object itself and sub identifier (if needed) on the
+ * pg_seclabel system catalog.
+ * If given 'new_label' is NULL, it tries to delete the specified entry.
+ * Elsewhere, it tries to insert (if no specified entry now) or update
+ * security label of the specified entry.
+ */
+static void
+SetLocalSecLabel(const ObjectAddress *object,
+				 const char *tag, const char *seclabel)
+{
+	Relation	pg_seclabel;
+	ScanKeyData	keys[4];
+	SysScanDesc	scan;
+	HeapTuple	oldtup;
+	HeapTuple	newtup = NULL;
+	Datum		values[Natts_pg_seclabel];
+	bool		nulls[Natts_pg_seclabel];
+	bool		replaces[Natts_pg_seclabel];
+
+	ScanKeyInit(&keys[0],
+				Anum_pg_seclabel_reloid,
+				BTEqualStrategyNumber, F_OIDEQ,
+                ObjectIdGetDatum(object->classId));
+	ScanKeyInit(&keys[1],
+				Anum_pg_seclabel_objoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(object->objectId));
+	ScanKeyInit(&keys[2],
+				Anum_pg_seclabel_subid,
+				BTEqualStrategyNumber, F_INT4EQ,
+				Int32GetDatum(object->objectSubId));
+	ScanKeyInit(&keys[3],
+				Anum_pg_seclabel_tag,
+				BTEqualStrategyNumber, F_TEXTEQ,
+				CStringGetTextDatum(tag));
+
+	pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
+
+	scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
+							  SnapshotNow, 4, keys);
+
+	oldtup = systable_getnext(scan);
+	if (HeapTupleIsValid(oldtup))
+	{
+		if (seclabel != NULL)
+		{
+			/*
+			 * update the specified security label entry
+			 */
+			memset(nulls, false, sizeof(nulls));
+			memset(replaces, false, sizeof(replaces));
+
+			replaces[Anum_pg_seclabel_label - 1] = true;
+			values[Anum_pg_seclabel_label - 1]
+				= CStringGetTextDatum(seclabel);
+
+			newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_seclabel),
+									   values, nulls, replaces);
+			simple_heap_update(pg_seclabel, &oldtup->t_self, newtup);
+
+			CatalogUpdateIndexes(pg_seclabel, newtup);
+
+			heap_freetuple(newtup);
+		}
+		else
+		{
+			/*
+			 * when seclabel = NULL, it means to remove the matched
+			 * entry from pg_seclabel.
+			 */
+			simple_heap_delete(pg_seclabel, &oldtup->t_self);
+		}
+	}
+	else if (seclabel != NULL)
+	{
+		/*
+		 * insert a new security label entry
+		 */
+		memset(nulls, false, sizeof(nulls));
+		values[Anum_pg_seclabel_reloid - 1] = ObjectIdGetDatum(object->classId);
+		values[Anum_pg_seclabel_objoid - 1] = ObjectIdGetDatum(object->objectId);
+		values[Anum_pg_seclabel_subid - 1] = Int32GetDatum(object->objectSubId);
+		values[Anum_pg_seclabel_tag - 1] = CStringGetTextDatum(tag);
+		values[Anum_pg_seclabel_label - 1] = CStringGetTextDatum(seclabel);
+
+		newtup = heap_form_tuple(RelationGetDescr(pg_seclabel),
+								 values, nulls);
+		simple_heap_insert(pg_seclabel, newtup);
+
+		CatalogUpdateIndexes(pg_seclabel, newtup);
+
+		heap_freetuple(newtup);
+	}
+	systable_endscan(scan);
+		
+	heap_close(pg_seclabel, RowExclusiveLock);
+}
+
+/*
+ * DeleteLocalSecLabel
+ *
+ * It tries to delete entries of security labels for the given OID
+ * of the relation, object itself and sub identifier (if needed) on
+ * the pg_seclabel system catalog.
+ * If given 'objectSubId' is 0, all security labels matching with
+ * classId and objectId will be removed.
+ */
+static void
+DeleteLocalSecLabel(const ObjectAddress *object)
+{
+	Relation	pg_seclabel;
+	ScanKeyData	keys[3];
+	SysScanDesc	scan;
+	HeapTuple	oldtup;
+	int			nkeys = 0;
+
+	ScanKeyInit(&keys[nkeys++],
+				Anum_pg_seclabel_reloid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(object->classId));
+	ScanKeyInit(&keys[nkeys++],
+				Anum_pg_seclabel_objoid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(object->objectId));
+	if (object->objectSubId != 0)
+	{
+		ScanKeyInit(&keys[nkeys++],
+					Anum_pg_seclabel_subid,
+					BTEqualStrategyNumber, F_INT4EQ,
+					Int32GetDatum(object->objectSubId));
+	}
+
+	pg_seclabel = heap_open(SecLabelRelationId, RowExclusiveLock);
+
+	scan = systable_beginscan(pg_seclabel, SecLabelObjectIndexId, true,
+							  SnapshotNow, nkeys, keys);
+	while (HeapTupleIsValid(oldtup = systable_getnext(scan)))
+	{
+		simple_heap_delete(pg_seclabel, &oldtup->t_self);
+	}
+	systable_endscan(scan);
+
+	heap_close(pg_seclabel, RowExclusiveLock);
+}
+
+/*
+ * GetSecurityLabel
+ *
+ * An internal API to get a security label of the specified object.
+ */
+char *
+GetSecurityLabel(const ObjectAddress *object, const char *tag)
+{
+	Assert(!IsSharedRelation(object->classId));
+
+	return GetLocalSecLabel(object, tag);
+}
+
+/*
+ * SetSecurityLabel
+ *
+ * An internal API to set a security label of the specified object.
+ */
+void
+SetSecurityLabel(const ObjectAddress *object,
+				 const char *tag, const char *seclabel)
+{
+	Assert(!IsSharedRelation(object->classId));
+
+	SetLocalSecLabel(object, tag, seclabel);
+}
+
+/*
+ * DeleteSecurityLabel
+ *
+ * An internal API to delete all the security labels of the specified object.
+ */
+void
+DeleteSecurityLabel(const ObjectAddress *object)
+{
+	/* Right now, nothing to do for the shared relation */
+	if (IsSharedRelation(object->classId))
+		return;
+
+	DeleteLocalSecLabel(object);
+}
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
index 4f437fd..a297402 100644
--- a/src/include/catalog/indexing.h
+++ b/src/include/catalog/indexing.h
@@ -281,6 +281,9 @@ DECLARE_UNIQUE_INDEX(pg_default_acl_oid_index, 828, on pg_default_acl using btre
 DECLARE_UNIQUE_INDEX(pg_db_role_setting_databaseid_rol_index, 2965, on pg_db_role_setting using btree(setdatabase oid_ops, setrole oid_ops));
 #define DbRoleSettingDatidRolidIndexId	2965
 
+DECLARE_UNIQUE_INDEX(pg_seclabel_object_index, 3038, on pg_seclabel using btree(reloid oid_ops, objoid oid_ops, subid int4_ops, tag text_ops));
+#define SecLabelObjectIndexId				3038
+
 /* last step of initialization script: build the indexes declared above */
 BUILD_INDICES
 
diff --git a/src/include/catalog/pg_seclabel.h b/src/include/catalog/pg_seclabel.h
new file mode 100644
index 0000000..7c1255c
--- /dev/null
+++ b/src/include/catalog/pg_seclabel.h
@@ -0,0 +1,43 @@
+/* -------------------------------------------------------------------------
+ *
+ * pg_seclabel.h
+ *    definition of the system "security label" relation (pg_seclabel)
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * -------------------------------------------------------------------------
+ */
+#ifndef PG_SECLABEL_H
+#define PG_SECLABEL_H
+
+#include "catalog/genbki.h"
+
+/* ----------------
+ *		pg_seclabel definition.  cpp turns this into
+ *		typedef struct FormData_pg_seclabel
+ * ----------------
+ */
+#define SecLabelRelationId		3037
+
+CATALOG(pg_seclabel,3037) BKI_WITHOUT_OIDS
+{
+	Oid			reloid;		/* OID of table containing the object */
+	Oid			objoid;		/* OID of the object itself */
+	int4		subid;		/* column number, or 0 if not used */
+	text		tag;		/* identifier of external security provider */
+	text		label;		/* security label of the object */
+} FormData_pg_seclabel;
+
+/* ----------------
+ *		compiler constants for pg_seclabel
+ * ----------------
+ */
+#define Natts_pg_seclabel			5
+#define Anum_pg_seclabel_reloid		1
+#define Anum_pg_seclabel_objoid		2
+#define Anum_pg_seclabel_subid		3
+#define Anum_pg_seclabel_tag		4
+#define Anum_pg_seclabel_label		5
+
+#endif	/* PG_SECLABEL_H */
diff --git a/src/include/catalog/toasting.h b/src/include/catalog/toasting.h
index fb6f678..fa47938 100644
--- a/src/include/catalog/toasting.h
+++ b/src/include/catalog/toasting.h
@@ -45,6 +45,7 @@ DECLARE_TOAST(pg_constraint, 2832, 2833);
 DECLARE_TOAST(pg_description, 2834, 2835);
 DECLARE_TOAST(pg_proc, 2836, 2837);
 DECLARE_TOAST(pg_rewrite, 2838, 2839);
+DECLARE_TOAST(pg_seclabel, 3039, 3040);
 DECLARE_TOAST(pg_statistic, 2840, 2841);
 DECLARE_TOAST(pg_trigger, 2336, 2337);
 
diff --git a/src/include/commands/seclabel.h b/src/include/commands/seclabel.h
new file mode 100644
index 0000000..b69fc07
--- /dev/null
+++ b/src/include/commands/seclabel.h
@@ -0,0 +1,25 @@
+/*
+ * seclabel.h
+ *
+ * Prototypes for functions in commands/seclabel.c
+ *
+ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ */
+#ifndef SECLABEL_H
+#define SECLABEL_H
+
+#include "catalog/dependency.h"
+
+/*
+ * Internal APIs
+ */
+extern char *GetSecurityLabel(const ObjectAddress *object,
+							  const char *tag);
+extern void  SetSecurityLabel(const ObjectAddress *object,
+							  const char *tag,
+							  const char *seclabel);
+extern void  DeleteSecurityLabel(const ObjectAddress *object);
+
+#endif	/* SECLABEL_H */
+
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
index 1d9e110..9596b0b 100644
--- a/src/test/regress/expected/sanity_check.out
+++ b/src/test/regress/expected/sanity_check.out
@@ -114,6 +114,7 @@ SELECT relname, relhasindex
  pg_pltemplate           | t
  pg_proc                 | t
  pg_rewrite              | t
+ pg_seclabel             | t
  pg_shdepend             | t
  pg_shdescription        | t
  pg_statistic            | t
@@ -153,7 +154,7 @@ SELECT relname, relhasindex
  timetz_tbl              | f
  tinterval_tbl           | f
  varchar_tbl             | f
-(142 rows)
+(143 rows)
 
 --
 -- another sanity check: every system catalog that has OIDs should have
