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