You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by bl...@apache.org on 2016/11/21 17:50:17 UTC
[2/4] cassandra git commit: Add support for arithmetic operators
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/DecimalType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/DecimalType.java b/src/java/org/apache/cassandra/db/marshal/DecimalType.java
index f1586e0..b98bf00 100644
--- a/src/java/org/apache/cassandra/db/marshal/DecimalType.java
+++ b/src/java/org/apache/cassandra/db/marshal/DecimalType.java
@@ -18,6 +18,8 @@
package org.apache.cassandra.db.marshal;
import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.MathContext;
import java.nio.ByteBuffer;
import org.apache.cassandra.cql3.CQL3Type;
@@ -29,7 +31,7 @@ import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil;
-public class DecimalType extends AbstractType<BigDecimal>
+public class DecimalType extends NumberType<BigDecimal>
{
public static final DecimalType instance = new DecimalType();
@@ -40,6 +42,12 @@ public class DecimalType extends AbstractType<BigDecimal>
return true;
}
+ @Override
+ public boolean isFloatingPoint()
+ {
+ return true;
+ }
+
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
{
if (!o1.hasRemaining() || !o2.hasRemaining())
@@ -95,4 +103,70 @@ public class DecimalType extends AbstractType<BigDecimal>
{
return DecimalSerializer.instance;
}
+
+ @Override
+ protected int toInt(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected float toFloat(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected long toLong(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected double toDouble(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected BigInteger toBigInteger(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected BigDecimal toBigDecimal(ByteBuffer value)
+ {
+ return compose(value);
+ }
+
+ public ByteBuffer add(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return decompose(leftType.toBigDecimal(left).add(rightType.toBigDecimal(right), MathContext.DECIMAL128));
+ }
+
+ public ByteBuffer substract(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return decompose(leftType.toBigDecimal(left).subtract(rightType.toBigDecimal(right), MathContext.DECIMAL128));
+ }
+
+ public ByteBuffer multiply(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return decompose(leftType.toBigDecimal(left).multiply(rightType.toBigDecimal(right), MathContext.DECIMAL128));
+ }
+
+ public ByteBuffer divide(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return decompose(leftType.toBigDecimal(left).divide(rightType.toBigDecimal(right), MathContext.DECIMAL128));
+ }
+
+ public ByteBuffer mod(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return decompose(leftType.toBigDecimal(left).remainder(rightType.toBigDecimal(right), MathContext.DECIMAL128));
+ }
+
+ public ByteBuffer negate(ByteBuffer input)
+ {
+ return decompose(toBigDecimal(input).negate());
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/DoubleType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/DoubleType.java b/src/java/org/apache/cassandra/db/marshal/DoubleType.java
index d2309ee..b72d3e9 100644
--- a/src/java/org/apache/cassandra/db/marshal/DoubleType.java
+++ b/src/java/org/apache/cassandra/db/marshal/DoubleType.java
@@ -28,7 +28,7 @@ import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil;
-public class DoubleType extends AbstractType<Double>
+public class DoubleType extends NumberType<Double>
{
public static final DoubleType instance = new DoubleType();
@@ -39,6 +39,12 @@ public class DoubleType extends AbstractType<Double>
return true;
}
+ @Override
+ public boolean isFloatingPoint()
+ {
+ return true;
+ }
+
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
{
if (!o1.hasRemaining() || !o2.hasRemaining())
@@ -53,17 +59,14 @@ public class DoubleType extends AbstractType<Double>
if (source.isEmpty())
return ByteBufferUtil.EMPTY_BYTE_BUFFER;
- Double d;
try
{
- d = Double.valueOf(source);
+ return decompose(Double.valueOf(source));
}
catch (NumberFormatException e1)
{
throw new MarshalException(String.format("Unable to make double from '%s'", source), e1);
}
-
- return decompose(d);
}
@Override
@@ -100,8 +103,62 @@ public class DoubleType extends AbstractType<Double>
}
@Override
- protected int valueLengthIfFixed()
+ public int valueLengthIfFixed()
{
return 8;
}
+
+ @Override
+ protected int toInt(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected float toFloat(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected long toLong(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected double toDouble(ByteBuffer value)
+ {
+ return ByteBufferUtil.toDouble(value);
+ }
+
+ public ByteBuffer add(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toDouble(left) + rightType.toDouble(right));
+ }
+
+ public ByteBuffer substract(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toDouble(left) - rightType.toDouble(right));
+ }
+
+ public ByteBuffer multiply(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toDouble(left) * rightType.toDouble(right));
+ }
+
+ public ByteBuffer divide(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toDouble(left) / rightType.toDouble(right));
+ }
+
+ public ByteBuffer mod(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toDouble(left) % rightType.toDouble(right));
+ }
+
+ public ByteBuffer negate(ByteBuffer input)
+ {
+ return ByteBufferUtil.bytes(-toDouble(input));
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/EmptyType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/EmptyType.java b/src/java/org/apache/cassandra/db/marshal/EmptyType.java
index c653084..87b3a7f 100644
--- a/src/java/org/apache/cassandra/db/marshal/EmptyType.java
+++ b/src/java/org/apache/cassandra/db/marshal/EmptyType.java
@@ -78,7 +78,7 @@ public class EmptyType extends AbstractType<Void>
}
@Override
- protected int valueLengthIfFixed()
+ public int valueLengthIfFixed()
{
return 0;
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/FloatType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/FloatType.java b/src/java/org/apache/cassandra/db/marshal/FloatType.java
index 5445bbc..33d8344 100644
--- a/src/java/org/apache/cassandra/db/marshal/FloatType.java
+++ b/src/java/org/apache/cassandra/db/marshal/FloatType.java
@@ -29,7 +29,7 @@ import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil;
-public class FloatType extends AbstractType<Float>
+public class FloatType extends NumberType<Float>
{
public static final FloatType instance = new FloatType();
@@ -40,6 +40,12 @@ public class FloatType extends AbstractType<Float>
return true;
}
+ @Override
+ public boolean isFloatingPoint()
+ {
+ return true;
+ }
+
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
{
if (!o1.hasRemaining() || !o2.hasRemaining())
@@ -56,8 +62,7 @@ public class FloatType extends AbstractType<Float>
try
{
- float f = Float.parseFloat(source);
- return ByteBufferUtil.bytes(f);
+ return decompose(Float.parseFloat(source));
}
catch (NumberFormatException e1)
{
@@ -99,8 +104,56 @@ public class FloatType extends AbstractType<Float>
}
@Override
- protected int valueLengthIfFixed()
+ public int valueLengthIfFixed()
{
return 4;
}
+
+ @Override
+ protected int toInt(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected float toFloat(ByteBuffer value)
+ {
+ return ByteBufferUtil.toFloat(value);
+ }
+
+ @Override
+ protected double toDouble(ByteBuffer value)
+ {
+ return toFloat(value);
+ }
+
+ public ByteBuffer add(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toFloat(left) + rightType.toFloat(right));
+ }
+
+ public ByteBuffer substract(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toFloat(left) - rightType.toFloat(right));
+ }
+
+ public ByteBuffer multiply(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toFloat(left) * rightType.toFloat(right));
+ }
+
+ public ByteBuffer divide(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toFloat(left) / rightType.toFloat(right));
+ }
+
+ public ByteBuffer mod(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toFloat(left) % rightType.toFloat(right));
+ }
+
+ public ByteBuffer negate(ByteBuffer input)
+ {
+ return ByteBufferUtil.bytes(-toFloat(input));
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/Int32Type.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/Int32Type.java b/src/java/org/apache/cassandra/db/marshal/Int32Type.java
index 1c8c93e..a66f9dc 100644
--- a/src/java/org/apache/cassandra/db/marshal/Int32Type.java
+++ b/src/java/org/apache/cassandra/db/marshal/Int32Type.java
@@ -22,13 +22,13 @@ import java.nio.ByteBuffer;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.Constants;
import org.apache.cassandra.cql3.Term;
-import org.apache.cassandra.serializers.TypeSerializer;
import org.apache.cassandra.serializers.Int32Serializer;
import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.transport.ProtocolVersion;
+import org.apache.cassandra.serializers.TypeSerializer;
import org.apache.cassandra.utils.ByteBufferUtil;
-public class Int32Type extends AbstractType<Integer>
+public class Int32Type extends NumberType<Integer>
{
public static final Int32Type instance = new Int32Type();
@@ -112,8 +112,50 @@ public class Int32Type extends AbstractType<Integer>
}
@Override
- protected int valueLengthIfFixed()
+ public int valueLengthIfFixed()
{
return 4;
}
+
+ @Override
+ protected int toInt(ByteBuffer value)
+ {
+ return ByteBufferUtil.toInt(value);
+ }
+
+ @Override
+ protected float toFloat(ByteBuffer value)
+ {
+ return toInt(value);
+ }
+
+ public ByteBuffer add(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toInt(left) + rightType.toInt(right));
+ }
+
+ public ByteBuffer substract(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toInt(left) - rightType.toInt(right));
+ }
+
+ public ByteBuffer multiply(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toInt(left) * rightType.toInt(right));
+ }
+
+ public ByteBuffer divide(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toInt(left) / rightType.toInt(right));
+ }
+
+ public ByteBuffer mod(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toInt(left) % rightType.toInt(right));
+ }
+
+ public ByteBuffer negate(ByteBuffer input)
+ {
+ return ByteBufferUtil.bytes(-toInt(input));
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/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 944a231..e2b8518 100644
--- a/src/java/org/apache/cassandra/db/marshal/IntegerType.java
+++ b/src/java/org/apache/cassandra/db/marshal/IntegerType.java
@@ -17,6 +17,7 @@
*/
package org.apache.cassandra.db.marshal;
+import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
@@ -29,7 +30,7 @@ import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil;
-public final class IntegerType extends AbstractType<BigInteger>
+public final class IntegerType extends NumberType<BigInteger>
{
public static final IntegerType instance = new IntegerType();
@@ -184,4 +185,70 @@ public final class IntegerType extends AbstractType<BigInteger>
{
return IntegerSerializer.instance;
}
+
+ @Override
+ protected int toInt(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected float toFloat(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected long toLong(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected double toDouble(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected BigInteger toBigInteger(ByteBuffer value)
+ {
+ return compose(value);
+ }
+
+ @Override
+ protected BigDecimal toBigDecimal(ByteBuffer value)
+ {
+ return new BigDecimal(compose(value));
+ }
+
+ public ByteBuffer add(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return decompose(leftType.toBigInteger(left).add(rightType.toBigInteger(right)));
+ }
+
+ public ByteBuffer substract(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return decompose(leftType.toBigInteger(left).subtract(rightType.toBigInteger(right)));
+ }
+
+ public ByteBuffer multiply(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return decompose(leftType.toBigInteger(left).multiply(rightType.toBigInteger(right)));
+ }
+
+ public ByteBuffer divide(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return decompose(leftType.toBigInteger(left).divide(rightType.toBigInteger(right)));
+ }
+
+ public ByteBuffer mod(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return decompose(leftType.toBigInteger(left).remainder(rightType.toBigInteger(right)));
+ }
+
+ public ByteBuffer negate(ByteBuffer input)
+ {
+ return decompose(toBigInteger(input).negate());
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java b/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java
index 70767d4..de32a56 100644
--- a/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java
+++ b/src/java/org/apache/cassandra/db/marshal/LexicalUUIDType.java
@@ -86,7 +86,7 @@ public class LexicalUUIDType extends AbstractType<UUID>
}
@Override
- protected int valueLengthIfFixed()
+ public int valueLengthIfFixed()
{
return 16;
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/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 c852461..ef96e2e 100644
--- a/src/java/org/apache/cassandra/db/marshal/LongType.java
+++ b/src/java/org/apache/cassandra/db/marshal/LongType.java
@@ -28,7 +28,7 @@ import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil;
-public class LongType extends AbstractType<Long>
+public class LongType extends NumberType<Long>
{
public static final LongType instance = new LongType();
@@ -120,8 +120,56 @@ public class LongType extends AbstractType<Long>
}
@Override
- protected int valueLengthIfFixed()
+ public int valueLengthIfFixed()
{
return 8;
}
+
+ @Override
+ protected int toInt(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected float toFloat(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected long toLong(ByteBuffer value)
+ {
+ return ByteBufferUtil.toLong(value);
+ }
+
+ public ByteBuffer add(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toLong(left) + rightType.toLong(right));
+ }
+
+ public ByteBuffer substract(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toLong(left) - rightType.toLong(right));
+ }
+
+ public ByteBuffer multiply(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toLong(left) * rightType.toLong(right));
+ }
+
+ public ByteBuffer divide(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toLong(left) / rightType.toLong(right));
+ }
+
+ public ByteBuffer mod(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes(leftType.toLong(left) % rightType.toLong(right));
+ }
+
+ public ByteBuffer negate(ByteBuffer input)
+ {
+ return ByteBufferUtil.bytes(-toLong(input));
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/NumberType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/NumberType.java b/src/java/org/apache/cassandra/db/marshal/NumberType.java
new file mode 100644
index 0000000..9e7697f
--- /dev/null
+++ b/src/java/org/apache/cassandra/db/marshal/NumberType.java
@@ -0,0 +1,223 @@
+/*
+ * 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.db.marshal;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+
+/**
+ * Base type for the numeric types.
+ */
+public abstract class NumberType<T extends Number> extends AbstractType<T>
+{
+ protected NumberType(ComparisonType comparisonType)
+ {
+ super(comparisonType);
+ }
+
+ /**
+ * Checks if this type support floating point numbers.
+ * @return {@code true} if this type support floating point numbers, {@code false} otherwise.
+ */
+ public boolean isFloatingPoint()
+ {
+ return false;
+ }
+
+ /**
+ * Converts the specified value into a <code>BigInteger</code> if allowed.
+ *
+ * @param value the value to convert
+ * @return the converted value
+ * @throws UnsupportedOperationException if the value cannot be converted without losing precision
+ */
+ protected BigInteger toBigInteger(ByteBuffer value)
+ {
+ return BigInteger.valueOf(toLong(value));
+ }
+
+ /**
+ * Converts the specified value into a <code>BigDecimal</code>.
+ *
+ * @param value the value to convert
+ * @return the converted value
+ */
+ protected BigDecimal toBigDecimal(ByteBuffer value)
+ {
+ double d = toDouble(value);
+
+ if (Double.isNaN(d))
+ throw new NumberFormatException("A NaN cannot be converted into a decimal");
+
+ if (Double.isInfinite(d))
+ throw new NumberFormatException("An infinite number cannot be converted into a decimal");
+
+ return BigDecimal.valueOf(d);
+ }
+
+ /**
+ * Converts the specified value into a <code>byte</code> if allowed.
+ *
+ * @param value the value to convert
+ * @return the converted value
+ * @throws UnsupportedOperationException if the value cannot be converted without losing precision
+ */
+ protected byte toByte(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Converts the specified value into a <code>short</code> if allowed.
+ *
+ * @param value the value to convert
+ * @return the converted value
+ * @throws UnsupportedOperationException if the value cannot be converted without losing precision
+ */
+ protected short toShort(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Converts the specified value into an <code>int</code> if allowed.
+ *
+ * @param value the value to convert
+ * @return the converted value
+ * @throws UnsupportedOperationException if the value cannot be converted without losing precision
+ */
+ protected int toInt(ByteBuffer value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Converts the specified value into a <code>long</code> if allowed.
+ *
+ * @param value the value to convert
+ * @return the converted value
+ * @throws UnsupportedOperationException if the value cannot be converted without losing precision
+ */
+ protected long toLong(ByteBuffer value)
+ {
+ return toInt(value);
+ }
+
+ /**
+ * Converts the specified value into a <code>float</code> if allowed.
+ *
+ * @param value the value to convert
+ * @return the converted value
+ * @throws UnsupportedOperationException if the value cannot be converted without losing precision
+ */
+ protected float toFloat(ByteBuffer value)
+ {
+ return toInt(value);
+ }
+
+ /**
+ * Converts the specified value into a <code>double</code> if allowed.
+ *
+ * @param value the value to convert
+ * @return the converted value
+ * @throws UnsupportedOperationException if the value cannot be converted without losing precision
+ */
+ protected double toDouble(ByteBuffer value)
+ {
+ return toLong(value);
+ }
+
+ /**
+ * Adds the left argument to the right one.
+ *
+ * @param leftType the type associated to the left argument
+ * @param left the left argument
+ * @param rightType the type associated to the right argument
+ * @param right the right argument
+ * @return the addition result
+ */
+ public abstract ByteBuffer add(NumberType<?> leftType,
+ ByteBuffer left,
+ NumberType<?> rightType,
+ ByteBuffer right);
+
+ /**
+ * Substracts the left argument from the right one.
+ *
+ * @param leftType the type associated to the left argument
+ * @param left the left argument
+ * @param rightType the type associated to the right argument
+ * @param right the right argument
+ * @return the substraction result
+ */
+ public abstract ByteBuffer substract(NumberType<?> leftType,
+ ByteBuffer left,
+ NumberType<?> rightType,
+ ByteBuffer right);
+
+ /**
+ * Multiplies the left argument with the right one.
+ *
+ * @param leftType the type associated to the left argument
+ * @param left the left argument
+ * @param rightType the type associated to the right argument
+ * @param right the right argument
+ * @return the multiplication result
+ */
+ public abstract ByteBuffer multiply(NumberType<?> leftType,
+ ByteBuffer left,
+ NumberType<?> rightType,
+ ByteBuffer right);
+
+ /**
+ * Divides the left argument by the right one.
+ *
+ * @param leftType the type associated to the left argument
+ * @param left the left argument
+ * @param rightType the type associated to the right argument
+ * @param right the right argument
+ * @return the division result
+ */
+ public abstract ByteBuffer divide(NumberType<?> leftType,
+ ByteBuffer left,
+ NumberType<?> rightType,
+ ByteBuffer right);
+
+ /**
+ * Return the remainder.
+ *
+ * @param leftType the type associated to the left argument
+ * @param left the left argument
+ * @param rightType the type associated to the right argument
+ * @param right the right argument
+ * @return the remainder
+ */
+ public abstract ByteBuffer mod(NumberType<?> leftType,
+ ByteBuffer left,
+ NumberType<?> rightType,
+ ByteBuffer right);
+
+ /**
+ * Negates the argument.
+ *
+ * @param input the argument to negate
+ * @return the negated argument
+ */
+ public abstract ByteBuffer negate(ByteBuffer input);
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/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 0eb0046..250dfdc 100644
--- a/src/java/org/apache/cassandra/db/marshal/ReversedType.java
+++ b/src/java/org/apache/cassandra/db/marshal/ReversedType.java
@@ -132,7 +132,7 @@ public class ReversedType<T> extends AbstractType<T>
}
@Override
- protected int valueLengthIfFixed()
+ public int valueLengthIfFixed()
{
return baseType.valueLengthIfFixed();
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/ShortType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/ShortType.java b/src/java/org/apache/cassandra/db/marshal/ShortType.java
index 7645ec6..b37a0b7 100644
--- a/src/java/org/apache/cassandra/db/marshal/ShortType.java
+++ b/src/java/org/apache/cassandra/db/marshal/ShortType.java
@@ -28,7 +28,7 @@ import org.apache.cassandra.serializers.TypeSerializer;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil;
-public class ShortType extends AbstractType<Short>
+public class ShortType extends NumberType<Short>
{
public static final ShortType instance = new ShortType();
@@ -91,4 +91,53 @@ public class ShortType extends AbstractType<Short>
{
return ShortSerializer.instance;
}
+
+ @Override
+ public int valueLengthIfFixed()
+ {
+ return 2;
+ }
+
+ @Override
+ public short toShort(ByteBuffer value)
+ {
+ return ByteBufferUtil.toShort(value);
+ }
+
+ @Override
+ public int toInt(ByteBuffer value)
+ {
+ return toShort(value);
+ }
+
+ @Override
+ public ByteBuffer add(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes((short) (leftType.toShort(left) + rightType.toShort(right)));
+ }
+
+ public ByteBuffer substract(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes((short) (leftType.toShort(left) - rightType.toShort(right)));
+ }
+
+ public ByteBuffer multiply(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes((short) (leftType.toShort(left) * rightType.toShort(right)));
+ }
+
+ public ByteBuffer divide(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes((short) (leftType.toShort(left) / rightType.toShort(right)));
+ }
+
+ public ByteBuffer mod(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
+ {
+ return ByteBufferUtil.bytes((short) (leftType.toShort(left) % rightType.toShort(right)));
+ }
+
+ public ByteBuffer negate(ByteBuffer input)
+ {
+ return ByteBufferUtil.bytes((short) -toShort(input));
+ }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java b/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java
index 36305a3..f8e58db 100644
--- a/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java
+++ b/src/java/org/apache/cassandra/db/marshal/TimeUUIDType.java
@@ -130,7 +130,7 @@ public class TimeUUIDType extends AbstractType<UUID>
}
@Override
- protected int valueLengthIfFixed()
+ public int valueLengthIfFixed()
{
return 16;
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/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 953ae1b..ae74e2f 100644
--- a/src/java/org/apache/cassandra/db/marshal/TimestampType.java
+++ b/src/java/org/apache/cassandra/db/marshal/TimestampType.java
@@ -128,7 +128,7 @@ public class TimestampType extends AbstractType<Date>
}
@Override
- protected int valueLengthIfFixed()
+ public int valueLengthIfFixed()
{
return 8;
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/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 60a63aa..71e946c 100644
--- a/src/java/org/apache/cassandra/db/marshal/TupleType.java
+++ b/src/java/org/apache/cassandra/db/marshal/TupleType.java
@@ -101,6 +101,11 @@ public class TupleType extends AbstractType<ByteBuffer>
return types;
}
+ public boolean isTuple()
+ {
+ return true;
+ }
+
public int compareCustom(ByteBuffer o1, ByteBuffer o2)
{
if (!o1.hasRemaining() || !o2.hasRemaining())
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/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 9722a52..27e3360 100644
--- a/src/java/org/apache/cassandra/db/marshal/UUIDType.java
+++ b/src/java/org/apache/cassandra/db/marshal/UUIDType.java
@@ -171,7 +171,7 @@ public class UUIDType extends AbstractType<UUID>
}
@Override
- protected int valueLengthIfFixed()
+ public int valueLengthIfFixed()
{
return 16;
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/db/marshal/UserType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/UserType.java b/src/java/org/apache/cassandra/db/marshal/UserType.java
index 176ab84..e47b7ac 100644
--- a/src/java/org/apache/cassandra/db/marshal/UserType.java
+++ b/src/java/org/apache/cassandra/db/marshal/UserType.java
@@ -86,6 +86,11 @@ public class UserType extends TupleType
return true;
}
+ public boolean isTuple()
+ {
+ return false;
+ }
+
@Override
public boolean isMultiCell()
{
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/exceptions/OperationExecutionException.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/exceptions/OperationExecutionException.java b/src/java/org/apache/cassandra/exceptions/OperationExecutionException.java
new file mode 100644
index 0000000..4f9ffa4
--- /dev/null
+++ b/src/java/org/apache/cassandra/exceptions/OperationExecutionException.java
@@ -0,0 +1,57 @@
+/*
+ * 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.exceptions;
+
+import java.util.List;
+
+import org.apache.cassandra.db.marshal.AbstractType;
+
+/**
+ * Thrown when an operation problem has occured (e.g. division by zero with integer).
+ */
+public final class OperationExecutionException extends RequestExecutionException
+{
+
+ /**
+ * Creates a new <code>OperationExecutionException</code> for the specified operation.
+ *
+ * @param operator the operator
+ * @param argTypes the argument types
+ * @param e the original Exception
+ * @return a new <code>OperationExecutionException</code> for the specified operation
+ */
+ public static OperationExecutionException create(char operator, List<AbstractType<?>> argTypes, Exception e)
+ {
+ List<String> cqlTypes = AbstractType.asCQLTypeStringList(argTypes);
+ return new OperationExecutionException(String.format("the operation '%s %s %s' failed: %s",
+ cqlTypes.get(0),
+ operator,
+ cqlTypes.get(1),
+ e.getMessage()));
+ }
+
+ /**
+ * Creates an <code>OperationExecutionException</code> with the specified message.
+ * @param msg the error message
+ */
+ public OperationExecutionException(String msg)
+ {
+ super(ExceptionCode.FUNCTION_FAILURE, msg);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/serializers/ByteSerializer.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/serializers/ByteSerializer.java b/src/java/org/apache/cassandra/serializers/ByteSerializer.java
index 9d34fbc..8428e62 100644
--- a/src/java/org/apache/cassandra/serializers/ByteSerializer.java
+++ b/src/java/org/apache/cassandra/serializers/ByteSerializer.java
@@ -28,12 +28,12 @@ public class ByteSerializer implements TypeSerializer<Byte>
public Byte deserialize(ByteBuffer bytes)
{
- return bytes == null || bytes.remaining() == 0 ? null : bytes.get(bytes.position());
+ return bytes == null || bytes.remaining() == 0 ? null : ByteBufferUtil.toByte(bytes);
}
public ByteBuffer serialize(Byte value)
{
- return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBuffer.allocate(1).put(0, value);
+ return value == null ? ByteBufferUtil.EMPTY_BYTE_BUFFER : ByteBufferUtil.bytes(value);
}
public void validate(ByteBuffer bytes) throws MarshalException
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/src/java/org/apache/cassandra/utils/ByteBufferUtil.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/utils/ByteBufferUtil.java b/src/java/org/apache/cassandra/utils/ByteBufferUtil.java
index fb1a9ec..b6f93bc 100644
--- a/src/java/org/apache/cassandra/utils/ByteBufferUtil.java
+++ b/src/java/org/apache/cassandra/utils/ByteBufferUtil.java
@@ -435,6 +435,18 @@ public class ByteBufferUtil
return bytes.getShort(bytes.position());
}
+ /**
+ * Convert a byte buffer to a short.
+ * Does not change the byte buffer position.
+ *
+ * @param bytes byte buffer to convert to byte
+ * @return byte representation of the byte buffer
+ */
+ public static byte toByte(ByteBuffer bytes)
+ {
+ return bytes.get(bytes.position());
+ }
+
public static long toLong(ByteBuffer bytes)
{
return bytes.getLong(bytes.position());
@@ -450,6 +462,11 @@ public class ByteBufferUtil
return bytes.getDouble(bytes.position());
}
+ public static ByteBuffer bytes(byte b)
+ {
+ return ByteBuffer.allocate(1).put(0, b);
+ }
+
public static ByteBuffer bytes(short s)
{
return ByteBuffer.allocate(2).putShort(0, s);
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/test/unit/org/apache/cassandra/cql3/CQLTester.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/CQLTester.java b/test/unit/org/apache/cassandra/cql3/CQLTester.java
index 2a5afc2..598addd 100644
--- a/test/unit/org/apache/cassandra/cql3/CQLTester.java
+++ b/test/unit/org/apache/cassandra/cql3/CQLTester.java
@@ -1432,7 +1432,7 @@ public abstract class CQLTester
return s;
}
- private static ByteBuffer makeByteBuffer(Object value, AbstractType type)
+ protected static ByteBuffer makeByteBuffer(Object value, AbstractType type)
{
if (value == null)
return null;
@@ -1463,7 +1463,7 @@ public abstract class CQLTester
return type.getString(bb);
}
- protected Object tuple(Object...values)
+ protected TupleValue tuple(Object...values)
{
return new TupleValue(values);
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/8b3de2f4/test/unit/org/apache/cassandra/cql3/functions/OperationFctsTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/functions/OperationFctsTest.java b/test/unit/org/apache/cassandra/cql3/functions/OperationFctsTest.java
new file mode 100644
index 0000000..6de5fdb
--- /dev/null
+++ b/test/unit/org/apache/cassandra/cql3/functions/OperationFctsTest.java
@@ -0,0 +1,744 @@
+/*
+ * 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.functions;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+import org.junit.Test;
+
+import org.apache.cassandra.cql3.CQLTester;
+import org.apache.cassandra.cql3.UntypedResultSet;
+import org.apache.cassandra.exceptions.OperationExecutionException;
+
+public class OperationFctsTest extends CQLTester
+{
+ @Test
+ public void testSingleOperations() throws Throwable
+ {
+ createTable("CREATE TABLE %s (a tinyint, b smallint, c int, d bigint, e float, f double, g varint, h decimal, PRIMARY KEY(a, b, c))");
+ execute("INSERT INTO %S (a, b, c, d, e, f, g, h) VALUES (1, 2, 3, 4, 5.5, 6.5, 7, 8.5)");
+
+ // Test additions
+ assertColumnNames(execute("SELECT a + a, b + a, c + a, d + a, e + a, f + a, g + a, h + a FROM %s WHERE a = 1 AND b = 2 AND c = 1 + 2"),
+ "a + a", "b + a", "c + a", "d + a", "e + a", "f + a", "g + a", "h + a");
+
+ assertRows(execute("SELECT a + a, b + a, c + a, d + a, e + a, f + a, g + a, h + a FROM %s WHERE a = 1 AND b = 2 AND c = 1 + 2"),
+ row((byte) 2, (short) 3, 4, 5L, 6.5F, 7.5, BigInteger.valueOf(8), BigDecimal.valueOf(9.5)));
+
+ assertRows(execute("SELECT a + b, b + b, c + b, d + b, e + b, f + b, g + b, h + b FROM %s WHERE a = 1 AND b = 2 AND c = 1 + 2"),
+ row((short) 3, (short) 4, 5, 6L, 7.5F, 8.5, BigInteger.valueOf(9), BigDecimal.valueOf(10.5)));
+
+ assertRows(execute("SELECT a + c, b + c, c + c, d + c, e + c, f + c, g + c, h + c FROM %s WHERE a = 1 AND b = 2 AND c = 1 + 2"),
+ row(4, 5, 6, 7L, 8.5F, 9.5, BigInteger.valueOf(10), BigDecimal.valueOf(11.5)));
+
+ assertRows(execute("SELECT a + d, b + d, c + d, d + d, e + d, f + d, g + d, h + d FROM %s WHERE a = 1 AND b = 2 AND c = 1 + 2"),
+ row(5L, 6L, 7L, 8L, 9.5, 10.5, BigInteger.valueOf(11), BigDecimal.valueOf(12.5)));
+
+ assertRows(execute("SELECT a + e, b + e, c + e, d + e, e + e, f + e, g + e, h + e FROM %s WHERE a = 1 AND b = 2 AND c = 1 + 2"),
+ row(6.5F, 7.5F, 8.5F, 9.5, 11.0F, 12.0, BigDecimal.valueOf(12.5), BigDecimal.valueOf(14.0)));
+
+ assertRows(execute("SELECT a + f, b + f, c + f, d + f, e + f, f + f, g + f, h + f FROM %s WHERE a = 1 AND b = 2 AND c = 1 + 2"),
+ row(7.5, 8.5, 9.5, 10.5, 12.0, 13.0, BigDecimal.valueOf(13.5), BigDecimal.valueOf(15.0)));
+
+ assertRows(execute("SELECT a + g, b + g, c + g, d + g, e + g, f + g, g + g, h + g FROM %s WHERE a = 1 AND b = 2 AND c = 1 + 2"),
+ row(BigInteger.valueOf(8),
+ BigInteger.valueOf(9),
+ BigInteger.valueOf(10),
+ BigInteger.valueOf(11),
+ BigDecimal.valueOf(12.5),
+ BigDecimal.valueOf(13.5),
+ BigInteger.valueOf(14),
+ BigDecimal.valueOf(15.5)));
+
+ assertRows(execute("SELECT a + h, b + h, c + h, d + h, e + h, f + h, g + h, h + h FROM %s WHERE a = 1 AND b = 2 AND c = 1 + 2"),
+ row(BigDecimal.valueOf(9.5),
+ BigDecimal.valueOf(10.5),
+ BigDecimal.valueOf(11.5),
+ BigDecimal.valueOf(12.5),
+ BigDecimal.valueOf(14.0),
+ BigDecimal.valueOf(15.0),
+ BigDecimal.valueOf(15.5),
+ BigDecimal.valueOf(17.0)));
+
+ // Test substractions
+
+ assertColumnNames(execute("SELECT a - a, b - a, c - a, d - a, e - a, f - a, g - a, h - a FROM %s WHERE a = 1 AND b = 2 AND c = 4 - 1"),
+ "a - a", "b - a", "c - a", "d - a", "e - a", "f - a", "g - a", "h - a");
+
+ assertRows(execute("SELECT a - a, b - a, c - a, d - a, e - a, f - a, g - a, h - a FROM %s WHERE a = 1 AND b = 2 AND c = 4 - 1"),
+ row((byte) 0, (short) 1, 2, 3L, 4.5F, 5.5, BigInteger.valueOf(6), BigDecimal.valueOf(7.5)));
+
+ assertRows(execute("SELECT a - b, b - b, c - b, d - b, e - b, f - b, g - b, h - b FROM %s WHERE a = 1 AND b = 2 AND c = 4 - 1"),
+ row((short) -1, (short) 0, 1, 2L, 3.5F, 4.5, BigInteger.valueOf(5), BigDecimal.valueOf(6.5)));
+
+ assertRows(execute("SELECT a - c, b - c, c - c, d - c, e - c, f - c, g - c, h - c FROM %s WHERE a = 1 AND b = 2 AND c = 4 - 1"),
+ row(-2, -1, 0, 1L, 2.5F, 3.5, BigInteger.valueOf(4), BigDecimal.valueOf(5.5)));
+
+ assertRows(execute("SELECT a - d, b - d, c - d, d - d, e - d, f - d, g - d, h - d FROM %s WHERE a = 1 AND b = 2 AND c = 4 - 1"),
+ row(-3L, -2L, -1L, 0L, 1.5, 2.5, BigInteger.valueOf(3), BigDecimal.valueOf(4.5)));
+
+ assertRows(execute("SELECT a - e, b - e, c - e, d - e, e - e, f - e, g - e, h - e FROM %s WHERE a = 1 AND b = 2 AND c = 4 - 1"),
+ row(-4.5F, -3.5F, -2.5F, -1.5, 0.0F, 1.0, BigDecimal.valueOf(1.5), BigDecimal.valueOf(3.0)));
+
+ assertRows(execute("SELECT a - f, b - f, c - f, d - f, e - f, f - f, g - f, h - f FROM %s WHERE a = 1 AND b = 2 AND c = 4 - 1"),
+ row(-5.5, -4.5, -3.5, -2.5, -1.0, 0.0, BigDecimal.valueOf(0.5), BigDecimal.valueOf(2.0)));
+
+ assertRows(execute("SELECT a - g, b - g, c - g, d - g, e - g, f - g, g - g, h - g FROM %s WHERE a = 1 AND b = 2 AND c = 4 - 1"),
+ row(BigInteger.valueOf(-6),
+ BigInteger.valueOf(-5),
+ BigInteger.valueOf(-4),
+ BigInteger.valueOf(-3),
+ BigDecimal.valueOf(-1.5),
+ BigDecimal.valueOf(-0.5),
+ BigInteger.valueOf(0),
+ BigDecimal.valueOf(1.5)));
+
+ assertRows(execute("SELECT a - h, b - h, c - h, d - h, e - h, f - h, g - h, h - h FROM %s WHERE a = 1 AND b = 2 AND c = 4 - 1"),
+ row(BigDecimal.valueOf(-7.5),
+ BigDecimal.valueOf(-6.5),
+ BigDecimal.valueOf(-5.5),
+ BigDecimal.valueOf(-4.5),
+ BigDecimal.valueOf(-3.0),
+ BigDecimal.valueOf(-2.0),
+ BigDecimal.valueOf(-1.5),
+ BigDecimal.valueOf(0.0)));
+
+ // Test multiplications
+
+ assertColumnNames(execute("SELECT a * a, b * a, c * a, d * a, e * a, f * a, g * a, h * a FROM %s WHERE a = 1 AND b = 2 AND c = 3 * 1"),
+ "a * a", "b * a", "c * a", "d * a", "e * a", "f * a", "g * a", "h * a");
+
+ assertRows(execute("SELECT a * a, b * a, c * a, d * a, e * a, f * a, g * a, h * a FROM %s WHERE a = 1 AND b = 2 AND c = 3 * 1"),
+ row((byte) 1, (short) 2, 3, 4L, 5.5F, 6.5, BigInteger.valueOf(7), new BigDecimal("8.50")));
+
+ assertRows(execute("SELECT a * b, b * b, c * b, d * b, e * b, f * b, g * b, h * b FROM %s WHERE a = 1 AND b = 2 AND c = 3 * 1"),
+ row((short) 2, (short) 4, 6, 8L, 11.0F, 13.0, BigInteger.valueOf(14), new BigDecimal("17.00")));
+
+ assertRows(execute("SELECT a * c, b * c, c * c, d * c, e * c, f * c, g * c, h * c FROM %s WHERE a = 1 AND b = 2 AND c = 3 * 1"),
+ row(3, 6, 9, 12L, 16.5F, 19.5, BigInteger.valueOf(21), new BigDecimal("25.50")));
+
+ assertRows(execute("SELECT a * d, b * d, c * d, d * d, e * d, f * d, g * d, h * d FROM %s WHERE a = 1 AND b = 2 AND c = 3 * 1"),
+ row(4L, 8L, 12L, 16L, 22.0, 26.0, BigInteger.valueOf(28), new BigDecimal("34.00")));
+
+ assertRows(execute("SELECT a * e, b * e, c * e, d * e, e * e, f * e, g * e, h * e FROM %s WHERE a = 1 AND b = 2 AND c = 3 * 1"),
+ row(5.5F, 11.0F, 16.5F, 22.0, 30.25F, 35.75, new BigDecimal("38.5"), new BigDecimal("46.75")));
+
+ assertRows(execute("SELECT a * f, b * f, c * f, d * f, e * f, f * f, g * f, h * f FROM %s WHERE a = 1 AND b = 2 AND c = 3 * 1"),
+ row(6.5, 13.0, 19.5, 26.0, 35.75, 42.25, new BigDecimal("45.5"), BigDecimal.valueOf(55.25)));
+
+ assertRows(execute("SELECT a * g, b * g, c * g, d * g, e * g, f * g, g * g, h * g FROM %s WHERE a = 1 AND b = 2 AND c = 3 * 1"),
+ row(BigInteger.valueOf(7),
+ BigInteger.valueOf(14),
+ BigInteger.valueOf(21),
+ BigInteger.valueOf(28),
+ new BigDecimal("38.5"),
+ new BigDecimal("45.5"),
+ BigInteger.valueOf(49),
+ new BigDecimal("59.5")));
+
+ assertRows(execute("SELECT a * h, b * h, c * h, d * h, e * h, f * h, g * h, h * h FROM %s WHERE a = 1 AND b = 2 AND c = 3 * 1"),
+ row(new BigDecimal("8.50"),
+ new BigDecimal("17.00"),
+ new BigDecimal("25.50"),
+ new BigDecimal("34.00"),
+ new BigDecimal("46.75"),
+ new BigDecimal("55.25"),
+ new BigDecimal("59.5"),
+ new BigDecimal("72.25")));
+
+ // Test divisions
+
+ assertColumnNames(execute("SELECT a / a, b / a, c / a, d / a, e / a, f / a, g / a, h / a FROM %s WHERE a = 1 AND b = 2 AND c = 3 / 1"),
+ "a / a", "b / a", "c / a", "d / a", "e / a", "f / a", "g / a", "h / a");
+
+ assertRows(execute("SELECT a / a, b / a, c / a, d / a, e / a, f / a, g / a, h / a FROM %s WHERE a = 1 AND b = 2 AND c = 3 / 1"),
+ row((byte) 1, (short) 2, 3, 4L, 5.5F, 6.5, BigInteger.valueOf(7), new BigDecimal("8.5")));
+
+ assertRows(execute("SELECT a / b, b / b, c / b, d / b, e / b, f / b, g / b, h / b FROM %s WHERE a = 1 AND b = 2 AND c = 3 / 1"),
+ row((short) 0, (short) 1, 1, 2L, 2.75F, 3.25, BigInteger.valueOf(3), new BigDecimal("4.25")));
+
+ assertRows(execute("SELECT a / c, b / c, c / c, d / c, e / c, f / c, g / c, h / c FROM %s WHERE a = 1 AND b = 2 AND c = 3 / 1"),
+ row(0, 0, 1, 1L, 1.8333334F, 2.1666666666666665, BigInteger.valueOf(2), new BigDecimal("2.833333333333333333333333333333333")));
+
+ assertRows(execute("SELECT a / d, b / d, c / d, d / d, e / d, f / d, g / d, h / d FROM %s WHERE a = 1 AND b = 2 AND c = 3 / 1"),
+ row(0L, 0L, 0L, 1L, 1.375, 1.625, BigInteger.valueOf(1), new BigDecimal("2.125")));
+
+ assertRows(execute("SELECT a / e, b / e, c / e, d / e, e / e, f / e, g / e, h / e FROM %s WHERE a = 1 AND b = 2 AND c = 3 / 1"),
+ row(0.18181819F, 0.36363637F, 0.54545456F, 0.7272727272727273, 1.0F, 1.1818181818181819, new BigDecimal("1.272727272727272727272727272727273"), new BigDecimal("1.545454545454545454545454545454545")));
+
+ assertRows(execute("SELECT a / f, b / f, c / f, d / f, e / f, f / f, g / f, h / f FROM %s WHERE a = 1 AND b = 2 AND c = 3 / 1"),
+ row(0.15384615384615385, 0.3076923076923077, 0.46153846153846156, 0.6153846153846154, 0.8461538461538461, 1.0, new BigDecimal("1.076923076923076923076923076923077"), new BigDecimal("1.307692307692307692307692307692308")));
+
+ assertRows(execute("SELECT a / g, b / g, c / g, d / g, e / g, f / g, g / g, h / g FROM %s WHERE a = 1 AND b = 2 AND c = 3 / 1"),
+ row(BigInteger.valueOf(0),
+ BigInteger.valueOf(0),
+ BigInteger.valueOf(0),
+ BigInteger.valueOf(0),
+ new BigDecimal("0.7857142857142857142857142857142857"),
+ new BigDecimal("0.9285714285714285714285714285714286"),
+ BigInteger.valueOf(1),
+ new BigDecimal("1.214285714285714285714285714285714")));
+
+ assertRows(execute("SELECT a / h, b / h, c / h, d / h, e / h, f / h, g / h, h / h FROM %s WHERE a = 1 AND b = 2 AND c = 3 / 1"),
+ row(new BigDecimal("0.1176470588235294117647058823529412"),
+ new BigDecimal("0.2352941176470588235294117647058824"),
+ new BigDecimal("0.3529411764705882352941176470588235"),
+ new BigDecimal("0.4705882352941176470588235294117647"),
+ new BigDecimal("0.6470588235294117647058823529411765"),
+ new BigDecimal("0.7647058823529411764705882352941176"),
+ new BigDecimal("0.8235294117647058823529411764705882"),
+ new BigDecimal("1")));
+
+ // Test modulo operations
+
+ assertColumnNames(execute("SELECT a %% a, b %% a, c %% a, d %% a, e %% a, f %% a, g %% a, h %% a FROM %s WHERE a = 1 AND b = 2 AND c = 23 %% 5"),
+ "a % a", "b % a", "c % a", "d % a", "e % a", "f % a", "g % a", "h % a");
+
+ assertRows(execute("SELECT a %% a, b %% a, c %% a, d %% a, e %% a, f %% a, g %% a, h %% a FROM %s WHERE a = 1 AND b = 2 AND c = 23 %% 5"),
+ row((byte) 0, (short) 0, 0, 0L, 0.5F, 0.5, BigInteger.valueOf(0), new BigDecimal("0.5")));
+
+ assertRows(execute("SELECT a %% b, b %% b, c %% b, d %% b, e %% b, f %% b, g %% b, h %% b FROM %s WHERE a = 1 AND b = 2 AND c = 23 %% 5"),
+ row((short) 1, (short) 0, 1, 0L, 1.5F, 0.5, BigInteger.valueOf(1), new BigDecimal("0.5")));
+
+ assertRows(execute("SELECT a %% c, b %% c, c %% c, d %% c, e %% c, f %% c, g %% c, h %% c FROM %s WHERE a = 1 AND b = 2 AND c = 23 %% 5"),
+ row(1, 2, 0, 1L, 2.5F, 0.5, BigInteger.valueOf(1), new BigDecimal("2.5")));
+
+ assertRows(execute("SELECT a %% d, b %% d, c %% d, d %% d, e %% d, f %% d, g %% d, h %% d FROM %s WHERE a = 1 AND b = 2 AND c = 23 %% 5"),
+ row(1L, 2L, 3L, 0L, 1.5, 2.5, BigInteger.valueOf(3), new BigDecimal("0.5")));
+
+ assertRows(execute("SELECT a %% e, b %% e, c %% e, d %% e, e %% e, f %% e, g %% e, h %% e FROM %s WHERE a = 1 AND b = 2 AND c = 23 %% 5"),
+ row(1.0F, 2.0F, 3.0F, 4.0, 0.0F, 1.0, new BigDecimal("1.5"), new BigDecimal("3.0")));
+
+ assertRows(execute("SELECT a %% f, b %% f, c %% f, d %% f, e %% f, f %% f, g %% f, h %% f FROM %s WHERE a = 1 AND b = 2 AND c = 23 %% 5"),
+ row(1.0, 2.0, 3.0, 4.0, 5.5, 0.0, new BigDecimal("0.5"), new BigDecimal("2.0")));
+
+ assertRows(execute("SELECT a %% g, b %% g, c %% g, d %% g, e %% g, f %% g, g %% g, h %% g FROM %s WHERE a = 1 AND b = 2 AND c = 23 %% 5"),
+ row(BigInteger.valueOf(1),
+ BigInteger.valueOf(2),
+ BigInteger.valueOf(3),
+ BigInteger.valueOf(4),
+ new BigDecimal("5.5"),
+ new BigDecimal("6.5"),
+ BigInteger.valueOf(0),
+ new BigDecimal("1.5")));
+
+ assertRows(execute("SELECT a %% h, b %% h, c %% h, d %% h, e %% h, f %% h, g %% h, h %% h FROM %s WHERE a = 1 AND b = 2 AND c = 23 %% 5"),
+ row(new BigDecimal("1.0"),
+ new BigDecimal("2.0"),
+ new BigDecimal("3.0"),
+ new BigDecimal("4.0"),
+ new BigDecimal("5.5"),
+ new BigDecimal("6.5"),
+ new BigDecimal("7"),
+ new BigDecimal("0.0")));
+
+ // Test negation
+
+ assertColumnNames(execute("SELECT -a, -b, -c, -d, -e, -f, -g, -h FROM %s WHERE a = 1 AND b = 2"),
+ "-a", "-b", "-c", "-d", "-e", "-f", "-g", "-h");
+
+ assertRows(execute("SELECT -a, -b, -c, -d, -e, -f, -g, -h FROM %s WHERE a = 1 AND b = 2"),
+ row((byte) -1, (short) -2, -3, -4L, -5.5F, -6.5, BigInteger.valueOf(-7), new BigDecimal("-8.5")));
+
+ // Test with null
+ execute("UPDATE %s SET d = ? WHERE a = ? AND b = ? AND c = ?", null, (byte) 1, (short) 2, 3);
+ assertRows(execute("SELECT a + d, b + d, c + d, d + d, e + d, f + d, g + d, h + d FROM %s WHERE a = 1 AND b = 2"),
+ row(null, null, null, null, null, null, null, null));
+ }
+
+ @Test
+ public void testSingleOperationsWithLiterals() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int, c1 tinyint, c2 smallint, v text, PRIMARY KEY(pk, c1, c2))");
+ execute("INSERT INTO %S (pk, c1, c2, v) VALUES (2, 2, 2, 'test')");
+
+ // There is only one function outputing tinyint
+ assertRows(execute("SELECT * FROM %s WHERE pk = 2 AND c1 = 1 + 1"),
+ row(2, (byte) 2, (short) 2, "test"));
+
+ // As the operation can only be a sum between tinyints the expected type is tinyint
+ assertInvalidMessage("Expected 1 byte for a tinyint (4)",
+ "SELECT * FROM %s WHERE pk = 2 AND c1 = 1 + ?", 1);
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = 2 AND c1 = 1 + ?", (byte) 1),
+ row(2, (byte) 2, (short) 2, "test"));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = 1 + 1 AND c1 = 2"),
+ row(2, (byte) 2, (short) 2, "test"));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = 2 AND c1 = 2 AND c2 = 1 + 1"),
+ row(2, (byte) 2, (short) 2, "test"));
+
+ assertRows(execute("SELECT * FROM %s WHERE pk = 2 AND c1 = 2 AND c2 = 1 * (1 + 1)"),
+ row(2, (byte) 2, (short) 2, "test"));
+
+ // tinyint, smallint and int could be used there so we need to disambiguate
+ assertInvalidMessage("Ambiguous '+' operation: use type casts to disambiguate",
+ "SELECT * FROM %s WHERE pk = ? + 1 AND c1 = 2", 1);
+
+ assertInvalidMessage("Ambiguous '+' operation: use type casts to disambiguate",
+ "SELECT * FROM %s WHERE pk = 2 AND c1 = 2 AND c2 = 1 * (? + 1)", 1);
+
+ assertRows(execute("SELECT 1 + 1, v FROM %s WHERE pk = 2 AND c1 = 2"),
+ row(2, "test"));
+
+ // As the output type is unknown the ? type cannot be determined
+ assertInvalidMessage("Ambiguous '+' operation: use type casts to disambiguate",
+ "SELECT 1 + ?, v FROM %s WHERE pk = 2 AND c1 = 2", 1);
+
+ // As the prefered type for the constants is int, the returned type will be int
+ assertRows(execute("SELECT 100 + 50, v FROM %s WHERE pk = 2 AND c1 = 2"),
+ row(150, "test"));
+
+ // As the output type is unknown the ? type cannot be determined
+ assertInvalidMessage("Ambiguous '+' operation: use type casts to disambiguate",
+ "SELECT ? + 50, v FROM %s WHERE pk = 2 AND c1 = 2", 100);
+
+ createTable("CREATE TABLE %s (a tinyint, b smallint, c int, d bigint, e float, f double, g varint, h decimal, PRIMARY KEY(a, b))"
+ + " WITH CLUSTERING ORDER BY (b DESC)"); // Make sure we test with ReversedTypes
+ execute("INSERT INTO %S (a, b, c, d, e, f, g, h) VALUES (1, 2, 3, 4, 5.5, 6.5, 7, 8.5)");
+
+ // Test additions
+ assertColumnNames(execute("SELECT a + 1, b + 1, c + 1, d + 1, e + 1, f + 1, g + 1, h + 1 FROM %s WHERE a = 1 AND b = 2"),
+ "a + 1", "b + 1", "c + 1", "d + 1", "e + 1", "f + 1", "g + 1", "h + 1");
+
+ assertRows(execute("SELECT a + 1, b + 1, c + 1, d + 1, e + 1, f + 1, g + 1, h + 1 FROM %s WHERE a = 1 AND b = 2"),
+ row(2, 3, 4, 5L, 6.5F, 7.5, BigInteger.valueOf(8), BigDecimal.valueOf(9.5)));
+
+ assertRows(execute("SELECT 2 + a, 2 + b, 2 + c, 2 + d, 2 + e, 2 + f, 2 + g, 2 + h FROM %s WHERE a = 1 AND b = 2"),
+ row(3, 4, 5, 6L, 7.5F, 8.5, BigInteger.valueOf(9), BigDecimal.valueOf(10.5)));
+
+ long bigInt = Integer.MAX_VALUE + 10L;
+
+ assertRows(execute("SELECT a + " + bigInt + ","
+ + " b + " + bigInt + ","
+ + " c + " + bigInt + ","
+ + " d + " + bigInt + ","
+ + " e + " + bigInt + ","
+ + " f + " + bigInt + ","
+ + " g + " + bigInt + ","
+ + " h + " + bigInt + " FROM %s WHERE a = 1 AND b = 2"),
+ row(1L + bigInt,
+ 2L + bigInt,
+ 3L + bigInt,
+ 4L + bigInt,
+ 5.5 + bigInt,
+ 6.5 + bigInt,
+ BigInteger.valueOf(bigInt + 7),
+ BigDecimal.valueOf(bigInt + 8.5)));
+
+ assertRows(execute("SELECT a + 5.5, b + 5.5, c + 5.5, d + 5.5, e + 5.5, f + 5.5, g + 5.5, h + 5.5 FROM %s WHERE a = 1 AND b = 2"),
+ row(6.5, 7.5, 8.5, 9.5, 11.0, 12.0, BigDecimal.valueOf(12.5), BigDecimal.valueOf(14.0)));
+
+ assertRows(execute("SELECT a + 6.5, b + 6.5, c + 6.5, d + 6.5, e + 6.5, f + 6.5, g + 6.5, h + 6.5 FROM %s WHERE a = 1 AND b = 2"),
+ row(7.5, 8.5, 9.5, 10.5, 12.0, 13.0, BigDecimal.valueOf(13.5), BigDecimal.valueOf(15.0)));
+
+ // Test substractions
+
+ assertColumnNames(execute("SELECT a - 1, b - 1, c - 1, d - 1, e - 1, f - 1, g - 1, h - 1 FROM %s WHERE a = 1 AND b = 2"),
+ "a - 1", "b - 1", "c - 1", "d - 1", "e - 1", "f - 1", "g - 1", "h - 1");
+
+ assertRows(execute("SELECT a - 1, b - 1, c - 1, d - 1, e - 1, f - 1, g - 1, h - 1 FROM %s WHERE a = 1 AND b = 2"),
+ row(0, 1, 2, 3L, 4.5F, 5.5, BigInteger.valueOf(6), BigDecimal.valueOf(7.5)));
+
+ assertRows(execute("SELECT a - 2, b - 2, c - 2, d - 2, e - 2, f - 2, g - 2, h - 2 FROM %s WHERE a = 1 AND b = 2"),
+ row(-1, 0, 1, 2L, 3.5F, 4.5, BigInteger.valueOf(5), BigDecimal.valueOf(6.5)));
+
+ assertRows(execute("SELECT a - 3, b - 3, 3 - 3, d - 3, e - 3, f - 3, g - 3, h - 3 FROM %s WHERE a = 1 AND b = 2"),
+ row(-2, -1, 0, 1L, 2.5F, 3.5, BigInteger.valueOf(4), BigDecimal.valueOf(5.5)));
+
+ assertRows(execute("SELECT a - " + bigInt + ","
+ + " b - " + bigInt + ","
+ + " c - " + bigInt + ","
+ + " d - " + bigInt + ","
+ + " e - " + bigInt + ","
+ + " f - " + bigInt + ","
+ + " g - " + bigInt + ","
+ + " h - " + bigInt + " FROM %s WHERE a = 1 AND b = 2"),
+ row(1L - bigInt,
+ 2L - bigInt,
+ 3L - bigInt,
+ 4L - bigInt,
+ 5.5 - bigInt,
+ 6.5 - bigInt,
+ BigInteger.valueOf(7 - bigInt),
+ BigDecimal.valueOf(8.5 - bigInt)));
+
+ assertRows(execute("SELECT a - 5.5, b - 5.5, c - 5.5, d - 5.5, e - 5.5, f - 5.5, g - 5.5, h - 5.5 FROM %s WHERE a = 1 AND b = 2"),
+ row(-4.5, -3.5, -2.5, -1.5, 0.0, 1.0, BigDecimal.valueOf(1.5), BigDecimal.valueOf(3.0)));
+
+ assertRows(execute("SELECT a - 6.5, b - 6.5, c - 6.5, d - 6.5, e - 6.5, f - 6.5, g - 6.5, h - 6.5 FROM %s WHERE a = 1 AND b = 2"),
+ row(-5.5, -4.5, -3.5, -2.5, -1.0, 0.0, BigDecimal.valueOf(0.5), BigDecimal.valueOf(2.0)));
+
+ // Test multiplications
+
+ assertColumnNames(execute("SELECT a * 1, b * 1, c * 1, d * 1, e * 1, f * 1, g * 1, h * 1 FROM %s WHERE a = 1 AND b = 2"),
+ "a * 1", "b * 1", "c * 1", "d * 1", "e * 1", "f * 1", "g * 1", "h * 1");
+
+ assertRows(execute("SELECT a * 1, b * 1, c * 1, d * 1, e * 1, f * 1, g * 1, h * 1 FROM %s WHERE a = 1 AND b = 2"),
+ row(1, 2, 3, 4L, 5.5F, 6.5, BigInteger.valueOf(7), new BigDecimal("8.50")));
+
+ assertRows(execute("SELECT a * 2, b * 2, c * 2, d * 2, e * 2, f * 2, g * 2, h * 2 FROM %s WHERE a = 1 AND b = 2"),
+ row(2, 4, 6, 8L, 11.0F, 13.0, BigInteger.valueOf(14), new BigDecimal("17.00")));
+
+ assertRows(execute("SELECT a * 3, b * 3, c * 3, d * 3, e * 3, f * 3, g * 3, h * 3 FROM %s WHERE a = 1 AND b = 2"),
+ row(3, 6, 9, 12L, 16.5F, 19.5, BigInteger.valueOf(21), new BigDecimal("25.50")));
+
+ assertRows(execute("SELECT a * " + bigInt + ","
+ + " b * " + bigInt + ","
+ + " c * " + bigInt + ","
+ + " d * " + bigInt + ","
+ + " e * " + bigInt + ","
+ + " f * " + bigInt + ","
+ + " g * " + bigInt + ","
+ + " h * " + bigInt + " FROM %s WHERE a = 1 AND b = 2"),
+ row(1L * bigInt,
+ 2L * bigInt,
+ 3L * bigInt,
+ 4L * bigInt,
+ 5.5 * bigInt,
+ 6.5 * bigInt,
+ BigInteger.valueOf(7 * bigInt),
+ BigDecimal.valueOf(8.5 * bigInt)));
+
+ assertRows(execute("SELECT a * 5.5, b * 5.5, c * 5.5, d * 5.5, e * 5.5, f * 5.5, g * 5.5, h * 5.5 FROM %s WHERE a = 1 AND b = 2"),
+ row(5.5, 11.0, 16.5, 22.0, 30.25, 35.75, new BigDecimal("38.5"), new BigDecimal("46.75")));
+
+ assertRows(execute("SELECT a * 6.5, b * 6.5, c * 6.5, d * 6.5, e * 6.5, 6.5 * f, g * 6.5, h * 6.5 FROM %s WHERE a = 1 AND b = 2"),
+ row(6.5, 13.0, 19.5, 26.0, 35.75, 42.25, new BigDecimal("45.5"), BigDecimal.valueOf(55.25)));
+
+ // Test divisions
+
+ assertColumnNames(execute("SELECT a / 1, b / 1, c / 1, d / 1, e / 1, f / 1, g / 1, h / 1 FROM %s WHERE a = 1 AND b = 2"),
+ "a / 1", "b / 1", "c / 1", "d / 1", "e / 1", "f / 1", "g / 1", "h / 1");
+
+ assertRows(execute("SELECT a / 1, b / 1, c / 1, d / 1, e / 1, f / 1, g / 1, h / 1 FROM %s WHERE a = 1 AND b = 2"),
+ row(1, 2, 3, 4L, 5.5F, 6.5, BigInteger.valueOf(7), new BigDecimal("8.5")));
+
+ assertRows(execute("SELECT a / 2, b / 2, c / 2, d / 2, e / 2, f / 2, g / 2, h / 2 FROM %s WHERE a = 1 AND b = 2"),
+ row(0, 1, 1, 2L, 2.75F, 3.25, BigInteger.valueOf(3), new BigDecimal("4.25")));
+
+ assertRows(execute("SELECT a / 3, b / 3, c / 3, d / 3, e / 3, f / 3, g / 3, h / 3 FROM %s WHERE a = 1 AND b = 2"),
+ row(0, 0, 1, 1L, 1.8333334F, 2.1666666666666665, BigInteger.valueOf(2), new BigDecimal("2.833333333333333333333333333333333")));
+
+ assertRows(execute("SELECT a / " + bigInt + ","
+ + " b / " + bigInt + ","
+ + " c / " + bigInt + ","
+ + " d / " + bigInt + ","
+ + " e / " + bigInt + ","
+ + " f / " + bigInt + ","
+ + " g / " + bigInt + " FROM %s WHERE a = 1 AND b = 2"),
+ row(1L / bigInt,
+ 2L / bigInt,
+ 3L / bigInt,
+ 4L / bigInt,
+ 5.5 / bigInt,
+ 6.5 / bigInt,
+ BigInteger.valueOf(7).divide(BigInteger.valueOf(bigInt))));
+
+ assertRows(execute("SELECT a / 5.5, b / 5.5, c / 5.5, d / 5.5, e / 5.5, f / 5.5, g / 5.5, h / 5.5 FROM %s WHERE a = 1 AND b = 2"),
+ row(0.18181818181818182, 0.36363636363636365, 0.5454545454545454, 0.7272727272727273, 1.0, 1.1818181818181819, new BigDecimal("1.272727272727272727272727272727273"), new BigDecimal("1.545454545454545454545454545454545")));
+
+ assertRows(execute("SELECT a / 6.5, b / 6.5, c / 6.5, d / 6.5, e / 6.5, f / 6.5, g / 6.5, h / 6.5 FROM %s WHERE a = 1 AND b = 2"),
+ row(0.15384615384615385, 0.3076923076923077, 0.46153846153846156, 0.6153846153846154, 0.8461538461538461, 1.0, new BigDecimal("1.076923076923076923076923076923077"), new BigDecimal("1.307692307692307692307692307692308")));
+
+ // Test modulo operations
+
+ assertColumnNames(execute("SELECT a %% 1, b %% 1, c %% 1, d %% 1, e %% 1, f %% 1, g %% 1, h %% 1 FROM %s WHERE a = 1 AND b = 2"),
+ "a % 1", "b % 1", "c % 1", "d % 1", "e % 1", "f % 1", "g % 1", "h % 1");
+
+ assertRows(execute("SELECT a %% 1, b %% 1, c %% 1, d %% 1, e %% 1, f %% 1, g %% 1, h %% 1 FROM %s WHERE a = 1 AND b = 2"),
+ row(0, 0, 0, 0L, 0.5F, 0.5, BigInteger.valueOf(0), new BigDecimal("0.5")));
+
+ assertRows(execute("SELECT a %% 2, b %% 2, c %% 2, d %% 2, e %% 2, f %% 2, g %% 2, h %% 2 FROM %s WHERE a = 1 AND b = 2"),
+ row(1, 0, 1, 0L, 1.5F, 0.5, BigInteger.valueOf(1), new BigDecimal("0.5")));
+
+ assertRows(execute("SELECT a %% 3, b %% 3, c %% 3, d %% 3, e %% 3, f %% 3, g %% 3, h %% 3 FROM %s WHERE a = 1 AND b = 2"),
+ row(1, 2, 0, 1L, 2.5F, 0.5, BigInteger.valueOf(1), new BigDecimal("2.5")));
+
+ assertRows(execute("SELECT a %% " + bigInt + ","
+ + " b %% " + bigInt + ","
+ + " c %% " + bigInt + ","
+ + " d %% " + bigInt + ","
+ + " e %% " + bigInt + ","
+ + " f %% " + bigInt + ","
+ + " g %% " + bigInt + ","
+ + " h %% " + bigInt + " FROM %s WHERE a = 1 AND b = 2"),
+ row(1L % bigInt,
+ 2L % bigInt,
+ 3L % bigInt,
+ 4L % bigInt,
+ 5.5 % bigInt,
+ 6.5 % bigInt,
+ BigInteger.valueOf(7 % bigInt),
+ BigDecimal.valueOf(8.5 % bigInt)));
+
+ assertRows(execute("SELECT a %% 5.5, b %% 5.5, c %% 5.5, d %% 5.5, e %% 5.5, f %% 5.5, g %% 5.5, h %% 5.5 FROM %s WHERE a = 1 AND b = 2"),
+ row(1.0, 2.0, 3.0, 4.0, 0.0, 1.0, new BigDecimal("1.5"), new BigDecimal("3.0")));
+
+ assertRows(execute("SELECT a %% 6.5, b %% 6.5, c %% 6.5, d %% 6.5, e %% 6.5, f %% 6.5, g %% 6.5, h %% 6.5 FROM %s WHERE a = 1 AND b = 2"),
+ row(1.0, 2.0, 3.0, 4.0, 5.5, 0.0, new BigDecimal("0.5"), new BigDecimal("2.0")));
+
+ assertRows(execute("SELECT a, b, 1 + 1, 2 - 1, 2 * 2, 2 / 1 , 2 %% 1, (int) -1 FROM %s WHERE a = 1 AND b = 2"),
+ row((byte) 1, (short) 2, 2, 1, 4, 2, 0, -1));
+ }
+
+ @Test
+ public void testWithCounters() throws Throwable
+ {
+ createTable("CREATE TABLE %s (a int PRIMARY KEY, b counter)");
+ execute("UPDATE %s SET b = b + 1 WHERE a = 1");
+ execute("UPDATE %s SET b = b + 1 WHERE a = 1");
+ assertRows(execute("SELECT b FROM %s WHERE a = 1"), row(2L));
+
+ assertRows(execute("SELECT b + (tinyint) 1,"
+ + " b + (smallint) 1,"
+ + " b + 1,"
+ + " b + (bigint) 1,"
+ + " b + (float) 1.5,"
+ + " b + 1.5,"
+ + " b + (varint) 1,"
+ + " b + (decimal) 1.5,"
+ + " b + b FROM %s WHERE a = 1"),
+ row(3L, 3L, 3L, 3L, 3.5, 3.5, BigInteger.valueOf(3), new BigDecimal("3.5"), 4L));
+
+ assertRows(execute("SELECT b - (tinyint) 1,"
+ + " b - (smallint) 1,"
+ + " b - 1,"
+ + " b - (bigint) 1,"
+ + " b - (float) 1.5,"
+ + " b - 1.5,"
+ + " b - (varint) 1,"
+ + " b - (decimal) 1.5,"
+ + " b - b FROM %s WHERE a = 1"),
+ row(1L, 1L, 1L, 1L, 0.5, 0.5, BigInteger.valueOf(1), new BigDecimal("0.5"), 0L));
+
+ assertRows(execute("SELECT b * (tinyint) 1,"
+ + " b * (smallint) 1,"
+ + " b * 1,"
+ + " b * (bigint) 1,"
+ + " b * (float) 1.5,"
+ + " b * 1.5,"
+ + " b * (varint) 1,"
+ + " b * (decimal) 1.5,"
+ + " b * b FROM %s WHERE a = 1"),
+ row(2L, 2L, 2L, 2L, 3.0, 3.0, BigInteger.valueOf(2), new BigDecimal("3.00"), 4L));
+
+ assertRows(execute("SELECT b / (tinyint) 1,"
+ + " b / (smallint) 1,"
+ + " b / 1,"
+ + " b / (bigint) 1,"
+ + " b / (float) 0.5,"
+ + " b / 0.5,"
+ + " b / (varint) 1,"
+ + " b / (decimal) 0.5,"
+ + " b / b FROM %s WHERE a = 1"),
+ row(2L, 2L, 2L, 2L, 4.0, 4.0, BigInteger.valueOf(2), new BigDecimal("4"), 1L));
+
+ assertRows(execute("SELECT b %% (tinyint) 1,"
+ + " b %% (smallint) 1,"
+ + " b %% 1,"
+ + " b %% (bigint) 1,"
+ + " b %% (float) 0.5,"
+ + " b %% 0.5,"
+ + " b %% (varint) 1,"
+ + " b %% (decimal) 0.5,"
+ + " b %% b FROM %s WHERE a = 1"),
+ row(0L, 0L, 0L, 0L, 0.0, 0.0, BigInteger.valueOf(0), new BigDecimal("0.0"), 0L));
+
+ assertRows(execute("SELECT -b FROM %s WHERE a = 1"), row(-2L));
+ }
+
+ @Test
+ public void testPrecedenceAndParentheses() throws Throwable
+ {
+ createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY(a, b))");
+ execute("INSERT INTO %S (a, b, c, d) VALUES (2, 5, 25, 4)");
+
+ UntypedResultSet rs = execute("SELECT a - c / b + d FROM %s");
+ assertColumnNames(rs, "a - c / b + d");
+ assertRows(rs, row(1));
+
+ rs = execute("SELECT (c - b) / a + d FROM %s");
+ assertColumnNames(rs, "(c - b) / a + d");
+ assertRows(rs, row(14));
+
+ rs = execute("SELECT c / a / b FROM %s");
+ assertColumnNames(rs, "c / a / b");
+ assertRows(rs, row(2));
+
+ rs = execute("SELECT c / b / d FROM %s");
+ assertColumnNames(rs, "c / b / d");
+ assertRows(rs, row(1));
+
+ rs = execute("SELECT (c - a) %% d / a FROM %s");
+ assertColumnNames(rs, "(c - a) % d / a");
+ assertRows(rs, row(1));
+
+ rs = execute("SELECT (c - a) %% d / a + d FROM %s");
+ assertColumnNames(rs, "(c - a) % d / a + d");
+ assertRows(rs, row(5));
+
+ rs = execute("SELECT -(c - a) %% d / a + d FROM %s");
+ assertColumnNames(rs, "-(c - a) % d / a + d");
+ assertRows(rs, row(3));
+
+ rs = execute("SELECT (-c - a) %% d / a + d FROM %s");
+ assertColumnNames(rs, "(-c - a) % d / a + d");
+ assertRows(rs, row(3));
+
+ rs = execute("SELECT c - a %% d / a + d FROM %s");
+ assertColumnNames(rs, "c - a % d / a + d");
+ assertRows(rs, row(28));
+
+ rs = execute("SELECT (int)((c - a) %% d / (a + d)) FROM %s");
+ assertColumnNames(rs, "(int)((c - a) % d / (a + d))");
+ assertRows(rs, row(0));
+
+ // test with aliases
+ rs = execute("SELECT (int)((c - a) %% d / (a + d)) as result FROM %s");
+ assertColumnNames(rs, "result");
+ assertRows(rs, row(0));
+
+ rs = execute("SELECT c / a / b as divisions FROM %s");
+ assertColumnNames(rs, "divisions");
+ assertRows(rs, row(2));
+
+ assertRows(execute("SELECT * FROM %s WHERE a = ? AND b = (int) ? / 2 - 5", 2, 20),
+ row(2, 5, 25, 4));
+
+ assertRows(execute("SELECT * FROM %s WHERE a = ? AND b = (int) ? / (2 + 2)", 2, 20),
+ row(2, 5, 25, 4));
+ }
+
+ @Test
+ public void testWithDivisionByZero() throws Throwable
+ {
+ createTable("CREATE TABLE %s (a tinyint, b smallint, c int, d bigint, e float, f double, g varint, h decimal, PRIMARY KEY(a, b))");
+ execute("INSERT INTO %S (a, b, c, d, e, f, g, h) VALUES (0, 2, 3, 4, 5.5, 6.5, 7, 8.5)");
+
+ assertInvalidThrowMessage("the operation 'tinyint / tinyint' failed: / by zero",
+ OperationExecutionException.class,
+ "SELECT a / a FROM %s WHERE a = 0 AND b = 2");
+
+ assertInvalidThrowMessage("the operation 'smallint / tinyint' failed: / by zero",
+ OperationExecutionException.class,
+ "SELECT b / a FROM %s WHERE a = 0 AND b = 2");
+
+ assertInvalidThrowMessage("the operation 'int / tinyint' failed: / by zero",
+ OperationExecutionException.class,
+ "SELECT c / a FROM %s WHERE a = 0 AND b = 2");
+
+ assertInvalidThrowMessage("the operation 'bigint / tinyint' failed: / by zero",
+ OperationExecutionException.class,
+ "SELECT d / a FROM %s WHERE a = 0 AND b = 2");
+
+ assertInvalidThrowMessage("the operation 'smallint / smallint' failed: / by zero",
+ OperationExecutionException.class,
+ "SELECT a FROM %s WHERE a = 0 AND b = 10/0");
+
+ assertRows(execute("SELECT e / a FROM %s WHERE a = 0 AND b = 2"), row(Float.POSITIVE_INFINITY));
+ assertRows(execute("SELECT f / a FROM %s WHERE a = 0 AND b = 2"), row(Double.POSITIVE_INFINITY));
+
+ assertInvalidThrowMessage("the operation 'varint / tinyint' failed: BigInteger divide by zero",
+ OperationExecutionException.class,
+ "SELECT g / a FROM %s WHERE a = 0 AND b = 2");
+
+ assertInvalidThrowMessage("the operation 'decimal / tinyint' failed: Division by zero",
+ OperationExecutionException.class,
+ "SELECT h / a FROM %s WHERE a = 0 AND b = 2");
+ }
+
+ @Test
+ public void testWithNanAndInfinity() throws Throwable
+ {
+ createTable("CREATE TABLE %s (a int PRIMARY KEY, b double, c decimal)");
+ assertInvalidMessage("Ambiguous '+' operation: use type casts to disambiguate",
+ "INSERT INTO %S (a, b, c) VALUES (? + 1, ?, ?)", 0, Double.NaN, BigDecimal.valueOf(1));
+
+ execute("INSERT INTO %S (a, b, c) VALUES ((int) ? + 1, -?, ?)", 0, Double.NaN, BigDecimal.valueOf(1));
+
+ assertRows(execute("SELECT * FROM %s"), row(1, Double.NaN, BigDecimal.valueOf(1)));
+
+ assertRows(execute("SELECT a + NAN, b + 1 FROM %s"), row(Double.NaN, Double.NaN));
+ assertInvalidThrowMessage("the operation 'decimal + double' failed: A NaN cannot be converted into a decimal",
+ OperationExecutionException.class,
+ "SELECT c + NAN FROM %s");
+
+ assertRows(execute("SELECT a + (float) NAN, b + 1 FROM %s"), row(Float.NaN, Double.NaN));
+ assertInvalidThrowMessage("the operation 'decimal + float' failed: A NaN cannot be converted into a decimal",
+ OperationExecutionException.class,
+ "SELECT c + (float) NAN FROM %s");
+
+ execute("INSERT INTO %S (a, b, c) VALUES (?, ?, ?)", 1, Double.POSITIVE_INFINITY, BigDecimal.valueOf(1));
+ assertRows(execute("SELECT * FROM %s"), row(1, Double.POSITIVE_INFINITY, BigDecimal.valueOf(1)));
+
+ assertRows(execute("SELECT a + INFINITY, b + 1 FROM %s"), row(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
+ assertInvalidThrowMessage("the operation 'decimal + double' failed: An infinite number cannot be converted into a decimal",
+ OperationExecutionException.class,
+ "SELECT c + INFINITY FROM %s");
+
+ assertRows(execute("SELECT a + (float) INFINITY, b + 1 FROM %s"), row(Float.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
+ assertInvalidThrowMessage("the operation 'decimal + float' failed: An infinite number cannot be converted into a decimal",
+ OperationExecutionException.class,
+ "SELECT c + (float) INFINITY FROM %s");
+
+ execute("INSERT INTO %S (a, b, c) VALUES (?, ?, ?)", 1, Double.NEGATIVE_INFINITY, BigDecimal.valueOf(1));
+ assertRows(execute("SELECT * FROM %s"), row(1, Double.NEGATIVE_INFINITY, BigDecimal.valueOf(1)));
+
+ assertRows(execute("SELECT a + -INFINITY, b + 1 FROM %s"), row(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
+ assertInvalidThrowMessage("the operation 'decimal + double' failed: An infinite number cannot be converted into a decimal",
+ OperationExecutionException.class,
+ "SELECT c + -INFINITY FROM %s");
+
+ assertRows(execute("SELECT a + (float) -INFINITY, b + 1 FROM %s"), row(Float.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
+ assertInvalidThrowMessage("the operation 'decimal + float' failed: An infinite number cannot be converted into a decimal",
+ OperationExecutionException.class,
+ "SELECT c + (float) -INFINITY FROM %s");
+ }
+
+ @Test
+ public void testInvalidTypes() throws Throwable
+ {
+ createTable("CREATE TABLE %s (a int PRIMARY KEY, b boolean, c text)");
+ execute("INSERT INTO %S (a, b, c) VALUES (?, ?, ?)", 1, true, "test");
+
+ assertInvalidMessage("the '+' operation is not supported between a and b", "SELECT a + b FROM %s");
+ assertInvalidMessage("the '+' operation is not supported between b and c", "SELECT b + c FROM %s");
+ assertInvalidMessage("the '+' operation is not supported between b and 1", "SELECT b + 1 FROM %s");
+ assertInvalidMessage("the '+' operation is not supported between 1 and b", "SELECT 1 + b FROM %s");
+ assertInvalidMessage("the '+' operation is not supported between b and NaN", "SELECT b + NaN FROM %s");
+ assertInvalidMessage("the '/' operation is not supported between a and b", "SELECT a / b FROM %s");
+ assertInvalidMessage("the '/' operation is not supported between b and c", "SELECT b / c FROM %s");
+ assertInvalidMessage("the '/' operation is not supported between b and 1", "SELECT b / 1 FROM %s");
+ assertInvalidMessage("the '/' operation is not supported between NaN and b", "SELECT NaN / b FROM %s");
+ assertInvalidMessage("the '/' operation is not supported between -Infinity and b", "SELECT -Infinity / b FROM %s");
+ }
+
+ @Test
+ public void testOverflow() throws Throwable
+ {
+ createTable("CREATE TABLE %s (a int PRIMARY KEY, b tinyint, c smallint)");
+ execute("INSERT INTO %S (a, b, c) VALUES (?, ?, ?)", 1, (byte) 1, (short) 1);
+ assertRows(execute("SELECT a + (int) ?, b + (tinyint) ?, c + (smallint) ? FROM %s", 1, (byte) 1, (short) 1),
+ row(2, (byte) 2,(short) 2));
+ assertRows(execute("SELECT a + (int) ?, b + (tinyint) ?, c + (smallint) ? FROM %s", Integer.MAX_VALUE, Byte.MAX_VALUE, Short.MAX_VALUE),
+ row(Integer.MIN_VALUE, Byte.MIN_VALUE, Short.MIN_VALUE));
+ }
+}