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