001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/CaseMatchFunDef.java#5 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2006-2007 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.olap.fun; 011 012 import mondrian.olap.*; 013 import mondrian.calc.Calc; 014 import mondrian.calc.ExpCompiler; 015 import mondrian.calc.impl.ConstantCalc; 016 import mondrian.calc.impl.GenericCalc; 017 import mondrian.mdx.ResolvedFunCall; 018 019 import java.util.List; 020 import java.util.ArrayList; 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 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/CaseMatchFunDef.java#5 $ 035 * @since Mar 23, 2006 036 */ 037 class CaseMatchFunDef extends FunDefBase { 038 static final ResolverImpl Resolver = new ResolverImpl(); 039 040 private CaseMatchFunDef(FunDef dummyFunDef) { 041 super(dummyFunDef); 042 } 043 044 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 045 final Exp[] args = call.getArgs(); 046 final List<Calc> calcList = new ArrayList<Calc>(); 047 final Calc valueCalc = 048 compiler.compileScalar(args[0], true); 049 calcList.add(valueCalc); 050 final int matchCount = (args.length - 1) / 2; 051 final Calc[] matchCalcs = new Calc[matchCount]; 052 final Calc[] exprCalcs = new Calc[matchCount]; 053 for (int i = 0, j = 1; i < exprCalcs.length; i++) { 054 matchCalcs[i] = compiler.compileScalar(args[j++], true); 055 calcList.add(matchCalcs[i]); 056 exprCalcs[i] = compiler.compile(args[j++]); 057 calcList.add(exprCalcs[i]); 058 } 059 final Calc defaultCalc = 060 args.length % 2 == 0 ? 061 compiler.compile(args[args.length - 1]) : 062 ConstantCalc.constantNull(call.getType()); 063 calcList.add(defaultCalc); 064 final Calc[] calcs = calcList.toArray(new Calc[calcList.size()]); 065 066 return new GenericCalc(call) { 067 public Object evaluate(Evaluator evaluator) { 068 069 Object value = valueCalc.evaluate(evaluator); 070 for (int i = 0; i < matchCalcs.length; i++) { 071 Object match = matchCalcs[i].evaluate(evaluator); 072 if (match.equals(value)) { 073 return exprCalcs[i].evaluate(evaluator); 074 } 075 } 076 return defaultCalc.evaluate(evaluator); 077 } 078 079 public Calc[] getCalcs() { 080 return calcs; 081 } 082 }; 083 } 084 085 private static class ResolverImpl extends ResolverBase { 086 private ResolverImpl() { 087 super( 088 "_CaseMatch", 089 "Case <Expression> When <Expression> Then <Expression> [...] [Else <Expression>] End", 090 "Evaluates various expressions, and returns the corresponding expression for the first which matches a particular value.", 091 Syntax.Case); 092 } 093 094 public FunDef resolve( 095 Exp[] args, Validator validator, int[] conversionCount) { 096 if (args.length < 3) { 097 return null; 098 } 099 int valueType = args[0].getCategory(); 100 int returnType = args[2].getCategory(); 101 int j = 0; 102 int clauseCount = (args.length - 1) / 2; 103 int mismatchingArgs = 0; 104 if (!validator.canConvert(args[j++], valueType, conversionCount)) { 105 mismatchingArgs++; 106 } 107 for (int i = 0; i < clauseCount; i++) { 108 if (!validator.canConvert(args[j++], valueType, conversionCount)) { 109 mismatchingArgs++; 110 } 111 if (!validator.canConvert(args[j++], returnType, conversionCount)) { 112 mismatchingArgs++; 113 } 114 } 115 if (j < args.length) { 116 if (!validator.canConvert(args[j++], returnType, conversionCount)) { 117 mismatchingArgs++; 118 } 119 } 120 Util.assertTrue(j == args.length); 121 if (mismatchingArgs != 0) { 122 return null; 123 } 124 125 FunDef dummy = createDummyFunDef(this, returnType, args); 126 return new CaseMatchFunDef(dummy); 127 } 128 129 public boolean requiresExpression(int k) { 130 return true; 131 } 132 } 133 } 134 135 // End CaseMatchFunDef.java