>From ad60419074deef9f3d057e395ff08375afd9eeaa Mon Sep 17 00:00:00 2001 From: Craig Ringer Date: Mon, 20 Jan 2014 13:07:50 +0800 Subject: [PATCH 02/10] RLS: add pg_rowsecurity catalog --- doc/src/sgml/catalogs.sgml | 65 +++++++ src/backend/catalog/Makefile | 4 +- src/backend/catalog/dependency.c | 8 + src/backend/catalog/heap.c | 1 + src/backend/catalog/objectaddress.c | 50 +++++ src/backend/catalog/pg_rowsecurity.c | 287 +++++++++++++++++++++++++++++ src/backend/utils/cache/relcache.c | 17 +- src/include/catalog/dependency.h | 1 + src/include/catalog/indexing.h | 5 + src/include/catalog/pg_class.h | 25 +-- src/include/catalog/pg_rowsecurity.h | 74 ++++++++ src/include/parser/parse_node.h | 3 +- src/include/utils/rel.h | 2 + src/test/regress/expected/sanity_check.out | 1 + 14 files changed, 528 insertions(+), 15 deletions(-) create mode 100644 src/backend/catalog/pg_rowsecurity.c create mode 100644 src/include/catalog/pg_rowsecurity.h diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 2230c93..1ca088a 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -234,6 +234,11 @@ + pg_rowsecuritylevelsec + row-level security policy of relation + + + pg_seclabel security labels on database objects @@ -1876,6 +1881,16 @@ + relhasrowsecurity + bool + + + True if table has row-security policy; see + pg_rowsecurity catalog + + + + relhassubclass bool @@ -5157,6 +5172,56 @@ + + <structname>pg_rowsecurity</structname> + + + pg_rowsecurity + + + The catalog pg_rowsecurity stores expression + tree of row-security policy to be performed on a particular relation. + + + <structname>pg_rowsecurity</structname> Columns + + + + Name + Type + References + Description + + + + + rsecrelid + oid + pg_class.oid + The table this row-security is for + + + rseccmd + char + + The command this row-security is for. 'a' meaning all is only possible value right now. + + + rsecqual + pg_node_tree + + An expression tree to be performed as row-security policy + + + +
+ + + pg_class.relhasrowsecurity + must be true if a table has row-security policy in this catalog. + + +
<structname>pg_seclabel</structname> diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index a974bd5..beb73df 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -15,7 +15,7 @@ OBJS = catalog.o dependency.o heap.o index.o indexing.o namespace.o aclchk.o \ pg_constraint.o pg_conversion.o \ pg_depend.o pg_enum.o pg_inherits.o pg_largeobject.o pg_namespace.o \ pg_operator.o pg_proc.o pg_range.o pg_db_role_setting.o pg_shdepend.o \ - pg_type.o storage.o toasting.o + pg_rowsecurity.o pg_type.o storage.o toasting.o BKIFILES = postgres.bki postgres.description postgres.shdescription @@ -39,7 +39,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\ pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ pg_ts_parser.h pg_ts_template.h pg_extension.h \ pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \ - pg_foreign_table.h \ + pg_foreign_table.h pg_rowsecurity.h \ pg_default_acl.h pg_seclabel.h pg_shseclabel.h pg_collation.h pg_range.h \ toasting.h indexing.h \ ) diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index e511669..8f95b14 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -45,6 +45,7 @@ #include "catalog/pg_opfamily.h" #include "catalog/pg_proc.h" #include "catalog/pg_rewrite.h" +#include "catalog/pg_rowsecurity.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" #include "catalog/pg_ts_config.h" @@ -1249,6 +1250,10 @@ doDeletion(const ObjectAddress *object, int flags) RemoveEventTriggerById(object->objectId); break; + case OCLASS_ROWSECURITY: + RemoveRowSecurityById(object->objectId); + break; + default: elog(ERROR, "unrecognized object class: %u", object->classId); @@ -2316,6 +2321,9 @@ getObjectClass(const ObjectAddress *object) case EventTriggerRelationId: return OCLASS_EVENT_TRIGGER; + + case RowSecurityRelationId: + return OCLASS_ROWSECURITY; } /* shouldn't get here */ diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 2cf4bc0..5be195b 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -799,6 +799,7 @@ InsertPgClassTuple(Relation pg_class_desc, values[Anum_pg_class_relhaspkey - 1] = BoolGetDatum(rd_rel->relhaspkey); values[Anum_pg_class_relhasrules - 1] = BoolGetDatum(rd_rel->relhasrules); values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers); + values[Anum_pg_class_relhasrowsecurity - 1] = BoolGetDatum(rd_rel->relhasrowsecurity); values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass); values[Anum_pg_class_relispopulated - 1] = BoolGetDatum(rd_rel->relispopulated); values[Anum_pg_class_relreplident - 1] = CharGetDatum(rd_rel->relreplident); diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index 991c02a..870e477 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -2143,6 +2143,56 @@ getObjectDescription(const ObjectAddress *object) break; } + case OCLASS_ROWSECURITY: + { + Relation rsec_rel; + ScanKeyData skey; + SysScanDesc sscan; + HeapTuple tuple; + Form_pg_rowsecurity form_rsec; + + rsec_rel = heap_open(RowSecurityRelationId, AccessShareLock); + + ScanKeyInit(&skey, + ObjectIdAttributeNumber, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(object->objectId)); + sscan = systable_beginscan(rsec_rel, RowSecurityOidIndexId, + true, NULL, 1, &skey); + tuple = systable_getnext(sscan); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "could not find tuple for row-security %u", + object->objectId); + form_rsec = (Form_pg_rowsecurity) GETSTRUCT(tuple); + + appendStringInfo(&buffer, _("row-security of ")); + getRelationDescription(&buffer, form_rsec->rsecrelid); + switch (form_rsec->rseccmd) + { + case ROWSECURITY_CMD_ALL: + appendStringInfo(&buffer, _(" FOR ALL")); + break; + case ROWSECURITY_CMD_SELECT: + appendStringInfo(&buffer, _(" FOR SELECT")); + break; + case ROWSECURITY_CMD_INSERT: + appendStringInfo(&buffer, _(" FOR INSERT")); + break; + case ROWSECURITY_CMD_UPDATE: + appendStringInfo(&buffer, _(" FOR UPDATE")); + break; + case ROWSECURITY_CMD_DELETE: + appendStringInfo(&buffer, _(" FOR DELETE")); + break; + default: + elog(ERROR, "unexpected row-security command type: %c", + form_rsec->rseccmd); + } + systable_endscan(sscan); + heap_close(rsec_rel, AccessShareLock); + break; + } + default: appendStringInfo(&buffer, "unrecognized object %u %u %d", object->classId, diff --git a/src/backend/catalog/pg_rowsecurity.c b/src/backend/catalog/pg_rowsecurity.c new file mode 100644 index 0000000..7ee4e88 --- /dev/null +++ b/src/backend/catalog/pg_rowsecurity.c @@ -0,0 +1,287 @@ +/* ------------------------------------------------------------------------- + * + * pg_rowsecurity.c + * routines to support manipulation of the pg_rowsecurity catalog + * + * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * ------------------------------------------------------------------------- + */ +#include "postgres.h" +#include "access/genam.h" +#include "access/heapam.h" +#include "access/htup_details.h" +#include "access/sysattr.h" +#include "catalog/dependency.h" +#include "catalog/indexing.h" +#include "catalog/pg_class.h" +#include "catalog/pg_rowsecurity.h" +#include "catalog/pg_type.h" +#include "nodes/nodeFuncs.h" +#include "optimizer/clauses.h" +#include "parser/parse_clause.h" +#include "parser/parse_node.h" +#include "parser/parse_relation.h" +#include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/inval.h" +#include "utils/rel.h" +#include "utils/syscache.h" +#include "utils/tqual.h" + +/* + * Load row-security policy from the catalog, and keep it on + * the relation cache. + */ +void +RelationBuildRowSecurity(Relation relation) +{ + Relation catalog; + ScanKeyData skey; + SysScanDesc sscan; + HeapTuple tuple; + MemoryContext oldcxt; + MemoryContext rscxt = NULL; + RowSecurityDesc *rsdesc = NULL; + + catalog = heap_open(RowSecurityRelationId, AccessShareLock); + + ScanKeyInit(&skey, + Anum_pg_rowsecurity_rsecrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(relation))); + sscan = systable_beginscan(catalog, RowSecurityRelidIndexId, true, + NULL, 1, &skey); + PG_TRY(); + { + while (HeapTupleIsValid(tuple = systable_getnext(sscan))) + { + Datum value; + bool isnull; + char *temp; + + if (!rsdesc) + { + rscxt = AllocSetContextCreate(CacheMemoryContext, + "Row-security descriptor", + ALLOCSET_SMALL_MINSIZE, + ALLOCSET_SMALL_INITSIZE, + ALLOCSET_SMALL_MAXSIZE); + oldcxt = MemoryContextSwitchTo(rscxt); + rsdesc = palloc0(sizeof(RowSecurityDesc)); + rsdesc->rscxt = rscxt; + MemoryContextSwitchTo(oldcxt); + } + value = heap_getattr(tuple, Anum_pg_rowsecurity_rseccmd, + RelationGetDescr(catalog), &isnull); + Assert(!isnull); + + if (DatumGetChar(value) != ROWSECURITY_CMD_ALL) + { + ereport(WARNING, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Per-command row-security not implemented"))); + continue; + } + + value = heap_getattr(tuple, Anum_pg_rowsecurity_rsecqual, + RelationGetDescr(catalog), &isnull); + Assert(!isnull); + temp = TextDatumGetCString(value); + + oldcxt = MemoryContextSwitchTo(rscxt); + rsdesc->rsall.rsecid = HeapTupleGetOid(tuple); + rsdesc->rsall.qual = (Expr *) stringToNode(temp); + Assert(exprType((Node *)rsdesc->rsall.qual) == BOOLOID); + rsdesc->rsall.hassublinks + = contain_subplans((Node *)rsdesc->rsall.qual); + MemoryContextSwitchTo(oldcxt); + + pfree(temp); + } + } + PG_CATCH(); + { + if (rscxt != NULL) + MemoryContextDelete(rscxt); + PG_RE_THROW(); + } + PG_END_TRY(); + + systable_endscan(sscan); + heap_close(catalog, AccessShareLock); + + relation->rsdesc = rsdesc; +} + +/* + * Parse the supplied row-security policy, and insert/update a row + * of pg_rowsecurity catalog. + */ +static void +InsertOrUpdatePolicyRow(Relation relation, char rseccmd, Node *clause) +{ + Oid relationId = RelationGetRelid(relation); + Oid rowsecId; + ParseState *pstate; + RangeTblEntry *rte; + Node *qual; + Relation catalog; + ScanKeyData skeys[2]; + SysScanDesc sscan; + HeapTuple oldtup; + HeapTuple newtup; + Datum values[Natts_pg_rowsecurity]; + bool isnull[Natts_pg_rowsecurity]; + bool replaces[Natts_pg_rowsecurity]; + ObjectAddress target; + ObjectAddress myself; + + /* Parse the supplied clause */ + pstate = make_parsestate(NULL); + + rte = addRangeTableEntryForRelation(pstate, relation, + NULL, false, false); + addRTEtoQuery(pstate, rte, false, true, true); + + qual = transformWhereClause(pstate, copyObject(clause), + EXPR_KIND_ROW_SECURITY, + "ROW SECURITY"); + /* zero-clear */ + memset(values, 0, sizeof(values)); + memset(replaces, 0, sizeof(replaces)); + memset(isnull, 0, sizeof(isnull)); + + /* Update or Insert an entry to pg_rowsecurity catalog */ + catalog = heap_open(RowSecurityRelationId, RowExclusiveLock); + + ScanKeyInit(&skeys[0], + Anum_pg_rowsecurity_rsecrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationGetRelid(relation))); + ScanKeyInit(&skeys[1], + Anum_pg_rowsecurity_rseccmd, + BTEqualStrategyNumber, F_CHAREQ, + CharGetDatum(rseccmd)); + sscan = systable_beginscan(catalog, RowSecurityRelidIndexId, true, + NULL, 2, skeys); + oldtup = systable_getnext(sscan); + if (HeapTupleIsValid(oldtup)) + { + rowsecId = HeapTupleGetOid(oldtup); + + replaces[Anum_pg_rowsecurity_rsecqual - 1] = true; + values[Anum_pg_rowsecurity_rsecqual - 1] + = CStringGetTextDatum(nodeToString(qual)); + + newtup = heap_modify_tuple(oldtup, + RelationGetDescr(catalog), + values, isnull, replaces); + simple_heap_update(catalog, &newtup->t_self, newtup); + + deleteDependencyRecordsFor(RowSecurityRelationId, rowsecId, false); + } + else + { + values[Anum_pg_rowsecurity_rsecrelid - 1] + = ObjectIdGetDatum(relationId); + values[Anum_pg_rowsecurity_rseccmd - 1] + = CharGetDatum(rseccmd); + values[Anum_pg_rowsecurity_rsecqual - 1] + = CStringGetTextDatum(nodeToString(qual)); + newtup = heap_form_tuple(RelationGetDescr(catalog), + values, isnull); + rowsecId = simple_heap_insert(catalog, newtup); + } + CatalogUpdateIndexes(catalog, newtup); + + heap_freetuple(newtup); + + /* records dependencies of row-security policy and relation/columns */ + target.classId = RelationRelationId; + target.objectId = relationId; + target.objectSubId = 0; + + myself.classId = RowSecurityRelationId; + myself.objectId = rowsecId; + myself.objectSubId = 0; + + recordDependencyOn(&myself, &target, DEPENDENCY_AUTO); + + recordDependencyOnExpr(&myself, qual, pstate->p_rtable, + DEPENDENCY_NORMAL); + free_parsestate(pstate); + + systable_endscan(sscan); + heap_close(catalog, RowExclusiveLock); +} + +/* + * Remove row-security policy row of pg_rowsecurity + */ +static void +DeletePolicyRow(Relation relation, char rseccmd) +{ + Assert(rseccmd == ROWSECURITY_CMD_ALL); + + if (relation->rsdesc) + { + ObjectAddress address; + + address.classId = RowSecurityRelationId; + address.objectId = relation->rsdesc->rsall.rsecid; + address.objectSubId = 0; + + performDeletion(&address, DROP_RESTRICT, 0); + } + else + { + /* Nothing to do here */ + elog(INFO, "relation %s has no row-security policy, skipped", + RelationGetRelationName(relation)); + } +} + +/* + * Guts of row-security policy deletion. + */ +void +RemoveRowSecurityById(Oid rowsecId) +{ + Relation catalog; + ScanKeyData skey; + SysScanDesc sscan; + HeapTuple tuple; + Relation rel; + Oid relid; + + catalog = heap_open(RowSecurityRelationId, RowExclusiveLock); + + ScanKeyInit(&skey, + ObjectIdAttributeNumber, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(rowsecId)); + sscan = systable_beginscan(catalog, RowSecurityOidIndexId, true, + NULL, 1, &skey); + tuple = systable_getnext(sscan); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "could not find tuple for row-security %u", rowsecId); + + /* + * Open and exclusive-lock the relation the row-security belongs to. + */ + relid = ((Form_pg_rowsecurity) GETSTRUCT(tuple))->rsecrelid; + + rel = heap_open(relid, AccessExclusiveLock); + + simple_heap_delete(catalog, &tuple->t_self); + + /* Ensure relcache entries of other session being rebuilt */ + CacheInvalidateRelcache(rel); + + heap_close(rel, NoLock); + + systable_endscan(sscan); + heap_close(catalog, RowExclusiveLock); +} diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 2a46cfc..8ee5353 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -50,6 +50,7 @@ #include "catalog/pg_opclass.h" #include "catalog/pg_proc.h" #include "catalog/pg_rewrite.h" +#include "catalog/pg_rowsecurity.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" @@ -932,6 +933,11 @@ RelationBuildDesc(Oid targetRelId, bool insertIt) else relation->trigdesc = NULL; + if (relation->rd_rel->relhasrowsecurity) + RelationBuildRowSecurity(relation); + else + relation->rsdesc = NULL; + /* * if it's an index, initialize index-related information */ @@ -1840,6 +1846,8 @@ RelationDestroyRelation(Relation relation) MemoryContextDelete(relation->rd_indexcxt); if (relation->rd_rulescxt) MemoryContextDelete(relation->rd_rulescxt); + if (relation->rsdesc) + MemoryContextDelete(relation->rsdesc->rscxt); if (relation->rd_fdwroutine) pfree(relation->rd_fdwroutine); pfree(relation); @@ -3166,7 +3174,13 @@ RelationCacheInitializePhase3(void) relation->rd_rel->relhastriggers = false; restart = true; } - + if (relation->rd_rel->relhasrowsecurity && relation->rsdesc == NULL) + { + RelationBuildRowSecurity(relation); + if (relation->rsdesc == NULL) + relation->rd_rel->relhasrowsecurity = false; + restart = true; + } /* Release hold on the relation */ RelationDecrementReferenceCount(relation); @@ -4478,6 +4492,7 @@ load_relcache_init_file(bool shared) rel->rd_rules = NULL; rel->rd_rulescxt = NULL; rel->trigdesc = NULL; + rel->rsdesc = NULL; rel->rd_indexprs = NIL; rel->rd_indpred = NIL; rel->rd_exclops = NULL; diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 8948589..de9323e 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -147,6 +147,7 @@ typedef enum ObjectClass OCLASS_DEFACL, /* pg_default_acl */ OCLASS_EXTENSION, /* pg_extension */ OCLASS_EVENT_TRIGGER, /* pg_event_trigger */ + OCLASS_ROWSECURITY, /* pg_rowsecurity */ MAX_OCLASS /* MUST BE LAST */ } ObjectClass; diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 0515b75..4f46c5d 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -313,6 +313,11 @@ DECLARE_UNIQUE_INDEX(pg_extension_name_index, 3081, on pg_extension using btree( DECLARE_UNIQUE_INDEX(pg_range_rngtypid_index, 3542, on pg_range using btree(rngtypid oid_ops)); #define RangeTypidIndexId 3542 +DECLARE_UNIQUE_INDEX(pg_rowsecurity_oid_index, 5001, on pg_rowsecurity using btree(oid oid_ops)); +#define RowSecurityOidIndexId 5001 +DECLARE_UNIQUE_INDEX(pg_rowsecurity_relid_index, 5002, on pg_rowsecurity using btree(rsecrelid oid_ops, rseccmd char_ops)); +#define RowSecurityRelidIndexId 5002 + /* last step of initialization script: build the indexes declared above */ BUILD_INDICES diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index f2fb317..bbbf62d 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -65,6 +65,7 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83) BKI_SCHEMA_MACRO bool relhasrules; /* has (or has had) any rules */ bool relhastriggers; /* has (or has had) any TRIGGERs */ bool relhassubclass; /* has (or has had) derived classes */ + bool relhasrowsecurity; /* has (or has had) row-security policy */ bool relispopulated; /* matview currently holds query results */ char relreplident; /* see REPLICA_IDENTITY_xxx constants */ TransactionId relfrozenxid; /* all Xids < this are frozen in this rel */ @@ -94,7 +95,7 @@ typedef FormData_pg_class *Form_pg_class; * ---------------- */ -#define Natts_pg_class 29 +#define Natts_pg_class 30 #define Anum_pg_class_relname 1 #define Anum_pg_class_relnamespace 2 #define Anum_pg_class_reltype 3 @@ -118,12 +119,13 @@ typedef FormData_pg_class *Form_pg_class; #define Anum_pg_class_relhasrules 21 #define Anum_pg_class_relhastriggers 22 #define Anum_pg_class_relhassubclass 23 -#define Anum_pg_class_relispopulated 24 -#define Anum_pg_class_relreplident 25 -#define Anum_pg_class_relfrozenxid 26 -#define Anum_pg_class_relminmxid 27 -#define Anum_pg_class_relacl 28 -#define Anum_pg_class_reloptions 29 +#define Anum_pg_class_relhasrowsecurity 24 +#define Anum_pg_class_relispopulated 25 +#define Anum_pg_class_relreplident 26 +#define Anum_pg_class_relfrozenxid 27 +#define Anum_pg_class_relminmxid 28 +#define Anum_pg_class_relacl 29 +#define Anum_pg_class_reloptions 30 /* ---------------- * initial contents of pg_class @@ -138,13 +140,14 @@ typedef FormData_pg_class *Form_pg_class; * Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId; * similarly, "1" in relminmxid stands for FirstMultiXactId */ -DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 30 0 t f f f f t n 3 1 _null_ _null_ )); + +DATA(insert OID = 1247 ( pg_type PGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 30 0 t f f f f f t n 3 1 _null_ _null_ )); DESCR(""); -DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 21 0 f f f f f t n 3 1 _null_ _null_ )); +DATA(insert OID = 1249 ( pg_attribute PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 21 0 f f f f f f t n 3 1 _null_ _null_ )); DESCR(""); -DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 27 0 t f f f f t n 3 1 _null_ _null_ )); +DATA(insert OID = 1255 ( pg_proc PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 27 0 t f f f f f t n 3 1 _null_ _null_ )); DESCR(""); -DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 29 0 t f f f f t n 3 1 _null_ _null_ )); +DATA(insert OID = 1259 ( pg_class PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 30 0 t f f f f f t n 3 1 _null_ _null_ )); DESCR(""); diff --git a/src/include/catalog/pg_rowsecurity.h b/src/include/catalog/pg_rowsecurity.h new file mode 100644 index 0000000..10aed9a --- /dev/null +++ b/src/include/catalog/pg_rowsecurity.h @@ -0,0 +1,74 @@ +/* + * pg_rowsecurity.h + * definition of the system catalog for row-security policy (pg_rowsecurity) + * + * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + */ +#ifndef PG_ROWSECURITY_H +#define PG_ROWSECURITY_H + +#include "catalog/genbki.h" +#include "nodes/primnodes.h" +#include "utils/memutils.h" +#include "utils/relcache.h" + +/* ---------------- + * pg_rowlevelsec definition. cpp turns this into + * typedef struct FormData_pg_rowlevelsec + * ---------------- + */ +#define RowSecurityRelationId 5000 + +CATALOG(pg_rowsecurity,5000) +{ + /* Oid of the relation that has row-security policy */ + Oid rsecrelid; + + /* One of ROWSECURITY_CMD_* below */ + char rseccmd; +#ifdef CATALOG_VARLEN + pg_node_tree rsecqual; +#endif +} FormData_pg_rowsecurity; + +/* ---------------- + * Form_pg_rowlevelsec corresponds to a pointer to a row with + * the format of pg_rowlevelsec relation. + * ---------------- + */ +typedef FormData_pg_rowsecurity *Form_pg_rowsecurity; + +/* ---------------- + * compiler constants for pg_rowlevelsec + * ---------------- + */ +#define Natts_pg_rowsecurity 3 +#define Anum_pg_rowsecurity_rsecrelid 1 +#define Anum_pg_rowsecurity_rseccmd 2 +#define Anum_pg_rowsecurity_rsecqual 3 + +#define ROWSECURITY_CMD_ALL 'a' +#define ROWSECURITY_CMD_SELECT 's' +#define ROWSECURITY_CMD_INSERT 'i' +#define ROWSECURITY_CMD_UPDATE 'u' +#define ROWSECURITY_CMD_DELETE 'd' + +typedef struct +{ + Oid rsecid; + Expr *qual; + bool hassublinks; +} RowSecurityEntry; + +typedef struct +{ + MemoryContext rscxt; + RowSecurityEntry rsall; /* row-security policy for ALL */ +} RowSecurityDesc; + +extern void RelationBuildRowSecurity(Relation relation); +extern void RemoveRowSecurityById(Oid relationId); + +#endif /* PG_ROWSECURITY_H */ diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h index 85598e8..9c7c382 100644 --- a/src/include/parser/parse_node.h +++ b/src/include/parser/parse_node.h @@ -63,7 +63,8 @@ typedef enum ParseExprKind EXPR_KIND_INDEX_PREDICATE, /* index predicate */ EXPR_KIND_ALTER_COL_TRANSFORM, /* transform expr in ALTER COLUMN TYPE */ EXPR_KIND_EXECUTE_PARAMETER, /* parameter value in EXECUTE */ - EXPR_KIND_TRIGGER_WHEN /* WHEN condition in CREATE TRIGGER */ + EXPR_KIND_TRIGGER_WHEN, /* WHEN condition in CREATE TRIGGER */ + EXPR_KIND_ROW_SECURITY /* ROW SECURITY policy for a table */ } ParseExprKind; diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 9b8a4c9..83a8d03 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -18,6 +18,7 @@ #include "catalog/pg_am.h" #include "catalog/pg_class.h" #include "catalog/pg_index.h" +#include "catalog/pg_rowsecurity.h" #include "fmgr.h" #include "nodes/bitmapset.h" #include "rewrite/prs2lock.h" @@ -110,6 +111,7 @@ typedef struct RelationData RuleLock *rd_rules; /* rewrite rules */ MemoryContext rd_rulescxt; /* private memory cxt for rd_rules, if any */ TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */ + RowSecurityDesc *rsdesc; /* Row-security policy, or NULL */ /* * The index chosen as the relation's replication identity or diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index a62a3e3..a41344b 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -121,6 +121,7 @@ pg_pltemplate|t pg_proc|t pg_range|t pg_rewrite|t +pg_rowsecurity|t pg_seclabel|t pg_shdepend|t pg_shdescription|t -- 1.8.3.1