1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.expression;
import java.util.AbstractList;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.index.IndexCondition;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.value.Value;
import org.h2.value.ValueArray;
import org.h2.value.ValueBoolean;
import org.h2.value.ValueNull;
/**
* A condition with parameter as {@code = ANY(?)}.
*/
public class ConditionInParameter extends Condition {
private static final class ParameterList extends AbstractList<Expression> {
private final Parameter parameter;
ParameterList(Parameter parameter) {
this.parameter = parameter;
}
@Override
public Expression get(int index) {
Value value = parameter.getParamValue();
if (value instanceof ValueArray) {
return ValueExpression.get(((ValueArray) value).getList()[index]);
}
if (index != 0) {
throw new IndexOutOfBoundsException();
}
return ValueExpression.get(value);
}
@Override
public int size() {
if (!parameter.isValueSet()) {
return 0;
}
Value value = parameter.getParamValue();
if (value instanceof ValueArray) {
return ((ValueArray) value).getList().length;
}
return 1;
}
}
private final Database database;
private Expression left;
private final Parameter parameter;
/**
* Create a new {@code = ANY(?)} condition.
*
* @param database
* the database
* @param left
* the expression before {@code = ANY(?)}
* @param parameter
* parameter
*/
public ConditionInParameter(Database database, Expression left, Parameter parameter) {
this.database = database;
this.left = left;
this.parameter = parameter;
}
@Override
public Value getValue(Session session) {
Value l = left.getValue(session);
if (l == ValueNull.INSTANCE) {
return l;
}
boolean result = false;
boolean hasNull = false;
Value value = parameter.getValue(session);
if (value instanceof ValueArray) {
for (Value r : ((ValueArray) value).getList()) {
if (r == ValueNull.INSTANCE) {
hasNull = true;
} else {
r = r.convertTo(l.getType());
result = Comparison.compareNotNull(database, l, r, Comparison.EQUAL);
if (result) {
break;
}
}
}
} else {
if (value == ValueNull.INSTANCE) {
hasNull = true;
} else {
value = value.convertTo(l.getType());
result = Comparison.compareNotNull(database, l, value, Comparison.EQUAL);
}
}
if (!result && hasNull) {
return ValueNull.INSTANCE;
}
return ValueBoolean.get(result);
}
@Override
public void mapColumns(ColumnResolver resolver, int level) {
left.mapColumns(resolver, level);
}
@Override
public Expression optimize(Session session) {
left = left.optimize(session);
if (left.isConstant() && left == ValueExpression.getNull()) {
return left;
}
return this;
}
@Override
public void createIndexConditions(Session session, TableFilter filter) {
if (!(left instanceof ExpressionColumn)) {
return;
}
ExpressionColumn l = (ExpressionColumn) left;
if (filter != l.getTableFilter()) {
return;
}
filter.addIndexCondition(IndexCondition.getInList(l, new ParameterList(parameter)));
}
@Override
public void setEvaluatable(TableFilter tableFilter, boolean b) {
left.setEvaluatable(tableFilter, b);
}
@Override
public String getSQL() {
return '(' + left.getSQL() + " = ANY(" + parameter.getSQL() + "))";
}
@Override
public void updateAggregate(Session session) {
left.updateAggregate(session);
}
@Override
public boolean isEverything(ExpressionVisitor visitor) {
return left.isEverything(visitor) && parameter.isEverything(visitor);
}
@Override
public int getCost() {
return left.getCost();
}
}