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) 2004-2005 Julian Hyde 008// Copyright (C) 2005-2011 Pentaho 009// All Rights Reserved. 010*/ 011package mondrian.olap.fun; 012 013import mondrian.calc.*; 014import mondrian.calc.impl.AbstractListCalc; 015import mondrian.mdx.ResolvedFunCall; 016import mondrian.olap.*; 017 018import java.util.*; 019 020/** 021 * Definition of the <code>DrilldownMember</code> MDX function. 022 * 023 * @author Grzegorz Lojek 024 * @since 6 December, 2004 025 */ 026class DrilldownMemberFunDef extends FunDefBase { 027 static final String[] reservedWords = new String[] {"RECURSIVE"}; 028 static final ReflectiveMultiResolver Resolver = 029 new ReflectiveMultiResolver( 030 "DrilldownMember", 031 "DrilldownMember(<Set1>, <Set2>[, RECURSIVE])", 032 "Drills down the members in a set that are present in a second specified set.", 033 new String[]{"fxxx", "fxxxy"}, 034 DrilldownMemberFunDef.class, 035 reservedWords); 036 037 public DrilldownMemberFunDef(FunDef funDef) { 038 super(funDef); 039 } 040 041 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 042 final ListCalc listCalc1 = compiler.compileList(call.getArg(0)); 043 final ListCalc listCalc2 = compiler.compileList(call.getArg(1)); 044 final String literalArg = getLiteralArg(call, 2, "", reservedWords); 045 final boolean recursive = literalArg.equals("RECURSIVE"); 046 047 return new AbstractListCalc( 048 call, 049 new Calc[] {listCalc1, listCalc2}) 050 { 051 public TupleList evaluateList(Evaluator evaluator) { 052 final TupleList list1 = listCalc1.evaluateList(evaluator); 053 final TupleList list2 = listCalc2.evaluateList(evaluator); 054 return drilldownMember(list1, list2, evaluator); 055 } 056 057 /** 058 * Drills down an element. 059 * 060 * <p>Algorithm: If object is present in {@code memberSet} adds to 061 * result children of the object. If flag {@code recursive} is set 062 * then this method is called recursively for the children. 063 * 064 * @param evaluator Evaluator 065 * @param tuple Tuple (may have arity 1) 066 * @param memberSet Set of members 067 * @param resultList Result 068 */ 069 protected void drillDownObj( 070 Evaluator evaluator, 071 Member[] tuple, 072 Set<Member> memberSet, 073 TupleList resultList) 074 { 075 for (int k = 0; k < tuple.length; k++) { 076 Member member = tuple[k]; 077 if (memberSet.contains(member)) { 078 List<Member> children = 079 evaluator.getSchemaReader().getMemberChildren( 080 member); 081 final Member[] tuple2 = tuple.clone(); 082 for (Member childMember : children) { 083 tuple2[k] = childMember; 084 resultList.addTuple(tuple2); 085 if (recursive) { 086 drillDownObj( 087 evaluator, tuple2, memberSet, resultList); 088 } 089 } 090 break; 091 } 092 } 093 } 094 095 private TupleList drilldownMember( 096 TupleList v0, 097 TupleList v1, 098 Evaluator evaluator) 099 { 100 assert v1.getArity() == 1; 101 if (v0.isEmpty() || v1.isEmpty()) { 102 return v0; 103 } 104 105 Set<Member> set1 = new HashSet<Member>(v1.slice(0)); 106 107 TupleList result = TupleCollections.createList(v0.getArity()); 108 int i = 0, n = v0.size(); 109 final Member[] members = new Member[v0.getArity()]; 110 while (i < n) { 111 List<Member> o = v0.get(i++); 112 o.toArray(members); 113 result.add(o); 114 drillDownObj(evaluator, members, set1, result); 115 } 116 return result; 117 } 118 }; 119 } 120} 121 122// End DrilldownMemberFunDef.java