001 /* 002 // $Id: //open/mondrian/src/main/mondrian/rolap/agg/AndPredicate.java#5 $ 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) 2007-2008 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.rolap.agg; 011 012 import mondrian.rolap.RolapUtil; 013 import mondrian.rolap.StarPredicate; 014 import mondrian.rolap.BitKey; 015 import mondrian.rolap.sql.SqlQuery; 016 017 import java.util.*; 018 019 /** 020 * Predicate which is the intersection of a list of predicates. It evaluates to 021 * true if all of the predicates evaluate to true. 022 * 023 * @see OrPredicate 024 * 025 * @author jhyde 026 * @version $Id: //open/mondrian/src/main/mondrian/rolap/agg/AndPredicate.java#5 $ 027 */ 028 public class AndPredicate extends ListPredicate { 029 030 public AndPredicate(List<StarPredicate> predicateList) { 031 super(predicateList); 032 } 033 034 public boolean evaluate(List<Object> valueList) { 035 // NOTE: If we know that every predicate in the list is a 036 // ValueColumnPredicate, we could optimize the evaluate method by 037 // building a value list at construction time. But it's a tradeoff, 038 // considering the extra time and space required. 039 for (StarPredicate childPredicate : children) { 040 if (childPredicate.evaluate(valueList)) { 041 return true; 042 } 043 } 044 return false; 045 } 046 047 public StarPredicate and(StarPredicate predicate) { 048 if (predicate instanceof AndPredicate) { 049 ListPredicate that = (ListPredicate) predicate; 050 final List<StarPredicate> list = 051 new ArrayList<StarPredicate>(children); 052 list.addAll(that.children); 053 return new AndPredicate(list); 054 } else { 055 final List<StarPredicate> list = 056 new ArrayList<StarPredicate>(children); 057 list.add(predicate); 058 return new AndPredicate(list); 059 } 060 } 061 062 063 public StarPredicate or(StarPredicate predicate) { 064 List<StarPredicate> list = new ArrayList<StarPredicate>(); 065 list.add(this); 066 list.add(predicate); 067 return new OrPredicate(list); 068 } 069 070 public BitKey checkInList(SqlQuery sqlQuery, BitKey inListLHSBitKey) { 071 072 // AND predicate by itself is not using IN list; when it is 073 // one of the children to an OR predicate, then using IN list 074 // is helpful. The later is checked by passing in a bitmap that 075 // represent the LHS or the IN list, i.e. the columns that are 076 // constrained by the OR. 077 078 // If the child predicates contains null values, those predicates cannot 079 // be translated as IN list; however, the rest of the child predicates 080 // might still be translated to IN. 081 // For example, neither of the two AND conditions below(part of an OR list) 082 // can be translated using IN list, covering all the levels 083 // 084 // (null, null, San Francisco) 085 // (null, null, New York) 086 // 087 // However, after extracting the null part, they can be translated to: 088 // 089 // (country is null AND state is null AND city IN ("San Fancisco", "New York")) 090 // 091 // which is still more compact than the default AND/OR translation: 092 // 093 // (country is null AND state is null AND city = "San Francisco") OR 094 // (country is null AND state is null AND city = "New York") 095 // 096 // This method will mark all the columns that can be translated as part of IN 097 // list, so that similar predicates can be grouped together to form partial 098 // IN list sql. By default, all columns constrained by this predicates can be 099 // part of an IN list. 100 // 101 // This is very similar to the logic in SqlConstraintUtil.generateMultiValueInExpr(). 102 // The only difference being that the predicates here are all "flattened" so the 103 // hierarchy information is no longer available to guide the grouping of predicates 104 // with common parents. So some optimization possible in generateMultiValueInExpr() 105 // is not tried here, as they require implementing "longest common prefix" algorithm 106 // which is an overkill. 107 BitKey inListRHSBitKey = inListLHSBitKey.copy(); 108 109 if (!columnBitKey.equals(inListLHSBitKey) || 110 (children.size() > 1 && 111 !sqlQuery.getDialect().supportsMultiValueInExpr())) { 112 inListRHSBitKey.clear(); 113 } else { 114 for (StarPredicate predicate : children) { 115 // If any predicate requires comparison to null value, cannot use 116 // IN list for this predicate. 117 if (predicate instanceof ValueColumnPredicate) { 118 ValueColumnPredicate columnPred = ((ValueColumnPredicate) predicate); 119 if (columnPred.getValue() == RolapUtil.sqlNullValue) { 120 // This column predicate cannot be translated to IN 121 inListRHSBitKey.clear( 122 columnPred.getConstrainedColumn().getBitPosition()); 123 } 124 // else 125 // do nothing because this column predicate can be translated to IN 126 } else { 127 inListRHSBitKey.clear(); 128 break; 129 } 130 } 131 } 132 return inListRHSBitKey; 133 } 134 135 /* 136 * Generate value list for this predicate to be used in an IN-list 137 * sql predicate. 138 * 139 * The values in a multi-column IN list predicates are generated in the 140 * same order, based on the bit position from the columnBitKey. 141 * 142 */ 143 public void toInListSql(SqlQuery sqlQuery, StringBuilder buf, BitKey inListRHSBitKey) { 144 boolean firstValue = true; 145 buf.append("("); 146 /* 147 * Arranging children according to the bit position. This is required 148 * as RHS of IN list needs to list the column values in the same order. 149 */ 150 Set<ValueColumnPredicate> sortedPredicates = 151 new TreeSet<ValueColumnPredicate>(); 152 153 for (StarPredicate predicate : children) { 154 // inListPossible() checks gaurantees that predicate is of type 155 // ValueColumnPredicate 156 assert predicate instanceof ValueColumnPredicate; 157 if (inListRHSBitKey.get( 158 ((ValueColumnPredicate)predicate).getConstrainedColumn().getBitPosition())) { 159 sortedPredicates.add((ValueColumnPredicate)predicate); 160 } 161 } 162 163 for (ValueColumnPredicate predicate : sortedPredicates) { 164 if (firstValue) { 165 firstValue = false; 166 } else { 167 buf.append(", "); 168 } 169 sqlQuery.getDialect().quote( 170 buf, predicate.getValue(), 171 predicate.getConstrainedColumn().getDatatype()); 172 } 173 buf.append(")"); 174 } 175 176 protected String getOp() { 177 return "and"; 178 } 179 } 180 181 // End AndPredicate.java