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) 2008-2009 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.olap.fun; 011 012import mondrian.calc.*; 013import mondrian.calc.impl.*; 014import mondrian.mdx.ResolvedFunCall; 015import mondrian.olap.*; 016import mondrian.olap.type.*; 017 018/** 019 * Definition of the <code>Iif</code> MDX function. 020 * 021 * @author jhyde 022 * @since Jan 17, 2008 023 */ 024public class IifFunDef extends FunDefBase { 025 /** 026 * Creates an IifFunDef. 027 * 028 * @param name Name of the function, for example "Members". 029 * @param description Description of the function 030 * @param flags Encoding of the syntactic, return, and parameter types 031 */ 032 protected IifFunDef( 033 String name, 034 String description, 035 String flags) 036 { 037 super(name, description, flags); 038 } 039 040 public Type getResultType(Validator validator, Exp[] args) { 041 // This is messy. We have already decided which variant of Iif to use, 042 // and that involves some upcasts. For example, Iif(b, n, NULL) resolves 043 // to the type of n. We don't want to throw it away and take the most 044 // general type. So, for scalar types we create a type based on 045 // returnCategory. 046 // 047 // But for dimensional types (member, level, hierarchy, dimension, 048 // tuple) we want to preserve as much type information as possible, so 049 // we recompute the type based on the common types of all args. 050 // 051 // FIXME: We should pass more info into this method, such as the list 052 // of conversions computed while resolving overloadings. 053 switch (returnCategory) { 054 case Category.Numeric: 055 return new NumericType(); 056 case Category.String: 057 return new StringType(); 058 case Category.Logical: 059 return new BooleanType(); 060 default: 061 return TypeUtil.computeCommonType( 062 true, args[1].getType(), args[2].getType()); 063 } 064 } 065 066 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 067 final BooleanCalc booleanCalc = 068 compiler.compileBoolean(call.getArg(0)); 069 final Calc calc1 = 070 compiler.compileAs( 071 call.getArg(1), call.getType(), ResultStyle.ANY_LIST); 072 final Calc calc2 = 073 compiler.compileAs( 074 call.getArg(2), call.getType(), ResultStyle.ANY_LIST); 075 if (call.getType() instanceof SetType) { 076 return new GenericIterCalc(call) { 077 public Object evaluate(Evaluator evaluator) { 078 final boolean b = 079 booleanCalc.evaluateBoolean(evaluator); 080 Calc calc = b ? calc1 : calc2; 081 return calc.evaluate(evaluator); 082 } 083 084 public Calc[] getCalcs() { 085 return new Calc[] {booleanCalc, calc1, calc2}; 086 } 087 }; 088 } else { 089 return new GenericCalc(call) { 090 public Object evaluate(Evaluator evaluator) { 091 final boolean b = 092 booleanCalc.evaluateBoolean(evaluator); 093 Calc calc = b ? calc1 : calc2; 094 return calc.evaluate(evaluator); 095 } 096 097 public Calc[] getCalcs() { 098 return new Calc[] {booleanCalc, calc1, calc2}; 099 } 100 }; 101 } 102 } 103 104 // IIf(<Logical Expression>, <String Expression>, <String Expression>) 105 static final FunDefBase STRING_INSTANCE = new FunDefBase( 106 "IIf", 107 "Returns one of two string values determined by a logical test.", 108 "fSbSS") 109 { 110 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 111 final BooleanCalc booleanCalc = 112 compiler.compileBoolean(call.getArg(0)); 113 final StringCalc calc1 = compiler.compileString(call.getArg(1)); 114 final StringCalc calc2 = compiler.compileString(call.getArg(2)); 115 return new AbstractStringCalc( 116 call, new Calc[] {booleanCalc, calc1, calc2}) { 117 public String evaluateString(Evaluator evaluator) { 118 final boolean b = 119 booleanCalc.evaluateBoolean(evaluator); 120 StringCalc calc = b ? calc1 : calc2; 121 return calc.evaluateString(evaluator); 122 } 123 }; 124 } 125 }; 126 127 // IIf(<Logical Expression>, <Numeric Expression>, <Numeric Expression>) 128 static final FunDefBase NUMERIC_INSTANCE = 129 new IifFunDef( 130 "IIf", 131 "Returns one of two numeric values determined by a logical test.", 132 "fnbnn") 133 { 134 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) 135 { 136 final BooleanCalc booleanCalc = 137 compiler.compileBoolean(call.getArg(0)); 138 final Calc calc1 = compiler.compileScalar(call.getArg(1), true); 139 final Calc calc2 = compiler.compileScalar(call.getArg(2), true); 140 return new GenericCalc(call) { 141 public Object evaluate(Evaluator evaluator) { 142 final boolean b = 143 booleanCalc.evaluateBoolean(evaluator); 144 Calc calc = b ? calc1 : calc2; 145 return calc.evaluate(evaluator); 146 } 147 148 public Calc[] getCalcs() { 149 return new Calc[] {booleanCalc, calc1, calc2}; 150 } 151 }; 152 } 153 }; 154 155 // IIf(<Logical Expression>, <Tuple Expression>, <Tuple Expression>) 156 static final FunDefBase TUPLE_INSTANCE = 157 new IifFunDef( 158 "IIf", 159 "Returns one of two tuples determined by a logical test.", 160 "ftbtt") 161 { 162 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) 163 { 164 final BooleanCalc booleanCalc = 165 compiler.compileBoolean(call.getArg(0)); 166 final Calc calc1 = compiler.compileTuple(call.getArg(1)); 167 final Calc calc2 = compiler.compileTuple(call.getArg(2)); 168 return new GenericCalc(call) { 169 public Object evaluate(Evaluator evaluator) { 170 final boolean b = 171 booleanCalc.evaluateBoolean(evaluator); 172 Calc calc = b ? calc1 : calc2; 173 return calc.evaluate(evaluator); 174 } 175 176 public Calc[] getCalcs() { 177 return new Calc[] {booleanCalc, calc1, calc2}; 178 } 179 }; 180 } 181 }; 182 183 // IIf(<Logical Expression>, <Boolean Expression>, <Boolean Expression>) 184 static final FunDefBase BOOLEAN_INSTANCE = new FunDefBase( 185 "IIf", 186 "Returns boolean determined by a logical test.", 187 "fbbbb") 188 { 189 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 190 final BooleanCalc booleanCalc = 191 compiler.compileBoolean(call.getArg(0)); 192 final BooleanCalc booleanCalc1 = 193 compiler.compileBoolean(call.getArg(1)); 194 final BooleanCalc booleanCalc2 = 195 compiler.compileBoolean(call.getArg(2)); 196 Calc[] calcs = {booleanCalc, booleanCalc1, booleanCalc2}; 197 return new AbstractBooleanCalc(call, calcs) { 198 public boolean evaluateBoolean(Evaluator evaluator) { 199 final boolean condition = 200 booleanCalc.evaluateBoolean(evaluator); 201 if (condition) { 202 return booleanCalc1.evaluateBoolean(evaluator); 203 } else { 204 return booleanCalc2.evaluateBoolean(evaluator); 205 } 206 } 207 }; 208 } 209 }; 210 211 // IIf(<Logical Expression>, <Member Expression>, <Member Expression>) 212 static final IifFunDef MEMBER_INSTANCE = 213 new IifFunDef( 214 "IIf", 215 "Returns one of two member values determined by a logical test.", 216 "fmbmm"); 217 218 // IIf(<Logical Expression>, <Level Expression>, <Level Expression>) 219 static final IifFunDef LEVEL_INSTANCE = 220 new IifFunDef( 221 "IIf", 222 "Returns one of two level values determined by a logical test.", 223 "flbll"); 224 225 // IIf(<Logical Expression>, <Hierarchy Expression>, <Hierarchy Expression>) 226 static final IifFunDef HIERARCHY_INSTANCE = 227 new IifFunDef( 228 "IIf", 229 "Returns one of two hierarchy values determined by a logical test.", 230 "fhbhh"); 231 232 // IIf(<Logical Expression>, <Dimension Expression>, <Dimension Expression>) 233 static final IifFunDef DIMENSION_INSTANCE = 234 new IifFunDef( 235 "IIf", 236 "Returns one of two dimension values determined by a logical test.", 237 "fdbdd"); 238 239 // IIf(<Logical Expression>, <Set Expression>, <Set Expression>) 240 static final IifFunDef SET_INSTANCE = 241 new IifFunDef( 242 "IIf", 243 "Returns one of two set values determined by a logical test.", 244 "fxbxx"); 245} 246 247// End IifFunDef.java