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