001 /* 002 // This software is subject to the terms of the Common Public License 003 // Agreement, available at the following URL: 004 // http://www.opensource.org/licenses/cpl.html. 005 // Copyright (C) 2004-2005 TONBELLER AG 006 // All Rights Reserved. 007 // You must accept the terms of that agreement to use this software. 008 */ 009 package mondrian.rolap; 010 011 import java.util.ArrayList; 012 import java.util.List; 013 014 import javax.sql.DataSource; 015 016 import mondrian.olap.*; 017 import mondrian.rolap.sql.SqlQuery; 018 import mondrian.rolap.sql.TupleConstraint; 019 import mondrian.rolap.sql.SqlQuery.Dialect; 020 021 /** 022 * Computes a TopCount in SQL. 023 * 024 * @author av 025 * @since Nov 21, 2005 026 * @version $Id: //open/mondrian/src/main/mondrian/rolap/RolapNativeTopCount.java#22 $ 027 */ 028 public class RolapNativeTopCount extends RolapNativeSet { 029 030 public RolapNativeTopCount() { 031 super.setEnabled(MondrianProperties.instance().EnableNativeTopCount.get()); 032 } 033 034 static class TopCountConstraint extends SetConstraint { 035 String orderByExpr; 036 boolean ascending; 037 038 public TopCountConstraint( 039 CrossJoinArg[] args, RolapEvaluator evaluator, 040 String orderByExpr, boolean ascending) { 041 super(args, evaluator, true); 042 this.orderByExpr = orderByExpr; 043 this.ascending = ascending; 044 } 045 046 /** 047 * we alwas need to join the fact table because we want to evalutate 048 * the top count expression which involves a fact. 049 */ 050 protected boolean isJoinRequired() { 051 return true; 052 } 053 054 public void addConstraint(SqlQuery sqlQuery, RolapCube baseCube) { 055 if (orderByExpr != null) { 056 Dialect dialect = sqlQuery.getDialect(); 057 if (dialect.requiresOrderByAlias()) { 058 String alias = sqlQuery.nextColumnAlias(); 059 alias = dialect.quoteIdentifier(alias); 060 sqlQuery.addSelect(orderByExpr, alias); 061 sqlQuery.addOrderBy(alias, ascending, true, false); 062 } else { 063 sqlQuery.addOrderBy(orderByExpr, ascending, true, false); 064 } 065 } 066 super.addConstraint(sqlQuery, baseCube); 067 } 068 069 public Object getCacheKey() { 070 List<Object> key = new ArrayList<Object>(); 071 key.add(super.getCacheKey()); 072 key.add(orderByExpr); 073 key.add(ascending); 074 return key; 075 } 076 } 077 078 protected boolean restrictMemberTypes() { 079 return true; 080 } 081 082 NativeEvaluator createEvaluator(RolapEvaluator evaluator, FunDef fun, Exp[] args) { 083 boolean ascending; 084 085 if (!isEnabled()) 086 return null; 087 if (!TopCountConstraint.isValidContext(evaluator)) { 088 return null; 089 } 090 091 // is this "TopCount(<set>, <count>, [<numeric expr>])" 092 String funName = fun.getName(); 093 if ("TopCount".equalsIgnoreCase(funName)) { 094 ascending = false; 095 } else if ("BottomCount".equalsIgnoreCase(funName)) { 096 ascending = true; 097 } else { 098 return null; 099 } 100 if (args.length < 2 || args.length > 3) { 101 return null; 102 } 103 // extract the set expression 104 CrossJoinArg[] cargs = checkCrossJoinArg(evaluator, args[0]); 105 if (cargs == null) { 106 return null; 107 } 108 if (isPreferInterpreter(cargs, false)) { 109 return null; 110 } 111 112 // extract count 113 if (!(args[1] instanceof Literal)) { 114 return null; 115 } 116 int count = ((Literal) args[1]).getIntValue(); 117 118 // extract "order by" expression 119 SchemaReader schemaReader = evaluator.getSchemaReader(); 120 DataSource ds = schemaReader.getDataSource(); 121 122 // generate the ORDER BY Clause 123 SqlQuery sqlQuery = SqlQuery.newQuery(ds, "NativeTopCount"); 124 RolapNativeSql sql = new RolapNativeSql(sqlQuery); 125 String orderByExpr = null; 126 if (args.length == 3) { 127 orderByExpr = sql.generateTopCountOrderBy(args[2]); 128 if (orderByExpr == null) { 129 return null; 130 } 131 } 132 LOGGER.debug("using native topcount"); 133 evaluator = overrideContext(evaluator, cargs, sql.getStoredMeasure()); 134 135 TupleConstraint constraint = 136 new TopCountConstraint(cargs, evaluator, orderByExpr, ascending); 137 SetEvaluator sev = new SetEvaluator(cargs, schemaReader, constraint); 138 sev.setMaxRows(count); 139 return sev; 140 } 141 } 142 143 // End RolapNativeTopCount.java