001    /*
002    // $Id: //open/mondrian/src/main/mondrian/rolap/agg/ListPredicate.java#7 $
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.StarPredicate;
013    import mondrian.rolap.RolapStar;
014    import mondrian.rolap.BitKey;
015    import mondrian.rolap.sql.SqlQuery;
016    import mondrian.olap.Util;
017    
018    import java.util.HashMap;
019    import java.util.List;
020    import java.util.ArrayList;
021    
022    /**
023     * Base class for {@link AndPredicate} and {@link OrPredicate}.
024     *
025     * @see mondrian.rolap.agg.ListColumnPredicate
026     *
027     * @author jhyde
028     * @version $Id: //open/mondrian/src/main/mondrian/rolap/agg/ListPredicate.java#7 $
029     */
030    public abstract class ListPredicate implements StarPredicate {
031        protected final List<StarPredicate> children =
032            new ArrayList<StarPredicate>();
033    
034        /**
035         * Hash map of children predicates, keyed off of the hash code of each
036         * child.  Each entry in the map is a list of predicates matching that
037         * hash code.
038         */
039        private HashMap<Integer, List<StarPredicate>> childrenHashMap;
040    
041        /**
042         * Pre-computed hash code for this list column predicate
043         */
044        private int hashValue;
045    
046        protected final List<RolapStar.Column> columns =
047            new ArrayList<RolapStar.Column>();
048    
049        protected BitKey columnBitKey;
050    
051        protected ListPredicate(List<StarPredicate> predicateList) {
052            columnBitKey = null;
053            childrenHashMap = null;
054            hashValue = 0;
055            for (StarPredicate predicate : predicateList) {
056                if (columnBitKey == null) {
057                    columnBitKey =
058                        predicate.getConstrainedColumnBitKey().copy();
059                } else {
060                    columnBitKey =
061                        columnBitKey.or(predicate.getConstrainedColumnBitKey());
062                }
063                children.add(predicate);
064                for (RolapStar.Column column :
065                    predicate.getConstrainedColumnList()) {
066                    if (!columns.contains(column)) {
067                        columns.add(column);
068                    }
069                }
070            }
071        }
072    
073        public List<RolapStar.Column> getConstrainedColumnList() {
074            return columns;
075        }
076    
077        public BitKey getConstrainedColumnBitKey() {
078            return columnBitKey;
079        }
080    
081        public List<StarPredicate> getChildren() {
082            return children;
083        }
084    
085        public int hashCode() {
086            // Don't use the default list hashcode because we want a hash code
087            // that's not order dependent
088            if (hashValue == 0) {
089                hashValue = 37;
090                for (StarPredicate child : children) {
091                    int childHashCode = child.hashCode();
092                    if (childHashCode != 0) {
093                        hashValue *= childHashCode;
094                    }
095                }
096                hashValue ^= children.size();
097            }
098            return hashValue;
099        }
100    
101        public boolean equalConstraint(StarPredicate that) {
102            boolean isEqual =
103                that instanceof ListPredicate &&
104                getConstrainedColumnBitKey().equals(
105                    that.getConstrainedColumnBitKey());
106    
107            if (isEqual) {
108                ListPredicate thatPred = (ListPredicate) that;
109                if (getOp() != thatPred.getOp() ||
110                    getChildren().size() != thatPred.getChildren().size()) {
111                    isEqual = false;
112                }
113    
114                if (isEqual) {
115                    // Create a hash map of the children predicates, if not
116                    // already done
117                    if (childrenHashMap == null) {
118                        childrenHashMap =
119                            new HashMap<Integer, List<StarPredicate>>();
120                        for (StarPredicate thisChild : getChildren()) {
121                            Integer key = new Integer(thisChild.hashCode());
122                            List<StarPredicate> predList = childrenHashMap.get(key);
123                            if (predList == null) {
124                                predList = new ArrayList<StarPredicate>();
125                            }
126                            predList.add(thisChild);
127                            childrenHashMap.put(key, predList);
128                        }
129                    }
130    
131                    // Loop through thatPred's children predicates.  There needs
132                    // to be a matching entry in the hash map for each child
133                    // predicate.
134                    for (StarPredicate thatChild : thatPred.getChildren()) {
135                        List<StarPredicate> predList =
136                            childrenHashMap.get(thatChild.hashCode());
137                        if (predList == null) {
138                            isEqual = false;
139                            break;
140                        }
141                        boolean foundMatch = false;
142                        for (StarPredicate pred : predList) {
143                            if (thatChild.equalConstraint(pred)) {
144                                foundMatch = true;
145                                break;
146                            }
147                        }
148                        if (!foundMatch) {
149                            isEqual = false;
150                            break;
151                        }
152                    }
153                }
154            }
155    
156            return isEqual;
157    
158        }
159    
160        public StarPredicate minus(StarPredicate predicate) {
161            throw Util.needToImplement(this);
162        }
163    
164        public void toSql(SqlQuery sqlQuery, StringBuilder buf) {
165            if (children.size() == 1) {
166                children.get(0).toSql(sqlQuery, buf);
167            } else {
168                int k = 0;
169                buf.append("(");
170                for (StarPredicate child : children) {
171                    if (k++ > 0) {
172                        buf.append(" ").append(getOp()).append(" ");
173                    }
174                    child.toSql(sqlQuery, buf);
175                }
176                buf.append(")");
177            }
178        }
179    
180        protected abstract String getOp();
181    
182        public void describe(StringBuilder buf) {
183            buf.append(getOp()).append("(");
184            int k = 0;
185            for (StarPredicate child : children) {
186                if (k++ > 0) {
187                    buf.append(", ");
188                }
189                buf.append(child);
190            }
191            buf.append(')');
192        }
193    
194    
195        public String toString() {
196            final StringBuilder buf = new StringBuilder();
197            describe(buf);
198            return buf.toString();
199        }
200    }
201    
202    // End ListPredicate.java