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 19:00:35 UTC
[1/2] git commit: Accept subtypes for function results, type casts
Repository: cassandra
Updated Branches:
refs/heads/cassandra-2.1 2fe6de6a1 -> 9dcdb8b0b
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.1
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
[2/2] git commit: Merge branch 'cassandra-2.0' into cassandra-2.1
Posted by ty...@apache.org.
Merge branch 'cassandra-2.0' into cassandra-2.1
Conflicts:
src/java/org/apache/cassandra/cql3/TypeCast.java
src/java/org/apache/cassandra/cql3/statements/Selection.java
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/9dcdb8b0
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/9dcdb8b0
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/9dcdb8b0
Branch: refs/heads/cassandra-2.1
Commit: 9dcdb8b0b5bb5c92986b16380d650373c7f819d6
Parents: 2fe6de6 9da742d
Author: Tyler Hobbs <ty...@datastax.com>
Authored: Fri Jun 20 12:00:20 2014 -0500
Committer: Tyler Hobbs <ty...@datastax.com>
Committed: Fri Jun 20 12:00:20 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 | 2 +-
.../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 | 51 ++++++++++++++++++++
16 files changed, 119 insertions(+), 18 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9dcdb8b0/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 7288de6,dac254e..d7cb9ee
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,30 -1,25 +1,31 @@@
-2.0.9
- * Fix assertion error in CL.ANY timeout handling (CASSANDRA-7364)
- * Handle empty CFs in Memtable#maybeUpdateLiveRatio() (CASSANDRA-7401)
+2.1.0-rc2
+ * Modify reconcile logic to always pick a tombstone over a counter cell
+ (CASSANDRA-7346)
+ * Avoid incremental compaction on Windows (CASSANDRA-7365)
+ * Fix exception when querying a composite-keyed table with a collection index
+ (CASSANDRA-7372)
+ * Use node's host id in place of counter ids (CASSANDRA-7366)
* Fix native protocol CAS batches (CASSANDRA-7337)
+ * Reduce likelihood of contention on local paxos locking (CASSANDRA-7359)
+ * Upgrade to Pig 0.12.1 (CASSANDRA-6556)
+ * Make sure we clear out repair sessions from netstats (CASSANDRA-7329)
+ * Don't fail streams on failure detector downs (CASSANDRA-3569)
+ * Add optional keyspace to DROP INDEX statement (CASSANDRA-7314)
+ * Reduce run time for CQL tests (CASSANDRA-7327)
+ * Fix heap size calculation on Windows (CASSANDRA-7352, 7353)
+ * RefCount native frames from netty (CASSANDRA-7245)
+ * Use tarball dir instead of /var for default paths (CASSANDRA-7136)
+ * Remove rows_per_partition_to_cache keyword (CASSANDRA-7193)
+ * Fix schema change response in native protocol v3 (CASSANDRA-7413)
+Merged from 2.0:
+ * Fix assertion error in CL.ANY timeout handling (CASSANDRA-7364)
* Add per-CF range read request latency metrics (CASSANDRA-7338)
* Fix NPE in StreamTransferTask.createMessageForRetry() (CASSANDRA-7323)
- * Add conditional CREATE/DROP USER support (CASSANDRA-7264)
- * Swap local and global default read repair chances (CASSANDRA-7320)
- * Add missing iso8601 patterns for date strings (CASSANDRA-6973)
- * Support selecting multiple rows in a partition using IN (CASSANDRA-6875)
- * cqlsh: always emphasize the partition key in DESC output (CASSANDRA-7274)
- * Copy compaction options to make sure they are reloaded (CASSANDRA-7290)
- * Add option to do more aggressive tombstone compactions (CASSANDRA-6563)
- * Don't try to compact already-compacting files in HHOM (CASSANDRA-7288)
- * Add authentication support to shuffle (CASSANDRA-6484)
- * Cqlsh counts non-empty lines for "Blank lines" warning (CASSANDRA-7325)
* Make StreamSession#closeSession() idempotent (CASSANDRA-7262)
* Fix infinite loop on exception while streaming (CASSANDRA-7330)
- * 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/9dcdb8b0/src/java/org/apache/cassandra/cql3/TypeCast.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/TypeCast.java
index 45e8c5b,64261fa..e325e4d
--- a/src/java/org/apache/cassandra/cql3/TypeCast.java
+++ b/src/java/org/apache/cassandra/cql3/TypeCast.java
@@@ -30,32 -30,25 +30,32 @@@ public class TypeCast implements Term.R
this.term = term;
}
- public Term prepare(ColumnSpecification receiver) throws InvalidRequestException
+ public Term prepare(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
{
- if (!term.isAssignableTo(castedSpecOf(receiver)))
+ if (!term.isAssignableTo(keyspace, castedSpecOf(keyspace, receiver)))
throw new InvalidRequestException(String.format("Cannot cast value %s to type %s", term, type));
- if (!isAssignableTo(receiver))
+ if (!isAssignableTo(keyspace, receiver))
throw new InvalidRequestException(String.format("Cannot assign value %s to %s of type %s", this, receiver, receiver.type.asCQL3Type()));
- return term.prepare(receiver);
+ return term.prepare(keyspace, receiver);
}
- private ColumnSpecification castedSpecOf(ColumnSpecification receiver)
+ private ColumnSpecification castedSpecOf(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
{
- return new ColumnSpecification(receiver.ksName, receiver.cfName, new ColumnIdentifier(toString(), true), type.getType());
+ return new ColumnSpecification(receiver.ksName, receiver.cfName, new ColumnIdentifier(toString(), true), type.prepare(keyspace).getType());
}
- public boolean isAssignableTo(ColumnSpecification receiver)
+ public boolean isAssignableTo(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
{
- return receiver.type.isValueCompatibleWith(type.getType());
+ try
+ {
- return receiver.type.asCQL3Type().equals(type.prepare(keyspace));
++ return receiver.type.isValueCompatibleWith(type.prepare(keyspace).getType());
+ }
+ catch (InvalidRequestException e)
+ {
+ throw new AssertionError();
+ }
}
@Override
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9dcdb8b0/src/java/org/apache/cassandra/cql3/functions/FunctionCall.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9dcdb8b0/src/java/org/apache/cassandra/cql3/functions/Functions.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/functions/Functions.java
index 72aac3f,4f108cb..605e7b3
--- a/src/java/org/apache/cassandra/cql3/functions/Functions.java
+++ b/src/java/org/apache/cassandra/cql3/functions/Functions.java
@@@ -109,9 -109,9 +109,9 @@@ public abstract class Function
return candidate;
}
- private static void validateTypes(Function fun, List<? extends AssignementTestable> providedArgs, ColumnSpecification receiver) throws InvalidRequestException
+ private static void validateTypes(String keyspace, 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())
@@@ -132,9 -132,9 +132,9 @@@
}
}
- private static boolean isValidType(Function fun, List<? extends AssignementTestable> providedArgs, ColumnSpecification receiver)
+ private static boolean isValidType(String keyspace, Function fun, List<? extends AssignementTestable> providedArgs, ColumnSpecification receiver) throws InvalidRequestException
{
- 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/9dcdb8b0/src/java/org/apache/cassandra/cql3/statements/Selection.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/cql3/statements/Selection.java
index f4e0885,37ab384..dc31dde
--- a/src/java/org/apache/cassandra/cql3/statements/Selection.java
+++ b/src/java/org/apache/cassandra/cql3/statements/Selection.java
@@@ -370,18 -344,12 +370,18 @@@ public abstract class Selectio
}
}
- private interface Selector extends AssignementTestable
+ private static abstract class Selector implements AssignementTestable
{
- public ByteBuffer compute(ResultSetBuilder rs) throws InvalidRequestException;
+ public abstract ByteBuffer compute(ResultSetBuilder rs) throws InvalidRequestException;
+ public abstract AbstractType<?> getType();
+
+ public boolean isAssignableTo(String keyspace, ColumnSpecification receiver)
+ {
- return getType().asCQL3Type().equals(receiver.type.asCQL3Type());
++ return receiver.type.isValueCompatibleWith(getType());
+ }
}
- private static class SimpleSelector implements Selector
+ private static class SimpleSelector extends Selector
{
private final String columnName;
private final int idx;
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9dcdb8b0/src/java/org/apache/cassandra/db/marshal/AbstractType.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9dcdb8b0/src/java/org/apache/cassandra/db/marshal/BytesType.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9dcdb8b0/src/java/org/apache/cassandra/db/marshal/CompositeType.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9dcdb8b0/src/java/org/apache/cassandra/db/marshal/DateType.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/marshal/DateType.java
index 7003097,bf25d88..882e4cf
--- a/src/java/org/apache/cassandra/db/marshal/DateType.java
+++ b/src/java/org/apache/cassandra/db/marshal/DateType.java
@@@ -74,12 -81,13 +74,18 @@@ public class DateType extends AbstractT
return false;
}
+ public boolean isByteOrderComparable()
+ {
+ return true;
+ }
+
@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/9dcdb8b0/src/java/org/apache/cassandra/db/marshal/LongType.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9dcdb8b0/src/java/org/apache/cassandra/db/marshal/ReversedType.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9dcdb8b0/src/java/org/apache/cassandra/db/marshal/TupleType.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9dcdb8b0/src/java/org/apache/cassandra/db/marshal/UUIDType.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/9dcdb8b0/test/unit/org/apache/cassandra/cql3/TypeTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/TypeTest.java
index 0000000,f911a44..f22d49b
mode 000000,100644..100644
--- a/test/unit/org/apache/cassandra/cql3/TypeTest.java
+++ b/test/unit/org/apache/cassandra/cql3/TypeTest.java
@@@ -1,0 -1,144 +1,51 @@@
+ /*
+ * 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
++public class TypeTest extends CQLTester
+ {
- 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);
++ createTable("CREATE TABLE %s (a int, b uuid, PRIMARY KEY (a, b))");
++ execute("INSERT INTO %s (a, b) VALUES (0, now())");
++ UntypedResultSet results = execute("SELECT * FROM %s WHERE a=0 AND b < now()");
+ 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);
++ createTable("CREATE TABLE %s (a int, b timestamp, c bigint, d varint, PRIMARY KEY (a, b, c, d))");
++ execute("INSERT INTO %s (a, b, c, d) VALUES (0, unixTimestampOf(now()), dateOf(now()), dateOf(now()))");
++ UntypedResultSet results = execute("SELECT * FROM %s WHERE a=0 AND b < unixTimestampOf(now())");
+ 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);
++ createTable("CREATE TABLE %s (a int, b timeuuid, PRIMARY KEY (a, b)) WITH CLUSTERING ORDER BY (b DESC)");
++ execute("INSERT INTO %s (a, b) VALUES (0, now())");
++ UntypedResultSet results = execute("SELECT * FROM %s WHERE a=0 AND b < now()");
+ assertEquals(1, results.size());
-
- executePrepared(prepare(insert), QueryOptions.DEFAULT);
- results = executePrepared(prepare(select), QueryOptions.DEFAULT);
- assertEquals(2, results.size());
+ }
+ }