1 10 package mondrian.olap.fun; 11 12 import mondrian.olap.type.*; 13 import mondrian.olap.*; 14 import mondrian.calc.*; 15 import mondrian.calc.impl.AbstractTupleCalc; 16 import mondrian.calc.impl.AbstractMemberCalc; 17 import mondrian.mdx.ResolvedFunCall; 18 19 import java.util.List ; 20 import java.util.ArrayList ; 21 22 29 class SetItemFunDef extends FunDefBase { 30 static final Resolver intResolver = new ReflectiveMultiResolver( 31 "Item", 32 "<Set>.Item(<Index>)", 33 "Returns a tuple from the set specified in <Set>. The tuple to be returned is specified by the zero-based position of the tuple in the set in <Index>.", 34 new String [] {"mmxn"}, 35 SetItemFunDef.class); 36 37 static final Resolver stringResolver = new ResolverBase( 38 "Item", 39 "<Set>.Item(<String> [, ...])", 40 "Returns a tuple from the set specified in <Set>. The tuple to be returned is specified by the member name (or names) in <String>.", 41 Syntax.Method) { 42 43 public FunDef resolve( 44 Exp[] args, Validator validator, int[] conversionCount) { 45 if (args.length < 1) { 46 return null; 47 } 48 final Exp setExp = args[0]; 49 if (!(setExp.getType() instanceof SetType)) { 50 return null; 51 } 52 final SetType setType = (SetType) setExp.getType(); 53 int arity; 54 if (setType.getElementType() instanceof TupleType) { 55 arity = ((TupleType) setType.getElementType()).elementTypes.length; 56 } else { 57 arity = 1; 58 } 59 for (int i = 1; i < args.length; i++) { 61 if (!validator.canConvert( 62 args[i], Category.String, conversionCount)) { 63 return null; 64 } 65 } 66 if (args.length - 1 != arity) { 67 throw Util.newError("Argument count does not match set's cardinality " + arity); 68 } 69 final int category = arity == 1 ? Category.Member : Category.Tuple; 70 FunDef dummy = createDummyFunDef(this, category, args); 71 return new SetItemFunDef(dummy); 72 } 73 }; 74 75 public SetItemFunDef(FunDef dummyFunDef) { 76 super(dummyFunDef); 77 } 78 79 public Type getResultType(Validator validator, Exp[] args) { 80 SetType setType = (SetType) args[0].getType(); 81 return setType.getElementType(); 82 } 83 84 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 85 final ListCalc listCalc = 86 compiler.compileList(call.getArg(0)); 87 final Type elementType = ((SetType) listCalc.getType()).getElementType(); 88 final boolean isString = call.getArgCount() < 2 || 89 call.getArg(1).getType() instanceof StringType; 90 final IntegerCalc indexCalc; 91 final StringCalc[] stringCalcs; 92 List <Calc> calcList = new ArrayList <Calc>(); 93 calcList.add(listCalc); 94 if (isString) { 95 indexCalc = null; 96 stringCalcs = new StringCalc[call.getArgCount() - 1]; 97 for (int i = 0; i < stringCalcs.length; i++) { 98 stringCalcs[i] = compiler.compileString(call.getArg(i + 1)); 99 calcList.add(stringCalcs[i]); 100 } 101 } else { 102 stringCalcs = null; 103 indexCalc = compiler.compileInteger(call.getArg(1)); 104 calcList.add(indexCalc); 105 } 106 Calc[] calcs = calcList.toArray(new Calc[calcList.size()]); 107 if (elementType instanceof TupleType) { 108 final TupleType tupleType = (TupleType) elementType; 109 final Member[] nullTuple = makeNullTuple(tupleType); 110 if (isString) { 111 return new AbstractTupleCalc(call, calcs) { 112 public Member[] evaluateTuple(Evaluator evaluator) { 113 final List <Member[]> list = listCalc.evaluateList(evaluator); 114 assert list != null; 115 String [] results = new String [stringCalcs.length]; 116 for (int i = 0; i < stringCalcs.length; i++) { 117 results[i] = 118 stringCalcs[i].evaluateString(evaluator); 119 } 120 listLoop: 121 for (Member[] members : list) { 122 for (int j = 0; j < results.length; j++) { 123 String result = results[j]; 124 final Member member = members[j]; 125 if (!matchMember(member, result)) { 126 continue listLoop; 127 } 128 } 129 return members; 131 } 132 return null; 135 } 136 }; 137 } else { 138 return new AbstractTupleCalc(call, calcs) { 139 public Member[] evaluateTuple(Evaluator evaluator) { 140 final List list = listCalc.evaluateList(evaluator); 141 assert list != null; 142 final int index = indexCalc.evaluateInteger(evaluator); 143 int listSize = list.size(); 144 if (index >= listSize || index < 0) { 145 return nullTuple; 146 } else { 147 return (Member[]) list.get(index); 148 } 149 } 150 }; 151 } 152 } else { 153 final MemberType memberType = (MemberType) elementType; 154 final Member nullMember = makeNullMember(memberType); 155 if (isString) { 156 return new AbstractMemberCalc(call, calcs) { 157 public Member evaluateMember(Evaluator evaluator) { 158 final List <Member> list = listCalc.evaluateList(evaluator); 159 assert list != null; 160 final String result = 161 stringCalcs[0].evaluateString(evaluator); 162 for (Member member : list) { 163 if (matchMember(member, result)) { 164 return member; 165 } 166 } 167 return nullMember; 168 } 169 }; 170 } else { 171 return new AbstractMemberCalc(call, calcs) { 172 public Member evaluateMember(Evaluator evaluator) { 173 final List list = listCalc.evaluateList(evaluator); 174 assert list != null; 175 final int index = indexCalc.evaluateInteger(evaluator); 176 int listSize = list.size(); 177 if (index >= listSize || index < 0) { 178 return nullMember; 179 } else { 180 return (Member) list.get(index); 181 } 182 } 183 }; 184 } 185 } 186 } 187 188 private static boolean matchMember(final Member member, String name) { 189 return member.getName().equals(name); 190 } 191 192 Object makeNullMember(Evaluator evaluator, Exp[] args) { 193 final Type elementType = ((SetType) args[0].getType()).getElementType(); 194 return makeNullMemberOrTuple(elementType); 195 } 196 197 Object makeNullMemberOrTuple(final Type elementType) { 198 if (elementType instanceof MemberType) { 199 MemberType memberType = (MemberType) elementType; 200 return makeNullMember(memberType); 201 } else if (elementType instanceof TupleType) { 202 return makeNullTuple((TupleType) elementType); 203 } else { 204 throw Util.newInternal("bad type " + elementType); 205 } 206 } 207 } 208 209 | Popular Tags |