Repository: cassandra Updated Branches: refs/heads/trunk 1299ec319 -> 485c23d29
Fix type casting for counter columns patch by Benjamin Lerer; reviewed by Robert Stupp for CASSANDRA-10824 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/485c23d2 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/485c23d2 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/485c23d2 Branch: refs/heads/trunk Commit: 485c23d29b558b1561df3dc219e4e8f887c09234 Parents: 1299ec3 Author: Benjamin Lerer <[email protected]> Authored: Thu Dec 10 21:28:16 2015 +0100 Committer: Benjamin Lerer <[email protected]> Committed: Thu Dec 10 21:30:50 2015 +0100 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../cassandra/cql3/functions/CastFcts.java | 57 +++++++++++++++++--- .../cassandra/cql3/functions/CastFctsTest.java | 19 +++++++ 3 files changed, 70 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/485c23d2/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 9610181..dda12ba 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.2 + * Fix type casting for counter columns (CASSANDRA-10824) * Prevent running Cassandra as root (CASSANDRA-8142) * bound maximum in-flight commit log replay mutation bytes to 64 megabytes (CASSANDRA-8639) * Normalize all scripts (CASSANDRA-10679) http://git-wip-us.apache.org/repos/asf/cassandra/blob/485c23d2/src/java/org/apache/cassandra/cql3/functions/CastFcts.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/functions/CastFcts.java b/src/java/org/apache/cassandra/cql3/functions/CastFcts.java index 7349f0c..800ff65 100644 --- a/src/java/org/apache/cassandra/cql3/functions/CastFcts.java +++ b/src/java/org/apache/cassandra/cql3/functions/CastFcts.java @@ -146,7 +146,17 @@ public final class CastFcts java.util.function.Function<I, O> converter) { if (!inputType.equals(outputType)) - functions.add(JavaFunctionWrapper.create(inputType, outputType, converter)); + functions.add(wrapJavaFunction(inputType, outputType, converter)); + } + + @SuppressWarnings("unchecked") + private static <O, I> Function wrapJavaFunction(AbstractType<I> inputType, + AbstractType<O> outputType, + java.util.function.Function<I, O> converter) + { + return inputType.equals(CounterColumnType.instance) + ? JavaCounterFunctionWrapper.create(outputType, (java.util.function.Function<Long, O>) converter) + : JavaFunctionWrapper.create(inputType, outputType, converter); } private static String toLowerCaseString(CQL3Type type) @@ -192,7 +202,7 @@ public final class CastFcts * @param <I> the input parameter * @param <O> the output parameter */ - private static final class JavaFunctionWrapper<I, O> extends CastFunction<I, O> + private static class JavaFunctionWrapper<I, O> extends CastFunction<I, O> { /** * The java function used to convert the input type into the output one. @@ -206,21 +216,54 @@ public final class CastFcts return new JavaFunctionWrapper<I, O>(inputType, outputType, converter); } - private JavaFunctionWrapper(AbstractType<I> inputType, - AbstractType<O> outputType, - java.util.function.Function<I, O> converter) + protected JavaFunctionWrapper(AbstractType<I> inputType, + AbstractType<O> outputType, + java.util.function.Function<I, O> converter) { super(inputType, outputType); this.converter = converter; } - public ByteBuffer execute(int protocolVersion, List<ByteBuffer> parameters) + public final ByteBuffer execute(int protocolVersion, List<ByteBuffer> parameters) { ByteBuffer bb = parameters.get(0); if (bb == null) return null; - return outputType().decompose(converter.apply(inputType().compose(bb))); + return outputType().decompose(converter.apply(compose(bb))); + } + + protected I compose(ByteBuffer bb) + { + return inputType().compose(bb); + } + }; + + /** + * <code>JavaFunctionWrapper</code> for counter columns. + * + * <p>Counter columns need to be handled in a special way because their binary representation is converted into + * the one of a BIGINT before functions are applied.</p> + * + * @param <O> the output parameter + */ + private static class JavaCounterFunctionWrapper<O> extends JavaFunctionWrapper<Long, O> + { + public static <O> JavaFunctionWrapper<Long, O> create(AbstractType<O> outputType, + java.util.function.Function<Long, O> converter) + { + return new JavaCounterFunctionWrapper<O>(outputType, converter); + } + + protected JavaCounterFunctionWrapper(AbstractType<O> outputType, + java.util.function.Function<Long, O> converter) + { + super(CounterColumnType.instance, outputType, converter); + } + + protected Long compose(ByteBuffer bb) + { + return LongType.instance.compose(bb); } }; http://git-wip-us.apache.org/repos/asf/cassandra/blob/485c23d2/test/unit/org/apache/cassandra/cql3/functions/CastFctsTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/functions/CastFctsTest.java b/test/unit/org/apache/cassandra/cql3/functions/CastFctsTest.java index ed30f03..9b4b570 100644 --- a/test/unit/org/apache/cassandra/cql3/functions/CastFctsTest.java +++ b/test/unit/org/apache/cassandra/cql3/functions/CastFctsTest.java @@ -292,4 +292,23 @@ public class CastFctsTest extends CQLTester assertRows(execute("SELECT CAST(" + f + "(CAST(b AS int)) AS text) FROM %s"), row("2.0")); } + + @Test + public void testCounterCastsInSelectionClause() throws Throwable + { + createTable("CREATE TABLE %s (a int primary key, b counter)"); + + execute("UPDATE %s SET b = b + 2 WHERE a = 1"); + + assertRows(execute("SELECT CAST(b AS tinyint), " + + "CAST(b AS smallint), " + + "CAST(b AS int), " + + "CAST(b AS bigint), " + + "CAST(b AS float), " + + "CAST(b AS double), " + + "CAST(b AS decimal), " + + "CAST(b AS ascii), " + + "CAST(b AS text) FROM %s"), + row((byte) 2, (short) 2, 2, 2L, 2.0F, 2.0, BigDecimal.valueOf(2.0), "2", "2")); + } }
