File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\expression\ConditionAndOr.java.html

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