Expression valueListExpression = node.getValueList();
if (!(valueListExpression instanceof InListExpression)) {
throw new UnsupportedOperationException("Compilation of IN subquery is not supported yet");
}
ByteCodeNode value = process(node.getValue(), context);
ImmutableList.Builder<ByteCodeNode> values = ImmutableList.builder();
InListExpression valueList = (InListExpression) valueListExpression;
for (Expression test : valueList.getValues()) {
ByteCodeNode testNode = process(test, context);
values.add(testNode);
}
Type type = expressionTypes.get(node.getValue());
Class<?> javaType = type.getJavaType();
FunctionBinding hashCodeFunction = bootstrapFunctionBinder.bindOperator(
OperatorType.HASH_CODE,
getSessionByteCode,
ImmutableList.<ByteCodeNode>of(NOP),
ImmutableList.of(type));
ImmutableListMultimap.Builder<Integer, ByteCodeNode> hashBucketsBuilder = ImmutableListMultimap.builder();
ImmutableList.Builder<ByteCodeNode> defaultBucket = ImmutableList.builder();
ImmutableSet.Builder<Object> constantValuesBuilder = ImmutableSet.builder();
for (ByteCodeNode testNode : values.build()) {
if (testNode instanceof Constant) {
Constant constant = (Constant) testNode;
Object testValue = constant.getValue();
constantValuesBuilder.add(testValue);
if (javaType == boolean.class) {
// boolean constant is actually an integer type
testValue = ((Number) testValue).intValue() != 0;
}
int hashCode;
try {
hashCode = (int) hashCodeFunction.getCallSite().dynamicInvoker().invoke(testValue);
}
catch (Throwable throwable) {
throw new IllegalArgumentException("Error processing IN statement: error calculating hash code for " + testValue, throwable);
}
hashBucketsBuilder.put(hashCode, testNode);
}
else {
defaultBucket.add(testNode);
}
}
ImmutableListMultimap<Integer, ByteCodeNode> hashBuckets = hashBucketsBuilder.build();
ImmutableSet<Object> constantValues = constantValuesBuilder.build();
LabelNode end = new LabelNode("end");
LabelNode match = new LabelNode("match");
LabelNode noMatch = new LabelNode("noMatch");
LabelNode defaultLabel = new LabelNode("default");
ByteCodeNode switchBlock;
if (constantValues.size() < 1000) {
Block switchCaseBlocks = new Block(context);
LookupSwitchBuilder switchBuilder = lookupSwitchBuilder();
for (Entry<Integer, Collection<ByteCodeNode>> bucket : hashBuckets.asMap().entrySet()) {
LabelNode label = new LabelNode("inHash" + bucket.getKey());