You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ka...@apache.org on 2013/11/13 11:49:58 UTC

svn commit: r1541461 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/compile/ testing/org/apache/derbyTesting/functionTests/tests/lang/

Author: kahatlen
Date: Wed Nov 13 10:49:57 2013
New Revision: 1541461

URL: http://svn.apache.org/r1541461
Log:
DERBY-6411: Minimal select privilege should be checked in subqueries

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CompilerContextImpl.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CursorNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GrantRevokeDDLTest.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CompilerContextImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CompilerContextImpl.java?rev=1541461&r1=1541460&r2=1541461&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CompilerContextImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CompilerContextImpl.java Wed Nov 13 10:49:57 2013
@@ -745,18 +745,18 @@ public class CompilerContextImpl extends
 
 		//DERBY-4191
 		if( currPrivType == Authorizer.MIN_SELECT_PRIV){
-			//If we are here for MIN_SELECT_PRIV requirement, then first
-			//check if there is already a SELECT privilege requirement on any 
-			//of the columns in the table. If yes, then we do not need to add 
-			//MIN_SELECT_PRIV requirement for the table because that 
-			//requirement is already getting satisfied with the already
-			//existing SELECT privilege requirement
+            // If we are here for MIN_SELECT_PRIV requirement, then first
+            // check if there is already a SELECT privilege requirement on any
+            // of the columns in the table, or on the table itself. If yes,
+            // then we do not need to add MIN_SELECT_PRIV requirement for the
+            // table because that requirement is already getting satisfied with
+            // the already existing SELECT privilege requirement.
 			StatementTablePermission key = new StatementTablePermission( 
 					tableUUID, Authorizer.SELECT_PRIV);
-			StatementColumnPermission tableColumnPrivileges
-			  = requiredColumnPrivileges.get( key);
-			if( tableColumnPrivileges != null)
+            if (requiredColumnPrivileges.containsKey(key) ||
+                    requiredTablePrivileges.containsKey(key)) {
 				return;
+            }
 		}
 		if( currPrivType == Authorizer.SELECT_PRIV){
 			//If we are here for SELECT_PRIV requirement, then first check
@@ -766,10 +766,7 @@ public class CompilerContextImpl extends
 			//that, remove the MIN_SELECT_PRIV privilege requirement
 			StatementTablePermission key = new StatementTablePermission( 
 					tableUUID, Authorizer.MIN_SELECT_PRIV);
-			StatementColumnPermission tableColumnPrivileges
-			  = requiredColumnPrivileges.get( key);
-			if( tableColumnPrivileges != null)
-				requiredColumnPrivileges.remove(key);
+            requiredColumnPrivileges.remove(key);
 		}
 		
 		StatementTablePermission key = new StatementTablePermission( tableUUID, currPrivType);
@@ -808,10 +805,7 @@ public class CompilerContextImpl extends
 			//that, remove the MIN_SELECT_PRIV privilege requirement
 			StatementTablePermission key = new StatementTablePermission( 
 					table.getUUID(), Authorizer.MIN_SELECT_PRIV);
-			StatementColumnPermission tableColumnPrivileges
-			  = requiredColumnPrivileges.get( key);
-			if( tableColumnPrivileges != null)
-				requiredColumnPrivileges.remove(key);
+            requiredColumnPrivileges.remove(key);
 		}
 
 		StatementTablePermission key = new StatementTablePermission( table.getUUID(), currPrivType);

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CursorNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CursorNode.java?rev=1541461&r1=1541460&r2=1541461&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CursorNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CursorNode.java Wed Nov 13 10:49:57 2013
@@ -290,24 +290,15 @@ public class CursorNode extends DMLState
 							+ fromList.size()
 							+ " on return from RS.bindExpressions()");
 			}
-			
-			//DERBY-4191 Make sure that we have minimum select privilege on 
-			//each of the tables in the query.
-			getCompilerContext().pushCurrentPrivType(Authorizer.MIN_SELECT_PRIV);
-			FromList resultSetFromList = resultSet.getFromList();
-			for (int index = 0; index < resultSetFromList.size(); index++) {
-                Object fromTable = resultSetFromList.elementAt(index);
-                if (fromTable instanceof FromBaseTable) {
-                    collectTablePrivsAndStats((FromBaseTable)fromTable);
-                }
-            }
-			getCompilerContext().popCurrentPrivType();
 		}
 		finally
 		{
 			getCompilerContext().popCurrentPrivType();
 		}
 
+        // Collect tables whose indexes we'll want to check for staleness.
+        collectTablesWithPossiblyStaleStats();
+
 		// bind the order by
 		if (orderByList != null)
 		{
@@ -397,39 +388,30 @@ public class CursorNode extends DMLState
 	}
 
     /**
-     * Collects required privileges for all types of tables, and table
-     * descriptors for base tables whose index statistics we want to check for
-     * staleness (or to create).
-     *
-     * @param fromTable the table
+     * Collects table descriptors for base tables whose index statistics we
+     * want to check for staleness (or to create).
      */
-    private void collectTablePrivsAndStats(FromBaseTable fromTable) {
-        TableDescriptor td = fromTable.getTableDescriptor();
-        if (fromTable.isPrivilegeCollectionRequired()) {
-            // We ask for MIN_SELECT_PRIV requirement of the first column in
-            // the table. The first column is just a place holder. What we
-            // really do at execution time when we see we are looking for
-            // MIN_SELECT_PRIV privilege is as follows:
-            //
-            // 1) We will look for SELECT privilege at table level.
-            // 2) If not found, we will look for SELECT privilege on
-            //    ANY column, not necessarily the first column. But since
-            //    the constructor for column privilege requires us to pass
-            //    a column descriptor, we just choose the first column for
-            //    MIN_SELECT_PRIV requirement.
-            getCompilerContext().addRequiredColumnPriv(
-                    td.getColumnDescriptor(1));
+    private void collectTablesWithPossiblyStaleStats() throws StandardException {
+        if (!checkIndexStats) {
+            return;
         }
+
         // Save a list of base tables to check the index statistics for at a
         // later time. We want to compute statistics for base user tables only,
         // not for instance system tables or VTIs (see TableDescriptor for a
         // list of all available "table types").
-        if (checkIndexStats &&
-                td.getTableType() == TableDescriptor.BASE_TABLE_TYPE) {
-            if (statsToUpdate == null) {
-                statsToUpdate = new ArrayList<TableDescriptor>();
+        FromList fromList = resultSet.getFromList();
+        for (int i = 0; i < fromList.size(); i++) {
+            FromTable fromTable = (FromTable) fromList.elementAt(i);
+            if (fromTable.isBaseTable()) {
+                TableDescriptor td = fromTable.getTableDescriptor();
+                if (td.getTableType() == TableDescriptor.BASE_TABLE_TYPE) {
+                    if (statsToUpdate == null) {
+                        statsToUpdate = new ArrayList<TableDescriptor>();
+                    }
+                    statsToUpdate.add(td);
+                }
             }
-            statsToUpdate.add(td);
         }
     }
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java?rev=1541461&r1=1541460&r2=1541461&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java Wed Nov 13 10:49:57 2013
@@ -27,10 +27,12 @@ import java.util.Properties;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.SQLState;
 import org.apache.derby.iapi.services.context.ContextManager;
+import org.apache.derby.iapi.sql.compile.CompilerContext;
 import org.apache.derby.shared.common.sanity.SanityManager;
 import org.apache.derby.iapi.sql.compile.Optimizable;
 import org.apache.derby.iapi.sql.compile.OptimizableList;
 import org.apache.derby.iapi.sql.compile.Optimizer;
+import org.apache.derby.iapi.sql.conn.Authorizer;
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
 import org.apache.derby.iapi.util.JBitSet;
 import org.apache.derby.iapi.util.ReuseFactory;
@@ -355,6 +357,34 @@ class FromList extends    QueryTreeNodeV
 				referencesSessionSchema = true;
 			setElementAt(newNode, index);
 		}
+
+        // DERBY-4191: We must have some SELECT privilege on every table
+        // that we read from, even if we don't actually read any column
+        // values from it (for example if we do SELECT COUNT(*) FROM T).
+        // We ask for MIN_SELECT_PRIV requirement of the first column in
+        // the table. The first column is just a place holder. What we
+        // really do at execution time when we see we are looking for
+        // MIN_SELECT_PRIV privilege is as follows:
+        //
+        // 1) We will look for SELECT privilege at table level.
+        // 2) If not found, we will look for SELECT privilege on
+        //    ANY column, not necessarily the first column. But since
+        //    the constructor for column privilege requires us to pass
+        //    a column descriptor, we just choose the first column for
+        //    MIN_SELECT_PRIV requirement.
+        final CompilerContext cc = getCompilerContext();
+        cc.pushCurrentPrivType(Authorizer.MIN_SELECT_PRIV);
+        for (int index = 0; index < size; index++) {
+            fromTable = (FromTable) elementAt(index);
+            if (fromTable.isPrivilegeCollectionRequired() &&
+                    fromTable.isBaseTable() && !fromTable.forUpdate()) {
+                // This is a base table in the FROM list of a SELECT statement.
+                // Make sure we check for minimum SELECT privilege on it.
+                cc.addRequiredColumnPriv(
+                    fromTable.getTableDescriptor().getColumnDescriptor(1));
+            }
+        }
+        cc.popCurrentPrivType();
 	}
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java?rev=1541461&r1=1541460&r2=1541461&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java Wed Nov 13 10:49:57 2013
@@ -107,7 +107,7 @@ public abstract class QueryTreeNode impl
 	 * and then it is turned off while we process the query underlying the view
 	 * v1.             
 	 */
-	boolean isPrivilegeCollectionRequired = true;
+    private boolean isPrivilegeCollectionRequired = true;
 
     QueryTreeNode(ContextManager cm) {
         this.cm = cm;

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GrantRevokeDDLTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GrantRevokeDDLTest.java?rev=1541461&r1=1541460&r2=1541461&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GrantRevokeDDLTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GrantRevokeDDLTest.java Wed Nov 13 10:49:57 2013
@@ -10172,12 +10172,36 @@ public final class GrantRevokeDDLTest ex
         user2St.execute("update user1.t4191_table3 "+
         		"set c31 = ( select 1 from user1.view_t4191_table3 )");
 
-        //none of following selects will work because there is no select
-        //privilege available to user2 yet.
-        assertStatementError("42500", user2St, "select count(*) from user1.t4191");
-        assertStatementError("42500", user2St, "select count(1) from user1.t4191");
+        // None of following selects will work because there is no select
+        // privilege available to user2 yet. Each row in the array contains
+        // a statement and the expected results or update count if the
+        // minimum select privilege had been granted.
+        Object[][] requireMinimumSelectPrivilege = {
+            { "select count(*) from user1.t4191",          new String[][] {{"0"}} },
+            { "select count(1) from user1.t4191",          new String[][] {{"0"}} },
+            { "select 1 from user1.t4191",                 new String[0][] },
+            { "select 1 from user1.t4191 for update",      new String[0][] },
+            { "select 1 from user1.t4191 union values 2",  new String[][] {{"2"}} },
+            { "values 1 union select 1 from user1.t4191",  new String[][] {{"1"}} },
+            { "values (select count(*) from user1.t4191)", new String[][] {{"0"}} },
+            { "values (select count(1) from user1.t4191)", new String[][] {{"0"}} },
+            { "values ((select 1 from user1.t4191))",      new String[][] {{null}} },
+            // DERBY-6408: Next two queries should have returned FALSE.
+            { "values exists(select 1 from user1.t4191)",  new String[][] {{null}} },
+            { "values exists(select * from user1.t4191)",  new String[][] {{null}} },
+            { "select count(*) from (select 1 from user1.t4191) s", new String[][] {{"0"}} },
+            { "insert into user1.t4191_table3 select 1, 2 from user1.t4191", new Integer(0) },
+            { "update user1.t4191_table3 set c31 = 1 where exists (select * from user1.t4191)", new Integer(0) },
+            { "delete from user1.t4191_table3 where exists (select * from user1.t4191)", new Integer(0) },
+        };
+
+        for (int i = 0; i < requireMinimumSelectPrivilege.length; i++) {
+            String sql = (String) requireMinimumSelectPrivilege[i][0];
+            assertStatementError("42500", user2St, sql);
+        }
+
+        // Should fail because there is no select privilege on column Y.
         assertStatementError("42502", user2St, "select count(y) from user1.t4191");
-        assertStatementError("42500", user2St, "select 1 from user1.t4191");
         //update below should fail because user2 does not have update 
         //privileges on user1.t4191
         assertStatementError("42502", user2St, "update user1.t4191 set x=0");
@@ -10187,19 +10211,22 @@ public final class GrantRevokeDDLTest ex
         assertStatementError("42502", user2St, "update user1.t4191 set x=" +
 		" ( select z from user1.t4191_table2 )");
 
-        //grant select on user1.t4191(x) to user2 and now the above select 
-        //statements will work
+        // Grant select on user1.t4191(x) to user2 and now the above
+        // statements, which previously failed because they didn't have
+        // the minimum select privilege on the table, will work.
         user1St.execute("grant select(x) on t4191 to user2");
-        String[][] expRS = new String [][]
-                              {
-                                  {"0"}
-                              };
-        rs = user2St.executeQuery("select count(*) from user1.t4191");
-        JDBC.assertFullResultSet(rs, expRS, true);
-        rs = user2St.executeQuery("select count(1) from user1.t4191");
-        JDBC.assertFullResultSet(rs, expRS, true);
-        rs = user2St.executeQuery("select 1 from user1.t4191");
-        JDBC.assertEmpty(rs);
+
+        for (int i = 0; i < requireMinimumSelectPrivilege.length; i++) {
+            String sql = (String) requireMinimumSelectPrivilege[i][0];
+            Object expectedResult = requireMinimumSelectPrivilege[i][1];
+            if (expectedResult instanceof Integer) {
+                assertUpdateCount(
+                    user2St, ((Integer) expectedResult).intValue(), sql);
+            } else {
+                JDBC.assertFullResultSet(user2St.executeQuery(sql),
+                                         (String[][]) expectedResult);
+            }
+        }
 
         //user2 does not have select privilege on 2nd column from user1.t4191
         assertStatementError("42502", user2St, "select count(y) from user1.t4191");
@@ -10272,13 +10299,13 @@ public final class GrantRevokeDDLTest ex
         //following queries will still work because there is still a 
         //select privilege on user1.t4191 available to user2
         rs = user2St.executeQuery("select count(*) from user1.t4191");
-        JDBC.assertFullResultSet(rs, expRS, true);
+        JDBC.assertSingleValueResultSet(rs, "0");
         rs = user2St.executeQuery("select count(1) from user1.t4191");
-        JDBC.assertFullResultSet(rs, expRS, true);
+        JDBC.assertSingleValueResultSet(rs, "0");
         rs = user2St.executeQuery("select 1 from user1.t4191");
         JDBC.assertEmpty(rs);
         rs = user2St.executeQuery("select count(y) from user1.t4191");
-        JDBC.assertFullResultSet(rs, expRS, true);
+        JDBC.assertSingleValueResultSet(rs, "0");
         //grant select privilege on user1.t4191(x) back to user2 so following
         //update can succeed
         user1St.execute("grant select(x) on t4191 to user2");