001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/StrToTupleFunDef.java#7 $ 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.calc.Calc; 013 import mondrian.calc.ExpCompiler; 014 import mondrian.calc.StringCalc; 015 import mondrian.calc.impl.AbstractMemberCalc; 016 import mondrian.calc.impl.AbstractTupleCalc; 017 import mondrian.mdx.ResolvedFunCall; 018 import mondrian.mdx.DimensionExpr; 019 import mondrian.mdx.HierarchyExpr; 020 import mondrian.olap.*; 021 import mondrian.olap.type.Type; 022 import mondrian.olap.type.TupleType; 023 import mondrian.olap.type.MemberType; 024 import mondrian.olap.type.StringType; 025 import mondrian.resource.MondrianResource; 026 027 import java.util.ArrayList; 028 import java.util.List; 029 030 /** 031 * Definition of the <code>StrToTuple</code> MDX function. 032 * 033 * @author jhyde 034 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/StrToTupleFunDef.java#7 $ 035 * @since Mar 23, 2006 036 */ 037 class StrToTupleFunDef extends FunDefBase { 038 static final ResolverImpl Resolver = new ResolverImpl(); 039 040 private StrToTupleFunDef(int[] parameterTypes) { 041 super("StrToTuple", 042 null, 043 "Constructs a tuple from a string.", 044 Syntax.Function, Category.Tuple, parameterTypes); 045 } 046 047 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 048 final StringCalc stringCalc = compiler.compileString(call.getArg(0)); 049 Type elementType = call.getType(); 050 if (elementType instanceof MemberType) { 051 final Hierarchy hierarchy = elementType.getHierarchy(); 052 return new AbstractMemberCalc(call, new Calc[] {stringCalc}) { 053 public Member evaluateMember(Evaluator evaluator) { 054 String string = stringCalc.evaluateString(evaluator); 055 return parseMember(evaluator, string, hierarchy); 056 } 057 }; 058 } else { 059 TupleType tupleType = (TupleType) elementType; 060 final Hierarchy[] hierarchies = 061 new Hierarchy[tupleType.elementTypes.length]; 062 for (int i = 0; i < tupleType.elementTypes.length; i++) { 063 hierarchies[i] = tupleType.elementTypes[i].getHierarchy(); 064 } 065 return new AbstractTupleCalc(call, new Calc[] {stringCalc}) { 066 public Member[] evaluateTuple(Evaluator evaluator) { 067 String string = stringCalc.evaluateString(evaluator); 068 return parseTuple(evaluator, string, hierarchies); 069 } 070 }; 071 } 072 } 073 074 /** 075 * Parses a tuple, such as "([Gender].[M], [Marital Status].[S])". 076 * 077 * @param evaluator Evaluator, provides a {@link mondrian.olap.SchemaReader} 078 * and {@link Cube} 079 * @param string String to parse 080 * @param hierarchies Hierarchies of the members 081 * @return Tuple represented as array of members 082 */ 083 private Member[] parseTuple( 084 Evaluator evaluator, String string, Hierarchy[] hierarchies) 085 { 086 final Member[] members = new Member[hierarchies.length]; 087 int i = StrToSetFunDef.parseTuple( 088 evaluator, string, 0, members, hierarchies); 089 // todo: check for garbage at end of string 090 return members; 091 } 092 093 private Member parseMember( 094 Evaluator evaluator, String string, Hierarchy hierarchy) { 095 Member[] members = {null}; 096 int i = StrToSetFunDef.parseMember( 097 evaluator, string, 0, members, new Hierarchy[] {hierarchy}, 0); 098 // todo: check for garbage at end of string 099 return members[0]; 100 } 101 102 public Exp createCall(Validator validator, Exp[] args) { 103 final int argCount = args.length; 104 if (argCount <= 1) { 105 throw MondrianResource.instance().MdxFuncArgumentsNum.ex(getName()); 106 } 107 for (int i = 1; i < argCount; i++) { 108 final Exp arg = args[i]; 109 if (arg instanceof DimensionExpr) { 110 // if arg is a dimension, switch to dimension's default 111 // hierarchy 112 DimensionExpr dimensionExpr = (DimensionExpr) arg; 113 Dimension dimension = dimensionExpr.getDimension(); 114 args[i] = new HierarchyExpr(dimension.getHierarchy()); 115 } else if (arg instanceof HierarchyExpr) { 116 // nothing 117 } else { 118 throw MondrianResource.instance().MdxFuncNotHier.ex( 119 i + 1, getName()); 120 } 121 } 122 return super.createCall(validator, args); 123 } 124 125 public Type getResultType(Validator validator, Exp[] args) { 126 switch (args.length) { 127 case 1: 128 // This is a call to the standard version of StrToTuple, 129 // which doesn't give us any hints about type. 130 return new TupleType(null); 131 132 case 2: 133 final Type argType = args[1].getType(); 134 return new MemberType( 135 argType.getDimension(), 136 argType.getHierarchy(), 137 argType.getLevel(), 138 null); 139 140 default: { 141 // This is a call to Mondrian's extended version of 142 // StrToTuple, of the form 143 // StrToTuple(s, <Hier1>, ... , <HierN>) 144 // 145 // The result is a tuple 146 // (<Hier1>, ... , <HierN>) 147 final List<Type> list = new ArrayList<Type>(); 148 for (int i = 1; i < args.length; i++) { 149 Exp arg = args[i]; 150 final Type type = arg.getType(); 151 list.add(type); 152 } 153 final Type[] types = list.toArray(new Type[list.size()]); 154 return new TupleType(types); 155 } 156 } 157 } 158 159 private static class ResolverImpl extends ResolverBase { 160 ResolverImpl() { 161 super("StrToTuple", 162 "StrToTuple(<String Expression>)", 163 "Constructs a tuple from a string.", 164 Syntax.Function); 165 } 166 167 public FunDef resolve( 168 Exp[] args, Validator validator, int[] conversionCount) { 169 if (args.length < 1) { 170 return null; 171 } 172 Type type = args[0].getType(); 173 if (!(type instanceof StringType)) { 174 return null; 175 } 176 for (int i = 1; i < args.length; i++) { 177 Exp exp = args[i]; 178 if (!(exp instanceof DimensionExpr 179 || exp instanceof HierarchyExpr)) { 180 return null; 181 } 182 } 183 int[] argTypes = new int[args.length]; 184 argTypes[0] = Category.String; 185 for (int i = 1; i < argTypes.length; i++) { 186 argTypes[i] = Category.Hierarchy; 187 } 188 return new StrToTupleFunDef(argTypes); 189 } 190 191 public FunDef getFunDef() { 192 return new StrToTupleFunDef(new int[] {Category.String}); 193 } 194 } 195 } 196 197 // End StrToTupleFunDef.java