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

COVERAGE SUMMARY FOR SOURCE FILE [ConditionInSelect.java]

nameclass, %method, %block, %line, %
ConditionInSelect.java100% (1/1)92%  (11/12)95%  (366/384)95%  (82.8/87)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ConditionInSelect100% (1/1)92%  (11/12)95%  (366/384)95%  (82.8/87)
isDisjunctive (): boolean 0%   (0/1)0%   (0/2)0%   (0/1)
getValue (Session): Value 100% (1/1)89%  (117/131)94%  (20.8/22)
createIndexConditions (Session, TableFilter): void 100% (1/1)94%  (34/36)83%  (10/12)
ConditionInSelect (Database, Expression, Query, boolean, int): void 100% (1/1)100% (18/18)100% (7/7)
getCost (): int 100% (1/1)100% (8/8)100% (1/1)
getSQL (): String 100% (1/1)100% (58/58)100% (9/9)
getValueSlow (LocalResult, Value): Value 100% (1/1)100% (55/55)100% (18/18)
isEverything (ExpressionVisitor): boolean 100% (1/1)100% (14/14)100% (1/1)
mapColumns (ColumnResolver, int): void 100% (1/1)100% (19/19)100% (4/4)
optimize (Session): Expression 100% (1/1)100% (23/23)100% (6/6)
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.api.ErrorCode;
9import org.h2.command.dml.Query;
10import org.h2.engine.Database;
11import org.h2.engine.Session;
12import org.h2.index.IndexCondition;
13import org.h2.message.DbException;
14import org.h2.result.LocalResult;
15import org.h2.table.ColumnResolver;
16import org.h2.table.TableFilter;
17import org.h2.util.StringUtils;
18import org.h2.value.Value;
19import org.h2.value.ValueBoolean;
20import org.h2.value.ValueNull;
21 
22/**
23 * An 'in' condition with a subquery, as in WHERE ID IN(SELECT ...)
24 */
25public class ConditionInSelect extends Condition {
26 
27    private final Database database;
28    private Expression left;
29    private final Query query;
30    private final boolean all;
31    private final int compareType;
32    private int queryLevel;
33 
34    public ConditionInSelect(Database database, Expression left, Query query,
35            boolean all, int compareType) {
36        this.database = database;
37        this.left = left;
38        this.query = query;
39        this.all = all;
40        this.compareType = compareType;
41    }
42 
43    @Override
44    public Value getValue(Session session) {
45        query.setSession(session);
46        query.setDistinct(true);
47        LocalResult rows = query.query(0);
48        try {
49            Value l = left.getValue(session);
50            if (rows.getRowCount() == 0) {
51                return ValueBoolean.get(all);
52            } else if (l == ValueNull.INSTANCE) {
53                return l;
54            }
55            if (!session.getDatabase().getSettings().optimizeInSelect) {
56                return getValueSlow(rows, l);
57            }
58            if (all || (compareType != Comparison.EQUAL &&
59                    compareType != Comparison.EQUAL_NULL_SAFE)) {
60                return getValueSlow(rows, l);
61            }
62            int dataType = rows.getColumnType(0);
63            if (dataType == Value.NULL) {
64                return ValueBoolean.get(false);
65            }
66            l = l.convertTo(dataType);
67            if (rows.containsDistinct(new Value[] { l })) {
68                return ValueBoolean.get(true);
69            }
70            if (rows.containsDistinct(new Value[] { ValueNull.INSTANCE })) {
71                return ValueNull.INSTANCE;
72            }
73            return ValueBoolean.get(false);
74        } finally {
75            rows.close();
76        }
77    }
78 
79    private Value getValueSlow(LocalResult rows, Value l) {
80        // this only returns the correct result if the result has at least one
81        // row, and if l is not null
82        boolean hasNull = false;
83        boolean result = all;
84        while (rows.next()) {
85            boolean value;
86            Value r = rows.currentRow()[0];
87            if (r == ValueNull.INSTANCE) {
88                value = false;
89                hasNull = true;
90            } else {
91                value = Comparison.compareNotNull(database, l, r, compareType);
92            }
93            if (!value && all) {
94                result = false;
95                break;
96            } else if (value && !all) {
97                result = true;
98                break;
99            }
100        }
101        if (!result && hasNull) {
102            return ValueNull.INSTANCE;
103        }
104        return ValueBoolean.get(result);
105    }
106 
107    @Override
108    public void mapColumns(ColumnResolver resolver, int level) {
109        left.mapColumns(resolver, level);
110        query.mapColumns(resolver, level + 1);
111        this.queryLevel = Math.max(level, this.queryLevel);
112    }
113 
114    @Override
115    public Expression optimize(Session session) {
116        left = left.optimize(session);
117        query.setRandomAccessResult(true);
118        query.prepare();
119        if (query.getColumnCount() != 1) {
120            throw DbException.get(ErrorCode.SUBQUERY_IS_NOT_SINGLE_COLUMN);
121        }
122        // Can not optimize: the data may change
123        return this;
124    }
125 
126    @Override
127    public void setEvaluatable(TableFilter tableFilter, boolean b) {
128        left.setEvaluatable(tableFilter, b);
129        query.setEvaluatable(tableFilter, b);
130    }
131 
132    @Override
133    public String getSQL() {
134        StringBuilder buff = new StringBuilder();
135        buff.append('(').append(left.getSQL()).append(' ');
136        if (all) {
137            buff.append(Comparison.getCompareOperator(compareType)).
138                append(" ALL");
139        } else {
140            if (compareType == Comparison.EQUAL) {
141                buff.append("IN");
142            } else {
143                buff.append(Comparison.getCompareOperator(compareType)).
144                    append(" ANY");
145            }
146        }
147        buff.append("(\n").append(StringUtils.indent(query.getPlanSQL(), 4, false)).
148            append("))");
149        return buff.toString();
150    }
151 
152    @Override
153    public void updateAggregate(Session session) {
154        left.updateAggregate(session);
155        query.updateAggregate(session);
156    }
157 
158    @Override
159    public boolean isEverything(ExpressionVisitor visitor) {
160        return left.isEverything(visitor) && query.isEverything(visitor);
161    }
162 
163    @Override
164    public int getCost() {
165        return left.getCost() + query.getCostAsExpression();
166    }
167 
168    @Override
169    public void createIndexConditions(Session session, TableFilter filter) {
170        if (!session.getDatabase().getSettings().optimizeInList) {
171            return;
172        }
173        if (!(left instanceof ExpressionColumn)) {
174            return;
175        }
176        ExpressionColumn l = (ExpressionColumn) left;
177        if (filter != l.getTableFilter()) {
178            return;
179        }
180        ExpressionVisitor visitor = ExpressionVisitor.getNotFromResolverVisitor(filter);
181        if (!query.isEverything(visitor)) {
182            return;
183        }
184        filter.addIndexCondition(IndexCondition.getInQuery(l, query));
185    }
186 
187    @Override
188    public boolean isDisjunctive() {
189        return true;
190    }
191 
192}

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