Skip to content

Commit

Permalink
Use BigDecimal, not Double or Integer, to hold the value of numeric L…
Browse files Browse the repository at this point in the history
…iteralNode.

Deprecate corresponding LiteralNode.create methods.


git-svn-id: https://olap4j.svn.sourceforge.net/svnroot/olap4j/trunk@381 c6a108a4-781c-0410-a6c6-c2d559e19af0
  • Loading branch information
julianhyde committed Dec 17, 2010
1 parent ddaf934 commit 3bbe4b1
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 39 deletions.
36 changes: 35 additions & 1 deletion src/org/olap4j/mdx/LiteralNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
*/
package org.olap4j.mdx;

import org.olap4j.impl.Olap4jUtil;
import org.olap4j.type.*;

import java.io.PrintWriter;
import java.math.BigDecimal;

/**
* Represents a constant value, such as a string or number, in a parse tree.
Expand Down Expand Up @@ -50,6 +52,9 @@ private LiteralNode(
{
assert type != null;
assert (type instanceof NullType) == (value == null);
assert (type instanceof StringType || type instanceof SymbolType)
== (value instanceof String);
assert (type instanceof NumericType) == (value instanceof BigDecimal);
this.region = region;
this.type = type;
this.value = value;
Expand Down Expand Up @@ -112,6 +117,8 @@ public static LiteralNode createSymbol(
* @param value Value of literal; must not be null
*
* @return literal representing the floating-point value
*
* @deprecated Use {@link #createNumeric}
*/
public static LiteralNode create(
ParseRegion region,
Expand All @@ -120,7 +127,7 @@ public static LiteralNode create(
if (value == null) {
throw new IllegalArgumentException("value must not be null");
}
return new LiteralNode(region, new NumericType(), value);
return createNumeric(region, new BigDecimal(value), true);
}

/**
Expand All @@ -130,6 +137,8 @@ public static LiteralNode create(
* @param value Value of literal; must not be null
*
* @return literal representing the integer value
*
* @deprecated Use {@link #createNumeric}
*/
public static LiteralNode create(
ParseRegion region,
Expand All @@ -138,6 +147,27 @@ public static LiteralNode create(
if (value == null) {
throw new IllegalArgumentException("value must not be null");
}
return createNumeric(region, new BigDecimal(value), false);
}

/**
* Creates a numeric literal.
*
* @param region Region of source code
* @param value Value of literal; must not be null
* @param approximate Whether the literal is approximate
*
* @return literal representing the integer value
*/
public static LiteralNode createNumeric(
ParseRegion region,
BigDecimal value,
boolean approximate)
{
if (value == null) {
throw new IllegalArgumentException("value must not be null");
}
Olap4jUtil.discard(approximate); // reserved for future use
return new LiteralNode(region, new NumericType(), value);
}

Expand All @@ -156,6 +186,10 @@ public ParseRegion getRegion() {
/**
* Returns the value of this literal.
*
* <p>Value is always of type {@link String} (if the literal is a string or
* a symbol), of type {@link java.math.BigDecimal} (if the literal is
* numeric), or null (if the literal is of null type).
*
* @return value
*/
public Object getValue() {
Expand Down
9 changes: 6 additions & 3 deletions src/org/olap4j/mdx/parser/impl/DefaultMdxParser.cup
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
*/

import java_cup.runtime.*;

import java.math.BigDecimal;
import java.util.*;

import org.olap4j.Axis;
import org.olap4j.mdx.*;
import org.olap4j.mdx.parser.MdxParseException;
Expand Down Expand Up @@ -320,7 +323,7 @@ terminal
SOLIDUS; // /

// c. Typed terminals
terminal Double NUMBER;
terminal BigDecimal NUMBER;
terminal String ID;
terminal String QUOTED_ID;
terminal String AMP_QUOTED_ID;
Expand Down Expand Up @@ -410,7 +413,7 @@ non terminal List
non terminal ParseTreeNode[]
when_clause;

non terminal Double
non terminal BigDecimal
axis_number;

// Start symbol
Expand Down Expand Up @@ -855,7 +858,7 @@ value_expression_primary ::=
:}
| NUMBER:d {:
ParseRegion region = createRegion(dleft, dright);
RESULT = LiteralNode.create(region, d);
RESULT = LiteralNode.createNumeric(region, d, false);
:}
| identifier:i {:
RESULT = new IdentifierNode(i);
Expand Down
2 changes: 1 addition & 1 deletion src/org/olap4j/mdx/parser/impl/Scanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ private Symbol makeSymbol(int id, Object o) {
* @return number literal token
*/
private Symbol makeNumber(BigDecimal mantissa, int exponent) {
double d = mantissa.movePointRight(exponent).doubleValue();
BigDecimal d = mantissa.movePointRight(exponent);
return makeSymbol(DefaultMdxParserSym.NUMBER, d);
}

Expand Down
20 changes: 14 additions & 6 deletions testsrc/org/olap4j/ConnectionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -2425,14 +2425,19 @@ public void run() {
).start();
try {
final CellSet cellSet = olapStatement.executeOlapQuery(
"SELECT [Customers].Members * \n"
+ " [Time].Members on columns\n"
"SELECT Filter(\n"
+ " [Product].Members *\n"
+ " [Customers].Members *\n"
+ " [Time].[Time].Members,\n"
+ " 1 = 0) on columns\n"
+ "from [Sales]");
fail(
"expected exception indicating stmt had been canceled,"
+ " got cellSet " + cellSet);
} catch (OlapException e) {
assertTrue(e.getMessage().indexOf("Query canceled") >= 0);
assertTrue(
e.getMessage(),
e.getMessage().indexOf("Query canceled") >= 0);
}
if (exceptions[0] != null) {
throw exceptions[0];
Expand All @@ -2455,15 +2460,18 @@ public void testStatementTimeout() throws Throwable {
try {
final CellSet cellSet =
olapStatement.executeOlapQuery(
"SELECT [Store].Members * \n"
"SELECT Filter(\n"
+ " [Store].Members * \n"
+ " [Customers].Members * \n"
+ " [Time].Members on columns\n"
+ " [Time].[Time].Members, 1 = 0) on columns\n"
+ "from [Sales]");
fail(
"expected exception indicating timeout,"
+ " got cellSet " + cellSet);
} catch (OlapException e) {
assertTrue(e.getMessage().indexOf("Query timeout of ") >= 0);
assertTrue(
e.getMessage(),
e.getMessage().indexOf("Query timeout of ") >= 0);
}
}

Expand Down
2 changes: 1 addition & 1 deletion testsrc/org/olap4j/mdx/MdxTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ public void testQuoteEscaping() {
TestContext.assertEqualsVerbose(
"WITH\n"
+ "SET Foo AS\n"
+ " Filter(Bar.Members, (Instr(Name, \"'\") > 0.0))\n"
+ " Filter(Bar.Members, (Instr(Name, \"'\") > 0))\n"
+ "SELECT\n"
+ "FROM [Cube]",
rootNode.toString());
Expand Down
56 changes: 29 additions & 27 deletions testsrc/org/olap4j/test/ParserTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public void testScannerPunc() {
+ "from _Bar_Baz",
"WITH\n"
+ "MEMBER [Measures].__Foo AS\n"
+ " (1.0 + 2.0)\n"
+ " (1 + 2)\n"
+ "SELECT\n"
+ "__Foo ON COLUMNS\n"
+ "FROM _Bar_Baz");
Expand All @@ -208,7 +208,7 @@ public void testScannerPunc() {
+ "from Bar$Baz",
"WITH\n"
+ "MEMBER [Measures].$Foo AS\n"
+ " (1.0 + 2.0)\n"
+ " (1 + 2)\n"
+ "SELECT\n"
+ "$Foo ON COLUMNS\n"
+ "FROM Bar$Baz");
Expand All @@ -234,7 +234,7 @@ public void testUnparse() {
+ "where [Marital Status].[S]",
"WITH\n"
+ "MEMBER [Measures].[Foo] AS\n"
+ " 123.0\n"
+ " 123\n"
+ "SELECT\n"
+ "{[Measures].members} ON COLUMNS,\n"
+ "CrossJoin([Product].members, {[Gender].Children}) ON ROWS\n"
Expand Down Expand Up @@ -514,7 +514,7 @@ public void testCaseSwitch() {
+ "select {[foo]} on axis(0) from cube",
"WITH\n"
+ "MEMBER [Measures].[Foo] AS\n"
+ " CASE x WHEN 1.0 THEN 2.0 WHEN 3.0 THEN 4.0 ELSE 5.0 END\n"
+ " CASE x WHEN 1 THEN 2 WHEN 3 THEN 4 ELSE 5 END\n"
+ "SELECT\n"
+ "{[foo]} ON COLUMNS\n"
+ "FROM cube");
Expand Down Expand Up @@ -544,12 +544,12 @@ public void testIsEmpty() {

assertParseExpr(
"[Measures].[Unit Sales] IS EMPTY AND 1 IS NULL",
"(([Measures].[Unit Sales] IS EMPTY) AND (1.0 IS NULL))");
"(([Measures].[Unit Sales] IS EMPTY) AND (1 IS NULL))");

// FIXME: "NULL" should associate as "IS NULL" rather than "NULL + 56.0"
// FIXME: "NULL" should associate as "IS NULL" rather than "NULL + 56"
assertParseExpr(
"- x * 5 is empty is empty is null + 56",
"(((((- x) * 5.0) IS EMPTY) IS EMPTY) IS (NULL + 56.0))");
"(((((- x) * 5) IS EMPTY) IS EMPTY) IS (NULL + 56))");
}

public void testIs() {
Expand All @@ -565,27 +565,27 @@ public void testIsNull() {

assertParseExpr(
"[Measures].[Unit Sales] IS NULL AND 1 <> 2",
"(([Measures].[Unit Sales] IS NULL) AND (1.0 <> 2.0))");
"(([Measures].[Unit Sales] IS NULL) AND (1 <> 2))");

assertParseExpr(
"x is null or y is null and z = 5",
"((x IS NULL) OR ((y IS NULL) AND (z = 5.0)))");
"((x IS NULL) OR ((y IS NULL) AND (z = 5)))");

assertParseExpr(
"(x is null) + 56 > 6",
"(((x IS NULL) + 56.0) > 6.0)");
"(((x IS NULL) + 56) > 6)");

// FIXME: Should be:
// "(((((x IS NULL) AND (a = b)) OR ((c = (d + 5.0))) IS NULL) + 5.0)"
// "(((((x IS NULL) AND (a = b)) OR ((c = (d + 5))) IS NULL) + 5)"
assertParseExpr(
"x is null and a = b or c = d + 5 is null + 5",
"(((x IS NULL) AND (a = b)) OR ((c = (d + 5.0)) IS (NULL + 5.0)))");
"(((x IS NULL) AND (a = b)) OR ((c = (d + 5)) IS (NULL + 5)))");
}

public void testNull() {
assertParseExpr(
"Filter({[Measures].[Foo]}, Iif(1 = 2, NULL, 'X'))",
"Filter({[Measures].[Foo]}, Iif((1.0 = 2.0), NULL, \"X\"))");
"Filter({[Measures].[Foo]}, Iif((1 = 2), NULL, \"X\"))");
}

public void testCast() {
Expand All @@ -595,7 +595,7 @@ public void testCast() {

assertParseExpr(
"Cast(1 + 2 AS String)",
"CAST((1.0 + 2.0) AS String)");
"CAST((1 + 2) AS String)");
}

public void testId() {
Expand Down Expand Up @@ -670,7 +670,7 @@ public void testIdComplex() {
// compound key sans brackets
assertParseExpr(
"[Foo].&Key1&Key2 + 4",
"([Foo].&Key1&Key2 + 4.0)");
"([Foo].&Key1&Key2 + 4)");
// brackets are requred for numbers
assertParseExprFails(
"[Foo].&[1]&[Key2]&^3.[Bar]",
Expand Down Expand Up @@ -713,36 +713,38 @@ public void _testCloneQuery() throws SQLException {
*/
public void testNumbers() {
// Number: [+-] <digits> [ . <digits> ] [e [+-] <digits> ]
assertParseExpr("2", "2.0");
assertParseExpr("2", "2");

// leading '-' is treated as an operator -- that's ok
assertParseExpr("-3", "(- 3.0)");
assertParseExpr("-3", "(- 3)");

// leading '+' is ignored -- that's ok
assertParseExpr("+45", "45.0");
assertParseExpr("+45", "45");

// space bad
assertParseExprFails(
"4 ^5^",
"Syntax error at \\[1:35\\], token '5\\.0'");
"Syntax error at \\[1:35\\], token '5\\'");

assertParseExpr("3.14", "3.14");
assertParseExpr(".12345", "0.12345");

// lots of digits left and right of point
assertParseExpr("31415926535.89793", "3.141592653589793E10");
assertParseExpr("31415926535.89793", "31415926535.89793");
assertParseExpr(
"31415926535897.9314159265358979", "3.141592653589793E13");
"31415926535897.9314159265358979",
"31415926535897.9314159265358979");
assertParseExpr("3.141592653589793", "3.141592653589793");
assertParseExpr(
"-3141592653589793.14159265358979", "(- 3.141592653589793E15)");
"-3141592653589793.14159265358979",
"(- 3141592653589793.14159265358979)");

// exponents akimbo
assertParseExpr("1e2", "100.0");
assertParseExpr("1e2", "100");
assertParseExprFails(
"1e2e^3^", // todo: fix parser; should be "1e2^e3^"
"Syntax error at .* token 'e3'");
assertParseExpr("1.2e3", "1200.0");
assertParseExpr("1.2e3", "1200");
assertParseExpr("-1.2345e3", "(- 1234.5)");
assertParseExprFails(
"1.2e3.^4^", // todo: fix parser; should be "1.2e3^.4^"
Expand All @@ -769,7 +771,7 @@ public void testLargePrecision() {
+ "where ([Time].[1997].[Q2].[4])",
"WITH\n"
+ "MEMBER [Measures].[Small Number] AS\n"
+ " ([Measures].[Store Sales] / 9000.0)\n"
+ " ([Measures].[Store Sales] / 9000)\n"
+ "SELECT\n"
+ "{[Measures].[Small Number]} ON COLUMNS,\n"
+ "{Filter([Product].[Product Department].members, (([Measures].[Small Number] >= 0.3) AND ([Measures].[Small Number] <= 0.5000001234)))} ON ROWS\n"
Expand Down Expand Up @@ -836,7 +838,7 @@ public void testEmptyExpr() {
+ " ) ON COLUMNS\n"
+ "from [Sales]\n",
"SELECT\n"
+ "NON EMPTY HIERARCHIZE({DrillDownLevelTop({[Product].[All Products]}, 3.0, , [Measures].[Unit Sales])}) ON COLUMNS\n"
+ "NON EMPTY HIERARCHIZE({DrillDownLevelTop({[Product].[All Products]}, 3, , [Measures].[Unit Sales])}) ON COLUMNS\n"
+ "FROM [Sales]");

// more advanced; the actual test case in the bug
Expand All @@ -850,7 +852,7 @@ public void testEmptyExpr() {
+ "FROM [cube]",
"SELECT\n"
+ "{[Measures].[NetSales]} DIMENSION PROPERTIES PARENT_UNIQUE_NAME ON COLUMNS,\n"
+ "NON EMPTY HIERARCHIZE(AddCalculatedMembers({DrillDownLevelTop({[ProductDim].[Name].[All]}, 10.0, , [Measures].[NetSales])})) DIMENSION PROPERTIES PARENT_UNIQUE_NAME ON ROWS\n"
+ "NON EMPTY HIERARCHIZE(AddCalculatedMembers({DrillDownLevelTop({[ProductDim].[Name].[All]}, 10, , [Measures].[NetSales])})) DIMENSION PROPERTIES PARENT_UNIQUE_NAME ON ROWS\n"
+ "FROM [cube]");
}

Expand Down

0 comments on commit 3bbe4b1

Please sign in to comment.