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.AbstractListCalc; 014import mondrian.calc.impl.UnaryTupleList; 015import mondrian.mdx.*; 016import mondrian.olap.*; 017import mondrian.olap.type.*; 018import mondrian.resource.MondrianResource; 019 020import java.util.ArrayList; 021import java.util.List; 022 023/** 024 * Definition of the <code>StrToSet</code> MDX builtin function. 025 * 026 * @author jhyde 027 * @since Mar 23, 2006 028 */ 029class StrToSetFunDef extends FunDefBase { 030 static final ResolverImpl Resolver = new ResolverImpl(); 031 032 private StrToSetFunDef(int[] parameterTypes) { 033 super( 034 "StrToSet", 035 "<Set> StrToSet(<String>[, <Hierarchy>...])", 036 "Constructs a set from a string expression.", 037 Syntax.Function, Category.Set, parameterTypes); 038 } 039 040 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 041 final StringCalc stringCalc = compiler.compileString(call.getArg(0)); 042 SetType type = (SetType) call.getType(); 043 Type elementType = type.getElementType(); 044 if (elementType instanceof MemberType) { 045 final Hierarchy hierarchy = elementType.getHierarchy(); 046 return new AbstractListCalc(call, new Calc[] {stringCalc}) { 047 public TupleList evaluateList(Evaluator evaluator) { 048 String string = stringCalc.evaluateString(evaluator); 049 if (string == null) { 050 throw newEvalException( 051 MondrianResource.instance().NullValue.ex()); 052 } 053 return new UnaryTupleList( 054 parseMemberList(evaluator, string, hierarchy)); 055 } 056 }; 057 } else { 058 TupleType tupleType = (TupleType) elementType; 059 final List<Hierarchy> hierarchyList = tupleType.getHierarchies(); 060 return new AbstractListCalc(call, new Calc[] {stringCalc}) { 061 public TupleList evaluateList(Evaluator evaluator) { 062 String string = stringCalc.evaluateString(evaluator); 063 if (string == null) { 064 throw newEvalException( 065 MondrianResource.instance().NullValue.ex()); 066 } 067 return parseTupleList(evaluator, string, hierarchyList); 068 } 069 }; 070 } 071 } 072 073 public Exp createCall(Validator validator, Exp[] args) { 074 final int argCount = args.length; 075 if (argCount <= 1) { 076 throw MondrianResource.instance().MdxFuncArgumentsNum.ex(getName()); 077 } 078 for (int i = 1; i < argCount; i++) { 079 final Exp arg = args[i]; 080 if (arg instanceof DimensionExpr) { 081 // if arg is a dimension, switch to dimension's default 082 // hierarchy 083 DimensionExpr dimensionExpr = (DimensionExpr) arg; 084 Dimension dimension = dimensionExpr.getDimension(); 085 args[i] = new HierarchyExpr(dimension.getHierarchy()); 086 } else if (arg instanceof HierarchyExpr) { 087 // nothing 088 } else { 089 throw MondrianResource.instance().MdxFuncNotHier.ex( 090 i + 1, getName()); 091 } 092 } 093 return super.createCall(validator, args); 094 } 095 096 public Type getResultType(Validator validator, Exp[] args) { 097 switch (args.length) { 098 case 1: 099 // This is a call to the standard version of StrToSet, 100 // which doesn't give us any hints about type. 101 return new SetType(null); 102 103 case 2: 104 { 105 final Type argType = args[1].getType(); 106 return new SetType( 107 new MemberType( 108 argType.getDimension(), 109 argType.getHierarchy(), 110 argType.getLevel(), 111 null)); 112 } 113 114 default: 115 { 116 // This is a call to Mondrian's extended version of 117 // StrToSet, of the form 118 // StrToSet(s, <Hier1>, ... , <HierN>) 119 // 120 // The result is a set of tuples 121 // (<Hier1>, ... , <HierN>) 122 final List<MemberType> list = new ArrayList<MemberType>(); 123 for (int i = 1; i < args.length; i++) { 124 Exp arg = args[i]; 125 final Type argType = arg.getType(); 126 list.add(TypeUtil.toMemberType(argType)); 127 } 128 final MemberType[] types = 129 list.toArray(new MemberType[list.size()]); 130 TupleType.checkHierarchies(types); 131 return new SetType(new TupleType(types)); 132 } 133 } 134 } 135 136 private static class ResolverImpl extends ResolverBase { 137 ResolverImpl() { 138 super( 139 "StrToSet", 140 "StrToSet(<String Expression>)", 141 "Constructs a set from a string expression.", 142 Syntax.Function); 143 } 144 145 public FunDef resolve( 146 Exp[] args, 147 Validator validator, 148 List<Conversion> conversions) 149 { 150 if (args.length < 1) { 151 return null; 152 } 153 Type type = args[0].getType(); 154 if (!(type instanceof StringType) 155 && !(type instanceof NullType)) 156 { 157 return null; 158 } 159 for (int i = 1; i < args.length; i++) { 160 Exp exp = args[i]; 161 if (!(exp instanceof DimensionExpr 162 || exp instanceof HierarchyExpr)) 163 { 164 return null; 165 } 166 } 167 int[] argTypes = new int[args.length]; 168 argTypes[0] = Category.String; 169 for (int i = 1; i < argTypes.length; i++) { 170 argTypes[i] = Category.Hierarchy; 171 } 172 return new StrToSetFunDef(argTypes); 173 } 174 175 public FunDef getFunDef() { 176 return new StrToSetFunDef(new int[] {Category.String}); 177 } 178 } 179} 180 181// End StrToSetFunDef.java