Skip to content

Commit

Permalink
MONDRIAN: Fix bug 1888821, "Non Empty Crossjoin fails to enforce role…
Browse files Browse the repository at this point in the history
… access".

    Fix DrillThroughTest (Derby strangely lists columns in the ORDER BY clause as result columns).

[git-p4: depot-paths = "//open/mondrian/": change = 10748]
  • Loading branch information
julianhyde committed Mar 22, 2008
1 parent 1fbbfae commit c9d5e41
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 66 deletions.
74 changes: 60 additions & 14 deletions src/main/mondrian/rolap/RolapNativeSet.java
Expand Up @@ -92,11 +92,13 @@ public void addConstraint(SqlQuery sqlQuery, RolapCube baseCube) {
}

/**
* returns null to prevent the member/childern from being cached. There exists
* no valid MemberChildrenConstraint that would fetch those children that were
* extracted as a side effect from evaluating a non empty crossjoin
* Returns null to prevent the member/childern from being cached. There
* exists no valid MemberChildrenConstraint that would fetch those
* children that were extracted as a side effect from evaluating a non
* empty crossjoin
*/
public MemberChildrenConstraint getMemberChildrenConstraint(RolapMember parent) {
public MemberChildrenConstraint getMemberChildrenConstraint(
RolapMember parent) {
return null;
}

Expand Down Expand Up @@ -614,7 +616,11 @@ public void addConstraint(SqlQuery sqlQuery, RolapCube baseCube) {
* @return an {@link CrossJoinArg} instance describing the Descendants
* function, or null if <code>fun</code> represents something else.
*/
protected CrossJoinArg checkDescendants(FunDef fun, Exp[] args) {
protected CrossJoinArg checkDescendants(
Role role,
FunDef fun,
Exp[] args)
{
if (!"Descendants".equalsIgnoreCase(fun.getName())) {
return null;
}
Expand All @@ -635,6 +641,17 @@ protected CrossJoinArg checkDescendants(FunDef fun, Exp[] args) {
if (!isSimpleLevel(level)) {
return null;
}
// Descendants of a member in an access-controlled hierarchy cannot be
// converted to SQL. (We could be smarter; we don't currently notice
// when the member is in a part of the hierarchy that is not
// access-controlled.)
final Access access = role.getAccess(level.getHierarchy());
switch (access) {
case ALL:
break;
default:
return null;
}
return new DescendantsCrossJoinArg(level, member);
}

Expand All @@ -644,7 +661,11 @@ protected CrossJoinArg checkDescendants(FunDef fun, Exp[] args) {
* @return an {@link CrossJoinArg} instance describing the Level.members
* function, or null if <code>fun</code> represents something else.
*/
protected CrossJoinArg checkLevelMembers(FunDef fun, Exp[] args) {
protected CrossJoinArg checkLevelMembers(
Role role,
FunDef fun,
Exp[] args)
{
if (!"Members".equalsIgnoreCase(fun.getName())) {
return null;
}
Expand All @@ -658,6 +679,17 @@ protected CrossJoinArg checkLevelMembers(FunDef fun, Exp[] args) {
if (!isSimpleLevel(level)) {
return null;
}
// Members of a level in an access-controlled hierarchy cannot be
// converted to SQL. (We could be smarter; we don't currently notice
// when the level is in a part of the hierarchy that is not
// access-controlled.)
final Access access = role.getAccess(level.getHierarchy());
switch (access) {
case ALL:
break;
default:
return null;
}
return new DescendantsCrossJoinArg(level, null);
}

Expand All @@ -667,17 +699,19 @@ protected CrossJoinArg checkLevelMembers(FunDef fun, Exp[] args) {
* @return an {@link CrossJoinArg} instance describing the member.children
* function, or null if <code>fun</code> represents something else.
*/
protected CrossJoinArg checkMemberChildren(FunDef fun, Exp[] args) {
protected CrossJoinArg checkMemberChildren(
Role role,
FunDef fun,
Exp[] args)
{
if (!"Children".equalsIgnoreCase(fun.getName())) {
return null;
}
if (args.length != 1) {
return null;
}

/*
* Note: <Dimension>.Children is not recognized as a native expression.
*/

// Note: <Dimension>.Children is not recognized as a native expression.
if (!(args[0] instanceof MemberExpr)) {
return null;
}
Expand All @@ -691,6 +725,17 @@ protected CrossJoinArg checkMemberChildren(FunDef fun, Exp[] args) {
// no child level
return null;
}
// Children of a member in an access-controlled hierarchy cannot be
// converted to SQL. (We could be smarter; we don't currently notice
// when the member is in a part of the hierarchy that is not
// access-controlled.)
final Access access = role.getAccess(level.getHierarchy());
switch (access) {
case ALL:
break;
default:
return null;
}
return new DescendantsCrossJoinArg(level, member);
}

Expand Down Expand Up @@ -796,16 +841,17 @@ protected CrossJoinArg[] checkCrossJoinArg(
FunDef fun = funCall.getFunDef();
Exp[] args = funCall.getArgs();

final Role role = evaluator.getSchemaReader().getRole();
CrossJoinArg arg;
arg = checkMemberChildren(fun, args);
arg = checkMemberChildren(role, fun, args);
if (arg != null) {
return new CrossJoinArg[] {arg};
}
arg = checkLevelMembers(fun, args);
arg = checkLevelMembers(role, fun, args);
if (arg != null) {
return new CrossJoinArg[] {arg};
}
arg = checkDescendants(fun, args);
arg = checkDescendants(role, fun, args);
if (arg != null) {
return new CrossJoinArg[] {arg};
}
Expand Down
136 changes: 85 additions & 51 deletions testsrc/main/mondrian/test/AccessControlTest.java
Expand Up @@ -13,7 +13,6 @@

import junit.framework.Assert;
import mondrian.olap.*;
import mondrian.util.Bug;

/**
* <code>AccessControlTest</code> is a set of unit-tests for access-control.
Expand Down Expand Up @@ -811,58 +810,93 @@ public void testUnionRole() {
}

/**
* Test to verify that non empty crossjoins enforce role access
* Test to verify that non empty crossjoins enforce role access.
* Testcase for bug 1888821, "Non Empty Crossjoin fails to enforce role
* access".
*/
public void testNonEmptyAccess() {
if (Bug.Bug1888821Fixed) {
TestContext testContext =
TestContext.create(
null, null, null, null, null,
"<Role name=\"Role1\">\n"
+ " <SchemaGrant access=\"none\">\n"
+ " <CubeGrant cube=\"Sales\" access=\"all\">\n"
+ " <HierarchyGrant hierarchy=\"[Product]\" access=\"custom\">\n"
+ " <MemberGrant member=\"[Product].[Drink]\" access=\"all\"/>\n"
+ " </HierarchyGrant>\n"
+ " </CubeGrant>\n"
+ " </SchemaGrant>\n"
+ "</Role>")
.withRole("Role1");

// regular crossjoin returns the correct list of product children
testContext.assertQueryReturns(

"select {[Measures].[Unit Sales]} ON COLUMNS, " +
" Crossjoin({[Gender].[All Gender]}, " +
"[Product].[All Products].Children) ON ROWS " +
"from [Sales]",

fold(
"Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Measures].[Unit Sales]}\n" +
"Axis #2:\n" +
"{[Gender].[All Gender], [Product].[All Products].[Drink]}\n" +
"Row #0: 24,597\n"));

// non empty crossjoin does not
testContext.assertQueryReturns(

"select {[Measures].[Unit Sales]} ON COLUMNS, " +
"NON EMPTY Crossjoin({[Gender].[All Gender]}, " +
"[Product].[All Products].Children) ON ROWS " +
"from [Sales]",

fold(
"Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Measures].[Unit Sales]}\n" +
"Axis #2:\n" +
"{[Gender].[All Gender], [Product].[All Products].[Drink]}\n" +
"Row #0: 24,597\n"));
}
TestContext testContext =
TestContext.create(
null, null, null, null, null,
"<Role name=\"Role1\">\n"
+ " <SchemaGrant access=\"none\">\n"
+ " <CubeGrant cube=\"Sales\" access=\"all\">\n"
+ " <HierarchyGrant hierarchy=\"[Product]\" access=\"custom\">\n"
+ " <MemberGrant member=\"[Product].[Drink]\" access=\"all\"/>\n"
+ " </HierarchyGrant>\n"
+ " </CubeGrant>\n"
+ " </SchemaGrant>\n"
+ "</Role>")
.withRole("Role1");

// regular crossjoin returns the correct list of product children
final String expected =
fold("Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Measures].[Unit Sales]}\n" +
"Axis #2:\n" +
"{[Gender].[All Gender], [Product].[All Products].[Drink]}\n" +
"Row #0: 24,597\n");

testContext.assertQueryReturns(
"select {[Measures].[Unit Sales]} ON COLUMNS, " +
" Crossjoin({[Gender].[All Gender]}, " +
"[Product].[All Products].Children) ON ROWS " +
"from [Sales]",
expected);

// with bug 1888821, non empty crossjoin did not return the correct
// list
testContext.assertQueryReturns(
"select {[Measures].[Unit Sales]} ON COLUMNS, " +
"NON EMPTY Crossjoin({[Gender].[All Gender]}, " +
"[Product].[All Products].Children) ON ROWS " +
"from [Sales]",
expected);
}

public void testNonEmptyAccessLevelMembers() {
TestContext testContext =
TestContext.create(
null, null, null, null, null,
"<Role name=\"Role1\">\n"
+ " <SchemaGrant access=\"none\">\n"
+ " <CubeGrant cube=\"Sales\" access=\"all\">\n"
+ " <HierarchyGrant hierarchy=\"[Product]\" access=\"custom\">\n"
+ " <MemberGrant member=\"[Product].[Drink]\" access=\"all\"/>\n"
+ " </HierarchyGrant>\n"
+ " </CubeGrant>\n"
+ " </SchemaGrant>\n"
+ "</Role>")
.withRole("Role1");

// <Level>.members inside regular crossjoin returns the correct list of
// product members
final String expected =
fold("Axis #0:\n" +
"{}\n" +
"Axis #1:\n" +
"{[Measures].[Unit Sales]}\n" +
"Axis #2:\n" +
"{[Gender].[All Gender], [Product].[All Products].[Drink]}\n" +
"Row #0: 24,597\n");

testContext.assertQueryReturns(
"select {[Measures].[Unit Sales]} ON COLUMNS, " +
" Crossjoin({[Gender].[All Gender]}, " +
"[Product].[Product Family].Members) ON ROWS " +
"from [Sales]",
expected);

// with bug 1888821, <Level>.members inside non empty crossjoin did not
// return the correct list
testContext.assertQueryReturns(
"select {[Measures].[Unit Sales]} ON COLUMNS, " +
"NON EMPTY Crossjoin({[Gender].[All Gender]}, " +
"[Product].[Product Family].Members) ON ROWS " +
"from [Sales]",
expected);
}
}

Expand Down
8 changes: 7 additions & 1 deletion testsrc/main/mondrian/test/DrillThroughTest.java
Expand Up @@ -668,7 +668,13 @@ public void testTruncateLevelName() throws Exception {
connection = dataSource.getConnection();
final Statement statement = connection.createStatement();
final ResultSet resultSet = statement.executeQuery(sql);
assertEquals(6, resultSet.getMetaData().getColumnCount());
final int columnCount = resultSet.getMetaData().getColumnCount();
if (testContext.getDialect().isDerby()) {
// derby counts ORDER BY columns as columns. insane!
assertEquals(11, columnCount);
} else {
assertEquals(6, columnCount);
}
final String columnName = resultSet.getMetaData().getColumnName(5);
assertTrue(
columnName,
Expand Down

0 comments on commit c9d5e41

Please sign in to comment.