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) 2006-2011 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.olap.fun; 011 012import mondrian.calc.Calc; 013import mondrian.calc.ExpCompiler; 014import mondrian.calc.impl.ConstantCalc; 015import mondrian.calc.impl.GenericCalc; 016import mondrian.mdx.ResolvedFunCall; 017import mondrian.olap.*; 018 019import java.util.ArrayList; 020import java.util.List; 021 022/** 023 * Definition of the matched <code>CASE</code> MDX operator. 024 * 025 * Syntax is: 026 * <blockquote><pre><code>Case <Expression> 027 * When <Expression> Then <Expression> 028 * [...] 029 * [Else <Expression>] 030 * End</code></blockquote>. 031 * 032 * @see CaseTestFunDef 033 * @author jhyde 034 * @since Mar 23, 2006 035 */ 036class CaseMatchFunDef extends FunDefBase { 037 static final ResolverImpl Resolver = new ResolverImpl(); 038 039 private CaseMatchFunDef(FunDef dummyFunDef) { 040 super(dummyFunDef); 041 } 042 043 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 044 final Exp[] args = call.getArgs(); 045 final List<Calc> calcList = new ArrayList<Calc>(); 046 final Calc valueCalc = 047 compiler.compileScalar(args[0], true); 048 calcList.add(valueCalc); 049 final int matchCount = (args.length - 1) / 2; 050 final Calc[] matchCalcs = new Calc[matchCount]; 051 final Calc[] exprCalcs = new Calc[matchCount]; 052 for (int i = 0, j = 1; i < exprCalcs.length; i++) { 053 matchCalcs[i] = compiler.compileScalar(args[j++], true); 054 calcList.add(matchCalcs[i]); 055 exprCalcs[i] = compiler.compile(args[j++]); 056 calcList.add(exprCalcs[i]); 057 } 058 final Calc defaultCalc = 059 args.length % 2 == 0 060 ? compiler.compile(args[args.length - 1]) 061 : ConstantCalc.constantNull(call.getType()); 062 calcList.add(defaultCalc); 063 final Calc[] calcs = calcList.toArray(new Calc[calcList.size()]); 064 065 return new GenericCalc(call) { 066 public Object evaluate(Evaluator evaluator) { 067 Object value = valueCalc.evaluate(evaluator); 068 for (int i = 0; i < matchCalcs.length; i++) { 069 Object match = matchCalcs[i].evaluate(evaluator); 070 if (match.equals(value)) { 071 return exprCalcs[i].evaluate(evaluator); 072 } 073 } 074 return defaultCalc.evaluate(evaluator); 075 } 076 077 public Calc[] getCalcs() { 078 return calcs; 079 } 080 }; 081 } 082 083 private static class ResolverImpl extends ResolverBase { 084 private ResolverImpl() { 085 super( 086 "_CaseMatch", 087 "Case <Expression> When <Expression> Then <Expression> [...] [Else <Expression>] End", 088 "Evaluates various expressions, and returns the corresponding expression for the first which matches a particular value.", 089 Syntax.Case); 090 } 091 092 public FunDef resolve( 093 Exp[] args, 094 Validator validator, 095 List<Conversion> conversions) 096 { 097 if (args.length < 3) { 098 return null; 099 } 100 int valueType = args[0].getCategory(); 101 int returnType = args[2].getCategory(); 102 int j = 0; 103 int clauseCount = (args.length - 1) / 2; 104 int mismatchingArgs = 0; 105 if (!validator.canConvert(j, args[j++], valueType, conversions)) { 106 mismatchingArgs++; 107 } 108 for (int i = 0; i < clauseCount; i++) { 109 if (!validator.canConvert(j, args[j++], valueType, conversions)) 110 { 111 mismatchingArgs++; 112 } 113 if (!validator.canConvert( 114 j, args[j++], returnType, conversions)) 115 { 116 mismatchingArgs++; 117 } 118 } 119 if (j < args.length) { 120 if (!validator.canConvert( 121 j, args[j++], returnType, conversions)) 122 { 123 mismatchingArgs++; 124 } 125 } 126 Util.assertTrue(j == args.length); 127 if (mismatchingArgs != 0) { 128 return null; 129 } 130 131 FunDef dummy = createDummyFunDef(this, returnType, args); 132 return new CaseMatchFunDef(dummy); 133 } 134 135 public boolean requiresExpression(int k) { 136 return true; 137 } 138 } 139} 140 141// End CaseMatchFunDef.java