*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.166 2009/02/25 03:30:37 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.167 2009/03/05 17:30:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/heapam.h"
+#include "access/sysattr.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
Relation newrelation,
Index newvarno,
List **translated_vars);
+static Bitmapset *translate_col_privs(const Bitmapset *parent_privs,
+ List *translated_vars);
static Node *adjust_appendrel_attrs_mutator(Node *node,
AppendRelInfo *context);
static Relids adjust_relid_set(Relids relids, Index oldrelid, Index newrelid);
appinfo->parent_reloid = parentOID;
appinfos = lappend(appinfos, appinfo);
+ /*
+ * Translate the column permissions bitmaps to the child's attnums
+ * (we have to build the translated_vars list before we can do this).
+ * But if this is the parent table, leave copyObject's result alone.
+ */
+ if (childOID != parentOID)
+ {
+ childrte->selectedCols = translate_col_privs(rte->selectedCols,
+ appinfo->translated_vars);
+ childrte->modifiedCols = translate_col_privs(rte->modifiedCols,
+ appinfo->translated_vars);
+ }
+
/*
* Build a RowMarkClause if parent is marked FOR UPDATE/SHARE.
*/
*translated_vars = vars;
}
+/*
+ * translate_col_privs
+ * Translate a bitmapset representing per-column privileges from the
+ * parent rel's attribute numbering to the child's.
+ *
+ * The only surprise here is that we don't translate a parent whole-row
+ * reference into a child whole-row reference. That would mean requiring
+ * permissions on all child columns, which is overly strict, since the
+ * query is really only going to reference the inherited columns. Instead
+ * we set the per-column bits for all inherited columns.
+ */
+static Bitmapset *
+translate_col_privs(const Bitmapset *parent_privs,
+ List *translated_vars)
+{
+ Bitmapset *child_privs = NULL;
+ bool whole_row;
+ int attno;
+ ListCell *lc;
+
+ /* System attributes have the same numbers in all tables */
+ for (attno = FirstLowInvalidHeapAttributeNumber+1; attno < 0; attno++)
+ {
+ if (bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
+ parent_privs))
+ child_privs = bms_add_member(child_privs,
+ attno - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ /* Check if parent has whole-row reference */
+ whole_row = bms_is_member(InvalidAttrNumber - FirstLowInvalidHeapAttributeNumber,
+ parent_privs);
+
+ /* And now translate the regular user attributes, using the vars list */
+ attno = InvalidAttrNumber;
+ foreach(lc, translated_vars)
+ {
+ Var *var = (Var *) lfirst(lc);
+
+ attno++;
+ if (var == NULL) /* ignore dropped columns */
+ continue;
+ Assert(IsA(var, Var));
+ if (whole_row ||
+ bms_is_member(attno - FirstLowInvalidHeapAttributeNumber,
+ parent_privs))
+ child_privs = bms_add_member(child_privs,
+ var->varattno - FirstLowInvalidHeapAttributeNumber);
+ }
+
+ return child_privs;
+}
+
/*
* adjust_appendrel_attrs
* Copy the specified query or expression and translate Vars referring
DELETE FROM atest5 WHERE one = 1; -- fail
ERROR: permission denied for relation atest5
DELETE FROM atest5 WHERE two = 2; -- ok
+-- check inheritance cases
+SET SESSION AUTHORIZATION regressuser1;
+CREATE TABLE atestp1 (f1 int, f2 int) WITH OIDS;
+CREATE TABLE atestp2 (fx int, fy int) WITH OIDS;
+CREATE TABLE atestc (fz int) INHERITS (atestp1, atestp2);
+GRANT SELECT(fx,fy,oid) ON atestp2 TO regressuser2;
+GRANT SELECT(fx) ON atestc TO regressuser2;
+SET SESSION AUTHORIZATION regressuser2;
+SELECT fx FROM atestp2; -- ok
+ fx
+----
+(0 rows)
+
+SELECT fy FROM atestp2; -- fail, no privilege on atestc.fy
+ERROR: permission denied for relation atestc
+SELECT atestp2 FROM atestp2; -- fail, no privilege on atestc.fy
+ERROR: permission denied for relation atestc
+SELECT oid FROM atestp2; -- fail, no privilege on atestc.oid
+ERROR: permission denied for relation atestc
+SET SESSION AUTHORIZATION regressuser1;
+GRANT SELECT(fy,oid) ON atestc TO regressuser2;
+SET SESSION AUTHORIZATION regressuser2;
+SELECT fx FROM atestp2; -- still ok
+ fx
+----
+(0 rows)
+
+SELECT fy FROM atestp2; -- ok
+ fy
+----
+(0 rows)
+
+SELECT atestp2 FROM atestp2; -- ok
+ atestp2
+---------
+(0 rows)
+
+SELECT oid FROM atestp2; -- ok
+ oid
+-----
+(0 rows)
+
-- privileges on functions, languages
-- switch to superuser
\c -
DROP TABLE atest4;
DROP TABLE atest5;
DROP TABLE atest6;
+DROP TABLE atestc;
+DROP TABLE atestp1;
+DROP TABLE atestp2;
DROP GROUP regressgroup1;
DROP GROUP regressgroup2;
REVOKE USAGE ON LANGUAGE sql FROM regressuser1;
DELETE FROM atest5 WHERE one = 1; -- fail
DELETE FROM atest5 WHERE two = 2; -- ok
+-- check inheritance cases
+SET SESSION AUTHORIZATION regressuser1;
+CREATE TABLE atestp1 (f1 int, f2 int) WITH OIDS;
+CREATE TABLE atestp2 (fx int, fy int) WITH OIDS;
+CREATE TABLE atestc (fz int) INHERITS (atestp1, atestp2);
+GRANT SELECT(fx,fy,oid) ON atestp2 TO regressuser2;
+GRANT SELECT(fx) ON atestc TO regressuser2;
+
+SET SESSION AUTHORIZATION regressuser2;
+SELECT fx FROM atestp2; -- ok
+SELECT fy FROM atestp2; -- fail, no privilege on atestc.fy
+SELECT atestp2 FROM atestp2; -- fail, no privilege on atestc.fy
+SELECT oid FROM atestp2; -- fail, no privilege on atestc.oid
+
+SET SESSION AUTHORIZATION regressuser1;
+GRANT SELECT(fy,oid) ON atestc TO regressuser2;
+
+SET SESSION AUTHORIZATION regressuser2;
+SELECT fx FROM atestp2; -- still ok
+SELECT fy FROM atestp2; -- ok
+SELECT atestp2 FROM atestp2; -- ok
+SELECT oid FROM atestp2; -- ok
+
-- privileges on functions, languages
-- switch to superuser
DROP TABLE atest4;
DROP TABLE atest5;
DROP TABLE atest6;
+DROP TABLE atestc;
+DROP TABLE atestp1;
+DROP TABLE atestp2;
DROP GROUP regressgroup1;
DROP GROUP regressgroup2;