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) 2002-2005 Julian Hyde 008// Copyright (C) 2005-2011 Pentaho and others 009// All Rights Reserved. 010*/ 011package mondrian.olap.fun; 012 013import mondrian.calc.*; 014import mondrian.calc.impl.AbstractTupleCalc; 015import mondrian.mdx.ResolvedFunCall; 016import mondrian.olap.*; 017import mondrian.olap.type.*; 018 019import java.io.PrintWriter; 020import java.util.List; 021 022/** 023 * <code>TupleFunDef</code> implements the '(...)' operator which builds 024 * tuples, as in <code>([Time].CurrentMember, 025 * [Stores].[USA].[California])</code>. 026 * 027 * @author jhyde 028 * @since 3 March, 2002 029 */ 030public class TupleFunDef extends FunDefBase { 031 private final int[] argTypes; 032 static final ResolverImpl Resolver = new ResolverImpl(); 033 034 private TupleFunDef(int[] argTypes) { 035 super( 036 "()", 037 "(<Member> [, <Member>]...)", 038 "Parenthesis operator constructs a tuple. If there is only one member, the expression is equivalent to the member expression.", 039 Syntax.Parentheses, 040 Category.Tuple, 041 argTypes); 042 this.argTypes = argTypes; 043 } 044 045 public int getReturnCategory() { 046 return Category.Tuple; 047 } 048 049 public int[] getParameterCategories() { 050 return argTypes; 051 } 052 053 public void unparse(Exp[] args, PrintWriter pw) { 054 ExpBase.unparseList(pw, args, "(", ", ", ")"); 055 } 056 057 public Type getResultType(Validator validator, Exp[] args) { 058 // _Tuple(<Member1>[,<MemberI>]...), which is written 059 // (<Member1>[,<MemberI>]...), has type [Hie1] x ... x [HieN]. 060 // 061 // If there is only one member, it merely represents a parenthesized 062 // expression, whose Hierarchy is that of the member. 063 if (args.length == 1) { 064 return TypeUtil.toMemberType(args[0].getType()); 065 } else { 066 MemberType[] types = new MemberType[args.length]; 067 for (int i = 0; i < args.length; i++) { 068 Exp arg = args[i]; 069 types[i] = TypeUtil.toMemberType(arg.getType()); 070 } 071 TupleType.checkHierarchies(types); 072 return new TupleType(types); 073 } 074 } 075 076 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 077 final Exp[] args = call.getArgs(); 078 final MemberCalc[] memberCalcs = new MemberCalc[args.length]; 079 for (int i = 0; i < args.length; i++) { 080 memberCalcs[i] = compiler.compileMember(args[i]); 081 } 082 return new CalcImpl(call, memberCalcs); 083 } 084 085 public static class CalcImpl extends AbstractTupleCalc { 086 private final MemberCalc[] memberCalcs; 087 088 public CalcImpl(ResolvedFunCall call, MemberCalc[] memberCalcs) { 089 super(call, memberCalcs); 090 this.memberCalcs = memberCalcs; 091 } 092 093 public Member[] evaluateTuple(Evaluator evaluator) { 094 final Member[] members = new Member[memberCalcs.length]; 095 for (int i = 0; i < members.length; i++) { 096 final Member member = 097 members[i] = 098 memberCalcs[i].evaluateMember(evaluator); 099 if (member == null || member.isNull()) { 100 return null; 101 } 102 } 103 return members; 104 } 105 106 public MemberCalc[] getMemberCalcs() { 107 return memberCalcs; 108 } 109 } 110 111 private static class ResolverImpl extends ResolverBase { 112 public ResolverImpl() { 113 super("()", null, null, Syntax.Parentheses); 114 } 115 116 public FunDef resolve( 117 Exp[] args, 118 Validator validator, 119 List<Conversion> conversions) 120 { 121 // Compare with TupleFunDef.getReturnCategory(). For example, 122 // ([Gender].members) is a set, 123 // ([Gender].[M]) is a member, 124 // (1 + 2) is a numeric, 125 // but 126 // ([Gender].[M], [Marital Status].[S]) is a tuple. 127 if (args.length == 1) { 128 return new ParenthesesFunDef(args[0].getCategory()); 129 } else { 130 final int[] argTypes = new int[args.length]; 131 for (int i = 0; i < args.length; i++) { 132 // Arg must be a member: 133 // OK: ([Gender].[S], [Time].[1997]) (member, member) 134 // OK: ([Gender], [Time]) (dimension, dimension) 135 // Not OK: 136 // ([Gender].[S], [Store].[Store City]) (member, level) 137 if (!validator.canConvert( 138 i, args[i], Category.Member, conversions)) 139 { 140 return null; 141 } 142 argTypes[i] = Category.Member; 143 } 144 return new TupleFunDef(argTypes); 145 } 146 } 147 } 148} 149 150// End TupleFunDef.java