diff -rpNU3 base/src/backend/Makefile pgace/src/backend/Makefile
--- base/src/backend/Makefile	2008-03-19 10:33:12.000000000 +0900
+++ pgace/src/backend/Makefile	2008-03-19 10:42:28.000000000 +0900
@@ -16,7 +16,7 @@ include $(top_builddir)/src/Makefile.glo
 
 SUBDIRS = access bootstrap catalog parser commands executor lib libpq \
 	main nodes optimizer port postmaster regex rewrite \
-	storage tcop tsearch utils $(top_builddir)/src/timezone
+	security storage tcop tsearch utils $(top_builddir)/src/timezone
 
 include $(srcdir)/common.mk
 
diff -rpNU3 base/src/backend/access/common/heaptuple.c pgace/src/backend/access/common/heaptuple.c
--- base/src/backend/access/common/heaptuple.c	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/backend/access/common/heaptuple.c	2008-04-21 13:09:57.000000000 +0900
@@ -67,6 +67,7 @@
 #include "access/heapam.h"
 #include "access/tuptoaster.h"
 #include "executor/tuptable.h"
+#include "security/pgace.h"
 
 
 /* Does att's datatype allow packing into the 1-byte-header varlena format? */
@@ -473,6 +474,9 @@ heap_attisnull(HeapTuple tup, int attnum
 		case MinCommandIdAttributeNumber:
 		case MaxTransactionIdAttributeNumber:
 		case MaxCommandIdAttributeNumber:
+#ifdef SECURITY_SYSATTR_NAME
+		case SecurityAttributeNumber:
+#endif
 			/* these are never null */
 			break;
 
@@ -785,6 +789,11 @@ heap_getsysattr(HeapTuple tup, int attnu
 		case TableOidAttributeNumber:
 			result = ObjectIdGetDatum(tup->t_tableOid);
 			break;
+#ifdef SECURITY_SYSATTR_NAME
+		case SecurityAttributeNumber:
+			result = ObjectIdGetDatum(HeapTupleGetSecurity(tup));
+			break;
+#endif
 		default:
 			elog(ERROR, "invalid attnum: %d", attnum);
 			result = 0;			/* keep compiler quiet */
@@ -816,6 +825,7 @@ heap_copytuple(HeapTuple tuple)
 	newTuple->t_tableOid = tuple->t_tableOid;
 	newTuple->t_data = (HeapTupleHeader) ((char *) newTuple + HEAPTUPLESIZE);
 	memcpy((char *) newTuple->t_data, (char *) tuple->t_data, tuple->t_len);
+	HeapTupleSetSecurity(newTuple, HeapTupleGetSecurity(tuple));
 	return newTuple;
 }
 
@@ -909,6 +919,10 @@ heap_form_tuple(TupleDesc tupleDescripto
 	if (tupleDescriptor->tdhasoid)
 		len += sizeof(Oid);
 
+#ifdef SECURITY_SYSATTR_NAME
+	len += sizeof(Oid);
+#endif
+
 	hoff = len = MAXALIGN(len); /* align user data safely */
 
 	data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
@@ -940,6 +954,10 @@ heap_form_tuple(TupleDesc tupleDescripto
 	if (tupleDescriptor->tdhasoid)		/* else leave infomask = 0 */
 		td->t_infomask = HEAP_HASOID;
 
+#ifdef SECURITY_SYSATTR_NAME
+	td->t_infomask |= HEAP_HASSECURITY;
+#endif
+
 	heap_fill_tuple(tupleDescriptor,
 					values,
 					isnull,
@@ -1020,6 +1038,10 @@ heap_formtuple(TupleDesc tupleDescriptor
 	if (tupleDescriptor->tdhasoid)
 		len += sizeof(Oid);
 
+#ifdef SECURITY_SYSATTR_NAME
+	len += sizeof(Oid);
+#endif
+
 	hoff = len = MAXALIGN(len); /* align user data safely */
 
 	data_len = ComputeDataSize(tupleDescriptor, values, nulls);
@@ -1051,6 +1073,10 @@ heap_formtuple(TupleDesc tupleDescriptor
 	if (tupleDescriptor->tdhasoid)		/* else leave infomask = 0 */
 		td->t_infomask = HEAP_HASOID;
 
+#ifdef SECURITY_SYSATTR_NAME
+	td->t_infomask |= HEAP_HASSECURITY;
+#endif
+
 	DataFill(tupleDescriptor,
 			 values,
 			 nulls,
@@ -1129,6 +1155,7 @@ heap_modify_tuple(HeapTuple tuple,
 	newTuple->t_tableOid = tuple->t_tableOid;
 	if (tupleDesc->tdhasoid)
 		HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
+	HeapTupleSetSecurity(newTuple, HeapTupleGetSecurity(tuple));
 
 	return newTuple;
 }
@@ -1201,6 +1228,7 @@ heap_modifytuple(HeapTuple tuple,
 	newTuple->t_tableOid = tuple->t_tableOid;
 	if (tupleDesc->tdhasoid)
 		HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple));
+	HeapTupleSetSecurity(newTuple, HeapTupleGetSecurity(tuple));
 
 	return newTuple;
 }
@@ -1847,6 +1875,10 @@ heap_form_minimal_tuple(TupleDesc tupleD
 	if (tupleDescriptor->tdhasoid)
 		len += sizeof(Oid);
 
+#ifdef SECURITY_SYSATTR_NAME
+	len += sizeof(Oid);
+#endif
+
 	hoff = len = MAXALIGN(len); /* align user data safely */
 
 	data_len = heap_compute_data_size(tupleDescriptor, values, isnull);
@@ -1868,6 +1900,10 @@ heap_form_minimal_tuple(TupleDesc tupleD
 	if (tupleDescriptor->tdhasoid)		/* else leave infomask = 0 */
 		tuple->t_infomask = HEAP_HASOID;
 
+#ifdef SECURITY_SYSATTR_NAME
+	tuple->t_infomask |= HEAP_HASSECURITY;
+#endif
+
 	heap_fill_tuple(tupleDescriptor,
 					values,
 					isnull,
@@ -1979,6 +2015,11 @@ heap_addheader(int natts,		/* max domain
 	hoff = offsetof(HeapTupleHeaderData, t_bits);
 	if (withoid)
 		hoff += sizeof(Oid);
+
+#ifdef SECURITY_SYSATTR_NAME
+	hoff += sizeof(Oid);
+#endif
+
 	hoff = MAXALIGN(hoff);
 	len = hoff + structlen;
 
@@ -1997,6 +2038,10 @@ heap_addheader(int natts,		/* max domain
 	if (withoid)				/* else leave infomask = 0 */
 		td->t_infomask = HEAP_HASOID;
 
+#ifdef SECURITY_SYSATTR_NAME
+	td->t_infomask |= HEAP_HASSECURITY;
+#endif
+
 	memcpy((char *) td + hoff, structure, structlen);
 
 	return tuple;
diff -rpNU3 base/src/backend/access/heap/heapam.c pgace/src/backend/access/heap/heapam.c
--- base/src/backend/access/heap/heapam.c	2008-04-08 16:31:35.000000000 +0900
+++ pgace/src/backend/access/heap/heapam.c	2008-04-08 16:41:21.000000000 +0900
@@ -50,6 +50,7 @@
 #include "catalog/namespace.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "security/pgace.h"
 #include "storage/procarray.h"
 #include "storage/smgr.h"
 #include "utils/datum.h"
@@ -1922,6 +1923,9 @@ heap_insert(Relation relation, HeapTuple
 Oid
 simple_heap_insert(Relation relation, HeapTuple tup)
 {
+	if (!pgaceHeapTupleInsert(relation, tup, true, false))
+		elog(ERROR, "simple_heap_insert on %s failed due to security reason",
+			 		 RelationGetRelationName(relation));
 	return heap_insert(relation, tup, GetCurrentCommandId(true), true, true);
 }
 
@@ -2203,6 +2207,9 @@ simple_heap_delete(Relation relation, It
 	ItemPointerData update_ctid;
 	TransactionId update_xmax;
 
+	if (!pgaceHeapTupleDelete(relation, tid, true, false))
+		elog(ERROR, "simple_heap_delete on %s failed due to security reason",
+			 		 RelationGetRelationName(relation));
 	result = heap_delete(relation, tid,
 						 &update_ctid, &update_xmax,
 						 GetCurrentCommandId(true), InvalidSnapshot,
@@ -2846,6 +2853,9 @@ simple_heap_update(Relation relation, It
 	ItemPointerData update_ctid;
 	TransactionId update_xmax;
 
+	if (!pgaceHeapTupleUpdate(relation, otid, tup, true, false))
+		elog(ERROR, "simple_heap_update on %s failed due to security reason",
+			 		RelationGetRelationName(relation));
 	result = heap_update(relation, otid, tup,
 						 &update_ctid, &update_xmax,
 						 GetCurrentCommandId(true), InvalidSnapshot,
diff -rpNU3 base/src/backend/access/heap/tuptoaster.c pgace/src/backend/access/heap/tuptoaster.c
--- base/src/backend/access/heap/tuptoaster.c	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/backend/access/heap/tuptoaster.c	2008-04-21 13:09:57.000000000 +0900
@@ -35,6 +35,7 @@
 #include "access/tuptoaster.h"
 #include "access/xact.h"
 #include "catalog/catalog.h"
+#include "security/pgace.h"
 #include "utils/fmgroids.h"
 #include "utils/pg_lzcompress.h"
 #include "utils/typcache.h"
@@ -591,6 +592,9 @@ toast_insert_or_update(Relation rel, Hea
 		hoff += BITMAPLEN(numAttrs);
 	if (newtup->t_data->t_infomask & HEAP_HASOID)
 		hoff += sizeof(Oid);
+#ifdef SECURITY_SYSATTR_NAME
+	hoff += sizeof(Oid);
+#endif
 	hoff = MAXALIGN(hoff);
 	Assert(hoff == newtup->t_data->t_hoff);
 	/* now convert to a limit on the tuple data size */
@@ -867,6 +871,9 @@ toast_insert_or_update(Relation rel, Hea
 			new_len += BITMAPLEN(numAttrs);
 		if (olddata->t_infomask & HEAP_HASOID)
 			new_len += sizeof(Oid);
+#ifdef SECURITY_SYSATTR_NAME
+		new_len += sizeof(Oid);
+#endif
 		new_len = MAXALIGN(new_len);
 		Assert(new_len == olddata->t_hoff);
 		new_data_len = heap_compute_data_size(tupleDesc,
@@ -1018,6 +1025,9 @@ toast_flatten_tuple_attribute(Datum valu
 		new_len += BITMAPLEN(numAttrs);
 	if (olddata->t_infomask & HEAP_HASOID)
 		new_len += sizeof(Oid);
+#ifdef SECURITY_SYSATTR_NAME
+	new_len += sizeof(Oid);
+#endif
 	new_len = MAXALIGN(new_len);
 	Assert(new_len == olddata->t_hoff);
 	new_data_len = heap_compute_data_size(tupleDesc,
@@ -1219,6 +1229,8 @@ toast_save_datum(Relation rel, Datum val
 		if (!HeapTupleIsValid(toasttup))
 			elog(ERROR, "failed to build TOAST tuple");
 
+		if (!pgaceHeapTupleInsert(toastrel, toasttup, true, false))
+			elog(ERROR, "failed to insert TOAST tuple due to security reason");
 		heap_insert(toastrel, toasttup, mycid, use_wal, use_fsm);
 
 		/*
diff -rpNU3 base/src/backend/bootstrap/bootparse.y pgace/src/backend/bootstrap/bootparse.y
--- base/src/backend/bootstrap/bootparse.y	2008-01-07 23:51:33.000000000 +0900
+++ pgace/src/backend/bootstrap/bootparse.y	2008-01-08 01:39:49.000000000 +0900
@@ -212,7 +212,8 @@ Boot_CreateStmt:
 													  0,
 													  ONCOMMIT_NOOP,
 													  (Datum) 0,
-													  true);
+													  true,
+													  NIL);
 						elog(DEBUG4, "relation created with oid %u", id);
 					}
 					do_end();
diff -rpNU3 base/src/backend/catalog/Makefile pgace/src/backend/catalog/Makefile
--- base/src/backend/catalog/Makefile	2008-03-12 14:14:35.000000000 +0900
+++ pgace/src/backend/catalog/Makefile	2008-03-12 14:39:14.000000000 +0900
@@ -34,6 +34,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_sr
 	pg_enum.h pg_namespace.h pg_conversion.h pg_depend.h \
 	pg_database.h pg_tablespace.h pg_pltemplate.h \
 	pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
+	pg_security.h \
 	pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
 	pg_ts_parser.h pg_ts_template.h \
 	toasting.h indexing.h \
diff -rpNU3 base/src/backend/catalog/catalog.c pgace/src/backend/catalog/catalog.c
--- base/src/backend/catalog/catalog.c	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/backend/catalog/catalog.c	2008-04-21 13:09:57.000000000 +0900
@@ -30,6 +30,7 @@
 #include "catalog/pg_database.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_pltemplate.h"
+#include "catalog/pg_security.h"
 #include "catalog/pg_shdepend.h"
 #include "catalog/pg_shdescription.h"
 #include "catalog/pg_tablespace.h"
@@ -258,6 +259,7 @@ IsSharedRelation(Oid relationId)
 		relationId == AuthMemRelationId ||
 		relationId == DatabaseRelationId ||
 		relationId == PLTemplateRelationId ||
+		relationId == SecurityRelationId ||
 		relationId == SharedDescriptionRelationId ||
 		relationId == SharedDependRelationId ||
 		relationId == TableSpaceRelationId)
@@ -270,6 +272,8 @@ IsSharedRelation(Oid relationId)
 		relationId == DatabaseNameIndexId ||
 		relationId == DatabaseOidIndexId ||
 		relationId == PLTemplateNameIndexId ||
+		relationId == SecurityOidIndexId ||
+		relationId == SecuritySeclabelIndexId ||
 		relationId == SharedDescriptionObjIndexId ||
 		relationId == SharedDependDependerIndexId ||
 		relationId == SharedDependReferenceIndexId ||
diff -rpNU3 base/src/backend/catalog/genbki.sh pgace/src/backend/catalog/genbki.sh
--- base/src/backend/catalog/genbki.sh	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/backend/catalog/genbki.sh	2008-04-21 13:09:57.000000000 +0900
@@ -139,6 +139,22 @@ for dir in $INCLUDE_DIRS; do
     fi
 done
 
+# Get SECURITY_SYSATTR_NAME from security/pgace.h
+for dir in $INCLUDE_DIRS; do
+    if [ -f "$dir/pg_config.h" ]; then
+        SECURITY_SYSATTR_NAME=`grep '#define[  ]*SECURITY_SYSATTR_NAME' $dir/pg_config.h | $AWK '{ print $3 }' | sed 's/\"//g'`
+        break
+    fi
+done
+
+function SECURITY_SYSATTR_NAME_filter() {
+    if [ -z "$SECURITY_SYSATTR_NAME" ]; then
+        grep -v SECURITY_SYSATTR_NAME;
+    else
+        cat
+    fi
+}
+
 touch ${OUTPUT_PREFIX}.description.$$
 touch ${OUTPUT_PREFIX}.shdescription.$$
 
@@ -152,7 +168,7 @@ touch ${OUTPUT_PREFIX}.shdescription.$$
 #	Substitute values of configuration constants
 # ----------------
 #
-cat $INFILES | \
+cat $INFILES | SECURITY_SYSATTR_NAME_filter | \
 sed -e 's;/\*.*\*/;;g' \
     -e 's;/\*;\
 /*\
@@ -176,6 +192,7 @@ sed -e "s/;[ 	]*$//g" \
     -e "s/FLOAT4PASSBYVAL/$FLOAT4PASSBYVAL/g" \
     -e "s/FLOAT8PASSBYVAL/$FLOAT8PASSBYVAL/g" \
     -e "s/PGNSP/$PG_CATALOG_NAMESPACE/g" \
+    -e "s/SECURITY_SYSATTR_NAME/$SECURITY_SYSATTR_NAME/g" \
 | $AWK '
 # ----------------
 #	now use awk to process remaining .h file..
diff -rpNU3 base/src/backend/catalog/heap.c pgace/src/backend/catalog/heap.c
--- base/src/backend/catalog/heap.c	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/backend/catalog/heap.c	2008-04-02 08:15:33.000000000 +0900
@@ -54,6 +54,7 @@
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "security/pgace.h"
 #include "storage/smgr.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
@@ -70,7 +71,8 @@ static void AddNewRelationTuple(Relation
 					Oid new_rel_oid, Oid new_type_oid,
 					Oid relowner,
 					char relkind,
-					Datum reloptions);
+					Datum reloptions,
+					List *pgace_attr_list);
 static Oid AddNewRelationType(const char *typeName,
 				   Oid typeNamespace,
 				   Oid new_rel_oid,
@@ -147,7 +149,21 @@ static FormData_pg_attribute a7 = {
 	true, 'p', 'i', true, false, false, true, 0
 };
 
+#ifdef SECURITY_SYSATTR_NAME
+/*
+ * SECURITY_SYSATTR_NAME is defined at PGACE header file.
+ * If SELinux is enabled, it is defined as "security_context"
+ */
+static FormData_pg_attribute a8 = {
+	0, {SECURITY_SYSATTR_NAME}, SECLABELOID, 0, sizeof(Oid),
+	SecurityAttributeNumber, 0, -1, -1,
+	true, 'p', 'i', true, false, false, true, 0
+};
+
+static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7, &a8};
+#else
 static const Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7};
+#endif
 
 /*
  * This function returns a Form_pg_attribute pointer for a system attribute.
@@ -470,7 +486,8 @@ AddNewAttributeTuples(Oid new_rel_oid,
 					  TupleDesc tupdesc,
 					  char relkind,
 					  bool oidislocal,
-					  int oidinhcount)
+					  int oidinhcount,
+					  List *pgace_attr_list)
 {
 	const Form_pg_attribute *dpp;
 	int			i;
@@ -505,6 +522,7 @@ AddNewAttributeTuples(Oid new_rel_oid,
 							 false,
 							 ATTRIBUTE_TUPLE_SIZE,
 							 (void *) *dpp);
+		pgaceCreateAttributeCommon(rel, tup, pgace_attr_list);
 
 		simple_heap_insert(rel, tup);
 
@@ -595,7 +613,8 @@ void
 InsertPgClassTuple(Relation pg_class_desc,
 				   Relation new_rel_desc,
 				   Oid new_rel_oid,
-				   Datum reloptions)
+				   Datum reloptions,
+				   List *pgace_attr_list)
 {
 	Form_pg_class rd_rel = new_rel_desc->rd_rel;
 	Datum		values[Natts_pg_class];
@@ -645,6 +664,7 @@ InsertPgClassTuple(Relation pg_class_des
 	 * be embarrassing to do this sort of thing in polite company.
 	 */
 	HeapTupleSetOid(tup, new_rel_oid);
+	pgaceCreateRelationCommon(pg_class_desc, tup, pgace_attr_list);
 
 	/* finally insert the new tuple, update the indexes, and clean up */
 	simple_heap_insert(pg_class_desc, tup);
@@ -668,7 +688,8 @@ AddNewRelationTuple(Relation pg_class_de
 					Oid new_type_oid,
 					Oid relowner,
 					char relkind,
-					Datum reloptions)
+					Datum reloptions,
+					List *pgace_attr_list)
 {
 	Form_pg_class new_rel_reltup;
 
@@ -728,7 +749,7 @@ AddNewRelationTuple(Relation pg_class_de
 	new_rel_desc->rd_att->tdtypeid = new_type_oid;
 
 	/* Now build and insert the tuple */
-	InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions);
+	InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions, pgace_attr_list);
 }
 
 
@@ -794,7 +815,8 @@ heap_create_with_catalog(const char *rel
 						 int oidinhcount,
 						 OnCommitAction oncommit,
 						 Datum reloptions,
-						 bool allow_system_table_mods)
+						 bool allow_system_table_mods,
+						 List *pgace_attr_list)
 {
 	Relation	pg_class_desc;
 	Relation	new_rel_desc;
@@ -966,13 +988,14 @@ heap_create_with_catalog(const char *rel
 						new_type_oid,
 						ownerid,
 						relkind,
-						reloptions);
+						reloptions,
+						pgace_attr_list);
 
 	/*
 	 * now add tuples to pg_attribute for the attributes in our new relation.
 	 */
 	AddNewAttributeTuples(relid, new_rel_desc->rd_att, relkind,
-						  oidislocal, oidinhcount);
+						  oidislocal, oidinhcount, pgace_attr_list);
 
 	/*
 	 * Make a dependency link to force the relation to be deleted if its
diff -rpNU3 base/src/backend/catalog/index.c pgace/src/backend/catalog/index.c
--- base/src/backend/catalog/index.c	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/backend/catalog/index.c	2008-04-02 08:15:33.000000000 +0900
@@ -624,7 +624,7 @@ index_create(Oid heapRelationId,
 	 */
 	InsertPgClassTuple(pg_class, indexRelation,
 					   RelationGetRelid(indexRelation),
-					   reloptions);
+					   reloptions, NIL);
 
 	/* done with pg_class */
 	heap_close(pg_class, RowExclusiveLock);
diff -rpNU3 base/src/backend/catalog/pg_aggregate.c pgace/src/backend/catalog/pg_aggregate.c
--- base/src/backend/catalog/pg_aggregate.c	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/backend/catalog/pg_aggregate.c	2008-04-02 08:15:33.000000000 +0900
@@ -214,8 +214,9 @@ AggregateCreate(const char *aggName,
 							  PointerGetDatum(NULL),	/* parameterModes */
 							  PointerGetDatum(NULL),	/* parameterNames */
 							  PointerGetDatum(NULL),	/* proconfig */
-							  1,	/* procost */
-							  0);		/* prorows */
+							  1,				/* procost */
+							  0,				/* prorows */
+							  NULL);			/* PGACE opaque */
 
 	/*
 	 * Okay to create the pg_aggregate entry.
diff -rpNU3 base/src/backend/catalog/pg_largeobject.c pgace/src/backend/catalog/pg_largeobject.c
--- base/src/backend/catalog/pg_largeobject.c	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/backend/catalog/pg_largeobject.c	2008-04-02 08:15:33.000000000 +0900
@@ -18,6 +18,8 @@
 #include "access/heapam.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_largeobject.h"
+#include "catalog/pg_security.h"
+#include "security/pgace.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/tqual.h"
@@ -58,6 +60,8 @@ LargeObjectCreate(Oid loid)
 
 	ntup = heap_formtuple(pg_largeobject->rd_att, values, nulls);
 
+	pgaceLargeObjectCreate(pg_largeobject, ntup);
+
 	/*
 	 * Insert it
 	 */
@@ -92,6 +96,8 @@ LargeObjectDrop(Oid loid)
 
 	while ((tuple = systable_getnext(sd)) != NULL)
 	{
+		if (!found)
+			pgaceLargeObjectDrop(pg_largeobject, tuple);
 		simple_heap_delete(pg_largeobject, &tuple->t_self);
 		found = true;
 	}
diff -rpNU3 base/src/backend/catalog/pg_proc.c pgace/src/backend/catalog/pg_proc.c
--- base/src/backend/catalog/pg_proc.c	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/backend/catalog/pg_proc.c	2008-04-02 08:15:33.000000000 +0900
@@ -28,6 +28,7 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "parser/parse_type.h"
+#include "security/pgace.h"
 #include "tcop/pquery.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
@@ -75,7 +76,8 @@ ProcedureCreate(const char *procedureNam
 				Datum parameterNames,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows)
+				float4 prorows,
+				void *pgaceItem)
 {
 	Oid			retval;
 	int			parameterCount;
@@ -338,6 +340,7 @@ ProcedureCreate(const char *procedureNam
 
 		/* Okay, do it... */
 		tup = heap_modifytuple(oldtup, tupDesc, values, nulls, replaces);
+		pgaceGramCreateFunction(rel, tup, (DefElem *)pgaceItem);
 		simple_heap_update(rel, &tup->t_self, tup);
 
 		ReleaseSysCache(oldtup);
@@ -347,6 +350,7 @@ ProcedureCreate(const char *procedureNam
 	{
 		/* Creating a new procedure */
 		tup = heap_formtuple(tupDesc, values, nulls);
+		pgaceGramCreateFunction(rel, tup, (DefElem *)pgaceItem);
 		simple_heap_insert(rel, tup);
 		is_update = false;
 	}
diff -rpNU3 base/src/backend/catalog/toasting.c pgace/src/backend/catalog/toasting.c
--- base/src/backend/catalog/toasting.c	2008-01-07 23:51:33.000000000 +0900
+++ pgace/src/backend/catalog/toasting.c	2008-01-08 01:39:49.000000000 +0900
@@ -199,7 +199,8 @@ create_toast_table(Relation rel, Oid toa
 										   0,
 										   ONCOMMIT_NOOP,
 										   (Datum) 0,
-										   true);
+										   true,
+										   NIL);
 
 	/* make the toast relation visible, else index creation will fail */
 	CommandCounterIncrement();
diff -rpNU3 base/src/backend/commands/cluster.c pgace/src/backend/commands/cluster.c
--- base/src/backend/commands/cluster.c	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/backend/commands/cluster.c	2008-04-21 13:09:57.000000000 +0900
@@ -668,7 +668,8 @@ make_new_heap(Oid OIDOldHeap, const char
 										  0,
 										  ONCOMMIT_NOOP,
 										  reloptions,
-										  allowSystemTableMods);
+										  allowSystemTableMods,
+										  NIL);
 
 	ReleaseSysCache(tuple);
 
diff -rpNU3 base/src/backend/commands/copy.c pgace/src/backend/commands/copy.c
--- base/src/backend/commands/copy.c	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/backend/commands/copy.c	2008-04-02 08:15:33.000000000 +0900
@@ -22,6 +22,7 @@
 
 #include "access/heapam.h"
 #include "access/xact.h"
+#include "catalog/heap.h"
 #include "catalog/namespace.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
@@ -34,6 +35,7 @@
 #include "optimizer/planner.h"
 #include "parser/parse_relation.h"
 #include "rewrite/rewriteHandler.h"
+#include "security/pgace.h"
 #include "storage/fd.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
@@ -160,6 +162,11 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+
+	/* dumpable/restorable system column support */
+	FmgrInfo	security_out_function;
+	bool		security_force_quot;
+	bool		security_force_notnull;
 } CopyStateData;
 
 typedef CopyStateData *CopyState;
@@ -243,7 +250,7 @@ static const char BinarySignature[11] = 
 /* non-export function prototypes */
 static void DoCopyTo(CopyState cstate);
 static void CopyTo(CopyState cstate);
-static void CopyOneRowTo(CopyState cstate, Oid tupleOid,
+static void CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid securityOid,
 			 Datum *values, bool *nulls);
 static void CopyFrom(CopyState cstate);
 static bool CopyReadLine(CopyState cstate);
@@ -1074,6 +1081,8 @@ DoCopy(const CopyStmt *stmt, const char 
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
+	pgaceCopyTable(cstate->rel, cstate->attnumlist, is_from);
+
 	num_phys_attrs = tupDesc->natts;
 
 	/* Convert FORCE QUOTE name list to per-column flags, check validity */
@@ -1094,6 +1103,10 @@ DoCopy(const CopyStmt *stmt, const char 
 						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
 				   errmsg("FORCE QUOTE column \"%s\" not referenced by COPY",
 						  NameStr(tupDesc->attrs[attnum - 1]->attname))));
+			if (pgaceIsSecuritySystemColumn(attnum)) {
+				cstate->security_force_quot = true;
+				continue;
+			}
 			cstate->force_quote_flags[attnum - 1] = true;
 		}
 	}
@@ -1116,6 +1129,9 @@ DoCopy(const CopyStmt *stmt, const char 
 						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
 				errmsg("FORCE NOT NULL column \"%s\" not referenced by COPY",
 					   NameStr(tupDesc->attrs[attnum - 1]->attname))));
+			if (pgaceIsSecuritySystemColumn(attnum))
+				continue; /* ignore, if specified */
+
 			cstate->force_notnull_flags[attnum - 1] = true;
 		}
 	}
@@ -1306,16 +1322,27 @@ CopyTo(CopyState cstate)
 		int			attnum = lfirst_int(cur);
 		Oid			out_func_oid;
 		bool		isvarlena;
+		FmgrInfo    *out_fmgr;
+		Form_pg_attribute pg_attribute;
+
+		if (pgaceIsSecuritySystemColumn(attnum)) {
+			/* PGACE: dumpable system column */
+			pg_attribute = SystemAttributeDefinition(attnum, false);
+			out_fmgr = &cstate->security_out_function;
+		} else {
+			pg_attribute = attr[attnum - 1];
+			out_fmgr = &cstate->out_functions[attnum - 1];
+		}
 
 		if (cstate->binary)
-			getTypeBinaryOutputInfo(attr[attnum - 1]->atttypid,
+			getTypeBinaryOutputInfo(pg_attribute->atttypid,
 									&out_func_oid,
 									&isvarlena);
 		else
-			getTypeOutputInfo(attr[attnum - 1]->atttypid,
+			getTypeOutputInfo(pg_attribute->atttypid,
 							  &out_func_oid,
 							  &isvarlena);
-		fmgr_info(out_func_oid, &cstate->out_functions[attnum - 1]);
+		fmgr_info(out_func_oid, out_fmgr);
 	}
 
 	/*
@@ -1371,6 +1398,12 @@ CopyTo(CopyState cstate)
 				hdr_delim = true;
 
 				colname = NameStr(attr[attnum - 1]->attname);
+				if (pgaceIsSecuritySystemColumn(attnum)) {
+					Form_pg_attribute sysatt = SystemAttributeDefinition(attnum, false);
+					colname = NameStr(sysatt->attname);
+				} else {
+					colname = NameStr(attr[attnum - 1]->attname);
+				}
 
 				CopyAttributeOutCSV(cstate, colname, false,
 									list_length(cstate->attnumlist) == 1);
@@ -1396,11 +1429,14 @@ CopyTo(CopyState cstate)
 		{
 			CHECK_FOR_INTERRUPTS();
 
+			if (!pgaceCopyToTuple(cstate->rel, cstate->attnumlist, tuple))
+				continue;
+
 			/* Deconstruct the tuple ... faster than repeated heap_getattr */
 			heap_deform_tuple(tuple, tupDesc, values, nulls);
 
 			/* Format and send the data */
-			CopyOneRowTo(cstate, HeapTupleGetOid(tuple), values, nulls);
+			CopyOneRowTo(cstate, HeapTupleGetOid(tuple), HeapTupleGetSecurity(tuple), values, nulls);
 		}
 
 		heap_endscan(scandesc);
@@ -1426,7 +1462,7 @@ CopyTo(CopyState cstate)
  * Emit one row during CopyTo().
  */
 static void
-CopyOneRowTo(CopyState cstate, Oid tupleOid, Datum *values, bool *nulls)
+CopyOneRowTo(CopyState cstate, Oid tupleOid, Oid tupleSecurity, Datum *values, bool *nulls)
 {
 	bool		need_delim = false;
 	FmgrInfo   *out_functions = cstate->out_functions;
@@ -1465,8 +1501,10 @@ CopyOneRowTo(CopyState cstate, Oid tuple
 	foreach(cur, cstate->attnumlist)
 	{
 		int			attnum = lfirst_int(cur);
-		Datum		value = values[attnum - 1];
-		bool		isnull = nulls[attnum - 1];
+		Datum		value;
+		bool		isnull;
+		bool		force_quot;
+		FmgrInfo	*out_fmgr;
 
 		if (!cstate->binary)
 		{
@@ -1475,6 +1513,19 @@ CopyOneRowTo(CopyState cstate, Oid tuple
 			need_delim = true;
 		}
 
+		/* PGACE: dumpable system column support */
+		if (pgaceIsSecuritySystemColumn(attnum)) {
+			value = tupleSecurity;
+			isnull = false;
+			force_quot = cstate->security_force_quot;
+			out_fmgr = &cstate->security_out_function;
+		} else {
+			value = values[attnum - 1];
+			isnull = nulls[attnum - 1];
+			force_quot = cstate->force_quote_flags[attnum - 1];
+			out_fmgr = &out_functions[attnum - 1];
+		}
+
 		if (isnull)
 		{
 			if (!cstate->binary)
@@ -1486,11 +1537,9 @@ CopyOneRowTo(CopyState cstate, Oid tuple
 		{
 			if (!cstate->binary)
 			{
-				string = OutputFunctionCall(&out_functions[attnum - 1],
-											value);
+				string = OutputFunctionCall(out_fmgr, value);
 				if (cstate->csv_mode)
-					CopyAttributeOutCSV(cstate, string,
-										cstate->force_quote_flags[attnum - 1],
+					CopyAttributeOutCSV(cstate, string, force_quot,
 										list_length(cstate->attnumlist) == 1);
 				else
 					CopyAttributeOutText(cstate, string);
@@ -1499,8 +1548,7 @@ CopyOneRowTo(CopyState cstate, Oid tuple
 			{
 				bytea	   *outputbytes;
 
-				outputbytes = SendFunctionCall(&out_functions[attnum - 1],
-											   value);
+				outputbytes = SendFunctionCall(out_fmgr, value);
 				CopySendInt32(cstate, VARSIZE(outputbytes) - VARHDRSZ);
 				CopySendData(cstate, VARDATA(outputbytes),
 							 VARSIZE(outputbytes) - VARHDRSZ);
@@ -1634,8 +1682,11 @@ CopyFrom(CopyState cstate)
 				num_defaults;
 	FmgrInfo   *in_functions;
 	FmgrInfo	oid_in_function;
+	FmgrInfo	security_in_function;
+	bool		security_in_function_prepared = false;
 	Oid		   *typioparams;
 	Oid			oid_typioparam;
+	Oid			security_typioparam;
 	int			attnum;
 	int			i;
 	Oid			in_func_oid;
@@ -1905,6 +1956,7 @@ CopyFrom(CopyState cstate)
 	{
 		bool		skip_tuple;
 		Oid			loaded_oid = InvalidOid;
+		Oid			loaded_security = InvalidOid;
 
 		CHECK_FOR_INTERRUPTS();
 
@@ -1979,6 +2031,35 @@ CopyFrom(CopyState cstate)
 				int			attnum = lfirst_int(cur);
 				int			m = attnum - 1;
 
+				if (pgaceIsSecuritySystemColumn(attnum)) {
+					Form_pg_attribute sysatt = SystemAttributeDefinition(attnum, false);
+					if (fieldno >= fldct)
+						ereport(ERROR,
+								(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+								 errmsg("missing data for column \"%s\"",
+										NameStr(sysatt->attname))));
+					string = field_strings[fieldno++];
+					cstate->cur_attname = NameStr(attr[m]->attname);
+					cstate->cur_attval = string;
+
+					if (!security_in_function_prepared) {
+						getTypeInputInfo(sysatt->atttypid, &in_func_oid,
+										 &security_typioparam);
+						fmgr_info(in_func_oid, &security_in_function);
+						security_in_function_prepared = true;
+					}
+					if (string) {
+						Datum d = InputFunctionCall(&security_in_function,
+													string,
+													security_typioparam,
+													sysatt->atttypmod);
+						loaded_security = ObjectIdGetDatum(d);
+					}
+					cstate->cur_attname = NULL;
+					cstate->cur_attval = NULL;
+					continue;
+				}
+
 				if (fieldno >= fldct)
 					ereport(ERROR,
 							(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
@@ -2049,6 +2130,33 @@ CopyFrom(CopyState cstate)
 				int			attnum = lfirst_int(cur);
 				int			m = attnum - 1;
 
+				if (pgaceIsSecuritySystemColumn(attnum)) {
+					Form_pg_attribute sysatt = SystemAttributeDefinition(attnum, false);
+					Datum d;
+
+					cstate->cur_attname = NameStr(sysatt->attname);
+					i++;
+
+					if (!security_in_function_prepared) {
+						Oid security_in_func_oid;
+						getTypeBinaryInputInfo(sysatt->atttypid,
+											   &security_in_func_oid,
+											   &security_typioparam);
+						fmgr_info(security_in_func_oid, &security_in_function);
+						security_in_function_prepared = true;
+					}
+					d = CopyReadBinaryAttribute(cstate,
+												i,
+												&security_in_function,
+												security_typioparam,
+												sysatt->atttypmod,
+												&isnull);
+					if (!isnull)
+						loaded_security = ObjectIdGetDatum(d);
+					cstate->cur_attname = NULL;
+					continue;
+				}
+
 				cstate->cur_attname = NameStr(attr[m]->attname);
 				i++;
 				values[m] = CopyReadBinaryAttribute(cstate,
@@ -2080,6 +2188,7 @@ CopyFrom(CopyState cstate)
 
 		if (cstate->oids && file_has_oids)
 			HeapTupleSetOid(tuple, loaded_oid);
+		HeapTupleSetSecurity(tuple, loaded_security);
 
 		/* Triggers and stuff need to be invoked in query context. */
 		MemoryContextSwitchTo(oldcontext);
@@ -2103,6 +2212,9 @@ CopyFrom(CopyState cstate)
 			}
 		}
 
+		if (!skip_tuple && !pgaceHeapTupleInsert(cstate->rel, tuple, false, false))
+			skip_tuple = true;
+
 		if (!skip_tuple)
 		{
 			/* Place tuple in tuple slot */
@@ -3379,6 +3491,17 @@ CopyGetAttnums(TupleDesc tupDesc, Relati
 					break;
 				}
 			}
+
+			/* PGACE: writable system column support */
+			if (attnum == InvalidAttrNumber)
+			{
+				Form_pg_attribute sysatt = SystemAttributeByName(name, true);
+				if (sysatt) {
+					if (pgaceIsSecuritySystemColumn(sysatt->attnum))
+						attnum = sysatt->attnum;
+				}
+			}
+
 			if (attnum == InvalidAttrNumber)
 			{
 				if (rel != NULL)
@@ -3428,7 +3551,7 @@ copy_dest_receive(TupleTableSlot *slot, 
 	slot_getallattrs(slot);
 
 	/* And send the data */
-	CopyOneRowTo(cstate, InvalidOid, slot->tts_values, slot->tts_isnull);
+	CopyOneRowTo(cstate, InvalidOid, InvalidOid, slot->tts_values, slot->tts_isnull);
 }
 
 /*
diff -rpNU3 base/src/backend/commands/dbcommands.c pgace/src/backend/commands/dbcommands.c
--- base/src/backend/commands/dbcommands.c	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/backend/commands/dbcommands.c	2008-04-21 13:09:57.000000000 +0900
@@ -40,6 +40,7 @@
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "postmaster/bgwriter.h"
+#include "security/pgace.h"
 #include "storage/freespace.h"
 #include "storage/ipc.h"
 #include "storage/procarray.h"
@@ -101,6 +102,7 @@ createdb(const CreatedbStmt *stmt)
 	DefElem    *dtemplate = NULL;
 	DefElem    *dencoding = NULL;
 	DefElem    *dconnlimit = NULL;
+	DefElem	   *dpgace_item = NULL;
 	char	   *dbname = stmt->dbname;
 	char	   *dbowner = NULL;
 	const char *dbtemplate = NULL;
@@ -161,6 +163,13 @@ createdb(const CreatedbStmt *stmt)
 					 errmsg("LOCATION is not supported anymore"),
 					 errhint("Consider using tablespaces instead.")));
 		}
+		else if (pgaceIsGramSecurityItem(defel)) {
+			if (dpgace_item)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options")));
+			dpgace_item = defel;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
@@ -434,6 +443,7 @@ createdb(const CreatedbStmt *stmt)
 						   new_record, new_record_nulls);
 
 	HeapTupleSetOid(tuple, dboid);
+	pgaceGramCreateDatabase(pg_database_rel, tuple, dpgace_item);
 
 	simple_heap_insert(pg_database_rel, tuple);
 
@@ -854,6 +864,7 @@ AlterDatabase(AlterDatabaseStmt *stmt)
 	ListCell   *option;
 	int			connlimit = -1;
 	DefElem    *dconnlimit = NULL;
+	DefElem	   *dpgace_item = NULL;
 	Datum		new_record[Natts_pg_database];
 	char		new_record_nulls[Natts_pg_database];
 	char		new_record_repl[Natts_pg_database];
@@ -871,6 +882,13 @@ AlterDatabase(AlterDatabaseStmt *stmt)
 						 errmsg("conflicting or redundant options")));
 			dconnlimit = defel;
 		}
+		else if (pgaceIsGramSecurityItem(defel)) {
+			if (dpgace_item)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options")));
+			dpgace_item = defel;
+		}
 		else
 			elog(ERROR, "option \"%s\" not recognized",
 				 defel->defname);
@@ -916,6 +934,7 @@ AlterDatabase(AlterDatabaseStmt *stmt)
 
 	newtuple = heap_modifytuple(tuple, RelationGetDescr(rel), new_record,
 								new_record_nulls, new_record_repl);
+	pgaceGramAlterDatabase(rel, newtuple, dpgace_item);
 	simple_heap_update(rel, &tuple->t_self, newtuple);
 
 	/* Update indexes */
diff -rpNU3 base/src/backend/commands/functioncmds.c pgace/src/backend/commands/functioncmds.c
--- base/src/backend/commands/functioncmds.c	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/backend/commands/functioncmds.c	2008-04-02 08:15:33.000000000 +0900
@@ -49,6 +49,7 @@
 #include "miscadmin.h"
 #include "parser/parse_func.h"
 #include "parser/parse_type.h"
+#include "security/pgace.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
@@ -413,7 +414,8 @@ compute_attributes_sql_style(List *optio
 							 bool *security_definer,
 							 ArrayType **proconfig,
 							 float4 *procost,
-							 float4 *prorows)
+							 float4 *prorows,
+							 DefElem **pgaceItem)
 {
 	ListCell   *option;
 	DefElem    *as_item = NULL;
@@ -445,6 +447,14 @@ compute_attributes_sql_style(List *optio
 						 errmsg("conflicting or redundant options")));
 			language_item = defel;
 		}
+		else if (pgaceIsGramSecurityItem(defel))
+		{
+			if (*pgaceItem)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options")));
+			*pgaceItem = defel;
+		}
 		else if (compute_common_attribute(defel,
 										  &volatility_item,
 										  &strict_item,
@@ -625,6 +635,7 @@ CreateFunction(CreateFunctionStmt *stmt)
 	HeapTuple	languageTuple;
 	Form_pg_language languageStruct;
 	List	   *as_clause;
+	DefElem	   *pgaceItem = NULL;
 
 	/* Convert list of names to a name and namespace */
 	namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
@@ -648,7 +659,7 @@ CreateFunction(CreateFunctionStmt *stmt)
 	compute_attributes_sql_style(stmt->options,
 								 &as_clause, &language,
 								 &volatility, &isStrict, &security,
-								 &proconfig, &procost, &prorows);
+								 &proconfig, &procost, &prorows, &pgaceItem);
 
 	/* Convert language name to canonical case */
 	languageName = case_translate_language_name(language);
@@ -802,7 +813,8 @@ CreateFunction(CreateFunctionStmt *stmt)
 					PointerGetDatum(parameterNames),
 					PointerGetDatum(proconfig),
 					procost,
-					prorows);
+					prorows,
+					pgaceItem);
 }
 
 
@@ -1152,6 +1164,7 @@ AlterFunction(AlterFunctionStmt *stmt)
 	List	   *set_items = NIL;
 	DefElem    *cost_item = NULL;
 	DefElem    *rows_item = NULL;
+	DefElem	   *pgaceItem = NULL;
 
 	rel = heap_open(ProcedureRelationId, RowExclusiveLock);
 
@@ -1183,6 +1196,15 @@ AlterFunction(AlterFunctionStmt *stmt)
 	{
 		DefElem    *defel = (DefElem *) lfirst(l);
 
+		if (pgaceIsGramSecurityItem(defel)) {
+			if (pgaceItem)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options")));
+			pgaceItem = defel;
+			continue;
+		}
+
 		if (compute_common_attribute(defel,
 									 &volatility_item,
 									 &strict_item,
@@ -1253,6 +1275,7 @@ AlterFunction(AlterFunctionStmt *stmt)
 		tup = heap_modifytuple(tup, RelationGetDescr(rel),
 							   repl_val, repl_null, repl_repl);
 	}
+	pgaceGramAlterFunction(rel, tup, pgaceItem);
 
 	/* Do the update */
 	simple_heap_update(rel, &tup->t_self, tup);
diff -rpNU3 base/src/backend/commands/lockcmds.c pgace/src/backend/commands/lockcmds.c
--- base/src/backend/commands/lockcmds.c	2008-01-07 23:51:33.000000000 +0900
+++ pgace/src/backend/commands/lockcmds.c	2008-01-08 01:39:49.000000000 +0900
@@ -18,6 +18,7 @@
 #include "catalog/namespace.h"
 #include "commands/lockcmds.h"
 #include "miscadmin.h"
+#include "security/pgace.h"
 #include "utils/acl.h"
 #include "utils/lsyscache.h"
 
@@ -59,6 +60,8 @@ LockTableCommand(LockStmt *lockstmt)
 			aclcheck_error(aclresult, ACL_KIND_CLASS,
 						   get_rel_name(reloid));
 
+		pgaceLockTable(reloid);
+
 		if (lockstmt->nowait)
 			rel = relation_open_nowait(reloid, lockstmt->mode);
 		else
diff -rpNU3 base/src/backend/commands/proclang.c pgace/src/backend/commands/proclang.c
--- base/src/backend/commands/proclang.c	2008-04-30 11:09:33.000000000 +0900
+++ pgace/src/backend/commands/proclang.c	2008-04-30 11:22:08.000000000 +0900
@@ -148,7 +148,8 @@ CreateProceduralLanguage(CreatePLangStmt
 										 PointerGetDatum(NULL),
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 NULL);
 		}
 
 		/*
@@ -181,7 +182,8 @@ CreateProceduralLanguage(CreatePLangStmt
 										 PointerGetDatum(NULL),
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 NULL);
 			}
 		}
 		else
diff -rpNU3 base/src/backend/commands/tablecmds.c pgace/src/backend/commands/tablecmds.c
--- base/src/backend/commands/tablecmds.c	2008-04-30 11:09:33.000000000 +0900
+++ pgace/src/backend/commands/tablecmds.c	2008-04-30 11:22:08.000000000 +0900
@@ -58,6 +58,7 @@
 #include "parser/parser.h"
 #include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteHandler.h"
+#include "security/pgace.h"
 #include "storage/smgr.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -437,7 +438,8 @@ DefineRelation(CreateStmt *stmt, char re
 										  parentOidCount,
 										  stmt->oncommit,
 										  reloptions,
-										  allowSystemTableMods);
+										  allowSystemTableMods,
+										  pgaceRelationAttrList(stmt));
 
 	StoreCatalogInheritance(relationId, inheritOids);
 
@@ -2126,6 +2128,7 @@ ATPrepCmd(List **wqueue, Relation rel, A
 		case AT_DisableRule:
 		case AT_AddInherit:		/* INHERIT / NO INHERIT */
 		case AT_DropInherit:
+		case AT_SetSecurityLabel:
 			ATSimplePermissions(rel, false);
 			/* These commands never recurse */
 			/* No command-specific prep needed */
@@ -2348,6 +2351,9 @@ ATExecCmd(AlteredTableInfo *tab, Relatio
 		case AT_DropInherit:
 			ATExecDropInherit(rel, (RangeVar *) cmd->def);
 			break;
+		case AT_SetSecurityLabel:
+			pgaceAlterRelationCommon(rel, cmd);
+			break;
 		default:				/* oops */
 			elog(ERROR, "unrecognized alter table type: %d",
 				 (int) cmd->subtype);
diff -rpNU3 base/src/backend/commands/trigger.c pgace/src/backend/commands/trigger.c
--- base/src/backend/commands/trigger.c	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/backend/commands/trigger.c	2008-04-02 08:15:33.000000000 +0900
@@ -31,6 +31,7 @@
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "parser/parse_func.h"
+#include "security/pgace.h"
 #include "tcop/utility.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -1597,6 +1598,12 @@ ExecCallTriggerFunc(TriggerData *trigdat
 	 */
 	InitFunctionCallInfoData(fcinfo, finfo, 0, (Node *) trigdata, NULL);
 
+	/* PGACE: permission check for trigegr function */
+	if (!pgaceCallFunctionTrigger(finfo, trigdata)) {
+		MemoryContextSwitchTo(oldContext);
+		return (HeapTuple) DatumGetPointer(NULL);
+	}
+
 	result = FunctionCallInvoke(&fcinfo);
 
 	MemoryContextSwitchTo(oldContext);
diff -rpNU3 base/src/backend/executor/execMain.c pgace/src/backend/executor/execMain.c
--- base/src/backend/executor/execMain.c	2008-04-30 11:09:33.000000000 +0900
+++ pgace/src/backend/executor/execMain.c	2008-04-30 11:22:08.000000000 +0900
@@ -48,6 +48,7 @@
 #include "optimizer/clauses.h"
 #include "parser/parse_clause.h"
 #include "parser/parsetree.h"
+#include "security/pgace.h"
 #include "storage/smgr.h"
 #include "utils/acl.h"
 #include "utils/lsyscache.h"
@@ -132,6 +133,8 @@ ExecutorStart(QueryDesc *queryDesc, int 
 	Assert(queryDesc != NULL);
 	Assert(queryDesc->estate == NULL);
 
+	pgaceExecutorStart(queryDesc, eflags);
+
 	/*
 	 * If the transaction is read-only, we need to check if any writes are
 	 * planned to non-temporary tables.  EXPLAIN is considered read-only.
@@ -1227,6 +1230,8 @@ ExecutePlan(EState *estate,
 
 	for (;;)
 	{
+		Oid __tts_security = InvalidOid;	/* PGACE: explicit security labaling */
+
 		/* Reset the per-output-tuple exprcontext */
 		ResetPerTupleExprContext(estate);
 
@@ -1351,6 +1356,13 @@ lnext:	;
 			}
 
 			/*
+			 * PGACE: security attribute system columnt support.
+			 * If client specified a explicit security label,
+			 * pgaceFetchSecurityLabel() fetch it via junk attribute.
+			 */
+			pgaceFetchSecurityAttribute(junkfilter, slot, &__tts_security);
+
+			/*
 			 * extract the 'ctid' junk attribute.
 			 */
 			if (operation == CMD_UPDATE || operation == CMD_DELETE)
@@ -1377,6 +1389,7 @@ lnext:	;
 			if (operation != CMD_DELETE)
 				slot = ExecFilterJunk(junkfilter, slot);
 		}
+		slot->tts_security = __tts_security;
 
 		/*
 		 * now that we have a tuple, do the appropriate thing with it.. either
@@ -1497,6 +1510,9 @@ ExecInsert(TupleTableSlot *slot,
 	resultRelInfo = estate->es_result_relation_info;
 	resultRelationDesc = resultRelInfo->ri_RelationDesc;
 
+	/* PGACE: put an explicit security labeling */
+	HeapTupleStoreSecurityFromSlot(tuple, slot);
+
 	/* BEFORE ROW INSERT Triggers */
 	if (resultRelInfo->ri_TrigDesc &&
 		resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
@@ -1533,6 +1549,13 @@ ExecInsert(TupleTableSlot *slot,
 		ExecConstraints(resultRelInfo, slot, estate);
 
 	/*
+	 * PGACE: check HeapTuple Insertion permission
+	 */
+	if (!pgaceHeapTupleInsert(resultRelationDesc, tuple,
+							  false, !!resultRelInfo->ri_projectReturning))
+		return;
+
+	/*
 	 * insert the tuple
 	 *
 	 * Note: heap_insert returns the tid (location) of the new tuple in the
@@ -1599,6 +1622,10 @@ ExecDelete(ItemPointer tupleid,
 			return;
 	}
 
+	if (!pgaceHeapTupleDelete(resultRelationDesc, tupleid,
+							  false, !!resultRelInfo->ri_projectReturning))
+		return;
+
 	/*
 	 * delete the tuple
 	 *
@@ -1735,6 +1762,9 @@ ExecUpdate(TupleTableSlot *slot,
 	resultRelInfo = estate->es_result_relation_info;
 	resultRelationDesc = resultRelInfo->ri_RelationDesc;
 
+	/* PGACE: put an explicit security attribute */
+	HeapTupleStoreSecurityFromSlot(tuple, slot);
+
 	/* BEFORE ROW UPDATE Triggers */
 	if (resultRelInfo->ri_TrigDesc &&
 		resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)
@@ -1778,6 +1808,11 @@ lreplace:;
 	if (resultRelationDesc->rd_att->constr)
 		ExecConstraints(resultRelInfo, slot, estate);
 
+	/* PGACE: check HeapTuple update permission */
+	if (!pgaceHeapTupleUpdate(resultRelationDesc, tupleid, tuple,
+							  false, !!resultRelInfo->ri_projectReturning))
+		return;
+
 	/*
 	 * replace the heap tuple
 	 *
@@ -2642,7 +2677,8 @@ OpenIntoRel(QueryDesc *queryDesc)
 											  0,
 											  into->onCommit,
 											  reloptions,
-											  allowSystemTableMods);
+											  allowSystemTableMods,
+											  NIL);
 
 	FreeTupleDesc(tupdesc);
 
@@ -2748,6 +2784,13 @@ intorel_receive(TupleTableSlot *slot, De
 
 	tuple = ExecCopySlotTuple(slot);
 
+	/* PGACE: store explicit security labeling and check HeapTuple insertion permission */
+	HeapTupleStoreSecurityFromSlot(tuple, slot);
+	if (!pgaceHeapTupleInsert(estate->es_into_relation_descriptor, tuple, false, false)) {
+		heap_freetuple(tuple);
+		return;
+	}
+
 	heap_insert(estate->es_into_relation_descriptor,
 				tuple,
 				estate->es_output_cid,
diff -rpNU3 base/src/backend/executor/execQual.c pgace/src/backend/executor/execQual.c
--- base/src/backend/executor/execQual.c	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/backend/executor/execQual.c	2008-04-21 13:09:57.000000000 +0900
@@ -47,6 +47,7 @@
 #include "nodes/makefuncs.h"
 #include "optimizer/planmain.h"
 #include "parser/parse_expr.h"
+#include "security/pgace.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
@@ -1747,6 +1748,8 @@ ExecEvalFunc(FuncExprState *fcache,
 	/* Go directly to ExecMakeFunctionResult on subsequent uses */
 	fcache->xprstate.evalfunc = (ExprStateEvalFunc) ExecMakeFunctionResult;
 
+	pgaceCallFunction(&fcache->func);
+
 	return ExecMakeFunctionResult(fcache, econtext, isNull, isDone);
 }
 
diff -rpNU3 base/src/backend/libpq/be-fsstubs.c pgace/src/backend/libpq/be-fsstubs.c
--- base/src/backend/libpq/be-fsstubs.c	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/backend/libpq/be-fsstubs.c	2008-04-02 08:15:33.000000000 +0900
@@ -45,6 +45,7 @@
 #include "libpq/be-fsstubs.h"
 #include "libpq/libpq-fs.h"
 #include "miscadmin.h"
+#include "security/pgace.h"
 #include "storage/fd.h"
 #include "storage/large_object.h"
 #include "utils/builtins.h"
@@ -371,6 +372,8 @@ lo_import_internal(text *filename, Oid l
 				 errmsg("could not open server file \"%s\": %m",
 						fnamebuf)));
 
+	pgaceLargeObjectImport(fd);
+
 	/*
 	 * create an inversion object
 	 */
@@ -448,6 +451,8 @@ lo_export(PG_FUNCTION_ARGS)
 				 errmsg("could not create server file \"%s\": %m",
 						fnamebuf)));
 
+	pgaceLargeObjectExport(fd, lobjId);
+
 	/*
 	 * read in from the inversion file and write to the filesystem
 	 */
diff -rpNU3 base/src/backend/nodes/copyfuncs.c pgace/src/backend/nodes/copyfuncs.c
--- base/src/backend/nodes/copyfuncs.c	2008-04-30 11:09:33.000000000 +0900
+++ pgace/src/backend/nodes/copyfuncs.c	2008-04-30 11:22:08.000000000 +0900
@@ -24,6 +24,7 @@
 
 #include "nodes/plannodes.h"
 #include "nodes/relation.h"
+#include "security/pgace.h"
 #include "utils/datum.h"
 
 
@@ -85,6 +86,7 @@ _copyPlannedStmt(PlannedStmt *from)
 	COPY_NODE_FIELD(rowMarks);
 	COPY_NODE_FIELD(relationOids);
 	COPY_SCALAR_FIELD(nParamExec);
+	COPY_NODE_FIELD(pgaceItem);
 
 	return newnode;
 }
@@ -1792,6 +1794,7 @@ _copyColumnDef(ColumnDef *from)
 	COPY_NODE_FIELD(raw_default);
 	COPY_STRING_FIELD(cooked_default);
 	COPY_NODE_FIELD(constraints);
+	COPY_NODE_FIELD(pgaceItem);
 
 	return newnode;
 }
@@ -1872,6 +1875,7 @@ _copyQuery(Query *from)
 	COPY_NODE_FIELD(limitCount);
 	COPY_NODE_FIELD(rowMarks);
 	COPY_NODE_FIELD(setOperations);
+	COPY_NODE_FIELD(pgaceItem);
 
 	return newnode;
 }
@@ -2108,6 +2112,7 @@ _copyCreateStmt(CreateStmt *from)
 	COPY_NODE_FIELD(options);
 	COPY_SCALAR_FIELD(oncommit);
 	COPY_STRING_FIELD(tablespacename);
+	COPY_NODE_FIELD(pgaceItem);
 
 	return newnode;
 }
@@ -3607,6 +3612,10 @@ copyObject(void *from)
 			break;
 
 		default:
+			retval = pgaceCopyObject(from);
+			if (retval)
+				break;
+
 			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
 			retval = from;		/* keep compiler quiet */
 			break;
diff -rpNU3 base/src/backend/nodes/outfuncs.c pgace/src/backend/nodes/outfuncs.c
--- base/src/backend/nodes/outfuncs.c	2008-04-30 11:09:33.000000000 +0900
+++ pgace/src/backend/nodes/outfuncs.c	2008-04-30 11:22:08.000000000 +0900
@@ -26,6 +26,7 @@
 #include "lib/stringinfo.h"
 #include "nodes/plannodes.h"
 #include "nodes/relation.h"
+#include "security/pgace.h"
 #include "utils/datum.h"
 
 
@@ -252,6 +253,7 @@ _outPlannedStmt(StringInfo str, PlannedS
 	WRITE_NODE_FIELD(rowMarks);
 	WRITE_NODE_FIELD(relationOids);
 	WRITE_INT_FIELD(nParamExec);
+	WRITE_NODE_FIELD(pgaceItem);
 }
 
 /*
@@ -1743,6 +1745,7 @@ _outQuery(StringInfo str, Query *node)
 	WRITE_NODE_FIELD(limitCount);
 	WRITE_NODE_FIELD(rowMarks);
 	WRITE_NODE_FIELD(setOperations);
+	WRITE_NODE_FIELD(pgaceItem);
 }
 
 static void
@@ -2445,6 +2448,8 @@ _outNode(StringInfo str, void *obj)
 				break;
 
 			default:
+				if (pgaceOutObject(str, obj))
+					break;
 
 				/*
 				 * This should be an ERROR, but it's too useful to be able to
diff -rpNU3 base/src/backend/nodes/readfuncs.c pgace/src/backend/nodes/readfuncs.c
--- base/src/backend/nodes/readfuncs.c	2008-01-07 23:51:33.000000000 +0900
+++ pgace/src/backend/nodes/readfuncs.c	2008-03-12 19:56:29.000000000 +0900
@@ -24,6 +24,7 @@
 
 #include "nodes/parsenodes.h"
 #include "nodes/readfuncs.h"
+#include "security/pgace.h"
 
 
 /*
@@ -154,6 +155,7 @@ _readQuery(void)
 	READ_NODE_FIELD(limitCount);
 	READ_NODE_FIELD(rowMarks);
 	READ_NODE_FIELD(setOperations);
+	READ_NODE_FIELD(pgaceItem);
 
 	READ_DONE();
 }
@@ -1126,8 +1128,9 @@ parseNodeString(void)
 		return_value = _readDeclareCursorStmt();
 	else
 	{
-		elog(ERROR, "badly formatted node string \"%.32s\"...", token);
-		return_value = NULL;	/* keep compiler quiet */
+		return_value = pgaceReadObject(token);
+		if (!return_value)
+			elog(ERROR, "badly formatted node string \"%.32s\"...", token);
 	}
 
 	return (Node *) return_value;
diff -rpNU3 base/src/backend/optimizer/plan/planner.c pgace/src/backend/optimizer/plan/planner.c
--- base/src/backend/optimizer/plan/planner.c	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/backend/optimizer/plan/planner.c	2008-04-21 13:09:57.000000000 +0900
@@ -101,6 +101,10 @@ planner(Query *parse, int cursorOptions,
 		result = (*planner_hook) (parse, cursorOptions, boundParams);
 	else
 		result = standard_planner(parse, cursorOptions, boundParams);
+
+	/* PGACE: pgaceItem is passed to PlannedStmt */
+	result->pgaceItem = parse->pgaceItem;
+
 	return result;
 }
 
diff -rpNU3 base/src/backend/parser/analyze.c pgace/src/backend/parser/analyze.c
--- base/src/backend/parser/analyze.c	2008-01-07 23:51:33.000000000 +0900
+++ pgace/src/backend/parser/analyze.c	2008-01-11 16:13:01.000000000 +0900
@@ -36,6 +36,7 @@
 #include "parser/parse_relation.h"
 #include "parser/parse_target.h"
 #include "parser/parsetree.h"
+#include "security/pgace.h"
 
 
 typedef struct
@@ -404,6 +405,9 @@ transformInsertStmt(ParseState *pstate, 
 		Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
 		pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
 
+		/* security attribute system column support */
+		pgaceTransformInsertStmt(&icolumns, &attrnos, selectQuery->targetList);
+
 		/*----------
 		 * Generate an expression list for the INSERT that selects all the
 		 * non-resjunk columns from the subquery.  (INSERT's tlist must be
@@ -563,14 +567,15 @@ transformInsertStmt(ParseState *pstate, 
 		Expr	   *expr = (Expr *) lfirst(lc);
 		ResTarget  *col;
 		TargetEntry *tle;
+		AttrNumber anum = (AttrNumber) lfirst_int(attnos);
 
 		col = (ResTarget *) lfirst(icols);
 		Assert(IsA(col, ResTarget));
 
 		tle = makeTargetEntry(expr,
-							  (AttrNumber) lfirst_int(attnos),
+							  anum,
 							  col->name,
-							  false);
+							  anum < 0 ? true : false);
 		qry->targetList = lappend(qry->targetList, tle);
 
 		icols = lnext(icols);
@@ -733,6 +738,7 @@ transformSelectStmt(ParseState *pstate, 
 	/* handle any SELECT INTO/CREATE TABLE AS spec */
 	if (stmt->intoClause)
 	{
+		pgaceTransformSelectStmt(qry->targetList);
 		qry->intoClause = stmt->intoClause;
 		if (stmt->intoClause->colNames)
 			applyColumnNames(qry->targetList, stmt->intoClause->colNames);
diff -rpNU3 base/src/backend/parser/gram.y pgace/src/backend/parser/gram.y
--- base/src/backend/parser/gram.y	2008-04-30 11:09:33.000000000 +0900
+++ pgace/src/backend/parser/gram.y	2008-04-30 11:22:08.000000000 +0900
@@ -56,6 +56,7 @@
 #include "commands/defrem.h"
 #include "nodes/makefuncs.h"
 #include "parser/gramparse.h"
+#include "security/pgace.h"
 #include "storage/lmgr.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
@@ -355,6 +356,8 @@ static Node *makeXmlExpr(XmlExprOp op, c
 %type <str>		OptTableSpace OptConsTableSpace OptTableSpaceOwner
 %type <list>	opt_check_option
 
+%type <defelt> OptSecurityItem SecurityItem
+
 %type <target>	xml_attribute_el
 %type <list>	xml_attribute_list xml_attributes
 %type <node>	xml_root_version opt_xml_root_standalone
@@ -1642,6 +1645,24 @@ alter_table_cmd:
 					n->def = (Node *) $3;
 					$$ = (Node *)n;
 				}
+			/* ALTER TABLE <relation> CONTEXT = '...' */
+			| SecurityItem
+				{
+					AlterTableCmd *n = makeNode(AlterTableCmd);
+					n->subtype = AT_SetSecurityLabel;
+					n->name = NULL;
+					n->def = (Node *) $1;
+					$$ = (Node *) n;
+				}
+			/* ALTER TABLE <relation> ALTER [COLUMN] <colname> CONTEXT = '...' */
+			| ALTER opt_column ColId SecurityItem
+				{
+					AlterTableCmd *n = makeNode(AlterTableCmd);
+					n->subtype = AT_SetSecurityLabel;
+					n->name = $3;
+					n->def = (Node *) $4;
+					$$ = (Node *) n;
+				}
 			| alter_rel_cmd
 				{
 					$$ = $1;
@@ -1888,7 +1909,7 @@ opt_using:
  *****************************************************************************/
 
 CreateStmt:	CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
-			OptInherit OptWith OnCommitOption OptTableSpace
+			OptInherit OptWith OnCommitOption OptTableSpace OptSecurityItem
 				{
 					CreateStmt *n = makeNode(CreateStmt);
 					$4->istemp = $2;
@@ -1899,10 +1920,11 @@ CreateStmt:	CREATE OptTemp TABLE qualifi
 					n->options = $9;
 					n->oncommit = $10;
 					n->tablespacename = $11;
+					n->pgaceItem = (Node *) $12;
 					$$ = (Node *)n;
 				}
 		| CREATE OptTemp TABLE qualified_name OF qualified_name
-			'(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace
+			'(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace OptSecurityItem
 				{
 					/* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied
 					 * by our inheritance capabilities. Let's try it...
@@ -1916,6 +1938,7 @@ CreateStmt:	CREATE OptTemp TABLE qualifi
 					n->options = $10;
 					n->oncommit = $11;
 					n->tablespacename = $12;
+					n->pgaceItem = (Node *) $13;
 					$$ = (Node *)n;
 				}
 		;
@@ -1958,13 +1981,14 @@ TableElement:
 			| TableConstraint					{ $$ = $1; }
 		;
 
-columnDef:	ColId Typename ColQualList
+columnDef:	ColId Typename ColQualList OptSecurityItem
 				{
 					ColumnDef *n = makeNode(ColumnDef);
 					n->colname = $1;
 					n->typename = $2;
 					n->constraints = $3;
 					n->is_local = true;
+					n->pgaceItem = (Node *) $4;
 					$$ = (Node *)n;
 				}
 		;
@@ -4289,6 +4313,10 @@ common_func_opt_item:
 					/* we abuse the normal content of a DefElem here */
 					$$ = makeDefElem("set", (Node *)$1);
 				}
+			| SecurityItem
+				{
+					$$ = $1;
+				}
 		;
 
 createfunc_opt_item:
@@ -5380,6 +5408,10 @@ createdb_opt_item:
 				{
 					$$ = makeDefElem("owner", NULL);
 				}
+			| SecurityItem
+				{
+					$$ = $1;
+				}
 		;
 
 /*
@@ -5428,6 +5460,10 @@ alterdb_opt_item:
 				{
 					$$ = makeDefElem("connectionlimit", (Node *)makeInteger($4));
 				}
+			| SecurityItem
+				{
+					$$ = $1;
+				}
 		;
 
 
@@ -8698,6 +8734,26 @@ target_el:	a_expr AS ColLabel
 				}
 		;
 
+/*****************************************************************************
+ *
+ * PGACE Security Items
+ *
+ *****************************************************************************/
+
+OptSecurityItem:
+			SecurityItem				{ $$ = $1; }
+			| /* EMPTY */				{ $$ = NULL; }
+			;
+
+SecurityItem:
+			IDENT '=' Sconst
+				{
+					DefElem *n = pgaceGramSecurityItem($1, $3);
+					if (n == NULL)
+						yyerror("syntax error");
+					$$ = n;
+				}
+			;
 
 /*****************************************************************************
  *
diff -rpNU3 base/src/backend/parser/parse_target.c pgace/src/backend/parser/parse_target.c
--- base/src/backend/parser/parse_target.c	2008-04-30 11:09:33.000000000 +0900
+++ pgace/src/backend/parser/parse_target.c	2008-04-30 11:22:08.000000000 +0900
@@ -26,6 +26,7 @@
 #include "parser/parse_relation.h"
 #include "parser/parse_target.h"
 #include "parser/parse_type.h"
+#include "security/pgace.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
 #include "utils/typcache.h"
@@ -335,14 +336,19 @@ transformAssignedExpr(ParseState *pstate
 	Relation	rd = pstate->p_target_relation;
 
 	Assert(rd != NULL);
-	if (attrno <= 0)
+	if (attrno > 0) {
+		attrtype = attnumTypeId(rd, attrno);
+		attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
+	} else if (pgaceIsSecuritySystemColumn(attrno)) {
+		attrtype = SECLABELOID;
+		attrtypmod = -1;
+	} else {
 		ereport(ERROR,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("cannot assign to system column \"%s\"",
 						colname),
 				 parser_errposition(pstate, location)));
-	attrtype = attnumTypeId(rd, attrno);
-	attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
+	}
 
 	/*
 	 * If the expression is a DEFAULT placeholder, insert the attribute's
@@ -483,6 +489,9 @@ updateTargetListEntry(ParseState *pstate
 	 */
 	tle->resno = (AttrNumber) attrno;
 	tle->resname = colname;
+
+	if (pgaceIsSecuritySystemColumn(attrno))
+		tle->resjunk = true;
 }
 
 
@@ -749,6 +758,7 @@ checkInsertTargets(ParseState *pstate, L
 		Bitmapset  *wholecols = NULL;
 		Bitmapset  *partialcols = NULL;
 		ListCell   *tl;
+		bool		security_attr = false;
 
 		foreach(tl, cols)
 		{
@@ -757,14 +767,31 @@ checkInsertTargets(ParseState *pstate, L
 			int			attrno;
 
 			/* Lookup column name, ereport on failure */
-			attrno = attnameAttNum(pstate->p_target_relation, name, false);
-			if (attrno == InvalidAttrNumber)
+			attrno = attnameAttNum(pstate->p_target_relation, name, true);
+			if (attrno == InvalidAttrNumber) {
 				ereport(ERROR,
 						(errcode(ERRCODE_UNDEFINED_COLUMN),
 					errmsg("column \"%s\" of relation \"%s\" does not exist",
 						   name,
 						 RelationGetRelationName(pstate->p_target_relation)),
 						 parser_errposition(pstate, col->location)));
+			} else if (attrno <= 0) {
+				if (pgaceIsSecuritySystemColumn(attrno)) {
+					if (security_attr)
+						ereport(ERROR,
+								(errcode(ERRCODE_DUPLICATE_COLUMN),
+								 errmsg("column \"%s\" specified more than once", name),
+								 parser_errposition(pstate, col->location)));
+					security_attr = true;
+					*attrnos = lappend_int(*attrnos, attrno);
+					continue;
+				}
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+						 errmsg("column \"%s\" of relation \"%s\" is system column",
+								name, RelationGetRelationName(pstate->p_target_relation)),
+						                         parser_errposition(pstate, col->location)));
+			}
 
 			/*
 			 * Check for duplicates, but only of whole columns --- we allow
diff -rpNU3 base/src/backend/postmaster/postmaster.c pgace/src/backend/postmaster/postmaster.c
--- base/src/backend/postmaster/postmaster.c	2008-04-30 11:09:33.000000000 +0900
+++ pgace/src/backend/postmaster/postmaster.c	2008-04-30 11:22:08.000000000 +0900
@@ -107,6 +107,7 @@
 #include "postmaster/pgarch.h"
 #include "postmaster/postmaster.h"
 #include "postmaster/syslogger.h"
+#include "security/pgace.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
@@ -1018,6 +1019,9 @@ PostmasterMain(int argc, char *argv[])
 	Assert(StartupPID != 0);
 	pmState = PM_STARTUP;
 
+	if (!pgaceInitializePostmaster())
+		ExitPostmaster(1);
+
 	status = ServerLoop();
 
 	/*
@@ -2050,9 +2054,11 @@ pmdie(SIGNAL_ARGS)
 				signal_child(PgArchPID, SIGQUIT);
 			if (PgStatPID != 0)
 				signal_child(PgStatPID, SIGQUIT);
+			pgaceFinalizePostmaster();
 			ExitPostmaster(0);
 			break;
 	}
+	pgaceFinalizePostmaster();
 
 	PG_SETMASK(&UnBlockSig);
 
diff -rpNU3 base/src/backend/rewrite/rewriteHandler.c pgace/src/backend/rewrite/rewriteHandler.c
--- base/src/backend/rewrite/rewriteHandler.c	2008-01-07 23:51:33.000000000 +0900
+++ pgace/src/backend/rewrite/rewriteHandler.c	2008-01-08 01:39:49.000000000 +0900
@@ -24,6 +24,7 @@
 #include "rewrite/rewriteDefine.h"
 #include "rewrite/rewriteHandler.h"
 #include "rewrite/rewriteManip.h"
+#include "security/pgace.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
 #include "commands/trigger.h"
@@ -1880,5 +1881,8 @@ QueryRewrite(Query *parsetree)
 	if (!foundOriginalQuery && lastInstead != NULL)
 		lastInstead->canSetTag = true;
 
+	/* PGACE: general queries proxy */
+	results = pgaceProxyQuery(results);
+
 	return results;
 }
diff -rpNU3 base/src/backend/security/Makefile pgace/src/backend/security/Makefile
--- base/src/backend/security/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ pgace/src/backend/security/Makefile	2008-03-13 13:21:22.000000000 +0900
@@ -0,0 +1,13 @@
+#
+# src/backend/security/Makefile
+#   Makefile for Security Purpose Extensions
+#
+# Copyright (c) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
+#
+subdir = src/backend/security
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+OBJS := pgaceCommon.o pgaceHooks.o
+
+include $(top_builddir)/src/backend/common.mk
diff -rpNU3 base/src/backend/security/pgaceCommon.c pgace/src/backend/security/pgaceCommon.c
--- base/src/backend/security/pgaceCommon.c	1970-01-01 09:00:00.000000000 +0900
+++ pgace/src/backend/security/pgaceCommon.c	2008-04-02 14:11:37.000000000 +0900
@@ -0,0 +1,715 @@
+/*
+ * src/backend/security/pgaceCommon.c
+ *   Common part of PostgreSQL Access Control Extension
+ * Copyright 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
+ */
+#include "postgres.h"
+
+#include "access/genam.h"
+#include "access/heapam.h"
+#include "access/xact.h"
+#include "catalog/catalog.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_attribute.h"
+#include "catalog/pg_largeobject.h"
+#include "catalog/pg_security.h"
+#include "catalog/pg_type.h"
+#include "executor/executor.h"
+#include "miscadmin.h"
+#include "nodes/makefuncs.h"
+#include "nodes/parsenodes.h"
+#include "parser/parse_expr.h"
+#include "security/pgace.h"
+#include "utils/builtins.h"
+#include "utils/fmgroids.h"
+#include "utils/syscache.h"
+#include "utils/tqual.h"
+#include <unistd.h>
+#include <sys/file.h>
+
+/*****************************************************************************
+ * Security attribute system column support
+ *****************************************************************************/
+#ifdef SECURITY_SYSATTR_NAME
+
+bool pgaceIsSecuritySystemColumn(int attrno)
+{
+	return ((attrno == SecurityAttributeNumber) ? true : false);
+}
+
+void pgaceTransformSelectStmt(List *targetList) {
+	ListCell *l;
+
+	foreach (l, targetList) {
+		TargetEntry *tle = lfirst(l);
+
+		if (tle->resjunk)
+			continue;
+		if (!strcmp(tle->resname, SECURITY_SYSATTR_NAME)) {
+			if (exprType((Node *) tle->expr) != SECLABELOID)
+				elog(ERROR, "type mismatch in explicit labeling");
+			tle->resjunk = true;
+			break;
+		}
+	}
+}
+
+void pgaceTransformInsertStmt(List **p_icolumns, List **p_attrnos, List *targetList) {
+	AttrNumber security_attrno = 0;
+	ListCell *lc;
+
+	foreach (lc, targetList) {
+		TargetEntry *tle = (TargetEntry *) lfirst(lc);
+
+		security_attrno++;
+		if (strcmp(tle->resname, SECURITY_SYSATTR_NAME))
+			continue;
+
+		if (list_length(*p_icolumns) < list_length(targetList)) {
+			List *__icolumns = NIL;
+			List *__attrnos = NIL;
+			ListCell *l1, *l2;
+			int index = 0;
+
+			forboth(l1, *p_icolumns, l2, *p_attrnos) {
+				if (++index == security_attrno) {
+					ResTarget *col = makeNode(ResTarget);
+					col->name = pstrdup(SECURITY_SYSATTR_NAME);
+					col->indirection = NIL;
+					col->val = NULL;
+					col->location = -1;
+
+					__icolumns = lappend(__icolumns, col);
+					__attrnos = lappend_int(__attrnos, SecurityAttributeNumber);
+				}
+				if (lfirst_int(l2) == SecurityAttributeNumber)
+					return;
+				__icolumns = lappend(__icolumns, lfirst(l1));
+				__attrnos = lappend_int(__attrnos, lfirst_int(l2));
+			}
+			*p_icolumns = __icolumns;
+			*p_attrnos = __attrnos;
+		}
+		break;
+	}
+}
+
+void pgaceFetchSecurityAttribute(JunkFilter *junkfilter, TupleTableSlot *slot, Oid *tts_security)
+{
+	AttrNumber attno;
+	Datum datum;
+	bool isnull;
+
+	attno = ExecFindJunkAttribute(junkfilter, SECURITY_SYSATTR_NAME);
+	if (attno != InvalidAttrNumber) {
+		datum = ExecGetJunkAttribute(slot, attno, &isnull);
+		if (!isnull)
+			*tts_security = DatumGetObjectId(datum);
+	}
+}
+#else  /* SECURITY_SYSATTR_NAME */
+
+bool pgaceIsSecuritySystemColumn(int attrno) {
+	return false;
+}
+
+void pgaceTransformSelectStmt(List *targetList) {
+	/* do nothing */
+}
+
+void pgaceTransformInsertStmt(List **p_icolumns,
+							  List **p_attrnos,
+							  List *targetList) {
+	/* do nothing */
+}
+
+void pgaceFetchSecurityAttribute(JunkFilter *junkfilter,
+								 TupleTableSlot *slot,
+								 Oid *tts_security) {
+	/* do nothing */
+}
+#endif /* SECURITY_SYSATTR_NAME */
+
+/*****************************************************************************
+ *   Extended SQL statements support
+ *****************************************************************************/
+
+/* CREATE TABLE with explicit CONTEXT */
+List *pgaceRelationAttrList(CreateStmt *stmt)
+{
+	List *result = NIL;
+	ListCell *l;
+	DefElem *defel, *newel;
+
+	if (stmt->pgaceItem) {
+		defel = (DefElem *) stmt->pgaceItem;
+
+		Assert(IsA(defel, DefElem));
+		if (!pgaceIsGramSecurityItem(defel))
+			elog(ERROR, "node is not a pgace security item");
+		newel = makeDefElem(NULL, (Node *) copyObject(defel));
+		result = lappend(result, newel);
+	}
+
+	foreach (l, stmt->tableElts) {
+		ColumnDef *cdef = (ColumnDef *) lfirst(l);
+		defel = (DefElem *) cdef->pgaceItem;
+
+		if (defel) {
+			Assert(IsA(defel, DefElem));
+			if (!pgaceIsGramSecurityItem(defel))
+				elog(ERROR, "node is not a pgace security item");
+			newel = makeDefElem(pstrdup(cdef->colname),
+								(Node *) copyObject(defel));
+			result = lappend(result, newel);
+		}
+	}
+	return result;
+}
+
+void pgaceCreateRelationCommon(Relation rel, HeapTuple tuple, List *pgace_attr_list) {
+	ListCell *l;
+
+	foreach (l, pgace_attr_list) {
+		DefElem *defel = (DefElem *) lfirst(l);
+
+		if (!defel->defname) {
+			Assert(pgaceIsGramSecurityItem((DefElem *)defel->arg));
+			pgaceGramCreateRelation(rel, tuple, (DefElem *)defel->arg);
+			break;
+		}
+	}
+}
+
+void pgaceCreateAttributeCommon(Relation rel, HeapTuple tuple, List *pgace_attr_list) {
+	Form_pg_attribute attr = (Form_pg_attribute) GETSTRUCT(tuple);
+	ListCell *l;
+
+	foreach (l, pgace_attr_list) {
+		DefElem *defel = lfirst(l);
+
+		if (!defel->defname)
+			continue;	/* for table */
+		if (!strcmp(defel->defname, NameStr(attr->attname))) {
+			Assert(pgaceIsGramSecurityItem((DefElem *)defel->arg));
+			pgaceGramCreateAttribute(rel, tuple, (DefElem *)defel->arg);
+			break;
+		}
+	}
+}
+
+/* ALTER <tblname> [ALTER <colname>] CONTEXT = 'xxx' statement */
+static void alterRelationCommon(Relation rel, DefElem *defel) {
+	Relation pg_class;
+	HeapTuple tuple;
+
+	pg_class = heap_open(RelationRelationId, RowExclusiveLock);
+
+	tuple = SearchSysCacheCopy(RELOID,
+							   ObjectIdGetDatum(RelationGetRelid(rel)),
+							   0, 0, 0);
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for relation '%s'", RelationGetRelationName(rel));
+	pgaceGramAlterRelation(rel, tuple, defel);
+
+	simple_heap_update(pg_class, &tuple->t_self, tuple);
+	CatalogUpdateIndexes(pg_class, tuple);
+
+	heap_freetuple(tuple);
+	heap_close(pg_class, RowExclusiveLock);
+}
+
+static void alterAttributeCommon(Relation rel, char *colName, DefElem *defel) {
+	Relation pg_attr;
+	HeapTuple tuple;
+
+	pg_attr = heap_open(AttributeRelationId, RowExclusiveLock);
+
+	tuple = SearchSysCacheCopyAttName(RelationGetRelid(rel), colName);
+	if (!HeapTupleIsValid(tuple))
+		elog(ERROR, "cache lookup failed for attribute '%s' of relation '%s'", 
+			 colName, RelationGetRelationName(rel));
+	pgaceGramAlterAttribute(rel, tuple, defel);
+
+	simple_heap_update(pg_attr, &tuple->t_self, tuple);
+	CatalogUpdateIndexes(pg_attr, tuple);
+
+	heap_freetuple(tuple);
+	heap_close(pg_attr, RowExclusiveLock);
+}
+
+void pgaceAlterRelationCommon(Relation rel, AlterTableCmd *cmd) {
+	DefElem *defel = (DefElem *) cmd->def;
+
+	Assert(IsA(defel, DefElem));
+
+	if (!pgaceIsGramSecurityItem(defel))
+		elog(ERROR, "unsupported pgace security item");
+
+	if (!cmd->name) {
+		alterRelationCommon(rel, defel);
+	} else {
+		alterAttributeCommon(rel, cmd->name, defel);
+	}
+}
+
+/*****************************************************************************
+ *   security_label type input/output handler
+ *****************************************************************************/
+static Oid early_security_label_to_sid(char *seclabel);
+static char *early_sid_to_security_label(Oid sid);
+#define EARLY_PG_SECURITY  "global/pg_security.bootstrap"
+
+static bool pg_security_is_available() {
+	/* -1 : early mode, 0: now in transfer, 1: available */
+	static int pg_security_state = -1;
+	char fname[MAXPGPATH];
+	FILE *filp;
+
+	if (pg_security_state > 0)
+		return true;
+	if (IsBootstrapProcessingMode() || pg_security_state==0)
+		return false;
+	/*
+	 * if initial setting up was not done, the cache file is remaining.
+	 * so we have to insert its contains into pg_selinux.
+	 * we can make decision of whether it already done, or not, by looking
+	 * the existance of 'EARLY_PG_SECURITY'.
+	 */
+	snprintf(fname, sizeof(fname), "%s/%s", DataDir, EARLY_PG_SECURITY);
+	filp = fopen(fname, "rb");
+	if (filp) {
+		Relation rel;
+		CatalogIndexState ind;
+		HeapTuple tuple;
+		char buffer[1024];
+		Oid secoid, metaoid;
+		Datum value;
+		char  isnull;
+
+		pg_security_state = 0;
+
+		PG_TRY();
+		{
+			rel = heap_open(SecurityRelationId, RowExclusiveLock);
+			ind = CatalogOpenIndexes(rel);
+			while (fscanf(filp, "%u %s", &secoid, buffer) == 2) {
+				metaoid = early_security_label_to_sid(pgaceSecurityLabelOfLabel(buffer));
+
+				value = DirectFunctionCall1(textin, CStringGetDatum(buffer));
+				isnull = ' ';
+				tuple = heap_formtuple(RelationGetDescr(rel), &value, &isnull);
+
+				HeapTupleSetOid(tuple, secoid);
+				HeapTupleSetSecurity(tuple, metaoid);
+
+				simple_heap_insert(rel, tuple);
+				CatalogIndexInsert(ind, tuple);
+
+				heap_freetuple(tuple);
+			}
+			CatalogCloseIndexes(ind);
+			heap_close(rel, RowExclusiveLock);
+
+			CommandCounterIncrement();
+		}
+		PG_CATCH();
+		{
+			fclose(filp);
+			PG_RE_THROW();
+		}
+		PG_END_TRY();
+		fclose(filp);
+		if (unlink(fname) != 0)
+			elog(ERROR, "PGACE: could not unlink '%s'", fname);
+	}
+	pg_security_state = 1;
+
+	return true;
+}
+
+static Oid early_security_label_to_sid(char *seclabel)
+{
+	char fname[MAXPGPATH], buffer[1024];
+	Oid sid, minsid = SecurityRelationId;
+	FILE *filp;
+
+	snprintf(fname, sizeof(fname), "%s/%s", DataDir, EARLY_PG_SECURITY);
+	filp = fopen(fname, "a+b");
+	if (!filp)
+		ereport(ERROR,
+				(errcode(ERRCODE_INTERNAL_ERROR),
+				 errmsg("could not open '%s'", fname)));
+	flock(fileno(filp), LOCK_EX);
+	while (fscanf(filp, "%u %s", &sid, buffer) == 2) {
+		if (!strcmp(seclabel, buffer)) {
+			fclose(filp);
+			return sid;
+		}
+		if (sid < minsid)
+			minsid = sid;
+	}
+	sid = minsid - 1;
+	fprintf(filp, "%u %s\n", sid, seclabel);
+	fclose(filp);
+
+	return sid;
+}
+
+static char *early_sid_to_security_label(Oid sid)
+{
+	char fname[MAXPGPATH], buffer[1024], *seclabel;
+	FILE *filp;
+	Oid __sid;
+
+	snprintf(fname, sizeof(fname), "%s/%s", DataDir, EARLY_PG_SECURITY);
+	filp = fopen(fname, "rb");
+	if (!filp)
+		goto not_found;
+
+	flock(fileno(filp), LOCK_SH);
+	while (fscanf(filp, "%u %s", &__sid, buffer) == 2) {
+		if (sid == __sid) {
+			fclose(filp);
+			return pstrdup(buffer);
+		}
+	}
+	fclose(filp);
+
+not_found:
+	seclabel = pgaceSecurityLabelCheckValid(NULL);
+	elog(seclabel ? NOTICE : ERROR,
+		 "PGACE: No text representation for sid = %u", sid);
+	return seclabel;
+}
+
+static Oid get_security_label_oid(Relation rel, CatalogIndexState ind, char *new_label)
+{
+	/* rel has to be opened with RowExclusiveLock */
+	char *mlabel_str, *__mlabel_str;
+	Datum mlabel_text;
+	HeapTuple tuple;
+	Oid label_oid;
+
+	mlabel_str = pgaceSecurityLabelOfLabel(new_label);
+	__mlabel_str = pgaceSecurityLabelCheckValid(mlabel_str);
+	if (mlabel_str != __mlabel_str)
+		elog(NOTICE, "PGACE: '%s' is not a valid security label,"
+					 " '%s' is applied instead.", mlabel_str, __mlabel_str);
+
+	/* 1. lookup syscache */
+	mlabel_text = DirectFunctionCall1(textin, CStringGetDatum(mlabel_str));
+	tuple = SearchSysCache(SECURITYLABEL,
+						   mlabel_text,
+						   0, 0, 0);
+	if (HeapTupleIsValid(tuple)) {
+		label_oid = HeapTupleGetSecurity(tuple);
+		ReleaseSysCache(tuple);
+	} else {
+		/* 2. lookup table on SnapshotSelf */
+		SysScanDesc scan;
+		ScanKeyData skey;
+
+		ScanKeyInit(&skey,
+					Anum_pg_security_seclabel,
+					BTEqualStrategyNumber, F_TEXTEQ,
+					PointerGetDatum(mlabel_text));
+		scan = systable_beginscan(rel, SecuritySeclabelIndexId,
+								  true, SnapshotSelf, 1, &skey);
+		tuple = systable_getnext(scan);
+		if (HeapTupleIsValid(tuple)) {
+			label_oid = HeapTupleGetSecurity(tuple);
+		} else {
+			/* 3. insert a new tuple into pg_security */
+			Datum value = PointerGetDatum(mlabel_text);
+			char isnull = ' ';
+			Oid meta_oid;
+
+			tuple = heap_formtuple(RelationGetDescr(rel),
+								   &value, &isnull);
+			meta_oid = GetNewOid(rel);
+			HeapTupleSetOid(tuple, meta_oid);
+			HeapTupleSetSecurity(tuple, meta_oid);
+
+			label_oid = simple_heap_insert(rel, tuple);
+			Assert(label_oid == meta_oid);
+
+			CatalogIndexInsert(ind, tuple);
+		}
+		systable_endscan(scan);
+	}
+	return label_oid;
+}
+
+static Oid security_label_to_sid(char *label_str)
+{
+	Datum label_text;
+	Oid label_oid;
+	HeapTuple tuple;
+
+	if (!pg_security_is_available())
+		return early_security_label_to_sid(label_str);
+
+	/* 1. lookup system cache first */
+	label_text = DirectFunctionCall1(textin, CStringGetDatum(label_str));
+	tuple = SearchSysCache(SECURITYLABEL,
+						   label_text,
+						   0, 0, 0);
+	if (HeapTupleIsValid(tuple)) {
+		label_oid = HeapTupleGetOid(tuple);
+		ReleaseSysCache(tuple);
+	} else {
+		/* 2. lookup within the current command ID */
+		Relation rel;
+		SysScanDesc scan;
+		ScanKeyData skey;
+		Oid meta_oid;
+
+		rel = heap_open(SecurityRelationId, RowExclusiveLock);
+		ScanKeyInit(&skey,
+					Anum_pg_security_seclabel,
+					BTEqualStrategyNumber, F_TEXTEQ,
+					PointerGetDatum(label_text));
+		scan = systable_beginscan(rel, SecuritySeclabelIndexId,
+								  true, SnapshotSelf, 1, &skey);
+		tuple = systable_getnext(scan);
+		if (HeapTupleIsValid(tuple)) {
+			label_oid = HeapTupleGetOid(tuple);
+		} else {
+			CatalogIndexState ind;
+			Datum value = PointerGetDatum(label_text);
+			char isnull = ' ';
+
+			ind = CatalogOpenIndexes(rel);
+
+			tuple = heap_formtuple(RelationGetDescr(rel),
+								   &value, &isnull);
+			meta_oid = get_security_label_oid(rel, ind, label_str);
+			HeapTupleSetSecurity(tuple, meta_oid);
+
+			label_oid = simple_heap_insert(rel, tuple);
+
+			CatalogIndexInsert(ind, tuple);
+			CatalogCloseIndexes(ind);
+		}
+		systable_endscan(scan);
+		heap_close(rel, RowExclusiveLock);
+	}
+	return label_oid;
+}
+
+static char *sid_to_security_label(Oid sid)
+{
+	HeapTuple tuple;
+	Datum tcon;
+	char *seclabel;
+	bool isnull, syscache = true;
+
+	if (!pg_security_is_available())
+		return early_sid_to_security_label(sid);
+
+	tuple = SearchSysCache(SECURITYOID,
+						   ObjectIdGetDatum(sid),
+						   0, 0, 0);
+	if (!HeapTupleIsValid(tuple)) {
+		Relation rel;
+		SysScanDesc scan;
+		ScanKeyData skey;
+
+		syscache = false;
+		rel = heap_open(SecurityRelationId, AccessShareLock);
+		ScanKeyInit(&skey,
+					ObjectIdAttributeNumber,
+					BTEqualStrategyNumber, F_OIDEQ,
+					ObjectIdGetDatum(sid));
+		scan = systable_beginscan(rel, SecurityOidIndexId,
+								  true, SnapshotSelf, 1, &skey);
+		tuple = systable_getnext(scan);
+		if (HeapTupleIsValid(tuple))
+			tuple = heap_copytuple(tuple);
+		systable_endscan(scan);
+		heap_close(rel, AccessShareLock);
+
+		if (!HeapTupleIsValid(tuple)) {
+			seclabel = pgaceSecurityLabelCheckValid(NULL);
+			elog(seclabel ? NOTICE : ERROR,
+				 "PGACE: No text representation for sid = %u", sid);
+			return seclabel;
+		}
+	}
+	tcon = SysCacheGetAttr(SECURITYOID,
+						   tuple,
+						   Anum_pg_security_seclabel,
+						   &isnull);
+	seclabel = DatumGetCString(DirectFunctionCall1(textout,
+												   PointerGetDatum(tcon)));
+	if (syscache)
+		ReleaseSysCache(tuple);
+
+	return seclabel;
+}
+
+/* security_label_in -- security_label input function */
+Datum
+security_label_in(PG_FUNCTION_ARGS)
+{
+	char *label = PG_GETARG_CSTRING(0);
+	char *__label;
+
+	label = pgaceSecurityLabelIn(label);
+	__label = pgaceSecurityLabelCheckValid(label);
+	if (label != __label)
+		elog(ERROR, "PGACE: '%s' is not a valid security label", label);
+
+	PG_RETURN_OID(security_label_to_sid(label));
+}
+
+/* security_label_out -- security_label output function */
+Datum
+security_label_out(PG_FUNCTION_ARGS)
+{
+	Oid sid = PG_GETARG_OID(0);
+	char *label = sid_to_security_label(sid);
+	char *__label = pgaceSecurityLabelCheckValid(label);
+	if (label != __label)
+		elog(NOTICE, "PGACE: '%s' is not a valid security label,"
+					 " '%s' is applied instead.", label, __label);
+	PG_RETURN_CSTRING(pgaceSecurityLabelOut(__label));
+}
+
+/* security_label_raw_in -- security_label input function in raw format */
+Datum
+security_label_raw_in(PG_FUNCTION_ARGS)
+{
+	char *label = PG_GETARG_CSTRING(0);
+	char *__label;
+
+	__label = pgaceSecurityLabelCheckValid(label);
+	if (label != __label)
+		elog(ERROR, "PGACE: '%s' is not a valid security label", label);
+
+	PG_RETURN_OID(security_label_to_sid(label));
+}
+
+/* security_label_raw_out -- security_label output function in raw format */
+Datum
+security_label_raw_out(PG_FUNCTION_ARGS)
+{
+	Oid sid = PG_GETARG_OID(0);
+	char *label = sid_to_security_label(sid);
+	char *__label = pgaceSecurityLabelCheckValid(label);
+
+	if (label != __label)
+		elog(NOTICE, "PGACE: '%s' is not a valid security label,"
+					 " '%s' is applied instead.", label, __label);
+	PG_RETURN_CSTRING(__label);
+}
+
+/* text_to_security_label -- security_label cast function */
+Datum
+text_to_security_label(PG_FUNCTION_ARGS)
+{
+	text *t = PG_GETARG_TEXT_P(0);
+	Datum seclabel;
+
+	seclabel = DirectFunctionCall1(textout,
+								   PointerGetDatum(t));
+	return DirectFunctionCall1(security_label_in, seclabel);
+}
+
+/* security_label_to_text -- security_label cast function */
+Datum
+security_label_to_text(PG_FUNCTION_ARGS)
+{
+	Oid sid = PG_GETARG_OID(0);
+	Datum seclabel;
+
+	seclabel = DirectFunctionCall1(security_label_out,
+								   ObjectIdGetDatum(sid));
+	return DirectFunctionCall1(textin, seclabel);
+}
+
+/*****************************************************************************
+ *	 Set/Get security attribute of Large Object
+ *****************************************************************************/
+Datum
+lo_get_security(PG_FUNCTION_ARGS)
+{
+	Oid loid = PG_GETARG_OID(0);
+	Oid lo_security = InvalidOid;
+	Relation rel;
+	ScanKeyData skey;
+	SysScanDesc sd;
+	HeapTuple tuple;
+	bool found = false;
+
+	ScanKeyInit(&skey,
+				Anum_pg_largeobject_loid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(loid));
+
+	rel = heap_open(LargeObjectRelationId, AccessShareLock);
+
+	sd = systable_beginscan(rel, LargeObjectLOidPNIndexId, true,
+							SnapshotNow, 1, &skey);
+
+	while ((tuple = systable_getnext(sd)) != NULL) {
+		lo_security = HeapTupleGetSecurity(tuple);
+		pgaceLargeObjectGetSecurity(tuple);
+		found = true;
+		break;
+	}
+	systable_endscan(sd);
+
+	heap_close(rel, AccessShareLock);
+
+	if (!found)
+		elog(ERROR, "large object %u does not exist", loid);
+
+	PG_RETURN_OID(lo_security);
+}
+
+Datum
+lo_set_security(PG_FUNCTION_ARGS)
+{
+	Oid loid = PG_GETARG_OID(0);
+	Oid lo_security = PG_GETARG_OID(1);
+	Relation rel;
+	ScanKeyData skey;
+	SysScanDesc sd;
+	HeapTuple tuple, newtup;
+	CatalogIndexState indstate;
+	bool found = false;
+
+	ScanKeyInit(&skey,
+				Anum_pg_largeobject_loid,
+				BTEqualStrategyNumber, F_OIDEQ,
+				ObjectIdGetDatum(loid));
+
+	rel = heap_open(LargeObjectRelationId, RowExclusiveLock);
+
+	indstate = CatalogOpenIndexes(rel);
+
+	sd = systable_beginscan(rel, LargeObjectLOidPNIndexId, true,
+							SnapshotNow, 1, &skey);
+
+	while ((tuple = systable_getnext(sd)) != NULL) {
+		newtup = heap_copytuple(tuple);
+		if (!found)
+			pgaceLargeObjectSetSecurity(newtup, lo_security);
+		HeapTupleSetSecurity(newtup, lo_security);
+		simple_heap_update(rel, &newtup->t_self, newtup);
+		CatalogUpdateIndexes(rel, newtup);
+		found = true;
+	}
+	systable_endscan(sd);
+	CatalogCloseIndexes(indstate);
+	heap_close(rel, RowExclusiveLock);
+
+	CommandCounterIncrement();
+
+	if (!found)
+		elog(ERROR, "large object %u does not exist.", loid);
+
+	PG_RETURN_BOOL(true);
+}
diff -rpNU3 base/src/backend/security/pgaceHooks.c pgace/src/backend/security/pgaceHooks.c
--- base/src/backend/security/pgaceHooks.c	1970-01-01 09:00:00.000000000 +0900
+++ pgace/src/backend/security/pgaceHooks.c	2008-03-13 14:06:46.000000000 +0900
@@ -0,0 +1,628 @@
+/*
+ * src/backend/security/pgaceHooks.c
+ *   Dummy functions of PostgreSQL Access Control Extension
+ *   when no users enables the framework.
+ * Copyright 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
+ */
+#include "postgres.h"
+
+#include "security/pgace.h"
+
+/******************************************************************
+ * Initialize / Finalize related hooks
+ ******************************************************************/
+
+/*
+ * pgaceShmemSize() have to return the size of shared memory segment
+ * required by PGACE implementation. If no shared memory segment needed,
+ * it should return 0.
+ */
+Size pgaceShmemSize(void)
+{
+	return (Size) 0;
+}
+
+/*
+ * pgaceInitialize() is called when a new PostgreSQL instance is generated.
+ * A PGACE implementation can initialize itself.
+ *
+ * @is_bootstrap : true, if bootstraping mode.
+ */
+void pgaceInitialize(bool is_bootstrap)
+{
+	/* do nothing */
+}
+
+/*
+ * pgaceInitializePostmaster() is called when a postmaster server process
+ * is started up. If it returns false, the server starting up process
+ * will be aborted.
+ */
+bool pgaceInitializePostmaster(void)
+{
+	return true;
+}
+
+/*
+ * pgaceFinalizePostmaster() is called when a postmaster server process
+ * is just ending up.
+ */
+void pgaceFinalizePostmaster(void)
+{
+	/* do nothing */
+}
+
+/******************************************************************
+ * SQL proxy hooks
+ ******************************************************************/
+
+/*
+ * pgaceProxyQuery() is called just after query rewrite phase.
+ * PGACE implementation can modify the query trees in this hook,
+ * if necessary.
+ *
+ * @queryList : a list of Query typed objects.
+ */
+List *pgaceProxyQuery(List *queryList)
+{
+	return queryList;
+}
+
+/*
+ * pgacePortalStart() is called on the top of PortalStart().
+ *
+ * @portal : a Portal object currently executed.
+ */
+void pgacePortalStart(Portal portal)
+{
+	/* do nothing */
+}
+
+/*
+ * pgaceExecutorStart() is called on the top of ExecutorStart().
+ *
+ * @queryDesc : a QueryDesc object given to ExecutorStart().
+ * @eflags    : eflags valus given to ExecutorStart().
+ *              if EXEC_FLAG_EXPLAIN_ONLY is set, no real access will run.
+ */
+void pgaceExecutorStart(QueryDesc *queryDesc, int eflags)
+{
+	/* do nothing */
+}
+
+/******************************************************************
+ * HeapTuple modification hooks
+ ******************************************************************/
+
+/*
+ * pgaceHeapTupleInsert() is called when a new tuple attempt to be inserted.
+ * If it returns false, this insertion of a new tuple will be cancelled.
+ * However, it does not generate any error.
+ *
+ * @rel            : the target relation
+ * @tuple          : the tuple attmpt to be inserted
+ * @is_internal    : true, if this operation is invoked by system internal processes.
+ * @with_returning : true, if INSERT statement has RETURNING clause.
+ */
+bool pgaceHeapTupleInsert(Relation rel, HeapTuple tuple,
+						  bool is_internal, bool with_returning)
+{
+	return true;
+}
+
+/*
+ * pgaceHeapTupleUpdate() is called when a tuple attempt to be updated.
+ * If it returns false, this update will be cancelled.
+ * However, it does not generate any error.
+ *
+ * @rel            : the target relation
+ * @otid           : ItemPointer of the tuple to be updated
+ * @newtup         : the new contains of the updated tuple
+ * @is_internal    : true, if this operation is invoked by system internal processes.
+ * @with_returning : true, if INSERT statement has RETURNING clause.
+ */
+bool pgaceHeapTupleUpdate(Relation rel, ItemPointer otid, HeapTuple newtup,
+						  bool is_internal, bool with_returning)
+{
+	return true;
+}
+
+/*
+ * pgaceHeapTupleDelete() is called when a tuple attempt to be deleted.
+ * If it returns false, this deletion will be cancelled.
+ * However, it does not generate any error.
+ *
+ * @rel            : the target relation
+ * @otid           : ItemPointer of the tuple to be deleted
+ * @is_internal    : true, if this operation is invoked by system internal processes.
+ * @with_returning : true, if INSERT statement has RETURNING clause.
+ */
+bool pgaceHeapTupleDelete(Relation rel, ItemPointer otid,
+						  bool is_internal, bool with_returning)
+{
+	return true;
+}
+
+/******************************************************************
+ * Extended SQL statement hooks
+ ******************************************************************/
+/*
+ * PGACE implementation can use pgaceGramSecurityItem() hook to extend
+ * SQL statement for security purpose. This hook is deployed on parser/gram.y
+ * as a part of the SQL grammer. If no SQL extension is necessary, it has to
+ * return NULL to cause yyerror().
+ *
+ * @defname : given <parameter> string
+ * @value   : given <value> string
+ */
+DefElem *pgaceGramSecurityItem(char *defname, char *value)
+{
+	return NULL;
+}
+
+/*
+ * PGACE implementation has to return true, if the given DefElem holds
+ * security item generated in pgaceGramSecurityItem(). false, if any other.
+ *
+ * @defel : given DefElem object
+ */
+bool pgaceIsGramSecurityItem(DefElem *defel)
+{
+	return false;
+}
+
+/*
+ * pgaceGramCreateRelation() is called to modify a tuple just before inserting
+ * a new relation with CREATE TABLE, if extended statement is used.
+ *
+ * @rel   : pg_class relation
+ * @tuple : a tuple of new relation
+ * @defel : extended statement
+ */
+void pgaceGramCreateRelation(Relation rel, HeapTuple tuple, DefElem *defel)
+{
+	/* do nothing */
+}
+
+/*
+ * pgaceGramCreateAttribute() is called to modify a tuple just before inserting
+ * a new attribute with CREATE TABLE, if extended statement is used.
+ *
+ * @rel   : pg_attribute relation
+ * @tuple : a tuple of new attribute
+ * @defel : extended statement
+ */
+void pgaceGramCreateAttribute(Relation rel, HeapTuple tuple, DefElem *defel)
+{
+	/* do nothing */
+}
+
+/*
+ * pgaceGramAlterRelation() is called to modify a tuple just before updating
+ * a relation with ALTER TABLE, if extended statement is used.
+ *
+ * @rel   : target relation
+ * @tuple : a tuple of new relation
+ * @defel : extended statement
+ */
+void pgaceGramAlterRelation(Relation rel, HeapTuple tuple, DefElem *defel)
+{
+	/* do nothing */
+}
+
+/*
+ * pgaceGramAlterAttribute() is called to modify a tuple just before updating
+ * an attribute with ALTER TABLE, if extended statement is specified.
+ *
+ * @rel   : target relation
+ * @tuple : a tuple of new attribute
+ * @defel : extended statement
+ */
+void pgaceGramAlterAttribute(Relation rel, HeapTuple tuple, DefElem *defel)
+{
+	/* do nothing */
+}
+
+/*
+ * pgaceGramCreateDatabase() is called to modify a tuple just before inserting
+ * a new database with CREATE DATABASE, if extended statement is used.
+ *
+ * @rel   : pg_database relation
+ * @tuple : a tuple of the new database
+ * @defel : extended statement
+ */
+void pgaceGramCreateDatabase(Relation rel, HeapTuple tuple, DefElem *defel)
+{
+	/* do nothing */
+}
+
+/*
+ * pgaceGramAlterDatabase() is called to modify a tuple just before updating
+ * a database with ALTER DATABASE, if extended statement is used.
+ *
+ * @rel   : pg_database relation
+ * @tuple : a tuple of the updated database
+ * @defel : extended statement
+ */
+void pgaceGramAlterDatabase(Relation rel, HeapTuple tuple, DefElem *defel)
+{
+	/* do nothing */
+}
+
+/*
+ * pgaceGramCreateFunction() is called to modify a tuple just before inserting
+ * a new function into pg_proc, if extended statement is used.
+ *
+ * @rel   : pg_proc relation
+ * @tuple : a tuple of the new function
+ * @defel : extended statement
+ */
+void pgaceGramCreateFunction(Relation rel, HeapTuple tuple, DefElem *defel)
+{
+	/* do nothing */
+}
+
+/*
+ * pgaceGramAlterFunction() is called to modify a tuple just before updating
+ * a function with ALTER FUNCTION, if extended statement is used.
+ *
+ * @rel   : pg_proc relation
+ * @tuple : a tuple of the function
+ * @defel : extended statement
+ */
+void pgaceGramAlterFunction(Relation rel, HeapTuple tuple, DefElem *defel)
+{
+	/* do nothing */
+}
+
+/******************************************************************
+ * DATABASE related hooks
+ ******************************************************************/
+
+/*
+ * pgaceSetDatabaseParam() is called when clients tries to set GUC variables
+ *
+ * @name   : The name of GUC variable
+ * @argstr : The new valus of GUC variable. If argstr is NULL, it means
+ *           clients tries to reset the variable.
+ */
+void pgaceSetDatabaseParam(const char *name, char *argstring)
+{
+	/* do nothing */
+}
+
+/*
+ * pgaceGetDatabaseParam() is called when clients tries to refer GUC variables
+ *
+ * @name : The name of GUC variable
+ */
+void pgaceGetDatabaseParam(const char *name)
+{
+	/* do nothing */
+}
+
+/******************************************************************
+ * FUNCTION related hooks
+ ******************************************************************/
+
+/*
+ * pgaceCallFunction() is called just before executing SQL function
+ * as a part of query.
+ *
+ * @finfo    : FmgrInfo object for the target function
+ */
+void pgaceCallFunction(FmgrInfo *finfo)
+{
+	/* do nothing */
+}
+
+/*
+ * pgaceCallFunctionTrigger() is called just before executing
+ * trigger function. 
+ * If it returns false, the trigger function will not be called and caller
+ * receives NULL tuple as a result. In the case when Before-Row triggers,
+ * it means the current operations on the tuple should be skipped.
+ *
+ * @finfo  : FmgrInfo object for the target function
+ * @tgdata : TriggerData object for the current trigger invokation
+ */
+bool pgaceCallFunctionTrigger(FmgrInfo *finfo, TriggerData *tgdata)
+{
+	return true;
+}
+
+/*
+ * pgaceCallFunctionFastPath() is called just before executing
+ * SQL function in the fast path.
+ *
+ * @finfo  : FmgrInfo object for the target function
+ */
+void pgaceCallFunctionFastPath(FmgrInfo *finfo)
+{
+	/* do nothing */
+}
+
+/*
+ * pgacePreparePlanCheck() is called before foreign key/primary key constraint checks,
+ * at ri_PlanCheck(). PGACE implementation can return its opaque data for any purpose.
+ *
+ * @rel : the target relation in which a constraint is configured
+ */
+Datum pgacePreparePlanCheck(Relation rel)
+{
+	return (Datum) 0;
+}
+
+/*
+ * pgaceRestorePlanCheck() is called after foreign key/primary key constraint checks,
+ * at ri_PlanCheck(). PGACE implementation can use an opaque data generated in the above
+ * pgacePreparePlanCheck().
+ *
+ * @rel         : the target relation in which a constraint is configured
+ * @pgace_saved : an opaque data returned from pgacePreparePlanCheck()
+ */
+void pgaceRestorePlanCheck(Relation rel, Datum pgace_saved)
+{
+	/* do nothing */
+}
+
+/******************************************************************
+ * TABLE related hooks
+ ******************************************************************/
+
+/*
+ * pgaceLockTable() is called when explicit LOCK statement used.
+ *
+ * @relid : the target relation id
+ */
+void pgaceLockTable(Oid relid)
+{
+	/* do nothing */
+}
+
+/******************************************************************
+ * COPY TO/COPY FROM statement hooks
+ ******************************************************************/
+
+/*
+ * pgaceCopyTable() is called when COPY TO/COPY FROM statement is processed
+ *
+ * @rel        : the target relation
+ * @attNumList : the list of attribute numbers
+ * @isFrom     : true, if the given statement is 'COPY FROM'
+ */
+void pgaceCopyTable(Relation rel, List *attNumList, bool isFrom) {
+	/* do nothing */
+}
+
+/*
+ * pgaceCopyToTuple() is called to check whether the given tuple should be
+ * filtered, or not in the process of COPY TO statement.
+ * If it returns false, the given tuple will be filtered from the result set
+ *
+ * @rel        : the target relation
+ * @attNumList : the list of attribute numbers
+ * @tuple      : the target tuple
+ */
+bool pgaceCopyToTuple(Relation rel, List *attNumList, HeapTuple tuple) {
+	return true;
+}
+
+/******************************************************************
+ * Loadable shared library module hooks
+ ******************************************************************/
+
+/*
+ * pgaceLoadSharedModule() is called just before load a shared library
+ * module.
+ *
+ * @filename : full path name of the shared library module
+ */
+void pgaceLoadSharedModule(const char *filename) {
+	/* do nothing */
+}
+
+/******************************************************************
+ * Binary Large Object (BLOB) hooks
+ ******************************************************************/
+
+/*
+ * pgaceLargeObjectGetSecurity() is called when lo_get_security() is executed
+ * It returns its security attribute.
+ *
+ * @tuple : a tuple which is a part of the target largeobject.
+ */
+void pgaceLargeObjectGetSecurity(HeapTuple tuple) {
+	elog(ERROR, "PGACE: There is no guest module.");
+}
+
+/*
+ * pgaceLargeObjectSetSecurity() is called when lo_set_security() is executed
+ *
+ * @tuple       : a tuple which is a part of the target largeobject.
+ * @lo_security : new security attribute specified
+ */
+void pgaceLargeObjectSetSecurity(HeapTuple tuple, Oid lo_security) {
+	elog(ERROR, "PGACE: There is no guest module.");
+}
+
+/*
+ * pgaceLargeObjectCreate() is called when a new large object is created
+ *
+ * @rel   : pg_largeobject relation opened with RowExclusiveLock
+ * @tuple : a new tuple for the new large object
+ */
+void pgaceLargeObjectCreate(Relation rel, HeapTuple tuple) {
+	/* do nothing */
+}
+
+/*
+ * pgaceLargeObjectDrop() is called when a large object is dropped once for
+ * a large object
+ *
+ * @rel   : pg_largeobject relation opened with RowExclusiveLock
+ * @tuple : one of the tuples within the target large object
+ */
+void pgaceLargeObjectDrop(Relation rel, HeapTuple tuple) {
+	/* do nothing */
+}
+
+/*
+ * pgaceLargeObjectRead is called when they read from a large object
+ *
+ * @rel   : pg_largeobject relation opened with AccessShareLock
+ * @tuple : the head tuple within the given large object
+ */
+void pgaceLargeObjectRead(Relation rel, HeapTuple tuple) {
+	/* do nothing */
+}
+
+/*
+ * pgaceLargeObjectWrite() is called when they write to a large object
+ *
+ * @rel    : pg_largeobject relation opened with RowExclusiveLock
+ * @newtup : the head tuple within the given large object
+ * @oldtup : the head tuple in older version, if exist
+ */
+void pgaceLargeObjectWrite(Relation rel, HeapTuple newtup, HeapTuple oldtup) {
+	/* do nothing */
+}
+
+/*
+ * pgaceLargeObjectTruncate() is called when they truncate a large object.
+ *
+ * @rel     : pg_largeobject relation opened with RowExclusiveLock
+ * @loid    : large object identifier
+ * @headtup : the head tuple to be truncated. NULL means this BLOB will be expanded.
+ */
+void pgaceLargeObjectTruncate(Relation rel, Oid loid, HeapTuple headtup) {
+	/* do nothing */
+}
+
+/*
+ * pgaceLargeObjectImport() is called when lo_import() is processed
+ *
+ * @fd : file descriptor to be inported
+ */
+void pgaceLargeObjectImport(int fd) {
+	/* do nothing */
+}
+
+/*
+ * pgaceLargeObjectExport() is called when lo_import() is processed
+ *
+ * @fd   : file descriptor to be exported
+ * @loid : large object to be exported
+ */
+void pgaceLargeObjectExport(int fd, Oid loid) {
+	/* do nothing */
+}
+
+/******************************************************************
+ * Security Label hooks
+ ******************************************************************/
+
+/*
+ * PGACE implementation can use pgaceSecurityLabelIn() hook to translate
+ * a input security label from external representation into internal one.
+ * If no translation is necessary, it has to return @seclabel as is.
+ *
+ * @seclabel : security label being input
+ */
+char *pgaceSecurityLabelIn(char *seclabel)
+{
+	return seclabel;
+}
+
+/*
+ * PGACE implementation can use pgaceSecurityLabelOut() hook to translate
+ * a security label in internal representation into external one.
+ * If no translation is necessary, it has to return @seclabel as is.
+ *
+ * @seclabel : security label being output
+ */
+char *pgaceSecurityLabelOut(char *seclabel)
+{
+	return seclabel;
+}
+
+/*
+ * pgaceSecurityLabelCheckValid() checks whether the @seclabel is valid or not.
+ * In addition, it can returns an alternative security label, if possible.
+ * 
+ * It has to return @seclabel as is, if @seclabel is a valid security label.
+ * It can return an alternative label, if @seclabel is NOT a valid one and
+ * there is an alternative. In any other case, it returns NULL.
+ * @seclabel may be NULL. In this case, @seclabel is always invalid.
+ *
+ * @seclabel : security label to be checked
+ */
+char *pgaceSecurityLabelCheckValid(char *seclabel)
+{
+	return seclabel;
+}
+
+/*
+ * pgaceSecurityLabelOfLabel() returns the security attribute of a newly
+ * generated tuple within pg_security
+ *
+ * @new_label : a text representation of security context which will be newly
+ *              inserted into pg_security.
+ */
+char *pgaceSecurityLabelOfLabel(char *new_label)
+{
+	return pstrdup("unlabeled");
+}
+
+/******************************************************************
+ * Extended node type hooks
+ ******************************************************************/
+
+/*
+ * If PGACE implementation requires new node type, a method to copy object.
+ * pgaceCopyObject() provides a hook to copy new node typed object.
+ * If a given object (@orig) has a tag extended by PGACE implementation,
+ * it have to copy and return it.
+ * If it returns NULL, @orig is not available for the PGACE implementation.
+ *
+ * @orig : a object which to copy
+ */
+Node *pgaceCopyObject(Node *orig)
+{
+	return NULL;
+}
+
+/*
+ * pgaceOutObject() provides a hook to translate a object to text representation.
+ * If a given object (@node) has a tag extended by PGACE implementation, it have
+ * to put a text representation into StringInfo.
+ * If it returns false, @node is not available for the PGACE implementation.
+ *
+ * @str  : StringInfo which to put the text representation
+ * @node : a object that text representation is required
+ */
+bool pgaceOutObject(StringInfo str, Node *node)
+{
+	return false;
+}
+
+/*
+ * pgaceReadObject() provides a hook to read a text representation of an object.
+ * If a given token is a tag extended by PGACE implementation, it have to create
+ * an object same as original one.
+ *
+ * @token : a tag for the object
+ */
+void *pgaceReadObject(char *token)
+{
+	return NULL;
+}
+
+/******************************************************************
+ * Extended functions stub
+ ******************************************************************/
+
+/*
+ * In this section, you can put function stubs when your security
+ * module is not activated.
+ */
diff -rpNU3 base/src/backend/storage/ipc/ipci.c pgace/src/backend/storage/ipc/ipci.c
--- base/src/backend/storage/ipc/ipci.c	2008-03-19 10:33:12.000000000 +0900
+++ pgace/src/backend/storage/ipc/ipci.c	2008-03-19 10:42:28.000000000 +0900
@@ -25,6 +25,7 @@
 #include "postmaster/autovacuum.h"
 #include "postmaster/bgwriter.h"
 #include "postmaster/postmaster.h"
+#include "security/pgace.h"
 #include "storage/freespace.h"
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
@@ -117,6 +118,7 @@ CreateSharedMemoryAndSemaphores(bool mak
 #ifdef EXEC_BACKEND
 		size = add_size(size, ShmemBackendArraySize());
 #endif
+		size = add_size(size, pgaceShmemSize());
 
 		/* freeze the addin request size and include it */
 		addin_request_allowed = false;
diff -rpNU3 base/src/backend/storage/large_object/inv_api.c pgace/src/backend/storage/large_object/inv_api.c
--- base/src/backend/storage/large_object/inv_api.c	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/backend/storage/large_object/inv_api.c	2008-04-21 13:09:57.000000000 +0900
@@ -39,6 +39,7 @@
 #include "catalog/pg_largeobject.h"
 #include "commands/comment.h"
 #include "libpq/libpq-fs.h"
+#include "security/pgace.h"
 #include "storage/large_object.h"
 #include "utils/fmgroids.h"
 #include "utils/resowner.h"
@@ -448,6 +449,10 @@ inv_read(LargeObjectDesc *obj_desc, char
 
 		if (HeapTupleHasNulls(tuple))	/* paranoia */
 			elog(ERROR, "null field found in pg_largeobject");
+
+		if (!nread)
+			pgaceLargeObjectRead(lo_heap_r, tuple);
+
 		data = (Form_pg_largeobject) GETSTRUCT(tuple);
 
 		/*
@@ -636,6 +641,8 @@ inv_write(LargeObjectDesc *obj_desc, con
 			replace[Anum_pg_largeobject_data - 1] = 'r';
 			newtup = heap_modifytuple(oldtuple, RelationGetDescr(lo_heap_r),
 									  values, nulls, replace);
+			if (nwritten - n == 0)
+				pgaceLargeObjectWrite(lo_heap_r, newtup, oldtuple);
 			simple_heap_update(lo_heap_r, &newtup->t_self, newtup);
 			CatalogIndexInsert(indstate, newtup);
 			heap_freetuple(newtup);
@@ -679,6 +686,8 @@ inv_write(LargeObjectDesc *obj_desc, con
 			values[Anum_pg_largeobject_pageno - 1] = Int32GetDatum(pageno);
 			values[Anum_pg_largeobject_data - 1] = PointerGetDatum(&workbuf);
 			newtup = heap_formtuple(lo_heap_r->rd_att, values, nulls);
+			if (nwritten - n == 0)
+				pgaceLargeObjectWrite(lo_heap_r, newtup, NULL);
 			simple_heap_insert(lo_heap_r, newtup);
 			CatalogIndexInsert(indstate, newtup);
 			heap_freetuple(newtup);
@@ -759,6 +768,7 @@ inv_truncate(LargeObjectDesc *obj_desc, 
 		olddata = (Form_pg_largeobject) GETSTRUCT(oldtuple);
 		Assert(olddata->pageno >= pageno);
 	}
+	pgaceLargeObjectTruncate(lo_heap_r, obj_desc->id, oldtuple);
 
 	/*
 	 * If we found the page of the truncation point we need to truncate the
diff -rpNU3 base/src/backend/tcop/fastpath.c pgace/src/backend/tcop/fastpath.c
--- base/src/backend/tcop/fastpath.c	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/backend/tcop/fastpath.c	2008-04-02 08:15:33.000000000 +0900
@@ -26,6 +26,7 @@
 #include "libpq/pqformat.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
+#include "security/pgace.h"
 #include "tcop/fastpath.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
@@ -354,6 +355,8 @@ HandleFunctionRequest(StringInfo msgBuf)
 	 */
 	InitFunctionCallInfoData(fcinfo, &fip->flinfo, 0, NULL, NULL);
 
+	pgaceCallFunctionFastPath(fcinfo.flinfo);
+
 	if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
 		rformat = parse_fcall_arguments(msgBuf, fip, &fcinfo);
 	else
diff -rpNU3 base/src/backend/tcop/postgres.c pgace/src/backend/tcop/postgres.c
--- base/src/backend/tcop/postgres.c	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/backend/tcop/postgres.c	2008-04-21 13:09:57.000000000 +0900
@@ -54,6 +54,7 @@
 #include "parser/parser.h"
 #include "postmaster/autovacuum.h"
 #include "rewrite/rewriteHandler.h"
+#include "security/pgace.h"
 #include "storage/freespace.h"
 #include "storage/ipc.h"
 #include "storage/proc.h"
@@ -631,6 +632,9 @@ pg_rewrite_query(Query *query)
 	{
 		/* don't rewrite utilities, just dump 'em into result list */
 		querytree_list = list_make1(query);
+
+		/* PGACE rewrite utility query, if necessary */
+		querytree_list = pgaceProxyQuery(querytree_list);
 	}
 	else
 	{
diff -rpNU3 base/src/backend/tcop/pquery.c pgace/src/backend/tcop/pquery.c
--- base/src/backend/tcop/pquery.c	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/backend/tcop/pquery.c	2008-04-02 08:15:33.000000000 +0900
@@ -19,6 +19,7 @@
 #include "commands/prepare.h"
 #include "commands/trigger.h"
 #include "miscadmin.h"
+#include "security/pgace.h"
 #include "tcop/pquery.h"
 #include "tcop/tcopprot.h"
 #include "tcop/utility.h"
@@ -456,6 +457,9 @@ PortalStart(Portal portal, ParamListInfo
 	AssertArg(PortalIsValid(portal));
 	AssertState(portal->status == PORTAL_DEFINED);
 
+	/* PGACE: PosrtalStart hook */
+	pgacePortalStart(portal);
+
 	/*
 	 * Set up global portal context pointers.
 	 */
diff -rpNU3 base/src/backend/utils/adt/ri_triggers.c pgace/src/backend/utils/adt/ri_triggers.c
--- base/src/backend/utils/adt/ri_triggers.c	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/backend/utils/adt/ri_triggers.c	2008-04-02 08:15:33.000000000 +0900
@@ -37,6 +37,7 @@
 #include "parser/parse_coerce.h"
 #include "parser/parse_relation.h"
 #include "miscadmin.h"
+#include "security/pgace.h"
 #include "utils/acl.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
@@ -3204,6 +3205,7 @@ ri_PlanCheck(const char *querystr, int n
 	Relation	query_rel;
 	Oid			save_userid;
 	bool		save_secdefcxt;
+	Datum		save_pgace;
 
 	/*
 	 * The query is always run against the FK table except when this is an
@@ -3221,7 +3223,18 @@ ri_PlanCheck(const char *querystr, int n
 	SetUserIdAndContext(RelationGetForm(query_rel)->relowner, true);
 
 	/* Create the plan */
-	qplan = SPI_prepare(querystr, nargs, argtypes);
+	save_pgace = pgacePreparePlanCheck(query_rel);
+	PG_TRY();
+	{
+		qplan = SPI_prepare(querystr, nargs, argtypes);
+	}
+	PG_CATCH();
+	{
+		pgaceRestorePlanCheck(query_rel, save_pgace);
+		PG_RE_THROW();
+	}
+	PG_END_TRY();
+	pgaceRestorePlanCheck(query_rel, save_pgace);
 
 	if (qplan == NULL)
 		elog(ERROR, "SPI_prepare returned %d for %s", SPI_result, querystr);
diff -rpNU3 base/src/backend/utils/cache/syscache.c pgace/src/backend/utils/cache/syscache.c
--- base/src/backend/utils/cache/syscache.c	2008-01-07 23:51:33.000000000 +0900
+++ pgace/src/backend/utils/cache/syscache.c	2008-01-08 01:39:49.000000000 +0900
@@ -39,6 +39,7 @@
 #include "catalog/pg_opfamily.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_rewrite.h"
+#include "catalog/pg_security.h"
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_ts_config.h"
 #include "catalog/pg_ts_config_map.h"
@@ -676,7 +677,31 @@ static const struct cachedesc cacheinfo[
 			0
 		},
 		1024
-	}
+	},
+	{SecurityRelationId,		/*SECURITYOID */
+		SecurityOidIndexId,
+		0,
+		1,
+		{
+			ObjectIdAttributeNumber,
+			0,
+			0,
+			0
+		},
+		128
+	},
+	{SecurityRelationId,		/* SECURITYLABEL */
+		SecuritySeclabelIndexId,
+		0,
+		1,
+		{
+			Anum_pg_security_seclabel,
+			0,
+			0,
+			0
+		},
+		128
+	},
 };
 
 static CatCache *SysCache[
diff -rpNU3 base/src/backend/utils/fmgr/dfmgr.c pgace/src/backend/utils/fmgr/dfmgr.c
--- base/src/backend/utils/fmgr/dfmgr.c	2008-01-07 23:51:33.000000000 +0900
+++ pgace/src/backend/utils/fmgr/dfmgr.c	2008-01-08 01:39:49.000000000 +0900
@@ -22,6 +22,7 @@
 #include "port/dynloader/win32.h"
 #endif
 #include "miscadmin.h"
+#include "security/pgace.h"
 #include "utils/dynamic_loader.h"
 #include "utils/hsearch.h"
 
@@ -73,7 +74,7 @@ char	   *Dynamic_library_path;
 static void *internal_load_library(const char *libname);
 static void internal_unload_library(const char *libname);
 static bool file_exists(const char *name);
-static char *expand_dynamic_library_name(const char *name);
+//static char *expand_dynamic_library_name(const char *name);
 static void check_restricted_library_name(const char *name);
 static char *substitute_libpath_macro(const char *name);
 static char *find_in_dynamic_libpath(const char *basename);
@@ -106,6 +107,9 @@ load_external_function(char *filename, c
 	/* Expand the possibly-abbreviated filename to an exact path name */
 	fullname = expand_dynamic_library_name(filename);
 
+	/* PGACE: check whether the module can be loaded, or not */
+	pgaceLoadSharedModule(fullname);
+
 	/* Load the shared library, unless we already did */
 	lib_handle = internal_load_library(fullname);
 
@@ -146,6 +150,9 @@ load_file(const char *filename, bool res
 	/* Expand the possibly-abbreviated filename to an exact path name */
 	fullname = expand_dynamic_library_name(filename);
 
+	/* PGACE: check whether the module can be loaded, or not */
+	pgaceLoadSharedModule(fullname);
+
 	/* Unload the library if currently loaded */
 	internal_unload_library(fullname);
 
@@ -395,7 +402,7 @@ file_exists(const char *name)
  *
  * The result will always be freshly palloc'd.
  */
-static char *
+char *
 expand_dynamic_library_name(const char *name)
 {
 	bool		have_slash;
diff -rpNU3 base/src/backend/utils/init/postinit.c pgace/src/backend/utils/init/postinit.c
--- base/src/backend/utils/init/postinit.c	2008-04-30 11:09:33.000000000 +0900
+++ pgace/src/backend/utils/init/postinit.c	2008-04-30 11:22:08.000000000 +0900
@@ -32,6 +32,7 @@
 #include "pgstat.h"
 #include "postmaster/autovacuum.h"
 #include "postmaster/postmaster.h"
+#include "security/pgace.h"
 #include "storage/backendid.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
@@ -613,6 +614,9 @@ InitPostgres(const char *in_dbname, Oid 
 	if (!bootstrap)
 		pgstat_bestart();
 
+	/* PGACE: initialize access control extension facility */
+	pgaceInitialize(bootstrap);
+
 	/* close the transaction we started above */
 	if (!bootstrap)
 		CommitTransactionCommand();
diff -rpNU3 base/src/backend/utils/misc/guc.c pgace/src/backend/utils/misc/guc.c
--- base/src/backend/utils/misc/guc.c	2008-04-30 11:09:33.000000000 +0900
+++ pgace/src/backend/utils/misc/guc.c	2008-04-30 11:22:08.000000000 +0900
@@ -55,6 +55,7 @@
 #include "postmaster/syslogger.h"
 #include "postmaster/walwriter.h"
 #include "regex/regex.h"
+#include "security/pgace.h"
 #include "storage/fd.h"
 #include "storage/freespace.h"
 #include "tcop/tcopprot.h"
@@ -344,6 +345,7 @@ static int	max_index_keys;
 static int	max_identifier_length;
 static int	block_size;
 static bool integer_datetimes;
+static char *security_sysattr_name;
 
 /* should be static, but commands/variable.c needs to get at these */
 char	   *role_string;
@@ -2406,6 +2408,20 @@ static struct config_string ConfigureNam
 	},
 #endif   /* USE_SSL */
 
+	{
+		{"security_sysattr_name", PGC_INTERNAL, PRESET_OPTIONS,
+			gettext_noop("Shows the name of security attribute system column"),
+			NULL,
+			GUC_REPORT | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+		},
+		&security_sysattr_name,
+#ifdef SECURITY_SYSATTR_NAME
+		SECURITY_SYSATTR_NAME, NULL, NULL,
+#else
+		"undefined", NULL, NULL,
+#endif
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
@@ -3405,6 +3421,8 @@ ResetAllOptions(void)
 {
 	int			i;
 
+	pgaceSetDatabaseParam("all", NULL);
+
 	for (i = 0; i < num_guc_variables; i++)
 	{
 		struct config_generic *gconf = guc_variables[i];
@@ -5306,6 +5324,7 @@ ExecSetVariableStmt(VariableSetStmt *stm
 	{
 		case VAR_SET_VALUE:
 		case VAR_SET_CURRENT:
+			pgaceSetDatabaseParam(stmt->name, ExtractSetVariableArgs(stmt));
 			set_config_option(stmt->name,
 							  ExtractSetVariableArgs(stmt),
 							  (superuser() ? PGC_SUSET : PGC_USERSET),
@@ -5363,6 +5382,7 @@ ExecSetVariableStmt(VariableSetStmt *stm
 			break;
 		case VAR_SET_DEFAULT:
 		case VAR_RESET:
+			pgaceSetDatabaseParam(stmt->name, NULL);
 			set_config_option(stmt->name,
 							  NULL,
 							  (superuser() ? PGC_SUSET : PGC_USERSET),
@@ -5711,6 +5731,9 @@ EmitWarningsOnPlaceholders(const char *c
 void
 GetPGVariable(const char *name, DestReceiver *dest)
 {
+	/* PGACE: check get param permission */
+	pgaceGetDatabaseParam(name);
+
 	if (guc_name_compare(name, "all") == 0)
 		ShowAllGUCConfig(dest);
 	else
diff -rpNU3 base/src/bin/ipcclean/Makefile pgace/src/bin/ipcclean/Makefile
--- base/src/bin/ipcclean/Makefile	1970-01-01 09:00:00.000000000 +0900
+++ pgace/src/bin/ipcclean/Makefile	2008-01-08 01:39:49.000000000 +0900
@@ -0,0 +1,32 @@
+#-------------------------------------------------------------------------
+#
+# Makefile for src/bin/ipcclean
+#
+# Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+# Portions Copyright (c) 1994, Regents of the University of California
+#
+# $PostgreSQL: pgsql/src/bin/ipcclean/Makefile,v 1.22 2008/01/01 19:45:55 momjian Exp $
+#
+#-------------------------------------------------------------------------
+
+subdir = src/bin/ipcclean
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+all: ipcclean
+
+ipcclean: ipcclean.sh
+	cp $< $@
+	chmod a+x $@
+
+install: all installdirs
+	$(INSTALL_SCRIPT) ipcclean '$(DESTDIR)$(bindir)/ipcclean'
+
+installdirs:
+	$(mkinstalldirs) '$(DESTDIR)$(bindir)'
+
+uninstall:
+	rm -f '$(DESTDIR)$(bindir)/ipcclean'
+
+clean distclean maintainer-clean:
+	rm -f ipcclean
diff -rpNU3 base/src/bin/ipcclean/ipcclean.sh pgace/src/bin/ipcclean/ipcclean.sh
--- base/src/bin/ipcclean/ipcclean.sh	1970-01-01 09:00:00.000000000 +0900
+++ pgace/src/bin/ipcclean/ipcclean.sh	2007-09-11 10:53:53.000000000 +0900
@@ -0,0 +1,116 @@
+#!/bin/sh
+#
+# $PostgreSQL: pgsql/src/bin/ipcclean/ipcclean.sh,v 1.18 2006/03/03 21:52:37 momjian Exp $
+#
+
+CMDNAME=`basename $0`
+
+if [ "$1" = '-?' -o "$1" = "--help" ]; then
+    echo "$CMDNAME cleans up shared memory and semaphores from aborted PostgreSQL"
+    echo "backends."
+    echo
+    echo "Usage:"
+    echo "  $CMDNAME"
+    echo
+    echo "Note: Since the utilities underlying this script are very different"
+    echo "from platform to platform, chances are that it might not work on"
+    echo "yours. If that is the case, please write to <pgsql-bugs@postgresql.org>"
+    echo "so that your platform can be supported in the future."
+    exit 0
+fi
+
+# test for running as root
+
+ISROOT="N"
+if id -u >/dev/null 2>&1
+then	if [ `id -u` -eq 0 ]
+	then	ISROOT="Y"
+	fi
+elif	# only check $LOGNAME if $USER is not set
+	[ "$USER" = 'root' -o \( ! "$USER" -a "$LOGNAME" = 'root' \) ]
+then	ISROOT="Y"
+fi
+
+if [ "$ISROOT" = "Y" ]
+then
+  (
+    echo "$CMDNAME: cannot be run as root" 1>&2
+    echo "Please log in (using, e.g., \"su\") as the (unprivileged) user that" 1>&2
+    echo "owned the server process." 1>&2
+  ) 1>&2
+    exit 1
+fi
+
+EffectiveUser=`id -n -u 2>/dev/null || whoami 2>/dev/null`
+
+#-----------------------------------
+# List of platform-specific hacks
+# Feel free to add yours here.
+#-----------------------------------
+#
+# This is based on RedHat 5.2.
+#
+if [ `uname` = 'Linux' ]; then
+    did_anything=
+
+    if ps x | grep -s '[p]ostmaster' >/dev/null 2>&1 ; then
+        echo "$CMDNAME: a postmaster is still running" 1>&2
+        exit 1
+    fi
+
+    # shared memory
+    for val in `ipcs -m -p | grep '^[0-9]' | awk '{printf "%s:%s:%s\n", $1, $3, $4}'`
+    do
+	save_IFS=$IFS
+	IFS=:
+	set X $val
+	shift
+	IFS=$save_IFS
+	ipcs_shmid=$1
+	ipcs_cpid=$2
+	ipcs_lpid=$3
+
+        # Note: We can do -n here, because we know the platform.
+        echo -n "Shared memory $ipcs_shmid ... "
+
+        # Don't do anything if process still running.
+        # (This check is conceptually phony, but it's
+        # useful anyway in practice.)
+        ps hj $ipcs_cpid $ipcs_lpid >/dev/null 2>&1
+        if [ "$?" -eq 0 ]; then
+            echo "skipped; process still exists (pid $ipcs_cpid or $ipcs_lpid)."
+	    continue
+	fi
+
+        # try remove
+        ipcrm shm $ipcs_shmid
+        if [ "$?" -eq 0 ]; then
+            did_anything=t
+        else
+            exit
+        fi
+    done
+
+    # semaphores
+    for val in `ipcs -s -c | grep '^[0-9]' | awk '{printf "%s\n", $1}'`; do
+        echo -n "Semaphore $val ... "
+        # try remove
+        ipcrm sem $val
+        if [ "$?" -eq 0 ]; then
+            did_anything=t
+        else
+            exit
+        fi
+    done
+
+    [ -z "$did_anything" ] && echo "$CMDNAME: nothing removed" && exit 1
+    exit 0
+fi # end Linux
+
+
+# This is the original implementation. It seems to work
+# on FreeBSD, SunOS/Solaris, HP-UX, IRIX, and probably
+# some others.
+
+ipcs | egrep '^m .*|^s .*' | egrep "$EffectiveUser" | \
+awk '{printf "ipcrm -%s %s\n", $1, $2}' '-' | sh
diff -rpNU3 base/src/include/access/htup.h pgace/src/include/access/htup.h
--- base/src/include/access/htup.h	2008-01-07 23:51:33.000000000 +0900
+++ pgace/src/include/access/htup.h	2008-01-10 12:42:25.000000000 +0900
@@ -161,7 +161,7 @@ typedef HeapTupleHeaderData *HeapTupleHe
 #define HEAP_HASVARWIDTH		0x0002	/* has variable-width attribute(s) */
 #define HEAP_HASEXTERNAL		0x0004	/* has external stored attribute(s) */
 #define HEAP_HASOID				0x0008	/* has an object-id field */
-/* bit 0x0010 is available */
+#define HEAP_HASSECURITY		0x0010	/* has an security attribute field */
 #define HEAP_COMBOCID			0x0020	/* t_cid is a combo cid */
 #define HEAP_XMAX_EXCL_LOCK		0x0040	/* xmax is exclusive locker */
 #define HEAP_XMAX_SHARED_LOCK	0x0080	/* xmax is shared locker */
@@ -347,6 +347,28 @@ do { \
 	(tup)->t_infomask2 = ((tup)->t_infomask2 & ~HEAP_NATTS_MASK) | (natts) \
 )
 
+#define HeapTupleHeaderGetSecurity(tup)									\
+	(																	\
+		((tup)->t_infomask & HEAP_HASSECURITY)							\
+		? (*((Oid *)((char *)(tup) + (tup)->t_hoff						\
+					 - (((tup)->t_infomask & HEAP_HASOID) ? sizeof(Oid) : 0) \
+					 - sizeof(Oid))))									\
+		: InvalidOid													\
+	)
+
+#define HeapTupleHeaderSetSecurity(tup, security)						\
+	do {																\
+		Assert((tup)->t_infomask & HEAP_HASSECURITY);					\
+		*((Oid *)((char *)(tup) + (tup)->t_hoff							\
+				  - (((tup)->t_infomask & HEAP_HASOID) ? sizeof(Oid) : 0) \
+				  - sizeof(Oid))) = (security);							\
+	} while(0)
+
+#define HeapTupleGetSecurity(tuple)				\
+	HeapTupleHeaderGetSecurity((tuple)->t_data)
+
+#define HeapTupleSetSecurity(tuple, security)	\
+	HeapTupleHeaderSetSecurity((tuple)->t_data, (security))
 
 /*
  * BITMAPLEN(NATTS) -
@@ -402,7 +424,12 @@ do { \
 #define MaxTransactionIdAttributeNumber			(-5)
 #define MaxCommandIdAttributeNumber				(-6)
 #define TableOidAttributeNumber					(-7)
+#ifdef SECURITY_SYSATTR_NAME
+#define SecurityAttributeNumber					(-8)
+#define FirstLowInvalidHeapAttributeNumber		(-9)
+#else
 #define FirstLowInvalidHeapAttributeNumber		(-8)
+#endif
 
 
 /*
diff -rpNU3 base/src/include/catalog/heap.h pgace/src/include/catalog/heap.h
--- base/src/include/catalog/heap.h	2008-01-07 23:51:33.000000000 +0900
+++ pgace/src/include/catalog/heap.h	2008-01-08 01:39:49.000000000 +0900
@@ -52,7 +52,8 @@ extern Oid heap_create_with_catalog(cons
 						 int oidinhcount,
 						 OnCommitAction oncommit,
 						 Datum reloptions,
-						 bool allow_system_table_mods);
+						 bool allow_system_table_mods,
+						 List *pgace_attr_list);
 
 extern void heap_drop_with_catalog(Oid relid);
 
@@ -65,7 +66,8 @@ extern List *heap_truncate_find_FKs(List
 extern void InsertPgClassTuple(Relation pg_class_desc,
 				   Relation new_rel_desc,
 				   Oid new_rel_oid,
-				   Datum reloptions);
+				   Datum reloptions,
+				   List *pgace_attr_list);
 
 extern List *AddRelationRawConstraints(Relation rel,
 						  List *rawColDefaults,
diff -rpNU3 base/src/include/catalog/indexing.h pgace/src/include/catalog/indexing.h
--- base/src/include/catalog/indexing.h	2008-01-07 23:51:33.000000000 +0900
+++ pgace/src/include/catalog/indexing.h	2008-01-08 01:39:49.000000000 +0900
@@ -252,6 +252,11 @@ DECLARE_UNIQUE_INDEX(pg_type_oid_index, 
 DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index, 2704, on pg_type using btree(typname name_ops, typnamespace oid_ops));
 #define TypeNameNspIndexId	2704
 
+DECLARE_UNIQUE_INDEX(pg_security_oid_index, 3401, on pg_security using btree(oid oid_ops));
+#define SecurityOidIndexId	3401
+DECLARE_UNIQUE_INDEX(pg_security_seclabel_index, 3402, on pg_security using btree(seclabel text_ops));
+#define SecuritySeclabelIndexId	3402
+
 /* last step of initialization script: build the indexes declared above */
 BUILD_INDICES
 
diff -rpNU3 base/src/include/catalog/pg_attribute.h pgace/src/include/catalog/pg_attribute.h
--- base/src/include/catalog/pg_attribute.h	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/include/catalog/pg_attribute.h	2008-04-21 13:09:57.000000000 +0900
@@ -277,6 +277,7 @@ DATA(insert ( 1247 cmin				29 0  4  -4 0
 DATA(insert ( 1247 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1247 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1247 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0));
+DATA(insert ( 1247 SECURITY_SYSATTR_NAME 3403 0  4  -8 0 -1 -1 t p i t f f t 0));
 
 /* ----------------
  *		pg_proc
@@ -333,6 +334,7 @@ DATA(insert ( 1255 cmin				29 0  4  -4 0
 DATA(insert ( 1255 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1255 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1255 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0));
+DATA(insert ( 1255 SECURITY_SYSATTR_NAME 3403 0 4 -8 0 -1 -1 t p i t f f t 0));
 
 /* ----------------
  *		pg_attribute
@@ -381,6 +383,7 @@ DATA(insert ( 1249 cmin				29 0  4  -4 0
 DATA(insert ( 1249 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1249 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1249 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0));
+DATA(insert ( 1249 SECURITY_SYSATTR_NAME 3403 0 4 -8 0 -1 -1 t p i t f f t 0));
 
 /* ----------------
  *		pg_class
@@ -449,6 +452,7 @@ DATA(insert ( 1259 cmin				29 0  4  -4 0
 DATA(insert ( 1259 xmax				28 0  4  -5 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1259 cmax				29 0  4  -6 0 -1 -1 t p i t f f t 0));
 DATA(insert ( 1259 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0));
+DATA(insert ( 1259 SECURITY_SYSATTR_NAME 3403 0 4 -8 0 -1 -1 t p i t f f t 0));
 
 /* ----------------
  *		pg_index
diff -rpNU3 base/src/include/catalog/pg_cast.h pgace/src/include/catalog/pg_cast.h
--- base/src/include/catalog/pg_cast.h	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/include/catalog/pg_cast.h	2008-04-02 08:15:33.000000000 +0900
@@ -338,4 +338,10 @@ DATA(insert ( 1560 1560 1685 i ));
 DATA(insert ( 1562 1562 1687 i ));
 DATA(insert ( 1700 1700 1703 i ));
 
+/*
+ * Security Label to/from text representation
+ */
+DATA(insert (25 3403 3408 i));
+DATA(insert (3403 25 3409 i));
+
 #endif   /* PG_CAST_H */
diff -rpNU3 base/src/include/catalog/pg_proc.h pgace/src/include/catalog/pg_proc.h
--- base/src/include/catalog/pg_proc.h	2008-04-30 11:09:33.000000000 +0900
+++ pgace/src/include/catalog/pg_proc.h	2008-04-30 11:22:08.000000000 +0900
@@ -4127,6 +4127,16 @@ DESCR("I/O");
 DATA(insert OID = 2963 (  uuid_hash		   PGNSP PGUID 12 1 0 f f t f i 1 23 "2950" _null_ _null_ _null_ uuid_hash - _null_ _null_ ));
 DESCR("hash");
 
+/* PostgreSQL Access Control Extension related functions */
+DATA(insert OID = 3404 ( security_label_in		PGNSP PGUID 12 1 0 f f t f i 1 3403 "2275"  _null_ _null_ _null_ security_label_in      - _null_ _null_ ));
+DATA(insert OID = 3405 ( security_label_out		PGNSP PGUID 12 1 0 f f t f i 1 2275 "3403"  _null_ _null_ _null_ security_label_out     - _null_ _null_ ));
+DATA(insert OID = 3406 ( security_label_raw_in		PGNSP PGUID 12 1 0 f f t f i 1 3403 "2275"  _null_ _null_ _null_ security_label_raw_in  - _null_ _null_ ));
+DATA(insert OID = 3407 ( security_label_raw_out		PGNSP PGUID 12 1 0 f f t f i 1 2275 "3403"  _null_ _null_ _null_ security_label_raw_out - _null_ _null_ ));
+DATA(insert OID = 3408 ( text_to_security_label		PGNSP PGUID 12 1 0 f f t f i 1 3403 "25"    _null_ _null_ _null_ text_to_security_label - _null_ _null_ ));
+DATA(insert OID = 3409 ( security_label_to_text		PGNSP PGUID 12 1 0 f f t f i 1 25 "3403"    _null_ _null_ _null_ security_label_to_text - _null_ _null_ ));
+DATA(insert OID = 3410 ( lo_get_security		PGNSP PGUID 12 1 0 f f t f v 1 3403 "26"    _null_ _null_ _null_ lo_get_security        - _null_ _null_ ));
+DATA(insert OID = 3411 ( lo_set_security		PGNSP PGUID 12 1 0 f f t f v 2 16 "26 3403" _null_ _null_ _null_ lo_set_security        - _null_ _null_ ));
+
 /* enum related procs */
 DATA(insert OID = 3504 (  anyenum_in	PGNSP PGUID 12 1 0 f f t f i 1 3500 "2275" _null_ _null_ _null_ anyenum_in - _null_ _null_ ));
 DESCR("I/O");
diff -rpNU3 base/src/include/catalog/pg_proc_fn.h pgace/src/include/catalog/pg_proc_fn.h
--- base/src/include/catalog/pg_proc_fn.h	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/include/catalog/pg_proc_fn.h	2008-04-02 14:11:37.000000000 +0900
@@ -33,7 +33,8 @@ extern Oid ProcedureCreate(const char *p
 				Datum parameterNames,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows);
+				float4 prorows,
+				void *pgaceItem);
 
 extern bool function_parse_error_transpose(const char *prosrc);
 
diff -rpNU3 base/src/include/catalog/pg_security.h pgace/src/include/catalog/pg_security.h
--- base/src/include/catalog/pg_security.h	1970-01-01 09:00:00.000000000 +0900
+++ pgace/src/include/catalog/pg_security.h	2007-09-21 01:08:03.000000000 +0900
@@ -0,0 +1,31 @@
+/*
+ * src/include/catalog/pg_security.h
+ *    Definition of the security label relation (pg_security)
+ *
+ * Copyright (c) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
+ */
+#ifndef PG_SECURITY_H
+#define PG_SECURITY_H
+
+#define SecurityRelationId		3400
+
+CATALOG(pg_security,3400) BKI_SHARED_RELATION
+{
+	text		seclabel;		/* text representation of security label */
+} FormData_pg_security;
+
+/* ----------------
+ *     Form_pg_security corresponds to a pointer to a tuple with
+ *     the format of pg_security relation.
+ * ----------------
+ */
+typedef FormData_pg_security *Form_pg_security;
+
+/* ----------------
+ *		compiler constants for pg_selinux
+ * ----------------
+ */
+#define Natts_pg_security				1
+#define Anum_pg_security_seclabel		1
+
+#endif   /* PG_SELINUX_H */
diff -rpNU3 base/src/include/catalog/pg_type.h pgace/src/include/catalog/pg_type.h
--- base/src/include/catalog/pg_type.h	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/include/catalog/pg_type.h	2008-04-21 13:09:57.000000000 +0900
@@ -604,6 +604,9 @@ DATA(insert OID = 2283 ( anyelement		PGN
 #define ANYELEMENTOID	2283
 DATA(insert OID = 2776 ( anynonarray	PGNSP PGUID  4 t p t \054 0 0 0 anynonarray_in anynonarray_out - - - - - i p f 0 -1 0 _null_ _null_ ));
 #define ANYNONARRAYOID	2776
+DATA(insert OID = 3403 ( security_label PGNSP PGUID  4 t b t \054 0 0 0 security_label_in security_label_out - - - - - i p f 0 -1 0 _null_ _null_ ));
+DESCR("Security Label Identifier for PGACE");
+#define SECLABELOID		3403
 DATA(insert OID = 3500 ( anyenum		PGNSP PGUID  4 t p t \054 0 0 0 anyenum_in anyenum_out - - - - - i p f 0 -1 0 _null_ _null_ ));
 #define ANYENUMOID		3500
 
diff -rpNU3 base/src/include/executor/tuptable.h pgace/src/include/executor/tuptable.h
--- base/src/include/executor/tuptable.h	2008-01-07 23:51:33.000000000 +0900
+++ pgace/src/include/executor/tuptable.h	2008-01-08 01:39:49.000000000 +0900
@@ -118,6 +118,7 @@ typedef struct TupleTableSlot
 	MinimalTuple tts_mintuple;	/* set if it's a minimal tuple, else NULL */
 	HeapTupleData tts_minhdr;	/* workspace if it's a minimal tuple */
 	long		tts_off;		/* saved state for slot_deform_tuple */
+	Oid			tts_security;	/* pgace security system attribute */
 } TupleTableSlot;
 
 /*
@@ -139,6 +140,12 @@ typedef TupleTableData *TupleTable;
 #define TupIsNull(slot) \
 	((slot) == NULL || (slot)->tts_isempty)
 
+/*
+ * PGACE: HeapTupleStoreSecurityFromSlot
+ */
+#define HeapTupleStoreSecurityFromSlot(tuple, slot)		\
+	HeapTupleSetSecurity((tuple), (slot)->tts_security)
+
 /* in executor/execTuples.c */
 extern TupleTable ExecCreateTupleTable(int tableSize);
 extern void ExecDropTupleTable(TupleTable table, bool shouldFree);
diff -rpNU3 base/src/include/fmgr.h pgace/src/include/fmgr.h
--- base/src/include/fmgr.h	2008-04-21 12:55:32.000000000 +0900
+++ pgace/src/include/fmgr.h	2008-04-21 13:09:57.000000000 +0900
@@ -52,6 +52,9 @@ typedef struct FmgrInfo
 	void	   *fn_extra;		/* extra space for use by handler */
 	MemoryContext fn_mcxt;		/* memory context to store fn_extra in */
 	fmNodePtr	fn_expr;		/* expression parse tree for call, or NULL */
+
+	PGFunction	fn_pgace_addr;	/* PGACE opaque addr field */
+	Datum		fn_pgace_data;	/* PGACE opaque data field */
 } FmgrInfo;
 
 /*
@@ -518,6 +521,7 @@ extern Oid	get_call_expr_argtype(fmNodeP
  */
 extern char *Dynamic_library_path;
 
+extern char *expand_dynamic_library_name(const char *name);
 extern PGFunction load_external_function(char *filename, char *funcname,
 					   bool signalNotFound, void **filehandle);
 extern PGFunction lookup_external_function(void *filehandle, char *funcname);
diff -rpNU3 base/src/include/libpq/be-fsstubs.h pgace/src/include/libpq/be-fsstubs.h
--- base/src/include/libpq/be-fsstubs.h	2008-04-01 23:58:53.000000000 +0900
+++ pgace/src/include/libpq/be-fsstubs.h	2008-04-02 08:15:33.000000000 +0900
@@ -37,6 +37,9 @@ extern Datum lo_tell(PG_FUNCTION_ARGS);
 extern Datum lo_unlink(PG_FUNCTION_ARGS);
 extern Datum lo_truncate(PG_FUNCTION_ARGS);
 
+extern Datum lo_get_security(PG_FUNCTION_ARGS);
+extern Datum lo_set_security(PG_FUNCTION_ARGS);
+
 /*
  * These are not fmgr-callable, but are available to C code.
  * Probably these should have had the underscore-free names,
diff -rpNU3 base/src/include/nodes/parsenodes.h pgace/src/include/nodes/parsenodes.h
--- base/src/include/nodes/parsenodes.h	2008-04-30 11:09:33.000000000 +0900
+++ pgace/src/include/nodes/parsenodes.h	2008-04-30 11:22:08.000000000 +0900
@@ -131,6 +131,7 @@ typedef struct Query
 
 	Node	   *setOperations;	/* set-operation tree if this is top level of
 								 * a UNION/INTERSECT/EXCEPT query */
+	Node	   *pgaceItem;		/* PGACE: an opaque item for security purpose */
 } Query;
 
 
@@ -392,6 +393,7 @@ typedef struct ColumnDef
 	Node	   *