/*
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 1998-2005 Julian Hyde
// Copyright (C) 2005-2011 Pentaho and others
// All Rights Reserved.
*/
package mondrian.olap;
import mondrian.calc.Calc;
import mondrian.calc.ExpCompiler;
import mondrian.calc.impl.ConstantCalc;
import mondrian.mdx.MdxVisitor;
import mondrian.olap.type.*;
import org.olap4j.impl.UnmodifiableArrayMap;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.util.Map;
/**
* Represents a constant value, such as a string or number, in a parse tree.
*
* <p>Symbols, such as the <code>ASC</code> keyword in
* <code>Order([Store].Members, [Measures].[Unit Sales], ASC)</code>, are
* also represented as Literals.
*
* @author jhyde, 21 January, 1999
*/
public class Literal extends ExpBase {
// Data members.
public final int category;
private final Object o;
// Constants for commonly used literals.
public static final Literal nullValue = new Literal(Category.Null, null);
public static final Literal emptyString = new Literal(Category.String, "");
public static final Literal zero =
new Literal(Category.Numeric, BigDecimal.ZERO);
public static final Literal one =
new Literal(Category.Numeric, BigDecimal.ONE);
public static final Literal negativeOne =
new Literal(Category.Numeric, BigDecimal.ONE.negate());
public static final Literal doubleZero = zero;
public static final Literal doubleOne = one;
public static final Literal doubleNegativeOne = negativeOne;
private static final Map<BigDecimal, Literal> MAP =
UnmodifiableArrayMap.of(
BigDecimal.ZERO, zero,
BigDecimal.ONE, one,
BigDecimal.ONE.negate(), negativeOne);
/**
* Private constructor.
*
* <p>Use the creation methods {@link #createString(String)} etc.
*/
private Literal(int type, Object o) {
this.category = type;
this.o = o;
}
/**
* Creates a string literal.
* @see #createSymbol
*/
public static Literal createString(String s) {
return (s.equals(""))
? emptyString
: new Literal(Category.String, s);
}
/**
* Creates a symbol.
*
* @see #createString
*/
public static Literal createSymbol(String s) {
return new Literal(Category.Symbol, s);
}
/**
* Creates a numeric literal.
*
* @deprecated Use {@link #create(java.math.BigDecimal)}
*/
public static Literal create(Double d) {
return new Literal(Category.Numeric, new BigDecimal(d));
}
/**
* Creates an integer literal.
*
* @deprecated Use {@link #create(java.math.BigDecimal)}
*/
public static Literal create(Integer i) {
return new Literal(Category.Numeric, new BigDecimal(i));
}
/**
* Creates a numeric literal.
*
* <p>Using a {@link BigDecimal} allows us to store the precise value that
* the user typed. We will have to fit the value into a native
* {@code double} or {@code int} later on, but parse time is not the time to
* be throwing away information.
*/
public static Literal create(BigDecimal d) {
final Literal literal = MAP.get(d);
if (literal != null) {
return literal;
}
return new Literal(Category.Numeric, d);
}
public Literal clone() {
return this;
}
public void unparse(PrintWriter pw) {
switch (category) {
case Category.Symbol:
case Category.Numeric:
pw.print(o);
break;
case Category.String:
pw.print(Util.quoteForMdx((String) o));
break;
case Category.Null:
pw.print("NULL");
break;
default:
throw Util.newInternal("bad literal type " + category);
}
}
public int getCategory() {
return category;
}
public Type getType() {
switch (category) {
case Category.Symbol:
return new SymbolType();
case Category.Numeric:
return new NumericType();
case Category.String:
return new StringType();
case Category.Null:
return new NullType();
default:
throw Category.instance.badValue(category);
}
}
public Exp accept(Validator validator) {
return this;
}
public Calc accept(ExpCompiler compiler) {
return new ConstantCalc(getType(), o);
}
public Object accept(MdxVisitor visitor) {
return visitor.visit(this);
}
public Object getValue() {
return o;
}
public int getIntValue() {
if (o instanceof Number) {
return ((Number) o).intValue();
} else {
throw Util.newInternal("cannot convert " + o + " to int");
}
}
}
// End Literal.java