Skip to content

Commit

Permalink
MONDRIAN: changed boolean expressions to return true, false or null. …
Browse files Browse the repository at this point in the history
…Null is returned if the expression can not be evaluated because the data are not ready. Functions like IIF or Filter dont receive a random boolean value now, they can decide what value they want to use for null.

[git-p4: depot-paths = "//open/mondrian/": change = 2152]
  • Loading branch information
Andreas Voss committed Jun 16, 2004
1 parent fc1e9c8 commit fe68e24
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 28 deletions.
15 changes: 7 additions & 8 deletions build.xml
Expand Up @@ -675,51 +675,50 @@ build mondrian.war as in the runtime environment.">
<jarlib-resolve property="junit.library" failOnError="false" checkExtension="false">
<extension refid="junit.ext"/>
<location location="${testlib.dir}/junit.jar"/>
<url url="http://gump.covalent.net/jars/2004-05-16/junit/junit.jar" destfile="${testlib.dir}/junit.jar"/>
<url url="http://gump.covalent.net/jars/latest/junit/junit.jar" destfile="${testlib.dir}/junit.jar"/>
</jarlib-resolve>

<extension id="commons-dbcp.ext" extensionName="org.apache.commons.dbcp"/>
<jarlib-resolve property="commons-dbcp.library" failOnError="false" checkExtension="false">
<extension refid="commons-dbcp.ext"/>
<location location="${lib.dir}/commons-dbcp.jar"/>
<url url="http://gump.covalent.net/jars/2004-05-16/jakarta-commons/commons-dbcp.jar" destfile="${lib.dir}/commons-dbcp.jar"/>
<url url="http://gump.covalent.net/jars/latest/jakarta-commons/commons-dbcp.jar" destfile="${lib.dir}/commons-dbcp.jar"/>
</jarlib-resolve>

<extension id="commons-pool.ext" extensionName="org.apache.commons.pool"/>
<jarlib-resolve property="commons-pool.library" failOnError="false" checkExtension="false">
<extension refid="commons-pool.ext"/>
<location location="${lib.dir}/commons-pool.jar"/>
<url url="http://gump.covalent.net/jars/2004-05-16/jakarta-commons/commons-pool.jar" destfile="${lib.dir}/commons-pool.jar"/>
<url url="http://gump.covalent.net/jars/latest/jakarta-commons/commons-pool.jar" destfile="${lib.dir}/commons-pool.jar"/>
</jarlib-resolve>

<extension id="commons-collections.ext" extensionName="org.apache.commons.collections"/>
<jarlib-resolve property="commons-collections.library" failOnError="false" checkExtension="false">
<extension refid="commons-collections.ext"/>
<location location="${lib.dir}/commons-collections.jar"/>
<url url="http://gump.covalent.net/jars/2004-05-16/jakarta-commons/commons-collections.jar" destfile="${lib.dir}/commons-collections.jar"/>
<url url="http://gump.covalent.net/jars/latest/jakarta-commons/commons-collections.jar" destfile="${lib.dir}/commons-collections.jar"/>
</jarlib-resolve>

<extension id="xalan.ext" extensionName="org.apache.xalan"/>
<jarlib-resolve property="xalan.library" failOnError="false" checkExtension="false">
<extension refid="xalan.ext"/>
<location location="${lib.dir}/xalan.jar"/>
<url url="http://gump.covalent.net/jars/2004-05-16/xml-xalan/xalan.jar" destfile="${lib.dir}/xalan.jar"/>
<url url="http://gump.covalent.net/jars/latest/xml-xalan/xalan.jar" destfile="${lib.dir}/xalan.jar"/>
</jarlib-resolve>

<extension id="xml.ext" extensionName="org.xml"/>
<jarlib-resolve property="xml.library" failOnError="false" checkExtension="false">
<extension refid="xml.ext"/>
<location location="${lib.dir}/xml-apis.jar"/>
<url url="http://gump.covalent.net/jars/2004-05-16/xml-commons/xml-apis.jar" destfile="${lib.dir}/xml-apis.jar"/>
<url url="http://gump.covalent.net/jars/latest/xml-commons/xml-apis.jar" destfile="${lib.dir}/xml-apis.jar"/>
</jarlib-resolve>

<extension id="xerces.ext" extensionName="org.apache.xerces"/>
<jarlib-resolve property="xerces.library" failOnError="false" checkExtension="false">
<extension refid="xerces.ext"/>
<location location="${lib.dir}/xercesImpl.jar"/>
<url url="http://gump.covalent.net/jars/2004-05-16/xml-xerces2/xercesImpl.jar" destfile="${lib.dir}/xercesImpl.jar"/>
<url url="http://gump.covalent.net/jars/latest/xml-xerces2/xercesImpl.jar" destfile="${lib.dir}/xercesImpl.jar"/>
</jarlib-resolve>

</target>

<target name="war" depends="jar,copy-jars" description="
Expand Down
64 changes: 49 additions & 15 deletions src/main/mondrian/olap/fun/BuiltinFunTable.java
Expand Up @@ -984,7 +984,7 @@ public Object evaluate(Evaluator evaluator, Exp[] args) {
}));
define(new FunDefBase("IIf", "IIf(<Logical Expression>, <Numeric Expression1>, <Numeric Expression2>)", "Returns one of two numeric values determined by a logical test.", "fnbnn") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
boolean logical = getBooleanArg(evaluator, args, 0);
boolean logical = getBooleanArg(evaluator, args, 0, false);
return getDoubleArg(evaluator, args, logical ? 1 : 2, null);
}
});
Expand Down Expand Up @@ -1404,7 +1404,7 @@ public Object evaluate(Evaluator evaluator, Exp[] args) {
"unexpected type in set: " + o.getClass());
}
Boolean b = (Boolean) exp.evaluateScalar(evaluator2);
if (b.booleanValue()) {
if (b != null && b.booleanValue()) {
result.add(o);
}
}
Expand Down Expand Up @@ -1927,7 +1927,7 @@ public Object evaluate(Evaluator evaluator, Exp[] args) {

define(new FunDefBase("IIf", "IIf(<Logical Expression>, <String Expression1>, <String Expression2>)", "Returns one of two string values determined by a logical test.", "fSbSS") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
boolean logical = getBooleanArg(evaluator, args, 0);
boolean logical = getBooleanArg(evaluator, args, 0, false);
return getStringArg(evaluator, args, logical ? 1 : 2, null);
}
});
Expand Down Expand Up @@ -2096,7 +2096,7 @@ Object evaluateCaseTest(Evaluator evaluator, Exp[] args) {
int clauseCount = args.length / 2,
j = 0;
for (int i = 0; i < clauseCount; i++) {
boolean logical = getBooleanArg(evaluator, args, j++);
boolean logical = getBooleanArg(evaluator, args, j++, false);
if (logical) {
return getArg(evaluator, args, j);
} else {
Expand Down Expand Up @@ -2369,84 +2369,118 @@ public Object evaluate(Evaluator evaluator, Exp[] args) {
});
define(new FunDefBase("AND", "<Logical Expression> AND <Logical Expression>", "Returns the conjunction of two conditions.", "ibbb") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
return toBoolean(
getBooleanArg(evaluator, args, 0) &&
getBooleanArg(evaluator, args, 1));
// if the first arg is known and false, we dont evaluate the second
Boolean b1 = getBooleanArg(evaluator, args, 0);
if (b1 != null && !b1.booleanValue())
return Boolean.FALSE;
Boolean b2 = getBooleanArg(evaluator, args, 1);
if (b2 != null && !b2.booleanValue())
return Boolean.FALSE;
if (b1 == null || b2 == null)
return null;
return toBoolean(b1.booleanValue() && b2.booleanValue());
}
});
define(new FunDefBase("OR", "<Logical Expression> OR <Logical Expression>", "Returns the disjunction of two conditions.", "ibbb") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
// Only evaluate 2nd if first is false.
return toBoolean(
getBooleanArg(evaluator, args, 0) ||
getBooleanArg(evaluator, args, 1));
// if the first arg is known and true, we dont evaluate the second
Boolean b1 = getBooleanArg(evaluator, args, 0);
if (b1 != null && b1.booleanValue())
return Boolean.TRUE;
Boolean b2 = getBooleanArg(evaluator, args, 1);
if (b2 != null && b2.booleanValue())
return Boolean.TRUE;
if (b1 == null || b2 == null)
return null;
return toBoolean(b1.booleanValue() || b2.booleanValue());
}
});
define(new FunDefBase("XOR", "<Logical Expression> XOR <Logical Expression>", "Returns whether two conditions are mutually exclusive.", "ibbb") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
final boolean b0 = getBooleanArg(evaluator, args, 0);
final boolean b1 = getBooleanArg(evaluator, args, 1);
return toBoolean(b0 != b1);
Boolean b1 = getBooleanArg(evaluator, args, 0);
Boolean b2 = getBooleanArg(evaluator, args, 1);
if (b1 == null || b2 == null)
return null;
return toBoolean(b1.booleanValue() != b2.booleanValue());
}
});
define(new FunDefBase("NOT", "NOT <Logical Expression>", "Returns the negation of a condition.", "Pbb") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
return toBoolean(!getBooleanArg(evaluator, args, 0));
Boolean b = getBooleanArg(evaluator, args, 0);
if (b == null)
return null;
return toBoolean(!b.booleanValue());
}
});
define(new FunDefBase("=", "<String Expression> = <String Expression>", "Returns whether two expressions are equal.", "ibSS") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
String o0 = getStringArg(evaluator, args, 0, null),
o1 = getStringArg(evaluator, args, 1, null);
if (o0 == null || o1 == null)
return null;
return toBoolean(o0.equals(o1));
}
});
define(new FunDefBase("=", "<Numeric Expression> = <Numeric Expression>", "Returns whether two expressions are equal.", "ibnn") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
Double o0 = getDoubleArg(evaluator, args, 0),
o1 = getDoubleArg(evaluator, args, 1);
if (o0.isNaN() || o1.isNaN())
return null;
return toBoolean(o0.equals(o1));
}
});
define(new FunDefBase("<>", "<String Expression> <> <String Expression>", "Returns whether two expressions are not equal.", "ibSS") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
String o0 = getStringArg(evaluator, args, 0, null),
o1 = getStringArg(evaluator, args, 1, null);
if (o0 == null || o1 == null)
return null;
return toBoolean(!o0.equals(o1));
}
});
define(new FunDefBase("<>", "<Numeric Expression> <> <Numeric Expression>", "Returns whether two expressions are not equal.", "ibnn") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
Double o0 = getDoubleArg(evaluator, args, 0),
o1 = getDoubleArg(evaluator, args, 1);
if (o0.isNaN() || o1.isNaN())
return null;
return toBoolean(!o0.equals(o1));
}
});
define(new FunDefBase("<", "<Numeric Expression> < <Numeric Expression>", "Returns whether an expression is less than another.", "ibnn") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
Double o0 = getDoubleArg(evaluator, args, 0),
o1 = getDoubleArg(evaluator, args, 1);
if (o0.isNaN() || o1.isNaN())
return null;
return toBoolean(o0.compareTo(o1) < 0);
}
});
define(new FunDefBase("<=", "<Numeric Expression> <= <Numeric Expression>", "Returns whether an expression is less than or equal to another.", "ibnn") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
Double o0 = getDoubleArg(evaluator, args, 0),
o1 = getDoubleArg(evaluator, args, 1);
if (o0.isNaN() || o1.isNaN())
return null;
return toBoolean(o0.compareTo(o1) <= 0);
}
});
define(new FunDefBase(">", "<Numeric Expression> > <Numeric Expression>", "Returns whether an expression is greater than another.", "ibnn") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
Double o0 = getDoubleArg(evaluator, args, 0),
o1 = getDoubleArg(evaluator, args, 1);
if (o0.isNaN() || o1.isNaN())
return null;
return toBoolean(o0.compareTo(o1) > 0);
}
});
define(new FunDefBase(">=", "<Numeric Expression> >= <Numeric Expression>", "Returns whether an expression is greater than or equal to another.", "ibnn") {
public Object evaluate(Evaluator evaluator, Exp[] args) {
Double o0 = getDoubleArg(evaluator, args, 0),
o1 = getDoubleArg(evaluator, args, 1);
if (o0.isNaN() || o1.isNaN())
return null;
return toBoolean(o0.compareTo(o1) >= 0);
}
});
Expand Down
17 changes: 16 additions & 1 deletion src/main/mondrian/olap/fun/FunUtil.java
Expand Up @@ -99,11 +99,26 @@ static int getLiteralArg(Exp[] args, int i, int defaultValue, EnumeratedValues a
return allowedValues.getOrdinal(literal);
}

static boolean getBooleanArg(Evaluator evaluator, Exp[] args, int index) {
/**
* returns defaultValue, if the expression can not be evaluated because
* some required operands have not been loaded from the database yet.
*/
static boolean getBooleanArg(Evaluator evaluator, Exp[] args, int index, boolean defaultValue) {
Object o = getArg(evaluator, args, index);
if (o == null)
return defaultValue;
return ((Boolean) o).booleanValue();
}

/**
* returns null, if the expression can not be evaluated because
* some required operands have not been loaded from the database yet.
*/
static Boolean getBooleanArg(Evaluator evaluator, Exp[] args, int index) {
Object o = getArg(evaluator, args, index);
return (Boolean) o;
}

static int getIntArg(Evaluator evaluator, Exp[] args, int index) {
Object o = getScalarArg(evaluator, args, index);
if (o instanceof Number) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/mondrian/rolap/RolapResult.java
Expand Up @@ -35,7 +35,7 @@ class RolapResult extends ResultBase
AggregatingCellReader aggregatingReader;
FastBatchingCellReader batchingReader;
private int[] modulos;
private static final int MAX_AGGREGATION_PASS_COUNT = 3;
private static final int MAX_AGGREGATION_PASS_COUNT = 5;

RolapResult(Query query) {
this.query = query;
Expand Down
33 changes: 30 additions & 3 deletions testsrc/main/mondrian/test/BasicQueryTest.java
Expand Up @@ -469,7 +469,7 @@ public void testDrillThrough() {
" {[Product].Children} on rows" + nl +
"from Sales");
String sql = result.getCell(new int[] {0, 0}).getDrillThroughSQL(false);
// the following replacement is for databases in ANSI mode
// the following replacement is for databases in ANSI mode
// using '"' to quote identifiers
sql = sql.replace('"', '`');
assertEquals("select `time_by_day`.`the_year` as `Year`," +
Expand Down Expand Up @@ -505,7 +505,7 @@ public void testDrillThrough2() {
} else {
fname_plus_lname = " fname + ' ' + lname as `Name`,";
}
// the following replacement is for databases in ANSI mode
// the following replacement is for databases in ANSI mode
// using '"' to quote identifiers
sql = sql.replace('"', '`');
assertEquals("select `store`.`store_name` as `Store Name`," +
Expand Down Expand Up @@ -2653,7 +2653,7 @@ public void testBasketAnalysisAfterFlush() {
CachePool.instance().flush();
testBasketAnalysis();
}

/**
* <b>How Can I Perform Complex String Comparisons?</b>
*
Expand Down Expand Up @@ -3743,6 +3743,33 @@ public void testDependsOn() {
"Row #1: 15,111" + nl);
}

/**
* This resulted in OutOfMemoryException when the BatchingCellReader did not
* know the values for the tupels that were used in filters.
*/
public void testFilteredCrossJoin() {
CachePool.instance().flush();
Result result = runQuery(
"select {[Measures].[Store Sales]} on columns," + nl +
" NON EMPTY Crossjoin(" + nl +
" Filter([Customers].[Name].Members," + nl +
" (([Measures].[Store Sales]," + nl +
" [Store].[All Stores].[USA].[CA].[San Francisco].[Store 14]," + nl +
" [Time].[1997].[Q1].[1]) > 5.0))," + nl +
" Filter([Product].[Product Name].Members," + nl +
" (([Measures].[Store Sales]," + nl +
" [Store].[All Stores].[USA].[CA].[San Francisco].[Store 14]," + nl +
" [Time].[1997].[Q1].[1]) > 5.0))" + nl +
" ) ON rows" + nl +
"from [Sales]" + nl +
"where (" + nl +
" [Store].[All Stores].[USA].[CA].[San Francisco].[Store 14]," + nl +
" [Time].[1997].[Q1].[1]" + nl +
")" + nl);
// ok if no OutOfMemoryException occurs
Axis a = result.getAxes()[1];
assertEquals(12, a.positions.length);
}
}

// End BasicQueryTest.java

0 comments on commit fe68e24

Please sign in to comment.