001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 1998-2005 Julian Hyde 008// Copyright (C) 2005-2011 Pentaho and others 009// All Rights Reserved. 010*/ 011package mondrian.olap; 012 013import mondrian.calc.Calc; 014import mondrian.calc.ExpCompiler; 015import mondrian.calc.impl.ConstantCalc; 016import mondrian.mdx.MdxVisitor; 017import mondrian.olap.type.*; 018 019import org.olap4j.impl.UnmodifiableArrayMap; 020 021import java.io.PrintWriter; 022import java.math.BigDecimal; 023import java.util.Map; 024 025/** 026 * Represents a constant value, such as a string or number, in a parse tree. 027 * 028 * <p>Symbols, such as the <code>ASC</code> keyword in 029 * <code>Order([Store].Members, [Measures].[Unit Sales], ASC)</code>, are 030 * also represented as Literals. 031 * 032 * @author jhyde, 21 January, 1999 033 */ 034public class Literal extends ExpBase { 035 036 // Data members. 037 038 public final int category; 039 private final Object o; 040 041 042 // Constants for commonly used literals. 043 044 public static final Literal nullValue = new Literal(Category.Null, null); 045 046 public static final Literal emptyString = new Literal(Category.String, ""); 047 048 public static final Literal zero = 049 new Literal(Category.Numeric, BigDecimal.ZERO); 050 051 public static final Literal one = 052 new Literal(Category.Numeric, BigDecimal.ONE); 053 054 public static final Literal negativeOne = 055 new Literal(Category.Numeric, BigDecimal.ONE.negate()); 056 057 public static final Literal doubleZero = zero; 058 059 public static final Literal doubleOne = one; 060 061 public static final Literal doubleNegativeOne = negativeOne; 062 063 private static final Map<BigDecimal, Literal> MAP = 064 UnmodifiableArrayMap.of( 065 BigDecimal.ZERO, zero, 066 BigDecimal.ONE, one, 067 BigDecimal.ONE.negate(), negativeOne); 068 069 /** 070 * Private constructor. 071 * 072 * <p>Use the creation methods {@link #createString(String)} etc. 073 */ 074 private Literal(int type, Object o) { 075 this.category = type; 076 this.o = o; 077 } 078 079 /** 080 * Creates a string literal. 081 * @see #createSymbol 082 */ 083 public static Literal createString(String s) { 084 return (s.equals("")) 085 ? emptyString 086 : new Literal(Category.String, s); 087 } 088 089 /** 090 * Creates a symbol. 091 * 092 * @see #createString 093 */ 094 public static Literal createSymbol(String s) { 095 return new Literal(Category.Symbol, s); 096 } 097 098 /** 099 * Creates a numeric literal. 100 * 101 * @deprecated Use {@link #create(java.math.BigDecimal)} 102 */ 103 public static Literal create(Double d) { 104 return new Literal(Category.Numeric, new BigDecimal(d)); 105 } 106 107 /** 108 * Creates an integer literal. 109 * 110 * @deprecated Use {@link #create(java.math.BigDecimal)} 111 */ 112 public static Literal create(Integer i) { 113 return new Literal(Category.Numeric, new BigDecimal(i)); 114 } 115 116 /** 117 * Creates a numeric literal. 118 * 119 * <p>Using a {@link BigDecimal} allows us to store the precise value that 120 * the user typed. We will have to fit the value into a native 121 * {@code double} or {@code int} later on, but parse time is not the time to 122 * be throwing away information. 123 */ 124 public static Literal create(BigDecimal d) { 125 final Literal literal = MAP.get(d); 126 if (literal != null) { 127 return literal; 128 } 129 return new Literal(Category.Numeric, d); 130 } 131 132 public Literal clone() { 133 return this; 134 } 135 136 public void unparse(PrintWriter pw) { 137 switch (category) { 138 case Category.Symbol: 139 case Category.Numeric: 140 pw.print(o); 141 break; 142 case Category.String: 143 pw.print(Util.quoteForMdx((String) o)); 144 break; 145 case Category.Null: 146 pw.print("NULL"); 147 break; 148 default: 149 throw Util.newInternal("bad literal type " + category); 150 } 151 } 152 153 public int getCategory() { 154 return category; 155 } 156 157 public Type getType() { 158 switch (category) { 159 case Category.Symbol: 160 return new SymbolType(); 161 case Category.Numeric: 162 return new NumericType(); 163 case Category.String: 164 return new StringType(); 165 case Category.Null: 166 return new NullType(); 167 default: 168 throw Category.instance.badValue(category); 169 } 170 } 171 172 public Exp accept(Validator validator) { 173 return this; 174 } 175 176 public Calc accept(ExpCompiler compiler) { 177 return new ConstantCalc(getType(), o); 178 } 179 180 public Object accept(MdxVisitor visitor) { 181 return visitor.visit(this); 182 } 183 184 public Object getValue() { 185 return o; 186 } 187 188 public int getIntValue() { 189 if (o instanceof Number) { 190 return ((Number) o).intValue(); 191 } else { 192 throw Util.newInternal("cannot convert " + o + " to int"); 193 } 194 } 195 196} 197 198// End Literal.java