You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by ty...@apache.org on 2014/06/20 18:48:55 UTC
git commit: Accept subtypes for function results, type casts
Repository: cassandra
Updated Branches:
refs/heads/cassandra-2.0 f6c5e020a -> 9da742d5f
Accept subtypes for function results, type casts
Patch by Tyler Hobbs; reviewed by Sylvain Lebresne for CASSANDRA-6766
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/9da742d5
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/9da742d5
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/9da742d5
Branch: refs/heads/cassandra-2.0
Commit: 9da742d5f83e1b2563be1c0d45a0e3d65a38ec44
Parents: f6c5e02
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Fri Jun 20 11:48:04 2014 -0500
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Fri Jun 20 11:48:04 2014 -0500
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../org/apache/cassandra/cql3/TypeCast.java | 2 +-
.../cassandra/cql3/functions/FunctionCall.java | 2 +-
.../cassandra/cql3/functions/Functions.java | 4 +-
.../cassandra/cql3/statements/Selection.java | 6 +-
.../cassandra/db/marshal/AbstractType.java | 23 ++-
.../apache/cassandra/db/marshal/BytesType.java | 2 +-
.../cassandra/db/marshal/CompositeType.java | 8 +-
.../apache/cassandra/db/marshal/DateType.java | 6 +
.../cassandra/db/marshal/IntegerType.java | 6 +
.../apache/cassandra/db/marshal/LongType.java | 6 +
.../cassandra/db/marshal/ReversedType.java | 6 +
.../cassandra/db/marshal/TimestampType.java | 6 +
.../apache/cassandra/db/marshal/TupleType.java | 6 +-
.../apache/cassandra/db/marshal/UUIDType.java | 6 +
.../org/apache/cassandra/cql3/TypeTest.java | 144 +++++++++++++++++++
16 files changed, 214 insertions(+), 20 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 69cc46b..dac254e 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -19,6 +19,7 @@
* Reference sstables before populating key cache (CASSANDRA-7234)
* Account for range tombstones in min/max column names (CASSANDRA-7235)
* Improve sub range repair validation (CASSANDRA-7317)
+ * Accept subtypes for function results, type casts (CASSANDRA-6766)
Merged from 1.2:
* Handle possible integer overflow in FastByteArrayOutputStream (CASSANDRA-7373)
* cqlsh: 'ascii' values weren't formatted as text (CASSANDRA-7407)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/cql3/TypeCast.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/TypeCast.java b/src/java/org/apache/cassandra/cql3/TypeCast.java
index 66b5300..64261fa 100644
--- a/src/java/org/apache/cassandra/cql3/TypeCast.java
+++ b/src/java/org/apache/cassandra/cql3/TypeCast.java
@@ -48,7 +48,7 @@ public class TypeCast implements Term.Raw
public boolean isAssignableTo(ColumnSpecification receiver)
{
- return receiver.type.asCQL3Type().equals(type);
+ return receiver.type.isValueCompatibleWith(type.getType());
}
@Override
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java b/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java
index 8db03e6..3abf65e 100644
--- a/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java
+++ b/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java
@@ -142,7 +142,7 @@ public class FunctionCall extends Term.NonTerminal
// is used as argument of another, existing, function. In that case, we return true here because we'll catch
// the fact that the method is undefined latter anyway and with a more helpful error message that if we were
// to return false here.
- return returnType == null || receiver.type.asCQL3Type().equals(returnType.asCQL3Type());
+ return returnType == null || receiver.type.isValueCompatibleWith(returnType);
}
@Override
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/cql3/functions/Functions.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/functions/Functions.java b/src/java/org/apache/cassandra/cql3/functions/Functions.java
index 5f4201d..4f108cb 100644
--- a/src/java/org/apache/cassandra/cql3/functions/Functions.java
+++ b/src/java/org/apache/cassandra/cql3/functions/Functions.java
@@ -111,7 +111,7 @@ public abstract class Functions
private static void validateTypes(Function fun, List<? extends AssignementTestable> providedArgs, ColumnSpecification receiver) throws InvalidRequestException
{
- if (!receiver.type.asCQL3Type().equals(fun.returnType().asCQL3Type()))
+ if (!receiver.type.isValueCompatibleWith(fun.returnType()))
throw new InvalidRequestException(String.format("Type error: cannot assign result of function %s (type %s) to %s (type %s)", fun.name(), fun.returnType().asCQL3Type(), receiver, receiver.type.asCQL3Type()));
if (providedArgs.size() != fun.argsType().size())
@@ -134,7 +134,7 @@ public abstract class Functions
private static boolean isValidType(Function fun, List<? extends AssignementTestable> providedArgs, ColumnSpecification receiver)
{
- if (!receiver.type.asCQL3Type().equals(fun.returnType().asCQL3Type()))
+ if (!receiver.type.isValueCompatibleWith(fun.returnType()))
return false;
if (providedArgs.size() != fun.argsType().size())
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/cql3/statements/Selection.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/Selection.java b/src/java/org/apache/cassandra/cql3/statements/Selection.java
index 123ddc3..37ab384 100644
--- a/src/java/org/apache/cassandra/cql3/statements/Selection.java
+++ b/src/java/org/apache/cassandra/cql3/statements/Selection.java
@@ -369,7 +369,7 @@ public abstract class Selection
public boolean isAssignableTo(ColumnSpecification receiver)
{
- return type.asCQL3Type().equals(receiver.type.asCQL3Type());
+ return receiver.type.isValueCompatibleWith(type);
}
@Override
@@ -401,7 +401,7 @@ public abstract class Selection
public boolean isAssignableTo(ColumnSpecification receiver)
{
- return fun.returnType().asCQL3Type().equals(receiver.type.asCQL3Type());
+ return receiver.type.isValueCompatibleWith(fun.returnType());
}
@Override
@@ -446,7 +446,7 @@ public abstract class Selection
public boolean isAssignableTo(ColumnSpecification receiver)
{
- return receiver.type.asCQL3Type().equals(isWritetime ? CQL3Type.Native.BIGINT : CQL3Type.Native.INT);
+ return receiver.type.isValueCompatibleWith(isWritetime ? LongType.instance : Int32Type.instance);
}
@Override
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/db/marshal/AbstractType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/AbstractType.java b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
index a38733c..e92f272 100644
--- a/src/java/org/apache/cassandra/db/marshal/AbstractType.java
+++ b/src/java/org/apache/cassandra/db/marshal/AbstractType.java
@@ -242,15 +242,28 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>
}
/**
- * Returns true if values of the previous AbstracType can be read by the this
- * AbsractType. Note that this is a weaker version of isCompatibleWith, as it
- * does not require that both type compare values the same way.
+ * Returns true if values of the other AbstractType can be read and "reasonably" interpreted by the this
+ * AbstractType. Note that this is a weaker version of isCompatibleWith, as it does not require that both type
+ * compare values the same way.
+ *
+ * The restriction on the other type being "reasonably" interpreted is to prevent, for example, IntegerType from
+ * being compatible with all other types. Even though any byte string is a valid IntegerType value, it doesn't
+ * necessarily make sense to interpret a UUID or a UTF8 string as an integer.
*
* Note that a type should be compatible with at least itself.
*/
- public boolean isValueCompatibleWith(AbstractType<?> previous)
+ public boolean isValueCompatibleWith(AbstractType<?> otherType)
+ {
+ return isValueCompatibleWithInternal((otherType instanceof ReversedType) ? ((ReversedType) otherType).baseType : otherType);
+ }
+
+ /**
+ * Needed to handle ReversedType in value-compatibility checks. Subclasses should implement this instead of
+ * isValueCompatibleWith().
+ */
+ protected boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
{
- return isCompatibleWith(previous);
+ return isCompatibleWith(otherType);
}
/**
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/db/marshal/BytesType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/BytesType.java b/src/java/org/apache/cassandra/db/marshal/BytesType.java
index 9e122cc..7907c2d 100644
--- a/src/java/org/apache/cassandra/db/marshal/BytesType.java
+++ b/src/java/org/apache/cassandra/db/marshal/BytesType.java
@@ -66,7 +66,7 @@ public class BytesType extends AbstractType<ByteBuffer>
}
@Override
- public boolean isValueCompatibleWith(AbstractType<?> previous)
+ public boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
{
// BytesType can read anything
return true;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/db/marshal/CompositeType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/CompositeType.java b/src/java/org/apache/cassandra/db/marshal/CompositeType.java
index 2f537fb..946ba24 100644
--- a/src/java/org/apache/cassandra/db/marshal/CompositeType.java
+++ b/src/java/org/apache/cassandra/db/marshal/CompositeType.java
@@ -237,16 +237,16 @@ public class CompositeType extends AbstractCompositeType
}
@Override
- public boolean isValueCompatibleWith(AbstractType<?> previous)
+ public boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
{
- if (this == previous)
+ if (this == otherType)
return true;
- if (!(previous instanceof CompositeType))
+ if (!(otherType instanceof CompositeType))
return false;
// Extending with new components is fine
- CompositeType cp = (CompositeType)previous;
+ CompositeType cp = (CompositeType) otherType;
if (types.size() < cp.types.size())
return false;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/db/marshal/DateType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/DateType.java b/src/java/org/apache/cassandra/db/marshal/DateType.java
index 0c97688..bf25d88 100644
--- a/src/java/org/apache/cassandra/db/marshal/DateType.java
+++ b/src/java/org/apache/cassandra/db/marshal/DateType.java
@@ -82,6 +82,12 @@ public class DateType extends AbstractType<Date>
}
@Override
+ public boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
+ {
+ return this == otherType || otherType == TimestampType.instance || otherType == LongType.instance;
+ }
+
+ @Override
public CQL3Type asCQL3Type()
{
return CQL3Type.Native.TIMESTAMP;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/db/marshal/IntegerType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/IntegerType.java b/src/java/org/apache/cassandra/db/marshal/IntegerType.java
index 726769b..ec1c7ad 100644
--- a/src/java/org/apache/cassandra/db/marshal/IntegerType.java
+++ b/src/java/org/apache/cassandra/db/marshal/IntegerType.java
@@ -136,6 +136,12 @@ public final class IntegerType extends AbstractType<BigInteger>
return decompose(integerType);
}
+ @Override
+ public boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
+ {
+ return this == otherType || Int32Type.instance.isValueCompatibleWith(otherType) || LongType.instance.isValueCompatibleWith(otherType);
+ }
+
public CQL3Type asCQL3Type()
{
return CQL3Type.Native.VARINT;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/db/marshal/LongType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/LongType.java b/src/java/org/apache/cassandra/db/marshal/LongType.java
index 9ad078e..efe7223 100644
--- a/src/java/org/apache/cassandra/db/marshal/LongType.java
+++ b/src/java/org/apache/cassandra/db/marshal/LongType.java
@@ -74,6 +74,12 @@ public class LongType extends AbstractType<Long>
return decompose(longType);
}
+ @Override
+ public boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
+ {
+ return this == otherType || otherType == DateType.instance || otherType == TimestampType.instance;
+ }
+
public CQL3Type asCQL3Type()
{
return CQL3Type.Native.BIGINT;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/db/marshal/ReversedType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/ReversedType.java b/src/java/org/apache/cassandra/db/marshal/ReversedType.java
index ef8fb92..cd61bbe 100644
--- a/src/java/org/apache/cassandra/db/marshal/ReversedType.java
+++ b/src/java/org/apache/cassandra/db/marshal/ReversedType.java
@@ -84,6 +84,12 @@ public class ReversedType<T> extends AbstractType<T>
}
@Override
+ public boolean isValueCompatibleWith(AbstractType<?> otherType)
+ {
+ return this.baseType.isValueCompatibleWith(otherType);
+ }
+
+ @Override
public CQL3Type asCQL3Type()
{
return baseType.asCQL3Type();
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/db/marshal/TimestampType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/TimestampType.java b/src/java/org/apache/cassandra/db/marshal/TimestampType.java
index 69ead8e..d7ce47b 100644
--- a/src/java/org/apache/cassandra/db/marshal/TimestampType.java
+++ b/src/java/org/apache/cassandra/db/marshal/TimestampType.java
@@ -74,6 +74,12 @@ public class TimestampType extends AbstractType<Date>
return false;
}
+ @Override
+ public boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
+ {
+ return this == otherType || otherType == DateType.instance || otherType == LongType.instance;
+ }
+
public CQL3Type asCQL3Type()
{
return CQL3Type.Native.TIMESTAMP;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/db/marshal/TupleType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/TupleType.java b/src/java/org/apache/cassandra/db/marshal/TupleType.java
index 74211c8..12457e9 100644
--- a/src/java/org/apache/cassandra/db/marshal/TupleType.java
+++ b/src/java/org/apache/cassandra/db/marshal/TupleType.java
@@ -234,13 +234,13 @@ public class TupleType extends AbstractType<ByteBuffer>
}
@Override
- public boolean isValueCompatibleWith(AbstractType<?> previous)
+ public boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
{
- if (!(previous instanceof TupleType))
+ if (!(otherType instanceof TupleType))
return false;
// Extending with new components is fine, removing is not
- TupleType tt = (TupleType)previous;
+ TupleType tt = (TupleType) otherType;
if (size() < tt.size())
return false;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/src/java/org/apache/cassandra/db/marshal/UUIDType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/UUIDType.java b/src/java/org/apache/cassandra/db/marshal/UUIDType.java
index 969ff17..b2caa04 100644
--- a/src/java/org/apache/cassandra/db/marshal/UUIDType.java
+++ b/src/java/org/apache/cassandra/db/marshal/UUIDType.java
@@ -189,6 +189,12 @@ public class UUIDType extends AbstractType<UUID>
}
}
+ @Override
+ public boolean isValueCompatibleWithInternal(AbstractType<?> otherType)
+ {
+ return this == otherType || otherType == TimeUUIDType.instance;
+ }
+
public CQL3Type asCQL3Type()
{
return CQL3Type.Native.UUID;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9da742d5/test/unit/org/apache/cassandra/cql3/TypeTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/TypeTest.java b/test/unit/org/apache/cassandra/cql3/TypeTest.java
new file mode 100644
index 0000000..f911a44
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/TypeTest.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cassandra.cql3;
+
+import org.apache.cassandra.SchemaLoader;
+import org.apache.cassandra.db.ConsistencyLevel;
+import org.apache.cassandra.exceptions.RequestExecutionException;
+import org.apache.cassandra.exceptions.RequestValidationException;
+import org.apache.cassandra.gms.Gossiper;
+import org.apache.cassandra.service.ClientState;
+import org.apache.cassandra.service.QueryState;
+import org.apache.cassandra.transport.messages.ResultMessage;
+import org.apache.cassandra.utils.MD5Digest;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.apache.cassandra.cql3.QueryProcessor.process;
+import static org.apache.cassandra.cql3.QueryProcessor.processInternal;
+import static org.junit.Assert.assertEquals;
+
+public class TypeTest
+{
+ private static final Logger logger = LoggerFactory.getLogger(TypeTest.class);
+ static ClientState clientState;
+ static String keyspace = "cql3_type_test";
+
+ @BeforeClass
+ public static void setUpClass() throws Throwable
+ {
+ SchemaLoader.loadSchema();
+ executeSchemaChange("CREATE KEYSPACE IF NOT EXISTS %s WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}");
+ clientState = ClientState.forInternalCalls();
+ }
+
+ @AfterClass
+ public static void stopGossiper()
+ {
+ Gossiper.instance.stop();
+ }
+
+ private static void executeSchemaChange(String query) throws Throwable
+ {
+ try
+ {
+ process(String.format(query, keyspace), ConsistencyLevel.ONE);
+ } catch (RuntimeException exc)
+ {
+ throw exc.getCause();
+ }
+ }
+
+ private static UntypedResultSet execute(String query) throws Throwable
+ {
+ try
+ {
+ return processInternal(String.format(query, keyspace));
+ } catch (RuntimeException exc)
+ {
+ if (exc.getCause() != null)
+ throw exc.getCause();
+ throw exc;
+ }
+ }
+
+ private MD5Digest prepare(String query) throws RequestValidationException
+ {
+ ResultMessage.Prepared prepared = QueryProcessor.prepare(String.format(query, keyspace), clientState, false);
+ return prepared.statementId;
+ }
+
+ private UntypedResultSet executePrepared(MD5Digest statementId, QueryOptions options) throws RequestValidationException, RequestExecutionException
+ {
+ CQLStatement statement = QueryProcessor.instance.getPrepared(statementId);
+ ResultMessage message = statement.executeInternal(QueryState.forInternalCalls(), options);
+
+ if (message instanceof ResultMessage.Rows)
+ return new UntypedResultSet(((ResultMessage.Rows)message).result);
+ else
+ return null;
+ }
+
+ @Test
+ public void testNowToUUIDCompatibility() throws Throwable
+ {
+ executeSchemaChange("CREATE TABLE IF NOT EXISTS %s.uuid_now (a int, b uuid, PRIMARY KEY (a, b))");
+ String insert = "INSERT INTO %s.uuid_now (a, b) VALUES (0, now())";
+ String select = "SELECT * FROM %s.uuid_now WHERE a=0 AND b < now()";
+ execute(insert);
+ UntypedResultSet results = execute(select);
+ assertEquals(1, results.size());
+
+ executePrepared(prepare(insert), QueryOptions.DEFAULT);
+ results = executePrepared(prepare(select), QueryOptions.DEFAULT);
+ assertEquals(2, results.size());
+ }
+
+ @Test
+ public void testDateCompatibility() throws Throwable
+ {
+ executeSchemaChange("CREATE TABLE IF NOT EXISTS %s.date_compatibility (a int, b timestamp, c bigint, d varint, PRIMARY KEY (a, b, c, d))");
+ String insert = "INSERT INTO %s.date_compatibility (a, b, c, d) VALUES (0, unixTimestampOf(now()), dateOf(now()), dateOf(now()))";
+ String select = "SELECT * FROM %s.date_compatibility WHERE a=0 AND b < unixTimestampOf(now())";
+ execute(insert);
+ UntypedResultSet results = execute(select);
+ assertEquals(1, results.size());
+
+ executePrepared(prepare(insert), QueryOptions.DEFAULT);
+ results = executePrepared(prepare(select), QueryOptions.DEFAULT);
+ assertEquals(2, results.size());
+ }
+
+ @Test
+ public void testReversedTypeCompatibility() throws Throwable
+ {
+ executeSchemaChange("CREATE TABLE IF NOT EXISTS %s.uuid_now_reversed (a int, b timeuuid, PRIMARY KEY (a, b)) WITH CLUSTERING ORDER BY (b DESC)");
+ String insert = "INSERT INTO %s.uuid_now_reversed (a, b) VALUES (0, now())";
+ String select = "SELECT * FROM %s.uuid_now_reversed WHERE a=0 AND b < now()";
+ execute(insert);
+ UntypedResultSet results = execute(select);
+ assertEquals(1, results.size());
+
+ executePrepared(prepare(insert), QueryOptions.DEFAULT);
+ results = executePrepared(prepare(select), QueryOptions.DEFAULT);
+ assertEquals(2, results.size());
+ }
+}
\ No newline at end of file