EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.expression]

COVERAGE SUMMARY FOR SOURCE FILE [ConditionAndOr.java]

nameclass, %method, %block, %line, %
ConditionAndOr.java100% (1/1)93%  (13/14)84%  (538/644)85%  (114.9/135)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ConditionAndOr100% (1/1)93%  (13/14)84%  (538/644)85%  (114.9/135)
getExpression (boolean): Expression 0%   (0/1)0%   (0/8)0%   (0/1)
optimize (Session): Expression 100% (1/1)80%  (268/334)78%  (53/68)
getSQL (): String 100% (1/1)81%  (46/57)86%  (6/7)
getNotIfPossible (Session): Expression 100% (1/1)85%  (34/40)88%  (7/8)
getValue (Session): Value 100% (1/1)87%  (72/83)96%  (22/23)
isDisjunctive (): boolean 100% (1/1)88%  (14/16)87%  (0.9/1)
ConditionAndOr (int, Expression, Expression): void 100% (1/1)90%  (18/20)86%  (6/7)
addFilterConditions (TableFilter, boolean): void 100% (1/1)100% (19/19)100% (5/5)
createIndexConditions (Session, TableFilter): void 100% (1/1)100% (14/14)100% (4/4)
getCost (): int 100% (1/1)100% (8/8)100% (1/1)
isEverything (ExpressionVisitor): boolean 100% (1/1)100% (14/14)100% (1/1)
mapColumns (ColumnResolver, int): void 100% (1/1)100% (11/11)100% (3/3)
setEvaluatable (TableFilter, boolean): void 100% (1/1)100% (11/11)100% (3/3)
updateAggregate (Session): void 100% (1/1)100% (9/9)100% (3/3)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.expression;
7 
8import org.h2.engine.Session;
9import org.h2.engine.SysProperties;
10import org.h2.message.DbException;
11import org.h2.table.ColumnResolver;
12import org.h2.table.TableFilter;
13import org.h2.value.Value;
14import org.h2.value.ValueBoolean;
15import org.h2.value.ValueNull;
16 
17/**
18 * An 'and' or 'or' condition as in WHERE ID=1 AND NAME=?
19 */
20public class ConditionAndOr extends Condition {
21 
22    /**
23     * The AND condition type as in ID=1 AND NAME='Hello'.
24     */
25    public static final int AND = 0;
26 
27    /**
28     * The OR condition type as in ID=1 OR NAME='Hello'.
29     */
30    public static final int OR = 1;
31 
32    private final int andOrType;
33    private Expression left, right;
34 
35    public ConditionAndOr(int andOrType, Expression left, Expression right) {
36        this.andOrType = andOrType;
37        this.left = left;
38        this.right = right;
39        if (SysProperties.CHECK && (left == null || right == null)) {
40            DbException.throwInternalError();
41        }
42    }
43 
44    @Override
45    public String getSQL() {
46        String sql;
47        switch (andOrType) {
48        case AND:
49            sql = left.getSQL() + "\n    AND " + right.getSQL();
50            break;
51        case OR:
52            sql = left.getSQL() + "\n    OR " + right.getSQL();
53            break;
54        default:
55            throw DbException.throwInternalError("andOrType=" + andOrType);
56        }
57        return "(" + sql + ")";
58    }
59 
60    @Override
61    public void createIndexConditions(Session session, TableFilter filter) {
62        if (andOrType == AND) {
63            left.createIndexConditions(session, filter);
64            right.createIndexConditions(session, filter);
65        }
66    }
67 
68    @Override
69    public Expression getNotIfPossible(Session session) {
70        // (NOT (A OR B)): (NOT(A) AND NOT(B))
71        // (NOT (A AND B)): (NOT(A) OR NOT(B))
72        Expression l = left.getNotIfPossible(session);
73        if (l == null) {
74            l = new ConditionNot(left);
75        }
76        Expression r = right.getNotIfPossible(session);
77        if (r == null) {
78            r = new ConditionNot(right);
79        }
80        int reversed = andOrType == AND ? OR : AND;
81        return new ConditionAndOr(reversed, l, r);
82    }
83 
84    @Override
85    public Value getValue(Session session) {
86        Value l = left.getValue(session);
87        Value r;
88        switch (andOrType) {
89        case AND: {
90            if (Boolean.FALSE.equals(l.getBoolean())) {
91                return l;
92            }
93            r = right.getValue(session);
94            if (Boolean.FALSE.equals(r.getBoolean())) {
95                return r;
96            }
97            if (l == ValueNull.INSTANCE) {
98                return l;
99            }
100            if (r == ValueNull.INSTANCE) {
101                return r;
102            }
103            return ValueBoolean.get(true);
104        }
105        case OR: {
106            if (Boolean.TRUE.equals(l.getBoolean())) {
107                return l;
108            }
109            r = right.getValue(session);
110            if (Boolean.TRUE.equals(r.getBoolean())) {
111                return r;
112            }
113            if (l == ValueNull.INSTANCE) {
114                return l;
115            }
116            if (r == ValueNull.INSTANCE) {
117                return r;
118            }
119            return ValueBoolean.get(false);
120        }
121        default:
122            throw DbException.throwInternalError("type=" + andOrType);
123        }
124    }
125 
126    @Override
127    public Expression optimize(Session session) {
128        // NULL handling: see wikipedia,
129        // http://www-cs-students.stanford.edu/~wlam/compsci/sqlnulls
130        left = left.optimize(session);
131        right = right.optimize(session);
132        int lc = left.getCost(), rc = right.getCost();
133        if (rc < lc) {
134            Expression t = left;
135            left = right;
136            right = t;
137        }
138        // this optimization does not work in the following case,
139        // but NOT is optimized before:
140        // CREATE TABLE TEST(A INT, B INT);
141        // INSERT INTO TEST VALUES(1, NULL);
142        // SELECT * FROM TEST WHERE NOT (B=A AND B=0); // no rows
143        // SELECT * FROM TEST WHERE NOT (B=A AND B=0 AND A=0); // 1, NULL
144        if (session.getDatabase().getSettings().optimizeTwoEquals &&
145                andOrType == AND) {
146            // try to add conditions (A=B AND B=1: add A=1)
147            if (left instanceof Comparison && right instanceof Comparison) {
148                Comparison compLeft = (Comparison) left;
149                Comparison compRight = (Comparison) right;
150                Expression added = compLeft.getAdditional(
151                        session, compRight, true);
152                if (added != null) {
153                    added = added.optimize(session);
154                    ConditionAndOr a = new ConditionAndOr(AND, this, added);
155                    return a;
156                }
157            }
158        }
159        // TODO optimization: convert ((A=1 AND B=2) OR (A=1 AND B=3)) to
160        // (A=1 AND (B=2 OR B=3))
161        if (andOrType == OR &&
162                session.getDatabase().getSettings().optimizeOr) {
163            // try to add conditions (A=B AND B=1: add A=1)
164            if (left instanceof Comparison &&
165                    right instanceof Comparison) {
166                Comparison compLeft = (Comparison) left;
167                Comparison compRight = (Comparison) right;
168                Expression added = compLeft.getAdditional(
169                        session, compRight, false);
170                if (added != null) {
171                    return added.optimize(session);
172                }
173            } else if (left instanceof ConditionIn &&
174                    right instanceof Comparison) {
175                Expression added = ((ConditionIn) left).
176                        getAdditional((Comparison) right);
177                if (added != null) {
178                    return added.optimize(session);
179                }
180            } else if (right instanceof ConditionIn &&
181                    left instanceof Comparison) {
182                Expression added = ((ConditionIn) right).
183                        getAdditional((Comparison) left);
184                if (added != null) {
185                    return added.optimize(session);
186                }
187            } else if (left instanceof ConditionInConstantSet &&
188                    right instanceof Comparison) {
189                Expression added = ((ConditionInConstantSet) left).
190                        getAdditional(session, (Comparison) right);
191                if (added != null) {
192                    return added.optimize(session);
193                }
194            } else if (right instanceof ConditionInConstantSet &&
195                    left instanceof Comparison) {
196                Expression added = ((ConditionInConstantSet) right).
197                        getAdditional(session, (Comparison) left);
198                if (added != null) {
199                    return added.optimize(session);
200                }
201            }
202        }
203        // TODO optimization: convert .. OR .. to UNION if the cost is lower
204        Value l = left.isConstant() ? left.getValue(session) : null;
205        Value r = right.isConstant() ? right.getValue(session) : null;
206        if (l == null && r == null) {
207            return this;
208        }
209        if (l != null && r != null) {
210            return ValueExpression.get(getValue(session));
211        }
212        switch (andOrType) {
213        case AND:
214            if (l != null) {
215                if (Boolean.FALSE.equals(l.getBoolean())) {
216                    return ValueExpression.get(l);
217                } else if (Boolean.TRUE.equals(l.getBoolean())) {
218                    return right;
219                }
220            } else if (r != null) {
221                if (Boolean.FALSE.equals(r.getBoolean())) {
222                    return ValueExpression.get(r);
223                } else if (Boolean.TRUE.equals(r.getBoolean())) {
224                    return left;
225                }
226            }
227            break;
228        case OR:
229            if (l != null) {
230                if (Boolean.TRUE.equals(l.getBoolean())) {
231                    return ValueExpression.get(l);
232                } else if (Boolean.FALSE.equals(l.getBoolean())) {
233                    return right;
234                }
235            } else if (r != null) {
236                if (Boolean.TRUE.equals(r.getBoolean())) {
237                    return ValueExpression.get(r);
238                } else if (Boolean.FALSE.equals(r.getBoolean())) {
239                    return left;
240                }
241            }
242            break;
243        default:
244            DbException.throwInternalError("type=" + andOrType);
245        }
246        return this;
247    }
248 
249    @Override
250    public void addFilterConditions(TableFilter filter, boolean outerJoin) {
251        if (andOrType == AND) {
252            left.addFilterConditions(filter, outerJoin);
253            right.addFilterConditions(filter, outerJoin);
254        } else {
255            super.addFilterConditions(filter, outerJoin);
256        }
257    }
258 
259    @Override
260    public void mapColumns(ColumnResolver resolver, int level) {
261        left.mapColumns(resolver, level);
262        right.mapColumns(resolver, level);
263    }
264 
265    @Override
266    public void setEvaluatable(TableFilter tableFilter, boolean b) {
267        left.setEvaluatable(tableFilter, b);
268        right.setEvaluatable(tableFilter, b);
269    }
270 
271    @Override
272    public void updateAggregate(Session session) {
273        left.updateAggregate(session);
274        right.updateAggregate(session);
275    }
276 
277    @Override
278    public boolean isEverything(ExpressionVisitor visitor) {
279        return left.isEverything(visitor) && right.isEverything(visitor);
280    }
281 
282    @Override
283    public int getCost() {
284        return left.getCost() + right.getCost();
285    }
286 
287    @Override
288    public boolean isDisjunctive() {
289        return andOrType == OR || left.isDisjunctive() || right.isDisjunctive();
290    }
291 
292    /**
293     * Get the left or the right sub-expression of this condition.
294     *
295     * @param getLeft true to get the left sub-expression, false to get the
296     *            right sub-expression.
297     * @return the sub-expression
298     */
299    public Expression getExpression(boolean getLeft) {
300        return getLeft ? this.left : right;
301    }
302 
303}

[all classes][org.h2.expression]
EMMA 2.0.5312 (C) Vladimir Roubtsov