001    /*
002    // $Id: //open/mondrian/src/main/mondrian/rolap/RolapNativeFilter.java#21 $
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) 2005-2008 Julian Hyde
007    // Copyright (C) 2004-2005 TONBELLER AG
008    // All Rights Reserved.
009    // You must accept the terms of that agreement to use this software.
010    */
011    package mondrian.rolap;
012    
013    import java.util.ArrayList;
014    import java.util.List;
015    
016    import javax.sql.DataSource;
017    
018    import mondrian.olap.*;
019    import mondrian.rolap.sql.SqlQuery;
020    import mondrian.rolap.sql.TupleConstraint;
021    
022    /**
023     * Computes a Filter(set, condition) in SQL.
024     *
025     * @author av
026     * @since Nov 21, 2005
027     * @version $Id: //open/mondrian/src/main/mondrian/rolap/RolapNativeFilter.java#21 $
028     */
029    public class RolapNativeFilter extends RolapNativeSet {
030    
031        public RolapNativeFilter() {
032            super.setEnabled(MondrianProperties.instance().EnableNativeFilter.get());
033        }
034    
035        static class FilterConstraint extends SetConstraint {
036            String filterExpr;
037    
038            public FilterConstraint(CrossJoinArg[] args, RolapEvaluator evaluator, String filterByExpr) {
039                super(args, evaluator, true);
040                this.filterExpr = filterByExpr;
041            }
042    
043            /**
044             * we alwas need to join the fact table because we want to evalutate
045             * the filter expression against a fact.
046             */
047            protected boolean isJoinRequired() {
048                return true;
049            }
050    
051            public void addConstraint(SqlQuery sqlQuery, RolapCube baseCube) {
052                sqlQuery.addHaving(filterExpr);
053                super.addConstraint(sqlQuery, baseCube);
054            }
055    
056            public Object getCacheKey() {
057                List<Object> key = new ArrayList<Object>();
058                key.add(super.getCacheKey());
059                key.add(filterExpr);
060                return key;
061            }
062        }
063    
064        protected boolean restrictMemberTypes() {
065            return true;
066        }
067    
068        NativeEvaluator createEvaluator(RolapEvaluator evaluator, FunDef fun, Exp[] args) {
069            if (!isEnabled()) {
070                return null;
071            }
072            if (!FilterConstraint.isValidContext(evaluator)) {
073                return null;
074            }
075            // is this "Filter(<set>, <numeric expr>)"
076            String funName = fun.getName();
077            if (!"Filter".equalsIgnoreCase(funName)) {
078                return null;
079            }
080    
081            if (args.length != 2) {
082                return null;
083            }
084    
085            // extract the set expression
086            CrossJoinArg[] cargs = checkCrossJoinArg(evaluator, args[0]);
087            if (cargs == null) {
088                return null;
089            }
090            if (isPreferInterpreter(cargs, false)) {
091                return null;
092            }
093    
094            // extract "order by" expression
095            SchemaReader schemaReader = evaluator.getSchemaReader();
096            DataSource ds = schemaReader.getDataSource();
097    
098            // generate the WHERE condition
099            SqlQuery sqlQuery = SqlQuery.newQuery(ds, "NativeFilter");
100            RolapNativeSql sql = new RolapNativeSql(sqlQuery);
101            String filterExpr = sql.generateFilterCondition(args[1]);
102            if (filterExpr == null) {
103                return null;
104            }
105    
106            // check to see if evaluator contains a calculated member.
107            // this is necessary due to the SqlConstraintsUtils.addContextConstraint()
108            // method which gets called when generating the native SQL
109            if (SqlConstraintUtils.containsCalculatedMember(evaluator.getMembers())) {
110                return null;
111            }
112    
113            LOGGER.debug("using native filter");
114    
115            evaluator = overrideContext(evaluator, cargs, sql.getStoredMeasure());
116    
117            TupleConstraint constraint = new FilterConstraint(cargs, evaluator, filterExpr);
118            return new SetEvaluator(cargs, schemaReader, constraint);
119        }
120    
121    }
122    
123    // End RolapNativeFilter.java