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.ConstantCalc; 015import mondrian.mdx.ResolvedFunCall; 016import mondrian.olap.Evaluator; 017import mondrian.olap.FunDef; 018 019/** 020 * Definition of the <code>Head</code> and <code>Tail</code> 021 * MDX builtin functions. 022 * 023 * @author jhyde 024 * @since Mar 23, 2006 025 */ 026class HeadTailFunDef extends FunDefBase { 027 static final Resolver TailResolver = 028 new ReflectiveMultiResolver( 029 "Tail", 030 "Tail(<Set>[, <Count>])", 031 "Returns a subset from the end of a set.", 032 new String[] {"fxx", "fxxn"}, 033 HeadTailFunDef.class); 034 035 static final Resolver HeadResolver = 036 new ReflectiveMultiResolver( 037 "Head", 038 "Head(<Set>[, < Numeric Expression >])", 039 "Returns the first specified number of elements in a set.", 040 new String[] {"fxx", "fxxn"}, 041 HeadTailFunDef.class); 042 043 private final boolean head; 044 045 public HeadTailFunDef(FunDef dummyFunDef) { 046 super(dummyFunDef); 047 head = dummyFunDef.getName().equals("Head"); 048 } 049 050 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 051 final ListCalc listCalc = 052 compiler.compileList(call.getArg(0)); 053 final IntegerCalc integerCalc = 054 call.getArgCount() > 1 055 ? compiler.compileInteger(call.getArg(1)) 056 : ConstantCalc.constantInteger(1); 057 if (head) { 058 return new AbstractListCalc( 059 call, new Calc[] {listCalc, integerCalc}) 060 { 061 public TupleList evaluateList(Evaluator evaluator) { 062 final int savepoint = evaluator.savepoint(); 063 try { 064 evaluator.setNonEmpty(false); 065 TupleList list = listCalc.evaluateList(evaluator); 066 int count = integerCalc.evaluateInteger(evaluator); 067 return head(count, list); 068 } finally { 069 evaluator.restore(savepoint); 070 } 071 } 072 }; 073 } else { 074 return new AbstractListCalc( 075 call, new Calc[] {listCalc, integerCalc}) 076 { 077 public TupleList evaluateList(Evaluator evaluator) { 078 final int savepoint = evaluator.savepoint(); 079 try { 080 evaluator.setNonEmpty(false); 081 TupleList list = listCalc.evaluateList(evaluator); 082 int count = integerCalc.evaluateInteger(evaluator); 083 return tail(count, list); 084 } finally { 085 evaluator.restore(savepoint); 086 } 087 } 088 }; 089 } 090 } 091 092 static TupleList tail(final int count, final TupleList members) { 093 assert members != null; 094 final int memberCount = members.size(); 095 if (count >= memberCount) { 096 return members; 097 } 098 if (count <= 0) { 099 return TupleCollections.emptyList(members.getArity()); 100 } 101 return members.subList(members.size() - count, members.size()); 102 } 103 104 static TupleList head(final int count, final TupleList members) { 105 assert members != null; 106 if (count <= 0) { 107 return TupleCollections.emptyList(members.getArity()); 108 } 109 return members.subList(0, Math.min(count, members.size())); 110 } 111} 112 113// End HeadTailFunDef.java