mirror of https://github.com/apache/cassandra
Avoid unnecessary deserialization of terminal arguments when executing CQL functions
patch by Benjamin Lerer and Andrés de la Peña; reviewed by Benjamin Lerer for CASSANDRA-18566 Co-authored-by: Benjamin Lerer <b.lerer@gmail.com> Co-authored-by: Andrés de la Peña <a.penya.garcia@gmail.com>
This commit is contained in:
parent
ba3ad7487a
commit
4f3cb5de37
|
|
@ -1,4 +1,5 @@
|
|||
5.0
|
||||
* Avoid unnecessary deserialization of terminal arguments when executing CQL functions (CASSANDRA-18566)
|
||||
* Remove dependency on pytz library for setting CQLSH timezones on Python version >= 3.9 (CASSANDRA-17433)
|
||||
* Extend maximum expiration date (CASSANDRA-14227)
|
||||
* Add guardrail for partition tombstones and deprecate compaction_tombstone_warning_threshold (CASSANDRA-17194)
|
||||
|
|
|
|||
|
|
@ -522,7 +522,7 @@ public abstract class Constants
|
|||
ByteBuffer current = getCurrentCellBuffer(partitionKey, params);
|
||||
if (current == null)
|
||||
return;
|
||||
ByteBuffer newValue = type.add(type, current, type, increment);
|
||||
ByteBuffer newValue = type.add(type.compose(current), type.compose(increment));
|
||||
params.addCell(column, newValue);
|
||||
}
|
||||
else if (column.type instanceof StringType)
|
||||
|
|
|
|||
|
|
@ -114,7 +114,8 @@ public abstract class AggregateFcts
|
|||
return LongType.instance.decompose(count);
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
|
|
@ -157,14 +158,14 @@ public abstract class AggregateFcts
|
|||
return ((DecimalType) returnType()).decompose(sum);
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
BigDecimal number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
BigDecimal number = DecimalType.instance.compose(value);
|
||||
sum = sum.add(number);
|
||||
}
|
||||
};
|
||||
|
|
@ -198,15 +199,15 @@ public abstract class AggregateFcts
|
|||
return DecimalType.instance.decompose(avg);
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
BigDecimal number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
count++;
|
||||
BigDecimal number = DecimalType.instance.compose(value);
|
||||
|
||||
// avg = avg + (value - sum) / count.
|
||||
avg = avg.add(number.subtract(avg).divide(BigDecimal.valueOf(count), RoundingMode.HALF_EVEN));
|
||||
|
|
@ -238,14 +239,14 @@ public abstract class AggregateFcts
|
|||
return ((IntegerType) returnType()).decompose(sum);
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
BigInteger number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
BigInteger number = IntegerType.instance.compose(value);
|
||||
sum = sum.add(number);
|
||||
}
|
||||
};
|
||||
|
|
@ -283,15 +284,15 @@ public abstract class AggregateFcts
|
|||
return IntegerType.instance.decompose(sum.divide(BigInteger.valueOf(count)));
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
BigInteger number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
count++;
|
||||
BigInteger number = ((BigInteger) argTypes().get(0).compose(value));
|
||||
sum = sum.add(number);
|
||||
}
|
||||
};
|
||||
|
|
@ -323,14 +324,14 @@ public abstract class AggregateFcts
|
|||
return ((ByteType) returnType()).decompose(sum);
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
Number number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
Number number = ((Number) argTypes().get(0).compose(value));
|
||||
sum += number.byteValue();
|
||||
}
|
||||
};
|
||||
|
|
@ -348,7 +349,7 @@ public abstract class AggregateFcts
|
|||
{
|
||||
public Aggregate newAggregate()
|
||||
{
|
||||
return new AvgAggregate(ByteType.instance)
|
||||
return new AvgAggregate()
|
||||
{
|
||||
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
|
||||
{
|
||||
|
|
@ -383,14 +384,14 @@ public abstract class AggregateFcts
|
|||
return ((ShortType) returnType()).decompose(sum);
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
Number number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
Number number = ((Number) argTypes().get(0).compose(value));
|
||||
sum += number.shortValue();
|
||||
}
|
||||
};
|
||||
|
|
@ -408,7 +409,7 @@ public abstract class AggregateFcts
|
|||
{
|
||||
public Aggregate newAggregate()
|
||||
{
|
||||
return new AvgAggregate(ShortType.instance)
|
||||
return new AvgAggregate()
|
||||
{
|
||||
public ByteBuffer compute(ProtocolVersion protocolVersion)
|
||||
{
|
||||
|
|
@ -443,14 +444,14 @@ public abstract class AggregateFcts
|
|||
return ((Int32Type) returnType()).decompose(sum);
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
Number number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
Number number = ((Number) argTypes().get(0).compose(value));
|
||||
sum += number.intValue();
|
||||
}
|
||||
};
|
||||
|
|
@ -468,7 +469,7 @@ public abstract class AggregateFcts
|
|||
{
|
||||
public Aggregate newAggregate()
|
||||
{
|
||||
return new AvgAggregate(Int32Type.instance)
|
||||
return new AvgAggregate()
|
||||
{
|
||||
public ByteBuffer compute(ProtocolVersion protocolVersion)
|
||||
{
|
||||
|
|
@ -504,7 +505,7 @@ public abstract class AggregateFcts
|
|||
{
|
||||
public Aggregate newAggregate()
|
||||
{
|
||||
return new AvgAggregate(LongType.instance)
|
||||
return new AvgAggregate()
|
||||
{
|
||||
public ByteBuffer compute(ProtocolVersion protocolVersion)
|
||||
{
|
||||
|
|
@ -525,7 +526,7 @@ public abstract class AggregateFcts
|
|||
{
|
||||
public Aggregate newAggregate()
|
||||
{
|
||||
return new FloatSumAggregate(FloatType.instance)
|
||||
return new FloatSumAggregate()
|
||||
{
|
||||
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
|
||||
{
|
||||
|
|
@ -545,7 +546,7 @@ public abstract class AggregateFcts
|
|||
{
|
||||
public Aggregate newAggregate()
|
||||
{
|
||||
return new FloatAvgAggregate(FloatType.instance)
|
||||
return new FloatAvgAggregate()
|
||||
{
|
||||
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
|
||||
{
|
||||
|
|
@ -566,7 +567,7 @@ public abstract class AggregateFcts
|
|||
{
|
||||
public Aggregate newAggregate()
|
||||
{
|
||||
return new FloatSumAggregate(DoubleType.instance)
|
||||
return new FloatSumAggregate()
|
||||
{
|
||||
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
|
||||
{
|
||||
|
|
@ -586,13 +587,6 @@ public abstract class AggregateFcts
|
|||
private double compensation;
|
||||
private double simpleSum;
|
||||
|
||||
private final AbstractType<?> numberType;
|
||||
|
||||
public FloatSumAggregate(AbstractType<?> numberType)
|
||||
{
|
||||
this.numberType = numberType;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
sum = 0;
|
||||
|
|
@ -600,16 +594,18 @@ public abstract class AggregateFcts
|
|||
simpleSum = 0;
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
Number number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
double number = ((Number) numberType.compose(value)).doubleValue();
|
||||
simpleSum += number;
|
||||
double tmp = number - compensation;
|
||||
double d = number.doubleValue();
|
||||
|
||||
simpleSum += d;
|
||||
double tmp = d - compensation;
|
||||
double rounded = sum + tmp;
|
||||
compensation = (rounded - sum) - tmp;
|
||||
sum = rounded;
|
||||
|
|
@ -644,13 +640,6 @@ public abstract class AggregateFcts
|
|||
private BigDecimal bigSum = null;
|
||||
private boolean overflow = false;
|
||||
|
||||
private final AbstractType<?> numberType;
|
||||
|
||||
public FloatAvgAggregate(AbstractType<?> numberType)
|
||||
{
|
||||
this.numberType = numberType;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
sum = 0;
|
||||
|
|
@ -685,34 +674,35 @@ public abstract class AggregateFcts
|
|||
}
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
Number number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
count++;
|
||||
|
||||
double number = ((Number) numberType.compose(value)).doubleValue();
|
||||
double d = number.doubleValue();
|
||||
|
||||
if (overflow)
|
||||
{
|
||||
bigSum = bigSum.add(BigDecimal.valueOf(number));
|
||||
bigSum = bigSum.add(BigDecimal.valueOf(d));
|
||||
}
|
||||
else
|
||||
{
|
||||
simpleSum += number;
|
||||
simpleSum += d;
|
||||
double prev = sum;
|
||||
double tmp = number - compensation;
|
||||
double tmp = d - compensation;
|
||||
double rounded = sum + tmp;
|
||||
compensation = (rounded - sum) - tmp;
|
||||
sum = rounded;
|
||||
|
||||
if (Double.isInfinite(sum) && !Double.isInfinite(number))
|
||||
if (Double.isInfinite(sum) && !Double.isInfinite(d))
|
||||
{
|
||||
overflow = true;
|
||||
bigSum = BigDecimal.valueOf(prev).add(BigDecimal.valueOf(number));
|
||||
bigSum = BigDecimal.valueOf(prev).add(BigDecimal.valueOf(d));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -728,7 +718,7 @@ public abstract class AggregateFcts
|
|||
{
|
||||
public Aggregate newAggregate()
|
||||
{
|
||||
return new FloatAvgAggregate(DoubleType.instance)
|
||||
return new FloatAvgAggregate()
|
||||
{
|
||||
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
|
||||
{
|
||||
|
|
@ -758,7 +748,7 @@ public abstract class AggregateFcts
|
|||
{
|
||||
public Aggregate newAggregate()
|
||||
{
|
||||
return new AvgAggregate(LongType.instance)
|
||||
return new AvgAggregate()
|
||||
{
|
||||
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
|
||||
{
|
||||
|
|
@ -790,14 +780,15 @@ public abstract class AggregateFcts
|
|||
return min != null ? LongType.instance.decompose(min) : null;
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
Number number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
long lval = LongType.instance.compose(value);
|
||||
long lval = number.longValue();
|
||||
|
||||
if (min == null || lval < min)
|
||||
min = lval;
|
||||
|
|
@ -828,14 +819,15 @@ public abstract class AggregateFcts
|
|||
return max != null ? LongType.instance.decompose(max) : null;
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
Number number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
long lval = LongType.instance.compose(value);
|
||||
long lval = number.longValue();
|
||||
|
||||
if (max == null || lval > max)
|
||||
max = lval;
|
||||
|
|
@ -854,6 +846,13 @@ public abstract class AggregateFcts
|
|||
{
|
||||
return new NativeAggregateFunction("max", inputType, inputType)
|
||||
{
|
||||
@Override
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return FunctionArguments.newNoopInstance(version, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Aggregate newAggregate()
|
||||
{
|
||||
return new Aggregate()
|
||||
|
|
@ -870,9 +869,10 @@ public abstract class AggregateFcts
|
|||
return max;
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
ByteBuffer value = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
return;
|
||||
|
|
@ -895,6 +895,13 @@ public abstract class AggregateFcts
|
|||
{
|
||||
return new NativeAggregateFunction("min", inputType, inputType)
|
||||
{
|
||||
@Override
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return FunctionArguments.newNoopInstance(version, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Aggregate newAggregate()
|
||||
{
|
||||
return new Aggregate()
|
||||
|
|
@ -911,9 +918,10 @@ public abstract class AggregateFcts
|
|||
return min;
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
ByteBuffer value = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
return;
|
||||
|
|
@ -936,6 +944,13 @@ public abstract class AggregateFcts
|
|||
{
|
||||
return new NativeAggregateFunction("count", LongType.instance, inputType)
|
||||
{
|
||||
@Override
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return FunctionArguments.newNoopInstance(version, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Aggregate newAggregate()
|
||||
{
|
||||
return new Aggregate()
|
||||
|
|
@ -952,11 +967,10 @@ public abstract class AggregateFcts
|
|||
return ((LongType) returnType()).decompose(count);
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (arguments.get(0) == null)
|
||||
return;
|
||||
|
||||
count++;
|
||||
|
|
@ -980,14 +994,14 @@ public abstract class AggregateFcts
|
|||
return LongType.instance.decompose(sum);
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
Number number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
Number number = LongType.instance.compose(value);
|
||||
sum += number.longValue();
|
||||
}
|
||||
}
|
||||
|
|
@ -1004,13 +1018,6 @@ public abstract class AggregateFcts
|
|||
private BigInteger bigSum = null;
|
||||
private boolean overflow = false;
|
||||
|
||||
private final AbstractType<?> numberType;
|
||||
|
||||
public AvgAggregate(AbstractType<?> type)
|
||||
{
|
||||
this.numberType = type;
|
||||
}
|
||||
|
||||
public void reset()
|
||||
{
|
||||
count = 0;
|
||||
|
|
@ -1031,28 +1038,30 @@ public abstract class AggregateFcts
|
|||
}
|
||||
}
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values)
|
||||
@Override
|
||||
public void addInput(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = values.get(0);
|
||||
Number number = arguments.get(0);
|
||||
|
||||
if (value == null)
|
||||
if (number == null)
|
||||
return;
|
||||
|
||||
count++;
|
||||
long number = ((Number) numberType.compose(value)).longValue();
|
||||
long l = number.longValue();
|
||||
|
||||
if (overflow)
|
||||
{
|
||||
bigSum = bigSum.add(BigInteger.valueOf(number));
|
||||
bigSum = bigSum.add(BigInteger.valueOf(l));
|
||||
}
|
||||
else
|
||||
{
|
||||
long prev = sum;
|
||||
sum += number;
|
||||
sum += l;
|
||||
|
||||
if (((prev ^ sum) & (number ^ sum)) < 0)
|
||||
if (((prev ^ sum) & (l ^ sum)) < 0)
|
||||
{
|
||||
overflow = true;
|
||||
bigSum = BigInteger.valueOf(prev).add(BigInteger.valueOf(number));
|
||||
bigSum = BigInteger.valueOf(prev).add(BigInteger.valueOf(l));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package org.apache.cassandra.cql3.functions;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
|
@ -42,10 +41,10 @@ public interface AggregateFunction extends Function
|
|||
{
|
||||
/**
|
||||
* Adds the specified input to this aggregate.
|
||||
* @param protocolVersion native protocol version
|
||||
* @param values the values to add to the aggregate.
|
||||
*
|
||||
* @param arguments the values to add to the aggregate.
|
||||
*/
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values) throws InvalidRequestException;
|
||||
public void addInput(Arguments arguments) throws InvalidRequestException;
|
||||
|
||||
/**
|
||||
* Computes and returns the aggregate current value.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
* Utility used to deserialize function arguments.
|
||||
*/
|
||||
public interface ArgumentDeserializer
|
||||
{
|
||||
/**
|
||||
* An {@link ArgumentDeserializer} that do not deserialize data.
|
||||
*/
|
||||
ArgumentDeserializer NOOP_DESERIALIZER = (protocolVersion, buffer) -> buffer;
|
||||
|
||||
/**
|
||||
* Deserializes the specified function argument.
|
||||
*
|
||||
* @param protocolVersion the protocol version
|
||||
* @param buffer the serialized argument
|
||||
* @return the deserialized argument
|
||||
*/
|
||||
Object deserialize(ProtocolVersion protocolVersion, ByteBuffer buffer);
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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.nio.ByteBuffer;
|
||||
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
* The input arguments to a function.
|
||||
* <p>The class can be reused for calling the same function multiple times.</p>
|
||||
*/
|
||||
public interface Arguments
|
||||
{
|
||||
/**
|
||||
* Sets the specified value to the arguments
|
||||
*
|
||||
* @param i the argument position
|
||||
* @param buffer the serialized argument
|
||||
*/
|
||||
void set(int i, ByteBuffer buffer);
|
||||
|
||||
/**
|
||||
* Checks if at least one of the arguments is null.
|
||||
*
|
||||
* @return {@code true} if at least one of the arguments is null, {@code false} otherwise.
|
||||
*/
|
||||
boolean containsNulls();
|
||||
|
||||
/**
|
||||
* Returns the specified argument
|
||||
*
|
||||
* @param i the argument index
|
||||
* @return the specified argument
|
||||
*/
|
||||
<T> T get(int i);
|
||||
|
||||
/**
|
||||
* Returns the protocol version
|
||||
*
|
||||
* @return the protocol version
|
||||
*/
|
||||
ProtocolVersion getProtocolVersion();
|
||||
|
||||
/**
|
||||
* Returns the specified argument as a {@code boolean}.
|
||||
*
|
||||
* @param i the argument index
|
||||
* @return the specified argument as a {@code boolean}
|
||||
*/
|
||||
default boolean getAsBoolean(int i)
|
||||
{
|
||||
return this.<Boolean>get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified argument as a {@code byte}.
|
||||
*
|
||||
* @param i the argument index
|
||||
* @return the specified argument as a {@code byte}
|
||||
*/
|
||||
default byte getAsByte(int i)
|
||||
{
|
||||
return this.<Number>get(i).byteValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified argument as a {@code short}.
|
||||
*
|
||||
* @param i the argument index
|
||||
* @return the specified argument as a {@code short}
|
||||
*/
|
||||
default short getAsShort(int i)
|
||||
{
|
||||
return this.<Number>get(i).shortValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified argument as a {@code int}.
|
||||
*
|
||||
* @param i the argument index
|
||||
* @return the specified argument as a {@code int}
|
||||
*/
|
||||
default int getAsInt(int i)
|
||||
{
|
||||
return this.<Number>get(i).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified argument as a {@code long}.
|
||||
*
|
||||
* @param i the argument index
|
||||
* @return the specified argument as a {@code long}
|
||||
*/
|
||||
default long getAsLong(int i)
|
||||
{
|
||||
return this.<Number>get(i).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified argument as a {@code float}.
|
||||
*
|
||||
* @param i the argument index
|
||||
* @return the specified argument as a {@code float}
|
||||
*/
|
||||
default float getAsFloat(int i)
|
||||
{
|
||||
return this.<Number>get(i).floatValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified argument as a {@code double}.
|
||||
*
|
||||
* @param i the argument index
|
||||
* @return the specified argument as a {@code double}
|
||||
*/
|
||||
default double getAsDouble(int i)
|
||||
{
|
||||
return this.<Number>get(i).doubleValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current number of arguments.
|
||||
*
|
||||
* @return the current number of arguments.
|
||||
*/
|
||||
int size();
|
||||
}
|
||||
|
|
@ -18,9 +18,9 @@
|
|||
package org.apache.cassandra.cql3.functions;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.BytesType;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
|
|
@ -41,9 +41,23 @@ public abstract class BytesConversionFcts
|
|||
}
|
||||
}
|
||||
|
||||
private static abstract class BytesConversionFct extends NativeScalarFunction
|
||||
{
|
||||
public BytesConversionFct(String name, AbstractType<?> returnType, AbstractType<?>... argsType)
|
||||
{
|
||||
super(name, returnType, argsType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return FunctionArguments.newNoopInstance(version, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Most of the X_as_blob and blob_as_X functions are basically no-op since everything is
|
||||
// bytes internally. They only "trick" the type system.
|
||||
public static class ToBlobFunction extends NativeScalarFunction
|
||||
public static class ToBlobFunction extends BytesConversionFct
|
||||
{
|
||||
private final CQL3Type fromType;
|
||||
|
||||
|
|
@ -61,9 +75,9 @@ public abstract class BytesConversionFcts
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
return parameters.get(0);
|
||||
return arguments.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -73,7 +87,7 @@ public abstract class BytesConversionFcts
|
|||
}
|
||||
}
|
||||
|
||||
public static class FromBlobFunction extends NativeScalarFunction
|
||||
public static class FromBlobFunction extends BytesConversionFct
|
||||
{
|
||||
private final CQL3Type toType;
|
||||
|
||||
|
|
@ -91,9 +105,9 @@ public abstract class BytesConversionFcts
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
ByteBuffer val = parameters.get(0);
|
||||
ByteBuffer val = arguments.get(0);
|
||||
|
||||
if (val != null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -263,13 +263,13 @@ public final class CastFcts
|
|||
return new JavaFunctionWrapper<>(inputType(), outputType(), converter, true);
|
||||
}
|
||||
|
||||
public final ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
@Override
|
||||
public final ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
ByteBuffer bb = parameters.get(0);
|
||||
if (bb == null)
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
return outputType().decompose(converter.apply(compose(bb)));
|
||||
return outputType().decompose(converter.apply(arguments.get(0)));
|
||||
}
|
||||
|
||||
protected I compose(ByteBuffer bb)
|
||||
|
|
@ -350,9 +350,10 @@ public final class CastFcts
|
|||
return new CassandraFunctionWrapper<>(inputType(), outputType(), delegate, true);
|
||||
}
|
||||
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
return delegate.execute(protocolVersion, parameters);
|
||||
return delegate.execute(arguments);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -381,13 +382,25 @@ public final class CastFcts
|
|||
return new CastAsTextFunction<>(inputType(), outputType(), true);
|
||||
}
|
||||
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
@Override
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
ByteBuffer bb = parameters.get(0);
|
||||
if (bb == null)
|
||||
return new FunctionArguments(version, (protocolVersion, buffer) -> {
|
||||
AbstractType<?> argType = argTypes.get(0);
|
||||
if (buffer == null || (!buffer.hasRemaining() && argType.isEmptyValueMeaningless()))
|
||||
return null;
|
||||
|
||||
return argType.getSerializer().toCQLLiteral(buffer);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
return outputType().decompose(inputType().getSerializer().toCQLLiteral(bb));
|
||||
return outputType().decompose(arguments.get(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@
|
|||
package org.apache.cassandra.cql3.functions;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
|
@ -127,13 +126,12 @@ public class CollectionFcts
|
|||
return new NativeScalarFunction(name, outputType, inputType)
|
||||
{
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = parameters.get(0);
|
||||
if (value == null)
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
Map<K, V> map = inputType.compose(value);
|
||||
Map<K, V> map = arguments.get(0);
|
||||
Set<K> keys = map.keySet();
|
||||
return outputType.decompose(keys);
|
||||
}
|
||||
|
|
@ -156,13 +154,12 @@ public class CollectionFcts
|
|||
return new NativeScalarFunction(name, outputType, inputType)
|
||||
{
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = parameters.get(0);
|
||||
if (value == null)
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
Map<K, V> map = inputType.compose(value);
|
||||
Map<K, V> map = arguments.get(0);
|
||||
List<V> values = ImmutableList.copyOf(map.values());
|
||||
return outputType.decompose(values);
|
||||
}
|
||||
|
|
@ -182,13 +179,19 @@ public class CollectionFcts
|
|||
return new NativeScalarFunction(name, Int32Type.instance, inputType)
|
||||
{
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
ByteBuffer value = parameters.get(0);
|
||||
if (value == null)
|
||||
return FunctionArguments.newNoopInstance(version, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
int size = inputType.size(value);
|
||||
|
||||
int size = inputType.size(arguments.get(0));
|
||||
return Int32Type.instance.decompose(size);
|
||||
}
|
||||
};
|
||||
|
|
@ -356,15 +359,26 @@ public class CollectionFcts
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion version, List<ByteBuffer> parameters)
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
ByteBuffer value = parameters.get(0);
|
||||
if (value == null)
|
||||
return FunctionArguments.newNoopInstance(version, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
Arguments args = aggregateFunction.newArguments(arguments.getProtocolVersion());
|
||||
AggregateFunction.Aggregate aggregate = aggregateFunction.newAggregate();
|
||||
inputType.forEach(value, element -> aggregate.addInput(version, Collections.singletonList(element)));
|
||||
return aggregate.compute(version);
|
||||
|
||||
inputType.forEach(arguments.get(0), element -> {
|
||||
args.set(0, element);
|
||||
aggregate.addInput(args);
|
||||
});
|
||||
|
||||
return aggregate.compute(arguments.getProtocolVersion());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@ import org.apache.cassandra.db.marshal.*;
|
|||
import org.apache.cassandra.exceptions.FunctionExecutionException;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.utils.JsonUtils;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
|
@ -54,20 +53,23 @@ public class FromJsonFct extends NativeScalarFunction
|
|||
super(name.name, returnType, UTF8Type.instance);
|
||||
}
|
||||
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
assert parameters.size() == 1 : format("Unexpectedly got %d arguments for %s()", parameters.size(), name.name);
|
||||
ByteBuffer argument = parameters.get(0);
|
||||
if (argument == null)
|
||||
assert arguments.size() == 1 : format("Unexpectedly got %d arguments for %s()", arguments.size(), name.name);
|
||||
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
String jsonArg = UTF8Type.instance.getSerializer().deserialize(argument);
|
||||
String jsonArg = arguments.get(0);
|
||||
try
|
||||
{
|
||||
Object object = JsonUtils.JSON_OBJECT_MAPPER.readValue(jsonArg, Object.class);
|
||||
if (object == null)
|
||||
return null;
|
||||
return returnType.fromJSONObject(object).bindAndGet(QueryOptions.forProtocolVersion(protocolVersion));
|
||||
|
||||
return returnType.fromJSONObject(object)
|
||||
.bindAndGet(QueryOptions.forProtocolVersion(arguments.getProtocolVersion()));
|
||||
}
|
||||
catch (IOException exc)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.util.Optional;
|
|||
import org.apache.cassandra.cql3.AssignmentTestable;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.schema.Difference;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.github.jamm.Unmetered;
|
||||
|
||||
@Unmetered
|
||||
|
|
@ -72,6 +73,14 @@ public interface Function extends AssignmentTestable
|
|||
*/
|
||||
public String columnName(List<String> columnNames);
|
||||
|
||||
/**
|
||||
* Creates some new input arguments for this function.
|
||||
*
|
||||
* @param version the protocol version
|
||||
* @return some new input arguments for this function
|
||||
*/
|
||||
Arguments newArguments(ProtocolVersion version);
|
||||
|
||||
public default Optional<Difference> compare(Function other)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* 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.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
* Default {@link Arguments} implementation.
|
||||
*/
|
||||
public final class FunctionArguments implements Arguments
|
||||
{
|
||||
/**
|
||||
* An empty {@link FunctionArguments} for the current protocol.
|
||||
*/
|
||||
private static final FunctionArguments EMPTY = new FunctionArguments(ProtocolVersion.CURRENT);
|
||||
|
||||
/**
|
||||
* The deserializer used to deserialize the columns.
|
||||
*/
|
||||
private final ArgumentDeserializer[] deserializers;
|
||||
|
||||
/**
|
||||
* The protocol version.
|
||||
*/
|
||||
private final ProtocolVersion version;
|
||||
|
||||
/**
|
||||
* The deserialized arguments.
|
||||
*/
|
||||
private final Object[] arguments;
|
||||
|
||||
/**
|
||||
* Creates a new {@link FunctionArguments} for the specified types.
|
||||
*
|
||||
* @param version the protocol version
|
||||
* @param argTypes the argument types
|
||||
* @return a new {@link FunctionArguments} for the specified types.
|
||||
*/
|
||||
public static FunctionArguments newInstanceForUdf(ProtocolVersion version, List<UDFDataType> argTypes)
|
||||
{
|
||||
int size = argTypes.size();
|
||||
|
||||
if (size == 0)
|
||||
return emptyInstance(version);
|
||||
|
||||
ArgumentDeserializer[] deserializers = new ArgumentDeserializer[size];
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
deserializers[i] = argTypes.get(i).getArgumentDeserializer();
|
||||
|
||||
return new FunctionArguments(version, deserializers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolVersion getProtocolVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link FunctionArguments} that does not deserialize the arguments.
|
||||
*
|
||||
* @param version the protocol version
|
||||
* @param numberOfArguments the number of argument
|
||||
* @return a new {@link FunctionArguments} for the specified types.
|
||||
*/
|
||||
public static FunctionArguments newNoopInstance(ProtocolVersion version, int numberOfArguments)
|
||||
{
|
||||
ArgumentDeserializer[] deserializers = new ArgumentDeserializer[numberOfArguments];
|
||||
Arrays.fill(deserializers, ArgumentDeserializer.NOOP_DESERIALIZER);
|
||||
|
||||
return new FunctionArguments(version, deserializers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty {@link FunctionArguments}.
|
||||
*
|
||||
* @param version the protocol version
|
||||
* @return an empty {@link FunctionArguments}
|
||||
*/
|
||||
public static FunctionArguments emptyInstance(ProtocolVersion version)
|
||||
{
|
||||
if (version == ProtocolVersion.CURRENT)
|
||||
return EMPTY;
|
||||
|
||||
return new FunctionArguments(version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link FunctionArguments} for a native function.
|
||||
* <p>Native functions can use different {@link ArgumentDeserializer} to avoid instanciating primitive wrappers.</p>
|
||||
*
|
||||
* @param version the protocol version
|
||||
* @param argTypes the argument types
|
||||
* @return a new {@link FunctionArguments} for the specified types.
|
||||
*/
|
||||
public static FunctionArguments newInstanceForNativeFunction(ProtocolVersion version, List<AbstractType<?>> argTypes)
|
||||
{
|
||||
int size = argTypes.size();
|
||||
|
||||
if (size == 0)
|
||||
return emptyInstance(version);
|
||||
|
||||
ArgumentDeserializer[] deserializers = new ArgumentDeserializer[size];
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
deserializers[i] = argTypes.get(i).getArgumentDeserializer();
|
||||
|
||||
return new FunctionArguments(version, deserializers);
|
||||
}
|
||||
|
||||
public FunctionArguments(ProtocolVersion version, ArgumentDeserializer... deserializers)
|
||||
{
|
||||
this.version = version;
|
||||
this.deserializers = deserializers;
|
||||
this.arguments = new Object[deserializers.length];
|
||||
}
|
||||
|
||||
public void set(int i, ByteBuffer buffer)
|
||||
{
|
||||
arguments[i] = deserializers[i].deserialize(version, buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsNulls()
|
||||
{
|
||||
for (int i = 0; i < arguments.length; i++)
|
||||
{
|
||||
if (arguments[i] == null)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> T get(int i)
|
||||
{
|
||||
return (T) arguments[i];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return arguments.length;
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,6 @@ import org.apache.cassandra.cql3.statements.RequestValidations;
|
|||
import org.apache.cassandra.db.marshal.*;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest;
|
||||
|
|
@ -57,31 +56,35 @@ public class FunctionCall extends Term.NonTerminal
|
|||
t.collectMarkerSpecification(boundNames);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Term.Terminal bind(QueryOptions options) throws InvalidRequestException
|
||||
{
|
||||
return makeTerminal(fun, bindAndGet(options), options.getProtocolVersion());
|
||||
return makeTerminal(fun, bindAndGet(options));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer bindAndGet(QueryOptions options) throws InvalidRequestException
|
||||
{
|
||||
List<ByteBuffer> buffers = new ArrayList<>(terms.size());
|
||||
for (Term t : terms)
|
||||
Arguments arguments = fun.newArguments(options.getProtocolVersion());
|
||||
for (int i = 0, m = terms.size(); i < m; i++)
|
||||
{
|
||||
ByteBuffer functionArg = t.bindAndGet(options);
|
||||
RequestValidations.checkBindValueSet(functionArg, "Invalid unset value for argument in call to function %s", fun.name().name);
|
||||
buffers.add(functionArg);
|
||||
Term t = terms.get(i);
|
||||
ByteBuffer argument = t.bindAndGet(options);
|
||||
RequestValidations.checkBindValueSet(argument, "Invalid unset value for argument in call to function %s", fun.name().name);
|
||||
arguments.set(i, argument);
|
||||
}
|
||||
return executeInternal(options.getProtocolVersion(), fun, buffers);
|
||||
return executeInternal(fun, arguments);
|
||||
}
|
||||
|
||||
private static ByteBuffer executeInternal(ProtocolVersion protocolVersion, ScalarFunction fun, List<ByteBuffer> params) throws InvalidRequestException
|
||||
private static ByteBuffer executeInternal(ScalarFunction fun, Arguments arguments) throws InvalidRequestException
|
||||
{
|
||||
ByteBuffer result = fun.execute(protocolVersion, params);
|
||||
ByteBuffer result = fun.execute(arguments);
|
||||
try
|
||||
{
|
||||
// Check the method didn't lied on it's declared return type
|
||||
// Check the method didn't lie on it's declared return type
|
||||
if (result != null)
|
||||
fun.returnType().validate(result);
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (MarshalException e)
|
||||
|
|
@ -101,7 +104,7 @@ public class FunctionCall extends Term.NonTerminal
|
|||
return false;
|
||||
}
|
||||
|
||||
private static Term.Terminal makeTerminal(Function fun, ByteBuffer result, ProtocolVersion version) throws InvalidRequestException
|
||||
private static Term.Terminal makeTerminal(Function fun, ByteBuffer result) throws InvalidRequestException
|
||||
{
|
||||
if (result == null)
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -37,19 +37,16 @@ import java.util.concurrent.ThreadLocalRandom;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.io.ByteStreams;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.concurrent.NamedThreadFactory;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
import org.apache.cassandra.security.SecurityThreadGroup;
|
||||
import org.apache.cassandra.security.ThreadAwareSecurityManager;
|
||||
|
|
@ -68,8 +65,6 @@ public final class JavaBasedUDFunction extends UDFunction
|
|||
{
|
||||
private static final String BASE_PACKAGE = "org.apache.cassandra.cql3.udf.gen";
|
||||
|
||||
private static final Pattern JAVA_LANG_PREFIX = Pattern.compile("\\bjava\\.lang\\.");
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(JavaBasedUDFunction.class);
|
||||
|
||||
private static final AtomicInteger classSequence = new AtomicInteger();
|
||||
|
|
@ -192,13 +187,7 @@ public final class JavaBasedUDFunction extends UDFunction
|
|||
JavaBasedUDFunction(FunctionName name, List<ColumnIdentifier> argNames, List<AbstractType<?>> argTypes,
|
||||
AbstractType<?> returnType, boolean calledOnNullInput, String body)
|
||||
{
|
||||
super(name, argNames, argTypes, UDHelper.driverTypes(argTypes),
|
||||
returnType, UDHelper.driverType(returnType), calledOnNullInput, "java", body);
|
||||
|
||||
// javaParamTypes is just the Java representation for argTypes resp. argDataTypes
|
||||
TypeToken<?>[] javaParamTypes = UDHelper.typeTokens(argCodecs, calledOnNullInput);
|
||||
// javaReturnType is just the Java representation for returnType resp. returnTypeCodec
|
||||
TypeToken<?> javaReturnType = returnCodec.getJavaType();
|
||||
super(name, argNames, argTypes, returnType, calledOnNullInput, "java", body);
|
||||
|
||||
// put each UDF in a separate package to prevent cross-UDF code access
|
||||
String pkgName = BASE_PACKAGE + '.' + generateClassName(name, 'p');
|
||||
|
|
@ -228,16 +217,16 @@ public final class JavaBasedUDFunction extends UDFunction
|
|||
s = patternJavaDriver.matcher(body).replaceAll("org.apache.cassandra.cql3.functions.types.");
|
||||
break;
|
||||
case "arguments":
|
||||
s = generateArguments(javaParamTypes, argNames, false);
|
||||
s = generateArguments(argumentTypes, argNames, false);
|
||||
break;
|
||||
case "arguments_aggregate":
|
||||
s = generateArguments(javaParamTypes, argNames, true);
|
||||
s = generateArguments(argumentTypes, argNames, true);
|
||||
break;
|
||||
case "argument_list":
|
||||
s = generateArgumentList(javaParamTypes, argNames);
|
||||
s = generateArgumentList(argumentTypes, argNames);
|
||||
break;
|
||||
case "return_type":
|
||||
s = javaSourceName(javaReturnType);
|
||||
s = resultType.getJavaTypeName();
|
||||
break;
|
||||
case "execute_internal_name":
|
||||
s = executeInternalName;
|
||||
|
|
@ -338,9 +327,9 @@ public final class JavaBasedUDFunction extends UDFunction
|
|||
if (nonSyntheticMethodCount != 3 || cls.getDeclaredConstructors().length != 1)
|
||||
throw new InvalidRequestException("Check your source to not define additional Java methods or constructors");
|
||||
MethodType methodType = MethodType.methodType(void.class)
|
||||
.appendParameterTypes(TypeCodec.class, TypeCodec[].class, UDFContext.class);
|
||||
.appendParameterTypes(UDFDataType.class, UDFContext.class);
|
||||
MethodHandle ctor = MethodHandles.lookup().findConstructor(cls, methodType);
|
||||
this.javaUDF = (JavaUDF) ctor.invokeWithArguments(returnCodec, argCodecs, udfContext);
|
||||
this.javaUDF = (JavaUDF) ctor.invokeWithArguments(resultType, udfContext);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -364,19 +353,22 @@ public final class JavaBasedUDFunction extends UDFunction
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ExecutorService executor()
|
||||
{
|
||||
return executor;
|
||||
}
|
||||
|
||||
protected ByteBuffer executeUserDefined(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeUserDefined(Arguments arguments)
|
||||
{
|
||||
return javaUDF.executeImpl(protocolVersion, params);
|
||||
return javaUDF.executeImpl(arguments);
|
||||
}
|
||||
|
||||
protected Object executeAggregateUserDefined(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateUserDefined(Object state, Arguments arguments)
|
||||
{
|
||||
return javaUDF.executeAggregateImpl(protocolVersion, firstParam, params);
|
||||
return javaUDF.executeAggregateImpl(state, arguments);
|
||||
}
|
||||
|
||||
private static int countNewlines(StringBuilder javaSource)
|
||||
|
|
@ -409,22 +401,15 @@ public final class JavaBasedUDFunction extends UDFunction
|
|||
return sb.toString();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public static String javaSourceName(TypeToken<?> type)
|
||||
{
|
||||
String n = type.toString();
|
||||
return JAVA_LANG_PREFIX.matcher(n).replaceAll("");
|
||||
}
|
||||
|
||||
private static String generateArgumentList(TypeToken<?>[] paramTypes, List<ColumnIdentifier> argNames)
|
||||
private static String generateArgumentList(List<UDFDataType> argTypes, List<ColumnIdentifier> argNames)
|
||||
{
|
||||
// initial builder size can just be a guess (prevent temp object allocations)
|
||||
StringBuilder code = new StringBuilder(32 * paramTypes.length);
|
||||
for (int i = 0; i < paramTypes.length; i++)
|
||||
StringBuilder code = new StringBuilder(32 * argTypes.size());
|
||||
for (int i = 0; i < argTypes.size(); i++)
|
||||
{
|
||||
if (i > 0)
|
||||
code.append(", ");
|
||||
code.append(javaSourceName(paramTypes[i]))
|
||||
code.append(argTypes.get(i).getJavaTypeName())
|
||||
.append(' ')
|
||||
.append(argNames.get(i));
|
||||
}
|
||||
|
|
@ -450,36 +435,56 @@ public final class JavaBasedUDFunction extends UDFunction
|
|||
* {@code firstParam, (double) super.compose_double(protocolVersion, 1, params.get(1))}
|
||||
* </p>
|
||||
*/
|
||||
private static String generateArguments(TypeToken<?>[] paramTypes, List<ColumnIdentifier> argNames, boolean forAggregate)
|
||||
private static String generateArguments(List<UDFDataType> argTypes, List<ColumnIdentifier> argNames, boolean forAggregate)
|
||||
{
|
||||
StringBuilder code = new StringBuilder(64 * paramTypes.length);
|
||||
for (int i = 0; i < paramTypes.length; i++)
|
||||
int size = argTypes.size();
|
||||
StringBuilder code = new StringBuilder(64 * size);
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
UDFDataType argType = argTypes.get(i);
|
||||
if (i > 0)
|
||||
// add separator, if not the first argument
|
||||
code.append(",\n");
|
||||
|
||||
// add comment only if trace is enabled
|
||||
if (logger.isTraceEnabled())
|
||||
code.append(" /* parameter '").append(argNames.get(i)).append("' */\n");
|
||||
code.append(" /* argument '").append(argNames.get(i)).append("' */\n");
|
||||
|
||||
|
||||
code.append(" ");
|
||||
|
||||
// cast to Java type
|
||||
code.append(" (").append(javaSourceName(paramTypes[i])).append(") ");
|
||||
code.append('(').append(argType.getJavaTypeName()).append(") ");
|
||||
|
||||
if (forAggregate && i == 0)
|
||||
{
|
||||
// special case for aggregations where the state variable (1st arg to state + final function and
|
||||
// return value from state function) is not re-serialized
|
||||
code.append("firstParam");
|
||||
code.append("state");
|
||||
}
|
||||
else
|
||||
// generate object representation of input parameter (call UDFunction.compose)
|
||||
code.append(composeMethod(paramTypes[i])).append("(protocolVersion, ").append(i).append(", params.get(").append(forAggregate ? i - 1 : i).append("))");
|
||||
{
|
||||
// generate object representation of input parameter
|
||||
code.append("arguments.");
|
||||
appendGetMethodName(code, argType).append('(').append(forAggregate ? i - 1 : i).append(')');
|
||||
}
|
||||
}
|
||||
return code.toString();
|
||||
}
|
||||
|
||||
private static String composeMethod(TypeToken<?> type)
|
||||
/**
|
||||
* Appends the get method name for the specified type to avoid boxing.
|
||||
* @param code the builder to append to
|
||||
* @param type the data type
|
||||
* @return the builder
|
||||
*/
|
||||
private static StringBuilder appendGetMethodName(StringBuilder code, UDFDataType type)
|
||||
{
|
||||
return (type.isPrimitive()) ? ("super.compose_" + type.getRawType().getName()) : "super.compose";
|
||||
code.append("get");
|
||||
if (!type.isPrimitive())
|
||||
return code;
|
||||
|
||||
return code.append("As").append(StringUtils.capitalize(type.getJavaTypeName()));
|
||||
}
|
||||
|
||||
// Java source UDFs are a very simple compilation task, which allows us to let one class implement
|
||||
|
|
@ -696,4 +701,5 @@ public final class JavaBasedUDFunction extends UDFunction
|
|||
{
|
||||
return ThreadAwareSecurityManager.noPermissions;
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,7 @@
|
|||
package org.apache.cassandra.cql3.functions;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
|
|
@ -32,78 +30,62 @@ import org.apache.cassandra.transport.ProtocolVersion;
|
|||
*/
|
||||
public abstract class JavaUDF
|
||||
{
|
||||
private final TypeCodec<Object> returnCodec;
|
||||
private final TypeCodec<Object>[] argCodecs;
|
||||
|
||||
private final UDFDataType returnType;
|
||||
protected final UDFContext udfContext;
|
||||
|
||||
protected JavaUDF(TypeCodec<Object> returnCodec, TypeCodec<Object>[] argCodecs, UDFContext udfContext)
|
||||
protected JavaUDF(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
this.returnCodec = returnCodec;
|
||||
this.argCodecs = argCodecs;
|
||||
this.returnType = returnType;
|
||||
this.udfContext = udfContext;
|
||||
}
|
||||
|
||||
protected abstract ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params);
|
||||
protected abstract ByteBuffer executeImpl(Arguments arguments);
|
||||
|
||||
protected abstract Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params);
|
||||
protected abstract Object executeAggregateImpl(Object state, Arguments arguments);
|
||||
|
||||
protected Object compose(ProtocolVersion protocolVersion, int argIndex, ByteBuffer value)
|
||||
//~///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// The decompose method is overloaded to avoid boxing of the result if it is a primitive type.
|
||||
//~///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// do not remove - used by generated Java UDFs
|
||||
protected final ByteBuffer decompose(ProtocolVersion protocolVersion, Object value)
|
||||
{
|
||||
return UDFunction.compose(argCodecs, protocolVersion, argIndex, value);
|
||||
}
|
||||
|
||||
protected ByteBuffer decompose(ProtocolVersion protocolVersion, Object value)
|
||||
{
|
||||
return UDFunction.decompose(returnCodec, protocolVersion, value);
|
||||
return returnType.decompose(protocolVersion, value);
|
||||
}
|
||||
|
||||
// do not remove - used by generated Java UDFs
|
||||
protected float compose_float(ProtocolVersion protocolVersion, int argIndex, ByteBuffer value)
|
||||
protected final ByteBuffer decompose(ProtocolVersion protocolVersion, byte value)
|
||||
{
|
||||
assert value != null && value.remaining() > 0;
|
||||
return (float) UDHelper.deserialize(TypeCodec.cfloat(), protocolVersion, value);
|
||||
return returnType.decompose(protocolVersion, value);
|
||||
}
|
||||
|
||||
// do not remove - used by generated Java UDFs
|
||||
protected double compose_double(ProtocolVersion protocolVersion, int argIndex, ByteBuffer value)
|
||||
protected final ByteBuffer decompose(ProtocolVersion protocolVersion, short value)
|
||||
{
|
||||
assert value != null && value.remaining() > 0;
|
||||
return (double) UDHelper.deserialize(TypeCodec.cdouble(), protocolVersion, value);
|
||||
return returnType.decompose(protocolVersion, value);
|
||||
}
|
||||
|
||||
// do not remove - used by generated Java UDFs
|
||||
protected byte compose_byte(ProtocolVersion protocolVersion, int argIndex, ByteBuffer value)
|
||||
protected final ByteBuffer decompose(ProtocolVersion protocolVersion, int value)
|
||||
{
|
||||
assert value != null && value.remaining() > 0;
|
||||
return (byte) UDHelper.deserialize(TypeCodec.tinyInt(), protocolVersion, value);
|
||||
return returnType.decompose(protocolVersion, value);
|
||||
}
|
||||
|
||||
// do not remove - used by generated Java UDFs
|
||||
protected short compose_short(ProtocolVersion protocolVersion, int argIndex, ByteBuffer value)
|
||||
protected final ByteBuffer decompose(ProtocolVersion protocolVersion, long value)
|
||||
{
|
||||
assert value != null && value.remaining() > 0;
|
||||
return (short) UDHelper.deserialize(TypeCodec.smallInt(), protocolVersion, value);
|
||||
return returnType.decompose(protocolVersion, value);
|
||||
}
|
||||
|
||||
// do not remove - used by generated Java UDFs
|
||||
protected int compose_int(ProtocolVersion protocolVersion, int argIndex, ByteBuffer value)
|
||||
protected final ByteBuffer decompose(ProtocolVersion protocolVersion, float value)
|
||||
{
|
||||
assert value != null && value.remaining() > 0;
|
||||
return (int) UDHelper.deserialize(TypeCodec.cint(), protocolVersion, value);
|
||||
return returnType.decompose(protocolVersion, value);
|
||||
}
|
||||
|
||||
// do not remove - used by generated Java UDFs
|
||||
protected long compose_long(ProtocolVersion protocolVersion, int argIndex, ByteBuffer value)
|
||||
protected final ByteBuffer decompose(ProtocolVersion protocolVersion, double value)
|
||||
{
|
||||
assert value != null && value.remaining() > 0;
|
||||
return (long) UDHelper.deserialize(TypeCodec.bigint(), protocolVersion, value);
|
||||
}
|
||||
|
||||
// do not remove - used by generated Java UDFs
|
||||
protected boolean compose_boolean(ProtocolVersion protocolVersion, int argIndex, ByteBuffer value)
|
||||
{
|
||||
assert value != null && value.remaining() > 0;
|
||||
return (boolean) UDHelper.deserialize(TypeCodec.cboolean(), protocolVersion, value);
|
||||
return returnType.decompose(protocolVersion, value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,10 +21,11 @@ package org.apache.cassandra.cql3.functions;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.apache.cassandra.db.marshal.*;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
|
||||
public final class MathFcts
|
||||
{
|
||||
|
|
@ -47,83 +48,49 @@ public final class MathFcts
|
|||
log10Fct(t),
|
||||
roundFct(t)))
|
||||
.flatMap(Collection::stream)
|
||||
.forEach(f -> functions.add(f));
|
||||
.forEach(functions::add);
|
||||
}
|
||||
|
||||
public static NativeFunction absFct(final NumberType<?> type)
|
||||
{
|
||||
return new NativeScalarFunction("abs", type, type)
|
||||
{
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
{
|
||||
ByteBuffer bb = parameters.get(0);
|
||||
if (bb == null)
|
||||
return null;
|
||||
return type.abs(bb);
|
||||
}
|
||||
};
|
||||
return mathFct("abs", type, NumberType::abs);
|
||||
}
|
||||
|
||||
public static NativeFunction expFct(final NumberType<?> type)
|
||||
{
|
||||
return new NativeScalarFunction("exp", type, type)
|
||||
{
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
{
|
||||
ByteBuffer bb = parameters.get(0);
|
||||
if (bb == null)
|
||||
return null;
|
||||
return type.exp(bb);
|
||||
}
|
||||
};
|
||||
return mathFct("exp", type, NumberType::exp);
|
||||
}
|
||||
|
||||
public static NativeFunction logFct(final NumberType<?> type)
|
||||
{
|
||||
return new NativeScalarFunction("log", type, type)
|
||||
{
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
{
|
||||
ByteBuffer bb = parameters.get(0);
|
||||
if (bb == null)
|
||||
return null;
|
||||
return type.log(bb);
|
||||
|
||||
}
|
||||
};
|
||||
return mathFct("log", type, NumberType::log);
|
||||
}
|
||||
|
||||
public static NativeFunction log10Fct(final NumberType<?> type)
|
||||
{
|
||||
return new NativeScalarFunction("log10", type, type)
|
||||
{
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
{
|
||||
ByteBuffer bb = parameters.get(0);
|
||||
if (bb == null)
|
||||
return null;
|
||||
return type.log10(bb);
|
||||
|
||||
}
|
||||
};
|
||||
return mathFct("log10", type, NumberType::log10);
|
||||
}
|
||||
|
||||
public static NativeFunction roundFct(final NumberType<?> type)
|
||||
{
|
||||
return new NativeScalarFunction("round", type, type)
|
||||
return mathFct("round", type, NumberType::round);
|
||||
}
|
||||
|
||||
private static NativeFunction mathFct(String name,
|
||||
NumberType<?> type,
|
||||
BiFunction<NumberType<?>, Number, ByteBuffer> f)
|
||||
{
|
||||
return new NativeScalarFunction(name, type, type)
|
||||
{
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
public ByteBuffer execute(Arguments arguments) throws InvalidRequestException
|
||||
{
|
||||
ByteBuffer bb = parameters.get(0);
|
||||
if (bb == null)
|
||||
return null;
|
||||
return type.round(bb);
|
||||
Number number = arguments.get(0);
|
||||
|
||||
if (number == null)
|
||||
return null;
|
||||
|
||||
return f.apply(type, number);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.Arrays;
|
|||
import javax.annotation.Nullable;
|
||||
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
* Base class for our native/hardcoded functions.
|
||||
|
|
@ -59,4 +60,11 @@ public abstract class NativeFunction extends AbstractFunction
|
|||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return FunctionArguments.newInstanceForNativeFunction(version, argTypes);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,10 @@ package org.apache.cassandra.cql3.functions;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.Duration;
|
||||
import org.apache.cassandra.schema.SchemaConstants;
|
||||
import org.apache.cassandra.db.marshal.*;
|
||||
import org.apache.cassandra.exceptions.OperationExecutionException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
* Operation functions (Mathematics).
|
||||
|
|
@ -31,87 +31,59 @@ import org.apache.cassandra.transport.ProtocolVersion;
|
|||
*/
|
||||
public final class OperationFcts
|
||||
{
|
||||
private static enum OPERATION
|
||||
private enum OPERATION
|
||||
{
|
||||
ADDITION('+', "_add")
|
||||
{
|
||||
protected ByteBuffer executeOnNumerics(NumberType<?> resultType,
|
||||
NumberType<?> leftType,
|
||||
ByteBuffer left,
|
||||
NumberType<?> rightType,
|
||||
ByteBuffer right)
|
||||
protected ByteBuffer executeOnNumerics(NumberType<?> resultType, Number left, Number right)
|
||||
{
|
||||
return resultType.add(leftType, left, rightType, right);
|
||||
return resultType.add(left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteBuffer executeOnTemporals(TemporalType<?> type,
|
||||
ByteBuffer temporal,
|
||||
ByteBuffer duration)
|
||||
protected ByteBuffer executeOnTemporals(TemporalType<?> type, Number temporal, Duration duration)
|
||||
{
|
||||
return type.addDuration(temporal, duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteBuffer excuteOnStrings(StringType resultType,
|
||||
StringType leftType,
|
||||
ByteBuffer left,
|
||||
StringType rightType,
|
||||
ByteBuffer right)
|
||||
protected ByteBuffer excuteOnStrings(StringType resultType, String left, String right)
|
||||
{
|
||||
return resultType.concat(leftType, left, rightType, right);
|
||||
return resultType.concat(left, right);
|
||||
}
|
||||
},
|
||||
SUBSTRACTION('-', "_substract")
|
||||
{
|
||||
protected ByteBuffer executeOnNumerics(NumberType<?> resultType,
|
||||
NumberType<?> leftType,
|
||||
ByteBuffer left,
|
||||
NumberType<?> rightType,
|
||||
ByteBuffer right)
|
||||
protected ByteBuffer executeOnNumerics(NumberType<?> resultType, Number left, Number right)
|
||||
{
|
||||
return resultType.substract(leftType, left, rightType, right);
|
||||
return resultType.substract(left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteBuffer executeOnTemporals(TemporalType<?> type,
|
||||
ByteBuffer temporal,
|
||||
ByteBuffer duration)
|
||||
protected ByteBuffer executeOnTemporals(TemporalType<?> type, Number temporal, Duration duration)
|
||||
{
|
||||
return type.substractDuration(temporal, duration);
|
||||
}
|
||||
},
|
||||
MULTIPLICATION('*', "_multiply")
|
||||
{
|
||||
protected ByteBuffer executeOnNumerics(NumberType<?> resultType,
|
||||
NumberType<?> leftType,
|
||||
ByteBuffer left,
|
||||
NumberType<?> rightType,
|
||||
ByteBuffer right)
|
||||
protected ByteBuffer executeOnNumerics(NumberType<?> resultType, Number left, Number right)
|
||||
{
|
||||
return resultType.multiply(leftType, left, rightType, right);
|
||||
return resultType.multiply(left, right);
|
||||
}
|
||||
},
|
||||
DIVISION('/', "_divide")
|
||||
{
|
||||
protected ByteBuffer executeOnNumerics(NumberType<?> resultType,
|
||||
NumberType<?> leftType,
|
||||
ByteBuffer left,
|
||||
NumberType<?> rightType,
|
||||
ByteBuffer right)
|
||||
protected ByteBuffer executeOnNumerics(NumberType<?> resultType, Number left, Number right)
|
||||
{
|
||||
return resultType.divide(leftType, left, rightType, right);
|
||||
return resultType.divide(left, right);
|
||||
}
|
||||
},
|
||||
MODULO('%', "_modulo")
|
||||
{
|
||||
protected ByteBuffer executeOnNumerics(NumberType<?> resultType,
|
||||
NumberType<?> leftType,
|
||||
ByteBuffer left,
|
||||
NumberType<?> rightType,
|
||||
ByteBuffer right)
|
||||
protected ByteBuffer executeOnNumerics(NumberType<?> resultType, Number left, Number right)
|
||||
{
|
||||
return resultType.mod(leftType, left, rightType, right);
|
||||
return resultType.mod(left, right);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -135,17 +107,11 @@ public final class OperationFcts
|
|||
* Executes the operation between the specified numeric operand.
|
||||
*
|
||||
* @param resultType the result ype of the operation
|
||||
* @param leftType the type of the left operand
|
||||
* @param left the left operand
|
||||
* @param rightType the type of the right operand
|
||||
* @param right the right operand
|
||||
* @return the operation result
|
||||
*/
|
||||
protected abstract ByteBuffer executeOnNumerics(NumberType<?> resultType,
|
||||
NumberType<?> leftType,
|
||||
ByteBuffer left,
|
||||
NumberType<?> rightType,
|
||||
ByteBuffer right);
|
||||
protected abstract ByteBuffer executeOnNumerics(NumberType<?> resultType, Number left, Number right);
|
||||
|
||||
/**
|
||||
* Executes the operation on the specified temporal operand.
|
||||
|
|
@ -155,9 +121,7 @@ public final class OperationFcts
|
|||
* @param duration the duration
|
||||
* @return the operation result
|
||||
*/
|
||||
protected ByteBuffer executeOnTemporals(TemporalType<?> type,
|
||||
ByteBuffer temporal,
|
||||
ByteBuffer duration)
|
||||
protected ByteBuffer executeOnTemporals(TemporalType<?> type, Number temporal, Duration duration)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
|
@ -166,17 +130,11 @@ public final class OperationFcts
|
|||
* Executes the operation between the specified string operand.
|
||||
*
|
||||
* @param resultType the result type of the operation
|
||||
* @param leftType the type of the left operand
|
||||
* @param left the left operand
|
||||
* @param rightType the type of the right operand
|
||||
* @param right the right operand
|
||||
* @return the operation result
|
||||
*/
|
||||
protected ByteBuffer excuteOnStrings(StringType resultType,
|
||||
StringType leftType,
|
||||
ByteBuffer left,
|
||||
StringType rightType,
|
||||
ByteBuffer right)
|
||||
protected ByteBuffer excuteOnStrings(StringType resultType, String left, String right)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
|
@ -198,7 +156,8 @@ public final class OperationFcts
|
|||
|
||||
/**
|
||||
* Returns the {@code OPERATOR} with the specified symbol.
|
||||
* @param functionName the function name
|
||||
*
|
||||
* @param symbol a symbol
|
||||
* @return the {@code OPERATOR} with the specified symbol
|
||||
*/
|
||||
public static OPERATION fromSymbol(char symbol)
|
||||
|
|
@ -395,16 +354,15 @@ public final class OperationFcts
|
|||
return String.format("%s %s %s", columnNames.get(0), getOperator(), columnNames.get(1));
|
||||
}
|
||||
|
||||
public final ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
@Override
|
||||
public final ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
ByteBuffer left = parameters.get(0);
|
||||
ByteBuffer right = parameters.get(1);
|
||||
if (left == null || !left.hasRemaining() || right == null || !right.hasRemaining())
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
return doExecute(left, operation, right);
|
||||
return doExecute(arguments.get(0), operation, arguments.get(1));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
@ -412,13 +370,13 @@ public final class OperationFcts
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract ByteBuffer doExecute(ByteBuffer left, OPERATION operation, ByteBuffer right);
|
||||
protected abstract ByteBuffer doExecute(Object left, OPERATION operation, Object right);
|
||||
|
||||
/**
|
||||
* Returns the operator symbol.
|
||||
* @return the operator symbol
|
||||
*/
|
||||
private final char getOperator()
|
||||
private char getOperator()
|
||||
{
|
||||
return operation.symbol;
|
||||
}
|
||||
|
|
@ -438,13 +396,11 @@ public final class OperationFcts
|
|||
}
|
||||
|
||||
@Override
|
||||
protected ByteBuffer doExecute(ByteBuffer left, OPERATION operation, ByteBuffer right)
|
||||
protected ByteBuffer doExecute(Object left, OPERATION operation, Object right)
|
||||
{
|
||||
NumberType<?> leftType = (NumberType<?>) argTypes().get(0);
|
||||
NumberType<?> rightType = (NumberType<?>) argTypes().get(1);
|
||||
NumberType<?> resultType = (NumberType<?>) returnType();
|
||||
|
||||
return operation.executeOnNumerics(resultType, leftType, left, rightType, right);
|
||||
return operation.executeOnNumerics(resultType, (Number) left, (Number) right);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -459,13 +415,11 @@ public final class OperationFcts
|
|||
}
|
||||
|
||||
@Override
|
||||
protected ByteBuffer doExecute(ByteBuffer left, OPERATION operation, ByteBuffer right)
|
||||
protected ByteBuffer doExecute(Object left, OPERATION operation, Object right)
|
||||
{
|
||||
StringType leftType = (StringType) argTypes().get(0);
|
||||
StringType rightType = (StringType) argTypes().get(1);
|
||||
StringType resultType = (StringType) returnType();
|
||||
|
||||
return operation.excuteOnStrings(resultType, leftType, left, rightType, right);
|
||||
return operation.excuteOnStrings(resultType, (String) left, (String) right);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -474,17 +428,16 @@ public final class OperationFcts
|
|||
*/
|
||||
private static class TemporalOperationFunction extends OperationFunction
|
||||
{
|
||||
public TemporalOperationFunction(TemporalType<?> type,
|
||||
OPERATION operation)
|
||||
public TemporalOperationFunction(TemporalType<?> type, OPERATION operation)
|
||||
{
|
||||
super(type, type, operation, DurationType.instance);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteBuffer doExecute(ByteBuffer left, OPERATION operation, ByteBuffer right)
|
||||
protected ByteBuffer doExecute(Object left, OPERATION operation, Object right)
|
||||
{
|
||||
TemporalType<?> resultType = (TemporalType<?>) returnType();
|
||||
return operation.executeOnTemporals(resultType, left, right);
|
||||
return operation.executeOnTemporals(resultType, (Number) left, (Duration) right);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -504,15 +457,15 @@ public final class OperationFcts
|
|||
return String.format("-%s", columnNames.get(0));
|
||||
}
|
||||
|
||||
public final ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
@Override
|
||||
public final ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
ByteBuffer input = parameters.get(0);
|
||||
if (input == null)
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
NumberType<?> inputType = (NumberType<?>) argTypes().get(0);
|
||||
|
||||
return inputType.negate(input);
|
||||
return inputType.negate(arguments.get(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,5 +41,5 @@ public interface PartialScalarFunction extends ScalarFunction
|
|||
*
|
||||
* @return the list of input parameters for the function
|
||||
*/
|
||||
public List<ByteBuffer> getPartialParameters();
|
||||
public List<ByteBuffer> getPartialArguments();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
package org.apache.cassandra.cql3.functions;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.CqlBuilder;
|
||||
|
|
@ -64,7 +63,13 @@ final class PartiallyAppliedScalarFunction extends NativeScalarFunction implemen
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<ByteBuffer> getPartialParameters()
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return new PartialFunctionArguments(version, function, partialParameters, argTypes.size());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ByteBuffer> getPartialArguments()
|
||||
{
|
||||
return partialParameters;
|
||||
}
|
||||
|
|
@ -81,16 +86,10 @@ final class PartiallyAppliedScalarFunction extends NativeScalarFunction implemen
|
|||
return argTypes;
|
||||
}
|
||||
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters) throws InvalidRequestException
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments) throws InvalidRequestException
|
||||
{
|
||||
List<ByteBuffer> fullParameters = new ArrayList<>(partialParameters);
|
||||
int arg = 0;
|
||||
for (int i = 0; i < fullParameters.size(); i++)
|
||||
{
|
||||
if (fullParameters.get(i) == UNRESOLVED)
|
||||
fullParameters.set(i, parameters.get(arg++));
|
||||
}
|
||||
return function.execute(protocolVersion, fullParameters);
|
||||
return function.execute(arguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -110,4 +109,70 @@ final class PartiallyAppliedScalarFunction extends NativeScalarFunction implemen
|
|||
b.append(") -> ").append(returnType);
|
||||
return b.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* The arguments for a {@code PartiallyAppliedScalarFunction}.
|
||||
*
|
||||
*/
|
||||
private static final class PartialFunctionArguments implements Arguments
|
||||
{
|
||||
/**
|
||||
* The decorated arguments.
|
||||
*/
|
||||
private final Arguments arguments;
|
||||
|
||||
/**
|
||||
* The position of the unresolved arguments.
|
||||
*/
|
||||
private final int[] mapping;
|
||||
|
||||
public PartialFunctionArguments(ProtocolVersion version, ScalarFunction function, List<ByteBuffer> partialArguments, int unresolvedCount)
|
||||
{
|
||||
arguments = function.newArguments(version);
|
||||
mapping = new int[unresolvedCount];
|
||||
int mappingIndex = 0;
|
||||
for (int i = 0, m = partialArguments.size(); i < m; i++)
|
||||
{
|
||||
ByteBuffer argument = partialArguments.get(i);
|
||||
if (argument != Function.UNRESOLVED)
|
||||
{
|
||||
arguments.set(i, argument);
|
||||
}
|
||||
else
|
||||
{
|
||||
mapping[mappingIndex++] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProtocolVersion getProtocolVersion()
|
||||
{
|
||||
return arguments.getProtocolVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(int i, ByteBuffer buffer)
|
||||
{
|
||||
arguments.set(mapping[i], buffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsNulls()
|
||||
{
|
||||
return arguments.containsNulls();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(int i)
|
||||
{
|
||||
return arguments.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return arguments.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,20 +40,20 @@ class PreComputedScalarFunction extends NativeScalarFunction implements PartialS
|
|||
private final ProtocolVersion valueVersion;
|
||||
|
||||
private final ScalarFunction function;
|
||||
private final List<ByteBuffer> parameters;
|
||||
private final List<ByteBuffer> arguments;
|
||||
|
||||
PreComputedScalarFunction(AbstractType<?> returnType,
|
||||
ByteBuffer value,
|
||||
ProtocolVersion valueVersion,
|
||||
ScalarFunction function,
|
||||
List<ByteBuffer> parameters)
|
||||
List<ByteBuffer> arguments)
|
||||
{
|
||||
// Note that we never register those function, there are just used internally, so the name doesn't matter much
|
||||
super("__constant__", returnType);
|
||||
this.value = value;
|
||||
this.valueVersion = valueVersion;
|
||||
this.function = function;
|
||||
this.parameters = parameters;
|
||||
this.arguments = arguments;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -63,17 +63,24 @@ class PreComputedScalarFunction extends NativeScalarFunction implements PartialS
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<ByteBuffer> getPartialParameters()
|
||||
public List<ByteBuffer> getPartialArguments()
|
||||
{
|
||||
return parameters;
|
||||
return arguments;
|
||||
}
|
||||
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> nothing) throws InvalidRequestException
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments nothing) throws InvalidRequestException
|
||||
{
|
||||
if (protocolVersion == valueVersion)
|
||||
if (nothing.getProtocolVersion() == valueVersion)
|
||||
return value;
|
||||
|
||||
return function.execute(protocolVersion, parameters);
|
||||
Arguments args = function.newArguments(nothing.getProtocolVersion());
|
||||
for (int i = 0, m = arguments.size() ; i < m; i++)
|
||||
{
|
||||
args.set(i, arguments.get(i));;
|
||||
}
|
||||
|
||||
return function.execute(args);
|
||||
}
|
||||
|
||||
public ScalarFunction partialApplication(ProtocolVersion protocolVersion, List<ByteBuffer> nothing) throws InvalidRequestException
|
||||
|
|
|
|||
|
|
@ -43,18 +43,17 @@ public interface ScalarFunction extends Function
|
|||
}
|
||||
|
||||
/**
|
||||
* Applies this function to the specified parameter.
|
||||
* Applies this function to the specified arguments.
|
||||
*
|
||||
* @param protocolVersion protocol version used for parameters and return value
|
||||
* @param parameters the input parameters
|
||||
* @return the result of applying this function to the parameter
|
||||
* @throws InvalidRequestException if this function cannot not be applied to the parameter
|
||||
* @param arguments the input arguments for the function
|
||||
* @return the result of applying this function to the arguments
|
||||
* @throws InvalidRequestException if this function cannot not be applied to the arguments
|
||||
*/
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters) throws InvalidRequestException;
|
||||
public ByteBuffer execute(Arguments arguments) throws InvalidRequestException;
|
||||
|
||||
/**
|
||||
* Does a partial application of the function. That is, given only some of the parameters of the function provided,
|
||||
* return a new function that only expect the parameters not provided.
|
||||
* Does a partial application of the function. That is, given only some of the arguments of the function provided,
|
||||
* return a new function that only expect the arguments not provided.
|
||||
* <p>
|
||||
* To take an example, if you consider the function
|
||||
* <pre>
|
||||
|
|
@ -66,21 +65,21 @@ public interface ScalarFunction extends Function
|
|||
* </pre>
|
||||
* and such that for any value of {@code b} and {@code d}, {@code bar(b, d) == foo(3, b, 'bar', d)}.
|
||||
*
|
||||
* @param protocolVersion protocol version used for parameters
|
||||
* @param partialParameters a list of input parameters for the function where some parameters can be {@link #UNRESOLVED}.
|
||||
* The input <b>must</b> be of size {@code this.argsType().size()}. For convenience, it is
|
||||
* allowed both to pass a list with all parameters being {@link #UNRESOLVED} (the function is
|
||||
* then returned directly) and with none of them unresolved (in which case, if the function is pure,
|
||||
* it is computed and a dummy no-arg function returning the result is returned).
|
||||
* @return a function corresponding to the partial application of this function to the parameters of
|
||||
* {@code partialParameters} that are not {@link #UNRESOLVED}.
|
||||
* @param protocolVersion protocol version used for arguments
|
||||
* @param partialArguments a list of input arguments for the function where some arguments can be {@link #UNRESOLVED}.
|
||||
* The input <b>must</b> be of size {@code this.argsType().size()}. For convenience, it is
|
||||
* allowed both to pass a list with all arguments being {@link #UNRESOLVED} (the function is
|
||||
* then returned directly) and with none of them unresolved (in which case, if the function is pure,
|
||||
* it is computed and a dummy no-arg function returning the result is returned).
|
||||
* @return a function corresponding to the partial application of this function to the arguments of
|
||||
* {@code partialArguments} that are not {@link #UNRESOLVED}.
|
||||
*/
|
||||
public default ScalarFunction partialApplication(ProtocolVersion protocolVersion, List<ByteBuffer> partialParameters)
|
||||
default ScalarFunction partialApplication(ProtocolVersion protocolVersion, List<ByteBuffer> partialArguments)
|
||||
{
|
||||
int unresolvedCount = 0;
|
||||
for (ByteBuffer parameter : partialParameters)
|
||||
for (ByteBuffer argument : partialArguments)
|
||||
{
|
||||
if (parameter == UNRESOLVED)
|
||||
if (argument == UNRESOLVED)
|
||||
++unresolvedCount;
|
||||
}
|
||||
|
||||
|
|
@ -88,12 +87,20 @@ public interface ScalarFunction extends Function
|
|||
return this;
|
||||
|
||||
if (isPure() && unresolvedCount == 0)
|
||||
return new PreComputedScalarFunction(returnType(),
|
||||
execute(protocolVersion, partialParameters),
|
||||
protocolVersion,
|
||||
this,
|
||||
partialParameters);
|
||||
{
|
||||
Arguments arguments = newArguments(protocolVersion);
|
||||
for (int i = 0, m = partialArguments.size(); i < m; i++)
|
||||
{
|
||||
arguments.set(i, partialArguments.get(i));
|
||||
}
|
||||
|
||||
return new PartiallyAppliedScalarFunction(this, partialParameters, unresolvedCount);
|
||||
return new PreComputedScalarFunction(returnType(),
|
||||
execute(arguments),
|
||||
protocolVersion,
|
||||
this,
|
||||
partialArguments);
|
||||
}
|
||||
|
||||
return new PartiallyAppliedScalarFunction(this, partialArguments, unresolvedCount);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,10 +26,8 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import org.apache.cassandra.cql3.Duration;
|
||||
import org.apache.cassandra.db.marshal.*;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.TimeUUID;
|
||||
import org.apache.cassandra.utils.UUIDGen;
|
||||
|
||||
import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest;
|
||||
|
||||
|
|
@ -73,7 +71,7 @@ public abstract class TimeFcts
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
return type.now();
|
||||
}
|
||||
|
|
@ -92,9 +90,33 @@ public abstract class TimeFcts
|
|||
}
|
||||
}
|
||||
|
||||
public static abstract class TemporalConversionFunction extends NativeScalarFunction
|
||||
{
|
||||
protected TemporalConversionFunction(String name, AbstractType<?> returnType, AbstractType<?>... argsType)
|
||||
{
|
||||
super(name, returnType, argsType);
|
||||
}
|
||||
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
beforeExecution();
|
||||
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
return convertArgument(arguments.getAsLong(0));
|
||||
}
|
||||
|
||||
protected void beforeExecution()
|
||||
{
|
||||
}
|
||||
|
||||
protected abstract ByteBuffer convertArgument(long timeInMillis);
|
||||
}
|
||||
|
||||
public static final NativeFunction minTimeuuidFct = new MinTimeuuidFunction(false);
|
||||
|
||||
private static final class MinTimeuuidFunction extends NativeScalarFunction
|
||||
private static final class MinTimeuuidFunction extends TemporalConversionFunction
|
||||
{
|
||||
public MinTimeuuidFunction(boolean legacy)
|
||||
{
|
||||
|
|
@ -102,13 +124,9 @@ public abstract class TimeFcts
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
protected ByteBuffer convertArgument(long timeInMillis)
|
||||
{
|
||||
ByteBuffer bb = parameters.get(0);
|
||||
if (bb == null)
|
||||
return null;
|
||||
|
||||
return TimeUUID.minAtUnixMillis(TimestampType.instance.compose(bb).getTime()).toBytes();
|
||||
return TimeUUID.minAtUnixMillis(timeInMillis).toBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -120,7 +138,7 @@ public abstract class TimeFcts
|
|||
|
||||
public static final NativeFunction maxTimeuuidFct = new MaxTimeuuidFunction(false);
|
||||
|
||||
private static final class MaxTimeuuidFunction extends NativeScalarFunction
|
||||
private static final class MaxTimeuuidFunction extends TemporalConversionFunction
|
||||
{
|
||||
public MaxTimeuuidFunction(boolean legacy)
|
||||
{
|
||||
|
|
@ -128,13 +146,9 @@ public abstract class TimeFcts
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
protected ByteBuffer convertArgument(long timeInMillis)
|
||||
{
|
||||
ByteBuffer bb = parameters.get(0);
|
||||
if (bb == null)
|
||||
return null;
|
||||
|
||||
return TimeUUID.maxAtUnixMillis(TimestampType.instance.compose(bb).getTime()).toBytes();
|
||||
return TimeUUID.maxAtUnixMillis(timeInMillis).toBytes();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -155,7 +169,7 @@ public abstract class TimeFcts
|
|||
return new ToDateFunction(type, false);
|
||||
}
|
||||
|
||||
private static class ToDateFunction extends NativeScalarFunction
|
||||
private static class ToDateFunction extends TemporalConversionFunction
|
||||
{
|
||||
private final TemporalType<?> type;
|
||||
|
||||
|
|
@ -166,14 +180,9 @@ public abstract class TimeFcts
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
protected ByteBuffer convertArgument(long timeInMillis)
|
||||
{
|
||||
ByteBuffer bb = parameters.get(0);
|
||||
if (bb == null || !bb.hasRemaining())
|
||||
return null;
|
||||
|
||||
long millis = type.toTimeInMillis(bb);
|
||||
return SimpleDateType.instance.fromTimeInMillis(millis);
|
||||
return SimpleDateType.instance.fromTimeInMillis(timeInMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -200,7 +209,7 @@ public abstract class TimeFcts
|
|||
return new ToTimestampFunction(type, false);
|
||||
}
|
||||
|
||||
private static class ToTimestampFunction extends NativeScalarFunction
|
||||
private static class ToTimestampFunction extends TemporalConversionFunction
|
||||
{
|
||||
private final TemporalType<?> type;
|
||||
|
||||
|
|
@ -211,14 +220,9 @@ public abstract class TimeFcts
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
protected ByteBuffer convertArgument(long timeInMillis)
|
||||
{
|
||||
ByteBuffer bb = parameters.get(0);
|
||||
if (bb == null || !bb.hasRemaining())
|
||||
return null;
|
||||
|
||||
long millis = type.toTimeInMillis(bb);
|
||||
return TimestampType.instance.fromTimeInMillis(millis);
|
||||
return TimestampType.instance.fromTimeInMillis(timeInMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -245,7 +249,7 @@ public abstract class TimeFcts
|
|||
return new ToUnixTimestampFunction(type, false);
|
||||
}
|
||||
|
||||
private static class ToUnixTimestampFunction extends NativeScalarFunction
|
||||
private static class ToUnixTimestampFunction extends TemporalConversionFunction
|
||||
{
|
||||
private final TemporalType<?> type;
|
||||
|
||||
|
|
@ -256,13 +260,9 @@ public abstract class TimeFcts
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
protected ByteBuffer convertArgument(long timeInMillis)
|
||||
{
|
||||
ByteBuffer bb = parameters.get(0);
|
||||
if (bb == null || !bb.hasRemaining())
|
||||
return null;
|
||||
|
||||
return ByteBufferUtil.bytes(type.toTimeInMillis(bb));
|
||||
return ByteBufferUtil.bytes(timeInMillis);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -301,25 +301,17 @@ public abstract class TimeFcts
|
|||
&& (partialParameters.size() == 2 || partialParameters.get(2) != UNRESOLVED);
|
||||
}
|
||||
|
||||
public final ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
@Override
|
||||
public final ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
ByteBuffer timeBuffer = parameters.get(0);
|
||||
ByteBuffer durationBuffer = parameters.get(1);
|
||||
Long startingTime = getStartingTime(parameters);
|
||||
|
||||
if (timeBuffer == null || durationBuffer == null || startingTime == null)
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
Long time = toTimeInMillis(timeBuffer);
|
||||
Duration duration = DurationType.instance.compose(durationBuffer);
|
||||
|
||||
if (time == null || duration == null)
|
||||
return null;
|
||||
|
||||
|
||||
long time = arguments.getAsLong(0);
|
||||
Duration duration = arguments.get(1);
|
||||
long startingTime = getStartingTime(arguments);
|
||||
validateDuration(duration);
|
||||
|
||||
|
||||
long floor = Duration.floorTimestamp(time, duration, startingTime);
|
||||
|
||||
return fromTimeInMillis(floor);
|
||||
|
|
@ -328,20 +320,13 @@ public abstract class TimeFcts
|
|||
/**
|
||||
* Returns the time to use as the starting time.
|
||||
*
|
||||
* @param parameters the function parameters
|
||||
* @param arguments the function arguments
|
||||
* @return the time to use as the starting time
|
||||
*/
|
||||
private Long getStartingTime(List<ByteBuffer> parameters)
|
||||
private long getStartingTime(Arguments arguments)
|
||||
{
|
||||
if (parameters.size() == 3)
|
||||
{
|
||||
ByteBuffer startingTimeBuffer = parameters.get(2);
|
||||
|
||||
if (startingTimeBuffer == null)
|
||||
return null;
|
||||
|
||||
return toStartingTimeInMillis(startingTimeBuffer);
|
||||
}
|
||||
if (arguments.size() == 3)
|
||||
return arguments.getAsLong(2);
|
||||
|
||||
return ZERO;
|
||||
}
|
||||
|
|
@ -363,22 +348,6 @@ public abstract class TimeFcts
|
|||
* @return the serialized time
|
||||
*/
|
||||
protected abstract ByteBuffer fromTimeInMillis(long timeInMillis);
|
||||
|
||||
/**
|
||||
* Deserializes the specified input time.
|
||||
*
|
||||
* @param bytes the serialized time
|
||||
* @return the time in milliseconds
|
||||
*/
|
||||
protected abstract Long toTimeInMillis(ByteBuffer bytes);
|
||||
|
||||
/**
|
||||
* Deserializes the specified starting time.
|
||||
*
|
||||
* @param bytes the serialized starting time
|
||||
* @return the starting time in milliseconds
|
||||
*/
|
||||
protected abstract Long toStartingTimeInMillis(ByteBuffer bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -411,16 +380,6 @@ public abstract class TimeFcts
|
|||
{
|
||||
return TimestampType.instance.fromTimeInMillis(timeInMillis);
|
||||
}
|
||||
|
||||
protected Long toStartingTimeInMillis(ByteBuffer bytes)
|
||||
{
|
||||
return TimestampType.instance.toTimeInMillis(bytes);
|
||||
}
|
||||
|
||||
protected Long toTimeInMillis(ByteBuffer bytes)
|
||||
{
|
||||
return TimestampType.instance.toTimeInMillis(bytes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -453,16 +412,6 @@ public abstract class TimeFcts
|
|||
{
|
||||
return TimestampType.instance.fromTimeInMillis(timeInMillis);
|
||||
}
|
||||
|
||||
protected Long toStartingTimeInMillis(ByteBuffer bytes)
|
||||
{
|
||||
return TimestampType.instance.toTimeInMillis(bytes);
|
||||
}
|
||||
|
||||
protected Long toTimeInMillis(ByteBuffer bytes)
|
||||
{
|
||||
return UUIDGen.getAdjustedTimestamp(UUIDGen.getUUID(bytes));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -496,16 +445,6 @@ public abstract class TimeFcts
|
|||
return SimpleDateType.instance.fromTimeInMillis(timeInMillis);
|
||||
}
|
||||
|
||||
protected Long toStartingTimeInMillis(ByteBuffer bytes)
|
||||
{
|
||||
return SimpleDateType.instance.toTimeInMillis(bytes);
|
||||
}
|
||||
|
||||
protected Long toTimeInMillis(ByteBuffer bytes)
|
||||
{
|
||||
return SimpleDateType.instance.toTimeInMillis(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateDuration(Duration duration)
|
||||
{
|
||||
|
|
@ -527,19 +466,14 @@ public abstract class TimeFcts
|
|||
return partialParameters.get(0) == UNRESOLVED && partialParameters.get(1) != UNRESOLVED;
|
||||
}
|
||||
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
ByteBuffer timeBuffer = parameters.get(0);
|
||||
ByteBuffer durationBuffer = parameters.get(1);
|
||||
|
||||
if (timeBuffer == null || durationBuffer == null)
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
Long time = TimeType.instance.compose(timeBuffer);
|
||||
Duration duration = DurationType.instance.compose(durationBuffer);
|
||||
|
||||
if (time == null || duration == null)
|
||||
return null;
|
||||
long time = arguments.getAsLong(0);
|
||||
Duration duration = arguments.get(1);
|
||||
|
||||
long floor = Duration.floorTime(time, duration);
|
||||
|
||||
|
|
|
|||
|
|
@ -54,14 +54,26 @@ public class ToJsonFct extends NativeScalarFunction
|
|||
super(name, UTF8Type.instance, argType);
|
||||
}
|
||||
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters) throws InvalidRequestException
|
||||
@Override
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
assert parameters.size() == 1 : format("Expected 1 argument for %s(), but got %d", name.name, parameters.size());
|
||||
ByteBuffer parameter = parameters.get(0);
|
||||
if (parameter == null)
|
||||
return new FunctionArguments(version, (protocolVersion, buffer) -> {
|
||||
AbstractType<?> argType = argTypes.get(0);
|
||||
|
||||
if (buffer == null || (!buffer.hasRemaining() && argType.isEmptyValueMeaningless()))
|
||||
return null;
|
||||
|
||||
return argTypes.get(0).toJSONString(buffer, protocolVersion);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments) throws InvalidRequestException
|
||||
{
|
||||
if (arguments.containsNulls())
|
||||
return ByteBufferUtil.bytes("null");
|
||||
|
||||
return ByteBufferUtil.bytes(argTypes.get(0).toJSONString(parameter, protocolVersion));
|
||||
return ByteBufferUtil.bytes(arguments.<String>get(0));
|
||||
}
|
||||
|
||||
public static void addFunctionsTo(NativeFunctions functions)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
package org.apache.cassandra.cql3.functions;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.AssignmentTestable;
|
||||
|
|
@ -39,6 +40,14 @@ public class TokenFct extends NativeScalarFunction
|
|||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
ArgumentDeserializer[] deserializers = new ArgumentDeserializer[argTypes.size()];
|
||||
Arrays.fill(deserializers, ArgumentDeserializer.NOOP_DESERIALIZER);
|
||||
return new FunctionArguments(version, deserializers);
|
||||
}
|
||||
|
||||
private static AbstractType<?>[] getKeyTypes(TableMetadata metadata)
|
||||
{
|
||||
AbstractType<?>[] types = new AbstractType[metadata.partitionKeyColumns().size()];
|
||||
|
|
@ -48,12 +57,12 @@ public class TokenFct extends NativeScalarFunction
|
|||
return types;
|
||||
}
|
||||
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters) throws InvalidRequestException
|
||||
public ByteBuffer execute(Arguments arguments) throws InvalidRequestException
|
||||
{
|
||||
CBuilder builder = CBuilder.create(metadata.partitionKeyAsClusteringComparator());
|
||||
for (int i = 0; i < parameters.size(); i++)
|
||||
for (int i = 0; i < arguments.size(); i++)
|
||||
{
|
||||
ByteBuffer bb = parameters.get(i);
|
||||
ByteBuffer bb = arguments.get(i);
|
||||
if (bb == null)
|
||||
return null;
|
||||
builder.add(bb);
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.cql3.CqlBuilder;
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.UserType;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
|
|
@ -47,9 +46,9 @@ public class UDAggregate extends UserFunction implements AggregateFunction
|
|||
{
|
||||
protected static final Logger logger = LoggerFactory.getLogger(UDAggregate.class);
|
||||
|
||||
private final AbstractType<?> stateType;
|
||||
private final TypeCodec stateTypeCodec;
|
||||
private final TypeCodec returnTypeCodec;
|
||||
private final UDFDataType stateType;
|
||||
private final List<UDFDataType> argumentTypes;
|
||||
private final UDFDataType resultType;
|
||||
protected final ByteBuffer initcond;
|
||||
private final ScalarFunction stateFunction;
|
||||
private final ScalarFunction finalFunction;
|
||||
|
|
@ -64,9 +63,9 @@ public class UDAggregate extends UserFunction implements AggregateFunction
|
|||
super(name, argTypes, returnType);
|
||||
this.stateFunction = stateFunc;
|
||||
this.finalFunction = finalFunc;
|
||||
this.stateType = stateFunc.returnType();
|
||||
this.stateTypeCodec = UDHelper.codecFor(UDHelper.driverType(stateType));
|
||||
this.returnTypeCodec = UDHelper.codecFor(UDHelper.driverType(returnType));
|
||||
this.argumentTypes = UDFDataType.wrap(argTypes, false);
|
||||
this.resultType = UDFDataType.wrap(returnType, false);
|
||||
this.stateType = stateFunc != null ? UDFDataType.wrap(stateFunc.returnType(), false) : null;
|
||||
this.initcond = initcond;
|
||||
}
|
||||
|
||||
|
|
@ -105,6 +104,12 @@ public class UDAggregate extends UserFunction implements AggregateFunction
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return FunctionArguments.newInstanceForUdf(version, argumentTypes);
|
||||
}
|
||||
|
||||
public boolean hasReferenceTo(Function function)
|
||||
{
|
||||
return stateFunction == function || finalFunction == function;
|
||||
|
|
@ -115,7 +120,7 @@ public class UDAggregate extends UserFunction implements AggregateFunction
|
|||
{
|
||||
return any(argTypes(), t -> t.referencesUserType(name))
|
||||
|| returnType.referencesUserType(name)
|
||||
|| (null != stateType && stateType.referencesUserType(name))
|
||||
|| (null != stateType && stateType.toAbstractType().referencesUserType(name))
|
||||
|| stateFunction.referencesUserType(name)
|
||||
|| (null != finalFunction && finalFunction.referencesUserType(name));
|
||||
}
|
||||
|
|
@ -166,7 +171,7 @@ public class UDAggregate extends UserFunction implements AggregateFunction
|
|||
|
||||
public AbstractType<?> stateType()
|
||||
{
|
||||
return stateType;
|
||||
return stateType == null ? null : stateType.toAbstractType();
|
||||
}
|
||||
|
||||
public Aggregate newAggregate() throws InvalidRequestException
|
||||
|
|
@ -179,17 +184,18 @@ public class UDAggregate extends UserFunction implements AggregateFunction
|
|||
private Object state;
|
||||
private boolean needsInit = true;
|
||||
|
||||
public void addInput(ProtocolVersion protocolVersion, List<ByteBuffer> values) throws InvalidRequestException
|
||||
@Override
|
||||
public void addInput(Arguments arguments) throws InvalidRequestException
|
||||
{
|
||||
maybeInit(protocolVersion);
|
||||
maybeInit(arguments.getProtocolVersion());
|
||||
|
||||
long startTime = nanoTime();
|
||||
stateFunctionCount++;
|
||||
if (stateFunction instanceof UDFunction)
|
||||
{
|
||||
UDFunction udf = (UDFunction)stateFunction;
|
||||
if (udf.isCallableWrtNullable(values))
|
||||
state = udf.executeForAggregate(protocolVersion, state, values);
|
||||
if (udf.isCallableWrtNullable(arguments))
|
||||
state = udf.executeForAggregate(state, arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -202,7 +208,7 @@ public class UDAggregate extends UserFunction implements AggregateFunction
|
|||
{
|
||||
if (needsInit)
|
||||
{
|
||||
state = initcond != null ? UDHelper.deserialize(stateTypeCodec, protocolVersion, initcond.duplicate()) : null;
|
||||
state = initcond != null ? stateType.compose(protocolVersion, initcond.duplicate()) : null;
|
||||
stateFunctionDuration = 0;
|
||||
stateFunctionCount = 0;
|
||||
needsInit = false;
|
||||
|
|
@ -216,13 +222,13 @@ public class UDAggregate extends UserFunction implements AggregateFunction
|
|||
// final function is traced in UDFunction
|
||||
Tracing.trace("Executed UDA {}: {} call(s) to state function {} in {}\u03bcs", name(), stateFunctionCount, stateFunction.name(), stateFunctionDuration);
|
||||
if (finalFunction == null)
|
||||
return UDFunction.decompose(stateTypeCodec, protocolVersion, state);
|
||||
return stateType.decompose(protocolVersion, state);
|
||||
|
||||
if (finalFunction instanceof UDFunction)
|
||||
{
|
||||
UDFunction udf = (UDFunction)finalFunction;
|
||||
Object result = udf.executeForAggregate(protocolVersion, state, Collections.emptyList());
|
||||
return UDFunction.decompose(returnTypeCodec, protocolVersion, result);
|
||||
Object result = udf.executeForAggregate(state, FunctionArguments.emptyInstance(protocolVersion));
|
||||
return resultType.decompose(protocolVersion, result);
|
||||
}
|
||||
throw new UnsupportedOperationException("UDAs only support UDFs");
|
||||
}
|
||||
|
|
@ -281,7 +287,8 @@ public class UDAggregate extends UserFunction implements AggregateFunction
|
|||
|
||||
if (null != stateType && !stateType.equals(other.stateType))
|
||||
{
|
||||
if (stateType.asCQL3Type().toString().equals(other.stateType.asCQL3Type().toString()))
|
||||
if (stateType.toAbstractType().asCQL3Type().toString()
|
||||
.equals(other.stateType.toAbstractType().asCQL3Type().toString()))
|
||||
differsDeeply = true;
|
||||
else
|
||||
return Optional.of(Difference.SHALLOW);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public final class UDFByteCodeVerifier
|
|||
|
||||
public static final String JAVA_UDF_NAME = JavaUDF.class.getName().replace('.', '/');
|
||||
public static final String OBJECT_NAME = Object.class.getName().replace('.', '/');
|
||||
public static final String CTOR_SIG = "(Lorg/apache/cassandra/cql3/functions/types/TypeCodec;[Lorg/apache/cassandra/cql3/functions/types/TypeCodec;Lorg/apache/cassandra/cql3/functions/UDFContext;)V";
|
||||
public static final String CTOR_SIG = "(Lorg/apache/cassandra/cql3/functions/UDFDataType;Lorg/apache/cassandra/cql3/functions/UDFContext;)V";
|
||||
|
||||
private final Set<String> disallowedClasses = new HashSet<>();
|
||||
private final Multimap<String, String> disallowedMethodCalls = HashMultimap.create();
|
||||
|
|
@ -100,21 +100,21 @@ public final class UDFByteCodeVerifier
|
|||
{
|
||||
if (Opcodes.ACC_PUBLIC != access)
|
||||
errors.add("constructor not public");
|
||||
// allowed constructor - JavaUDF(TypeCodec returnCodec, TypeCodec[] argCodecs)
|
||||
// allowed constructor - JavaUDF(UDFDataType returnType, UDFContext udfContext)
|
||||
return new ConstructorVisitor(errors);
|
||||
}
|
||||
if ("executeImpl".equals(name) && "(Lorg/apache/cassandra/transport/ProtocolVersion;Ljava/util/List;)Ljava/nio/ByteBuffer;".equals(desc))
|
||||
if ("executeImpl".equals(name) && "(Lorg/apache/cassandra/cql3/functions/Arguments;)Ljava/nio/ByteBuffer;".equals(desc))
|
||||
{
|
||||
if (Opcodes.ACC_PROTECTED != access)
|
||||
errors.add("executeImpl not protected");
|
||||
// the executeImpl method - ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
// the executeImpl method - ByteBuffer executeImpl(Arguments arguments)
|
||||
return new ExecuteImplVisitor(errors);
|
||||
}
|
||||
if ("executeAggregateImpl".equals(name) && "(Lorg/apache/cassandra/transport/ProtocolVersion;Ljava/lang/Object;Ljava/util/List;)Ljava/lang/Object;".equals(desc))
|
||||
if ("executeAggregateImpl".equals(name) && "(Ljava/lang/Object;Lorg/apache/cassandra/cql3/functions/Arguments;)Ljava/lang/Object;".equals(desc))
|
||||
{
|
||||
if (Opcodes.ACC_PROTECTED != access)
|
||||
errors.add("executeAggregateImpl not protected");
|
||||
// the executeImpl method - ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
// the executeImpl method - ByteBuffer executeImpl(Object state, Arguments arguments)
|
||||
return new ExecuteImplVisitor(errors);
|
||||
}
|
||||
if ("<clinit>".equals(name))
|
||||
|
|
|
|||
|
|
@ -23,12 +23,18 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.DataType;
|
||||
import org.apache.cassandra.cql3.functions.types.TupleType;
|
||||
import org.apache.cassandra.cql3.functions.types.TupleValue;
|
||||
import org.apache.cassandra.cql3.functions.types.UDTValue;
|
||||
import org.apache.cassandra.cql3.functions.types.UserType;
|
||||
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.schema.CQLTypeParser;
|
||||
import org.apache.cassandra.schema.KeyspaceMetadata;
|
||||
import org.apache.cassandra.cql3.functions.types.*;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.JavaDriverUtils;
|
||||
|
||||
/**
|
||||
* Package private implementation of {@link UDFContext}
|
||||
|
|
@ -36,87 +42,68 @@ import org.apache.cassandra.utils.ByteBufferUtil;
|
|||
public final class UDFContextImpl implements UDFContext
|
||||
{
|
||||
private final KeyspaceMetadata keyspaceMetadata;
|
||||
private final Map<String, TypeCodec<Object>> byName = new HashMap<>();
|
||||
private final TypeCodec<Object>[] argCodecs;
|
||||
private final TypeCodec<Object> returnCodec;
|
||||
private final Map<String, UDFDataType> byName = new HashMap<>();
|
||||
private final List<UDFDataType> argTypes;
|
||||
private final UDFDataType returnType;
|
||||
|
||||
UDFContextImpl(List<ColumnIdentifier> argNames, TypeCodec<Object>[] argCodecs, TypeCodec<Object> returnCodec,
|
||||
UDFContextImpl(List<ColumnIdentifier> argNames,
|
||||
List<UDFDataType> argTypes,
|
||||
UDFDataType returnType,
|
||||
KeyspaceMetadata keyspaceMetadata)
|
||||
{
|
||||
for (int i = 0; i < argNames.size(); i++)
|
||||
byName.put(argNames.get(i).toString(), argCodecs[i]);
|
||||
this.argCodecs = argCodecs;
|
||||
this.returnCodec = returnCodec;
|
||||
byName.put(argNames.get(i).toString(), argTypes.get(i));
|
||||
this.argTypes = argTypes;
|
||||
this.returnType = returnType;
|
||||
this.keyspaceMetadata = keyspaceMetadata;
|
||||
}
|
||||
|
||||
public UDTValue newArgUDTValue(String argName)
|
||||
{
|
||||
return newUDTValue(codecFor(argName));
|
||||
return newUDTValue(getArgumentTypeByName(argName).toDataType());
|
||||
}
|
||||
|
||||
public UDTValue newArgUDTValue(int argNum)
|
||||
{
|
||||
return newUDTValue(codecFor(argNum));
|
||||
return newUDTValue(getArgumentTypeByIndex(argNum).toDataType());
|
||||
}
|
||||
|
||||
public UDTValue newReturnUDTValue()
|
||||
{
|
||||
return newUDTValue(returnCodec);
|
||||
return newUDTValue(returnType.toDataType());
|
||||
}
|
||||
|
||||
public UDTValue newUDTValue(String udtName)
|
||||
{
|
||||
Optional<org.apache.cassandra.db.marshal.UserType> udtType = keyspaceMetadata.types.get(ByteBufferUtil.bytes(udtName));
|
||||
DataType dataType = UDHelper.driverType(udtType.orElseThrow(
|
||||
DataType dataType = JavaDriverUtils.driverType(udtType.orElseThrow(
|
||||
() -> new IllegalArgumentException("No UDT named " + udtName + " in keyspace " + keyspaceMetadata.name)
|
||||
));
|
||||
));
|
||||
return newUDTValue(dataType);
|
||||
}
|
||||
|
||||
public TupleValue newArgTupleValue(String argName)
|
||||
{
|
||||
return newTupleValue(codecFor(argName));
|
||||
return newTupleValue(getArgumentTypeByName(argName).toDataType());
|
||||
}
|
||||
|
||||
public TupleValue newArgTupleValue(int argNum)
|
||||
{
|
||||
return newTupleValue(codecFor(argNum));
|
||||
return newTupleValue(getArgumentTypeByIndex(argNum).toDataType());
|
||||
}
|
||||
|
||||
public TupleValue newReturnTupleValue()
|
||||
{
|
||||
return newTupleValue(returnCodec);
|
||||
return newTupleValue(returnType.toDataType());
|
||||
}
|
||||
|
||||
public TupleValue newTupleValue(String cqlDefinition)
|
||||
{
|
||||
AbstractType<?> abstractType = CQLTypeParser.parse(keyspaceMetadata.name, cqlDefinition, keyspaceMetadata.types);
|
||||
DataType dataType = UDHelper.driverType(abstractType);
|
||||
DataType dataType = JavaDriverUtils.driverType(abstractType);
|
||||
return newTupleValue(dataType);
|
||||
}
|
||||
|
||||
private TypeCodec<Object> codecFor(int argNum)
|
||||
{
|
||||
if (argNum < 0 || argNum >= argCodecs.length)
|
||||
throw new IllegalArgumentException("Function does not declare an argument with index " + argNum);
|
||||
return argCodecs[argNum];
|
||||
}
|
||||
|
||||
private TypeCodec<Object> codecFor(String argName)
|
||||
{
|
||||
TypeCodec<Object> codec = byName.get(argName);
|
||||
if (codec == null)
|
||||
throw new IllegalArgumentException("Function does not declare an argument named '" + argName + '\'');
|
||||
return codec;
|
||||
}
|
||||
|
||||
private static UDTValue newUDTValue(TypeCodec<Object> codec)
|
||||
{
|
||||
DataType dataType = codec.getCqlType();
|
||||
return newUDTValue(dataType);
|
||||
}
|
||||
|
||||
private static UDTValue newUDTValue(DataType dataType)
|
||||
{
|
||||
if (!(dataType instanceof UserType))
|
||||
|
|
@ -125,12 +112,6 @@ public final class UDFContextImpl implements UDFContext
|
|||
return userType.newValue();
|
||||
}
|
||||
|
||||
private static TupleValue newTupleValue(TypeCodec<Object> codec)
|
||||
{
|
||||
DataType dataType = codec.getCqlType();
|
||||
return newTupleValue(dataType);
|
||||
}
|
||||
|
||||
private static TupleValue newTupleValue(DataType dataType)
|
||||
{
|
||||
if (!(dataType instanceof TupleType))
|
||||
|
|
@ -138,4 +119,19 @@ public final class UDFContextImpl implements UDFContext
|
|||
TupleType tupleType = (TupleType) dataType;
|
||||
return tupleType.newValue();
|
||||
}
|
||||
|
||||
private UDFDataType getArgumentTypeByIndex(int index)
|
||||
{
|
||||
if (index < 0 || index >= argTypes.size())
|
||||
throw new IllegalArgumentException("Function does not declare an argument with index " + index);
|
||||
return argTypes.get(index);
|
||||
}
|
||||
|
||||
private UDFDataType getArgumentTypeByName(String argName)
|
||||
{
|
||||
UDFDataType arg = byName.get(argName);
|
||||
if (arg == null)
|
||||
throw new IllegalArgumentException("Function does not declare an argument named '" + argName + '\'');
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
* 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.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.reflect.TypeToken;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.DataType;
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec.*;
|
||||
import org.apache.cassandra.cql3.functions.types.exceptions.InvalidTypeException;
|
||||
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.utils.JavaDriverUtils;
|
||||
|
||||
/**
|
||||
* Represents a data type used within the UDF/UDA.
|
||||
* </p>
|
||||
* Internaly, UDFs and UDAs use the Java driver types. This class maintains the mapping between the C* type
|
||||
* and the corresponding java driver type.
|
||||
*/
|
||||
public final class UDFDataType
|
||||
{
|
||||
private static final Pattern JAVA_LANG_PREFIX = Pattern.compile("\\bjava\\.lang\\.");
|
||||
|
||||
/**
|
||||
* The Cassandra type.
|
||||
*/
|
||||
private final AbstractType<?> abstractType;
|
||||
|
||||
/**
|
||||
* The Java driver type used to serialize and deserialize the UDF/UDA data.
|
||||
*/
|
||||
private final TypeCodec<?> typeCodec;
|
||||
|
||||
/**
|
||||
* The java type corresponding to this data type.
|
||||
*/
|
||||
private final TypeToken<?> javaType;
|
||||
|
||||
/**
|
||||
* Creates a new {@code UDFDataType} corresponding to the specified Cassandra type.
|
||||
*
|
||||
* @param abstractType the Cassandra type
|
||||
* @param usePrimitive {@code true} if the primitive type can be used.
|
||||
*/
|
||||
private UDFDataType(AbstractType<?> abstractType, boolean usePrimitive)
|
||||
{
|
||||
this.abstractType = abstractType;
|
||||
this.typeCodec = JavaDriverUtils.codecFor(abstractType);
|
||||
TypeToken<?> token = typeCodec.getJavaType();
|
||||
this.javaType = usePrimitive ? token.unwrap() : token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this type into the corresponding Cassandra type.
|
||||
* @return the corresponding Cassandra type
|
||||
*/
|
||||
public AbstractType<?> toAbstractType()
|
||||
{
|
||||
return abstractType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this type into the corresponding Java class.
|
||||
* @return the corresponding Java class.
|
||||
*/
|
||||
public Class<?> toJavaClass()
|
||||
{
|
||||
return typeCodec.getJavaType().getRawType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name of the java type corresponding to this class.
|
||||
*/
|
||||
public String getJavaTypeName()
|
||||
{
|
||||
String n = javaType.toString();
|
||||
return JAVA_LANG_PREFIX.matcher(n).replaceAll("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this type is corresponding to a Java primitive type.
|
||||
* @return {@code true} if this type is corresponding to a Java primitive type, {@code false} otherwise.
|
||||
*/
|
||||
public boolean isPrimitive()
|
||||
{
|
||||
return javaType.isPrimitive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code UDFDataType} corresponding to the specified type.
|
||||
*
|
||||
* @param abstractType the Cassandra type
|
||||
* @param usePrimitive {@code true} if the primitive type can be used.
|
||||
* @return the {@code UDFDataType} corresponding to the specified type.
|
||||
*/
|
||||
public static UDFDataType wrap(AbstractType<?> abstractType, boolean usePrimitive)
|
||||
{
|
||||
return new UDFDataType(abstractType, usePrimitive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code UDFDataType}s corresponding to the specified types.
|
||||
*
|
||||
* @param argTypes the Cassandra types
|
||||
* @param usePrimitive {@code true} if the primitive types can be used.
|
||||
* @return the {@code UDFDataType}s corresponding to the specified types.
|
||||
*/
|
||||
public static List<UDFDataType> wrap(List<AbstractType<?>> argTypes, boolean usePrimitive)
|
||||
{
|
||||
List<UDFDataType> types = new ArrayList<>(argTypes.size());
|
||||
for (AbstractType<?> argType : argTypes)
|
||||
{
|
||||
types.add(UDFDataType.wrap(argType, usePrimitive));
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this type into the corresponding Java driver type.
|
||||
* @return the corresponding Java driver type.
|
||||
*/
|
||||
public DataType toDataType()
|
||||
{
|
||||
return typeCodec.getCqlType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hashCode(abstractType, javaType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (!(obj instanceof UDFDataType))
|
||||
return false;
|
||||
|
||||
UDFDataType that = (UDFDataType) obj;
|
||||
|
||||
return abstractType.equals(that.abstractType) && javaType.equals(that.javaType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes the specified oject.
|
||||
*
|
||||
* @param protocolVersion the protocol version
|
||||
* @param buffer the serialized object
|
||||
* @return the deserialized object
|
||||
*/
|
||||
public Object compose(ProtocolVersion protocolVersion, ByteBuffer buffer)
|
||||
{
|
||||
if (buffer == null || (buffer.remaining() == 0 && abstractType.isEmptyValueMeaningless()))
|
||||
return null;
|
||||
|
||||
return typeCodec.deserialize(buffer, protocolVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialized the specified oject.
|
||||
*
|
||||
* @param protocolVersion the protocol version
|
||||
* @param value the value to serialize
|
||||
* @return the serialized object
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public ByteBuffer decompose(ProtocolVersion protocolVersion, Object value)
|
||||
{
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
if (!toJavaClass().isAssignableFrom(value.getClass()))
|
||||
throw new InvalidTypeException("Invalid value for CQL type " + toDataType().getName());
|
||||
|
||||
return ((TypeCodec<Object>) typeCodec).serialize(value, protocolVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialized the specified byte.
|
||||
*
|
||||
* @param protocolVersion the protocol version
|
||||
* @param value the value to serialize
|
||||
* @return the serialized byte
|
||||
*/
|
||||
public ByteBuffer decompose(ProtocolVersion protocolVersion, byte value)
|
||||
{
|
||||
if (!(typeCodec instanceof PrimitiveByteCodec))
|
||||
throw new InvalidTypeException("Invalid value for CQL type " + toDataType().getName());
|
||||
|
||||
return ((PrimitiveByteCodec) typeCodec).serializeNoBoxing(value, protocolVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialized the specified byte.
|
||||
*
|
||||
* @param protocolVersion the protocol version
|
||||
* @param value the value to serialize
|
||||
* @return the serialized byte
|
||||
*/
|
||||
public ByteBuffer decompose(ProtocolVersion protocolVersion, short value)
|
||||
{
|
||||
if (!(typeCodec instanceof PrimitiveShortCodec))
|
||||
throw new InvalidTypeException("Invalid value for CQL type " + toDataType().getName());
|
||||
|
||||
return ((PrimitiveShortCodec) typeCodec).serializeNoBoxing(value, protocolVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialized the specified byte.
|
||||
*
|
||||
* @param protocolVersion the protocol version
|
||||
* @param value the value to serialize
|
||||
* @return the serialized byte
|
||||
*/
|
||||
public ByteBuffer decompose(ProtocolVersion protocolVersion, int value)
|
||||
{
|
||||
if (!(typeCodec instanceof PrimitiveIntCodec))
|
||||
throw new InvalidTypeException("Invalid value for CQL type " + toDataType().getName());
|
||||
|
||||
return ((PrimitiveIntCodec) typeCodec).serializeNoBoxing(value, protocolVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialized the specified byte.
|
||||
*
|
||||
* @param protocolVersion the protocol version
|
||||
* @param value the value to serialize
|
||||
* @return the serialized byte
|
||||
*/
|
||||
public ByteBuffer decompose(ProtocolVersion protocolVersion, long value)
|
||||
{
|
||||
if (!(typeCodec instanceof PrimitiveLongCodec))
|
||||
throw new InvalidTypeException("Invalid value for CQL type " + toDataType().getName());
|
||||
|
||||
return ((PrimitiveLongCodec) typeCodec).serializeNoBoxing(value, protocolVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialized the specified byte.
|
||||
*
|
||||
* @param protocolVersion the protocol version
|
||||
* @param value the value to serialize
|
||||
* @return the serialized byte
|
||||
*/
|
||||
public ByteBuffer decompose(ProtocolVersion protocolVersion, float value)
|
||||
{
|
||||
if (!(typeCodec instanceof PrimitiveFloatCodec))
|
||||
throw new InvalidTypeException("Invalid value for CQL type " + toDataType().getName());
|
||||
|
||||
return ((PrimitiveFloatCodec) typeCodec).serializeNoBoxing(value, protocolVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialized the specified byte.
|
||||
*
|
||||
* @param protocolVersion the protocol version
|
||||
* @param value the value to serialize
|
||||
* @return the serialized byte
|
||||
*/
|
||||
public ByteBuffer decompose(ProtocolVersion protocolVersion, double value)
|
||||
{
|
||||
if (!(typeCodec instanceof PrimitiveDoubleCodec))
|
||||
throw new InvalidTypeException("Invalid value for CQL type " + toDataType().getName());
|
||||
|
||||
return ((PrimitiveDoubleCodec) typeCodec).serializeNoBoxing(value, protocolVersion);
|
||||
}
|
||||
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
// If the type is corresponding to a primitive one we can use the ArgumentDeserializer of the AbstractType
|
||||
if (isPrimitive())
|
||||
return abstractType.getArgumentDeserializer();
|
||||
|
||||
return this::compose;
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,6 @@ import java.lang.management.ThreadMXBean;
|
|||
import java.net.InetAddress;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
|
|
@ -46,7 +45,6 @@ import org.apache.cassandra.config.Config;
|
|||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.cql3.CqlBuilder;
|
||||
import org.apache.cassandra.cql3.functions.types.DataType;
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.UserType;
|
||||
|
|
@ -77,8 +75,8 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
|
|||
protected final String language;
|
||||
protected final String body;
|
||||
|
||||
protected final TypeCodec<Object>[] argCodecs;
|
||||
protected final TypeCodec<Object> returnCodec;
|
||||
protected final List<UDFDataType> argumentTypes;
|
||||
protected final UDFDataType resultType;
|
||||
protected final boolean calledOnNullInput;
|
||||
|
||||
protected final UDFContext udfContext;
|
||||
|
|
@ -115,6 +113,8 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
|
|||
"java/time/",
|
||||
"java/util/",
|
||||
"org/apache/cassandra/cql3/functions/types/",
|
||||
"org/apache/cassandra/cql3/functions/Arguments.class",
|
||||
"org/apache/cassandra/cql3/functions/UDFDataType.class",
|
||||
"org/apache/cassandra/cql3/functions/JavaUDF.class",
|
||||
"org/apache/cassandra/cql3/functions/UDFContext.class",
|
||||
"org/apache/cassandra/exceptions/",
|
||||
|
|
@ -210,32 +210,23 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
|
|||
boolean calledOnNullInput,
|
||||
String language,
|
||||
String body)
|
||||
{
|
||||
this(name, argNames, argTypes, UDHelper.driverTypes(argTypes), returnType,
|
||||
UDHelper.driverType(returnType), calledOnNullInput, language, body);
|
||||
}
|
||||
|
||||
protected UDFunction(FunctionName name,
|
||||
List<ColumnIdentifier> argNames,
|
||||
List<AbstractType<?>> argTypes,
|
||||
DataType[] argDataTypes,
|
||||
AbstractType<?> returnType,
|
||||
DataType returnDataType,
|
||||
boolean calledOnNullInput,
|
||||
String language,
|
||||
String body)
|
||||
{
|
||||
super(name, argTypes, returnType);
|
||||
assert new HashSet<>(argNames).size() == argNames.size() : "duplicate argument names";
|
||||
this.argNames = argNames;
|
||||
this.language = language;
|
||||
this.body = body;
|
||||
this.argCodecs = UDHelper.codecsFor(argDataTypes);
|
||||
this.returnCodec = UDHelper.codecFor(returnDataType);
|
||||
this.argumentTypes = UDFDataType.wrap(argTypes, !calledOnNullInput);
|
||||
this.resultType = UDFDataType.wrap(returnType, !calledOnNullInput);
|
||||
this.calledOnNullInput = calledOnNullInput;
|
||||
KeyspaceMetadata keyspaceMetadata = Schema.instance.getKeyspaceMetadata(name.keyspace);
|
||||
this.udfContext = new UDFContextImpl(argNames, argCodecs, returnCodec,
|
||||
keyspaceMetadata);
|
||||
this.udfContext = new UDFContextImpl(argNames, argumentTypes, resultType, keyspaceMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return FunctionArguments.newInstanceForUdf(version, argumentTypes);
|
||||
}
|
||||
|
||||
public static UDFunction tryCreate(FunctionName name,
|
||||
|
|
@ -294,12 +285,14 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
|
|||
return ImmediateExecutor.INSTANCE;
|
||||
}
|
||||
|
||||
protected Object executeAggregateUserDefined(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> parameters)
|
||||
@Override
|
||||
protected Object executeAggregateUserDefined(Object firstParam, Arguments arguments)
|
||||
{
|
||||
throw broken();
|
||||
}
|
||||
|
||||
public ByteBuffer executeUserDefined(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
@Override
|
||||
public ByteBuffer executeUserDefined(Arguments arguments)
|
||||
{
|
||||
throw broken();
|
||||
}
|
||||
|
|
@ -361,28 +354,29 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
|
|||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPure()
|
||||
{
|
||||
// Right now, we have no way to check if an UDF is pure. Due to that we consider them as non pure to avoid any risk.
|
||||
return false;
|
||||
}
|
||||
|
||||
public final ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
@Override
|
||||
public final ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
assertUdfsEnabled(language);
|
||||
|
||||
if (!isCallableWrtNullable(parameters))
|
||||
if (!isCallableWrtNullable(arguments))
|
||||
return null;
|
||||
|
||||
long tStart = nanoTime();
|
||||
parameters = makeEmptyParametersNull(parameters);
|
||||
|
||||
try
|
||||
{
|
||||
// Using async UDF execution is expensive (adds about 100us overhead per invocation on a Core-i7 MBPr).
|
||||
ByteBuffer result = DatabaseDescriptor.enableUserDefinedFunctionsThreads()
|
||||
? executeAsync(protocolVersion, parameters)
|
||||
: executeUserDefined(protocolVersion, parameters);
|
||||
? executeAsync(arguments)
|
||||
: executeUserDefined(arguments);
|
||||
|
||||
Tracing.trace("Executed UDF {} in {}\u03bcs", name(), (nanoTime() - tStart) / 1000);
|
||||
return result;
|
||||
|
|
@ -400,28 +394,21 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link ScalarFunction#execute(ProtocolVersion, List)} but the first parameter is already in non-serialized form.
|
||||
* Remaining parameters (2nd paramters and all others) are in {@code parameters}.
|
||||
* This is used to prevent superfluous (de)serialization of the state of aggregates.
|
||||
* Means: scalar functions of aggregates are called using this variant.
|
||||
*/
|
||||
public final Object executeForAggregate(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> parameters)
|
||||
public final Object executeForAggregate(Object state, Arguments arguments)
|
||||
{
|
||||
assertUdfsEnabled(language);
|
||||
|
||||
if (!calledOnNullInput && firstParam == null || !isCallableWrtNullable(parameters))
|
||||
if (!calledOnNullInput && state == null || !isCallableWrtNullable(arguments))
|
||||
return null;
|
||||
|
||||
long tStart = nanoTime();
|
||||
parameters = makeEmptyParametersNull(parameters);
|
||||
|
||||
try
|
||||
{
|
||||
// Using async UDF execution is expensive (adds about 100us overhead per invocation on a Core-i7 MBPr).
|
||||
Object result = DatabaseDescriptor.enableUserDefinedFunctionsThreads()
|
||||
? executeAggregateAsync(protocolVersion, firstParam, parameters)
|
||||
: executeAggregateUserDefined(protocolVersion, firstParam, parameters);
|
||||
? executeAggregateAsync(state, arguments)
|
||||
: executeAggregateUserDefined(state, arguments);
|
||||
Tracing.trace("Executed UDF {} in {}\u03bcs", name(), (nanoTime() - tStart) / 1000);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -477,29 +464,23 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
|
|||
}
|
||||
}
|
||||
|
||||
private ByteBuffer executeAsync(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
private ByteBuffer executeAsync(Arguments arguments)
|
||||
{
|
||||
ThreadIdAndCpuTime threadIdAndCpuTime = new ThreadIdAndCpuTime();
|
||||
|
||||
return async(threadIdAndCpuTime, () -> {
|
||||
threadIdAndCpuTime.setup();
|
||||
return executeUserDefined(protocolVersion, parameters);
|
||||
return executeUserDefined(arguments);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #executeAsync(ProtocolVersion, List)} but the first parameter is already in non-serialized form.
|
||||
* Remaining parameters (2nd paramters and all others) are in {@code parameters}.
|
||||
* This is used to prevent superfluous (de)serialization of the state of aggregates.
|
||||
* Means: scalar functions of aggregates are called using this variant.
|
||||
*/
|
||||
private Object executeAggregateAsync(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> parameters)
|
||||
private Object executeAggregateAsync(Object state, Arguments arguments)
|
||||
{
|
||||
ThreadIdAndCpuTime threadIdAndCpuTime = new ThreadIdAndCpuTime();
|
||||
|
||||
return async(threadIdAndCpuTime, () -> {
|
||||
threadIdAndCpuTime.setup();
|
||||
return executeAggregateUserDefined(protocolVersion, firstParam, parameters);
|
||||
return executeAggregateUserDefined(state, arguments);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -578,32 +559,16 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
|
|||
}
|
||||
}
|
||||
|
||||
private List<ByteBuffer> makeEmptyParametersNull(List<ByteBuffer> parameters)
|
||||
{
|
||||
List<ByteBuffer> r = new ArrayList<>(parameters.size());
|
||||
for (int i = 0; i < parameters.size(); i++)
|
||||
{
|
||||
ByteBuffer param = parameters.get(i);
|
||||
r.add(UDHelper.isNullOrEmpty(argTypes.get(i), param)
|
||||
? null : param);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
protected abstract ExecutorService executor();
|
||||
|
||||
public boolean isCallableWrtNullable(List<ByteBuffer> parameters)
|
||||
public boolean isCallableWrtNullable(Arguments arguments)
|
||||
{
|
||||
if (!calledOnNullInput)
|
||||
for (int i = 0; i < parameters.size(); i++)
|
||||
if (UDHelper.isNullOrEmpty(argTypes.get(i), parameters.get(i)))
|
||||
return false;
|
||||
return true;
|
||||
return calledOnNullInput || !arguments.containsNulls();
|
||||
}
|
||||
|
||||
protected abstract ByteBuffer executeUserDefined(ProtocolVersion protocolVersion, List<ByteBuffer> parameters);
|
||||
protected abstract ByteBuffer executeUserDefined(Arguments arguments);
|
||||
|
||||
protected abstract Object executeAggregateUserDefined(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> parameters);
|
||||
protected abstract Object executeAggregateUserDefined(Object firstParam, Arguments arguments);
|
||||
|
||||
public boolean isAggregate()
|
||||
{
|
||||
|
|
@ -630,23 +595,6 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
|
|||
return language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by UDF implementations (both Java code generated by {@link JavaBasedUDFunction}) to convert the C*
|
||||
* serialized representation to the Java object representation.
|
||||
*
|
||||
* @param protocolVersion the native protocol version used for serialization
|
||||
* @param argIndex index of the UDF input argument
|
||||
*/
|
||||
protected Object compose(ProtocolVersion protocolVersion, int argIndex, ByteBuffer value)
|
||||
{
|
||||
return compose(argCodecs, protocolVersion, argIndex, value);
|
||||
}
|
||||
|
||||
protected static Object compose(TypeCodec<Object>[] codecs, ProtocolVersion protocolVersion, int argIndex, ByteBuffer value)
|
||||
{
|
||||
return value == null ? null : UDHelper.deserialize(codecs[argIndex], protocolVersion, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by UDF implementations (both Java code generated by {@link JavaBasedUDFunction}) to convert the Java
|
||||
* object representation for the return value to the C* serialized representation.
|
||||
|
|
@ -655,12 +603,7 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
|
|||
*/
|
||||
protected ByteBuffer decompose(ProtocolVersion protocolVersion, Object value)
|
||||
{
|
||||
return decompose(returnCodec, protocolVersion, value);
|
||||
}
|
||||
|
||||
protected static ByteBuffer decompose(TypeCodec<Object> codec, ProtocolVersion protocolVersion, Object value)
|
||||
{
|
||||
return value == null ? null : UDHelper.serialize(codec, protocolVersion, value);
|
||||
return resultType.decompose(protocolVersion, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -746,7 +689,7 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
|
|||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Objects.hashCode(name, UserFunctions.typeHashCode(argTypes), UserFunctions.typeHashCode(returnType), returnType, language, body);
|
||||
return Objects.hashCode(name, UserFunctions.typeHashCode(argTypes), returnType, language, body);
|
||||
}
|
||||
|
||||
private static class UDFClassLoader extends ClassLoader
|
||||
|
|
|
|||
|
|
@ -1,143 +0,0 @@
|
|||
/*
|
||||
* 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.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.functions.types.*;
|
||||
import org.apache.cassandra.cql3.functions.types.exceptions.InvalidTypeException;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
* Helper class for User Defined Functions, Types and Aggregates.
|
||||
*/
|
||||
public final class UDHelper
|
||||
{
|
||||
private static final CodecRegistry codecRegistry = new CodecRegistry();
|
||||
|
||||
static TypeCodec<Object>[] codecsFor(DataType[] dataType)
|
||||
{
|
||||
TypeCodec<Object>[] codecs = new TypeCodec[dataType.length];
|
||||
for (int i = 0; i < dataType.length; i++)
|
||||
codecs[i] = codecFor(dataType[i]);
|
||||
return codecs;
|
||||
}
|
||||
|
||||
public static TypeCodec<Object> codecFor(DataType dataType)
|
||||
{
|
||||
return codecRegistry.codecFor(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an array containing the Java classes for the given {@link DataType}s.
|
||||
*
|
||||
* @param dataTypes array with UDF argument types
|
||||
* @param calledOnNullInput whether to allow {@code null} as an argument value
|
||||
* @return array of same size with UDF arguments
|
||||
*/
|
||||
public static TypeToken<?>[] typeTokens(TypeCodec<Object>[] dataTypes, boolean calledOnNullInput)
|
||||
{
|
||||
TypeToken<?>[] paramTypes = new TypeToken[dataTypes.length];
|
||||
for (int i = 0; i < paramTypes.length; i++)
|
||||
{
|
||||
TypeToken<?> typeToken = dataTypes[i].getJavaType();
|
||||
if (!calledOnNullInput)
|
||||
{
|
||||
// only care about classes that can be used in a data type
|
||||
Class<?> clazz = typeToken.getRawType();
|
||||
if (clazz == Integer.class)
|
||||
typeToken = TypeToken.of(int.class);
|
||||
else if (clazz == Long.class)
|
||||
typeToken = TypeToken.of(long.class);
|
||||
else if (clazz == Byte.class)
|
||||
typeToken = TypeToken.of(byte.class);
|
||||
else if (clazz == Short.class)
|
||||
typeToken = TypeToken.of(short.class);
|
||||
else if (clazz == Float.class)
|
||||
typeToken = TypeToken.of(float.class);
|
||||
else if (clazz == Double.class)
|
||||
typeToken = TypeToken.of(double.class);
|
||||
else if (clazz == Boolean.class)
|
||||
typeToken = TypeToken.of(boolean.class);
|
||||
}
|
||||
paramTypes[i] = typeToken;
|
||||
}
|
||||
return paramTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an array containing the {@link DataType}s for the
|
||||
* C* internal types.
|
||||
*
|
||||
* @param abstractTypes list with UDF argument types
|
||||
* @return array with argument types as {@link DataType}
|
||||
*/
|
||||
public static DataType[] driverTypes(List<AbstractType<?>> abstractTypes)
|
||||
{
|
||||
DataType[] argDataTypes = new DataType[abstractTypes.size()];
|
||||
for (int i = 0; i < argDataTypes.length; i++)
|
||||
argDataTypes[i] = driverType(abstractTypes.get(i));
|
||||
return argDataTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DataType} for the C* internal type.
|
||||
*/
|
||||
public static DataType driverType(AbstractType abstractType)
|
||||
{
|
||||
CQL3Type cqlType = abstractType.asCQL3Type();
|
||||
String abstractTypeDef = cqlType.getType().toString();
|
||||
return driverTypeFromAbstractType(abstractTypeDef);
|
||||
}
|
||||
|
||||
public static DataType driverTypeFromAbstractType(String abstractTypeDef)
|
||||
{
|
||||
return DataTypeClassNameParser.parseOne(abstractTypeDef,
|
||||
ProtocolVersion.CURRENT,
|
||||
codecRegistry);
|
||||
}
|
||||
|
||||
public static Object deserialize(TypeCodec<?> codec, ProtocolVersion protocolVersion, ByteBuffer value)
|
||||
{
|
||||
return codec.deserialize(value, protocolVersion);
|
||||
}
|
||||
|
||||
public static ByteBuffer serialize(TypeCodec<?> codec, ProtocolVersion protocolVersion, Object value)
|
||||
{
|
||||
if (!codec.getJavaType().getRawType().isAssignableFrom(value.getClass()))
|
||||
throw new InvalidTypeException("Invalid value for CQL type " + codec.getCqlType().getName());
|
||||
|
||||
return ((TypeCodec)codec).serialize(value, protocolVersion);
|
||||
}
|
||||
|
||||
public static Class<?> asJavaClass(TypeCodec<?> codec)
|
||||
{
|
||||
return codec.getJavaType().getRawType();
|
||||
}
|
||||
|
||||
public static boolean isNullOrEmpty(AbstractType<?> type, ByteBuffer bb)
|
||||
{
|
||||
return bb == null ||
|
||||
(bb.remaining() == 0 && type.isEmptyValueMeaningless());
|
||||
}
|
||||
}
|
||||
|
|
@ -22,7 +22,6 @@ import java.util.*;
|
|||
|
||||
import org.apache.cassandra.db.marshal.UUIDType;
|
||||
import org.apache.cassandra.serializers.UUIDSerializer;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
public abstract class UuidFcts
|
||||
{
|
||||
|
|
@ -33,7 +32,8 @@ public abstract class UuidFcts
|
|||
|
||||
public static final NativeFunction uuidFct = new NativeScalarFunction("uuid", UUIDType.instance)
|
||||
{
|
||||
public ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
return UUIDSerializer.instance.serialize(UUID.randomUUID());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import org.apache.cassandra.cql3.ColumnIdentifier;
|
|||
import org.apache.cassandra.cql3.CqlBuilder;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.Terms;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.Function;
|
||||
import org.apache.cassandra.cql3.functions.FunctionName;
|
||||
import org.apache.cassandra.cql3.functions.FunctionResolver;
|
||||
|
|
@ -64,7 +65,7 @@ import static org.apache.cassandra.cql3.statements.RequestValidations.invalidReq
|
|||
* CQL function actually has three arguments. The first argument is always ommitted when attaching the function to a
|
||||
* schema column. The value of that first argument is always the value of the masked column, in this case an int.
|
||||
*/
|
||||
public abstract class ColumnMask
|
||||
public class ColumnMask
|
||||
{
|
||||
public static final String DISABLED_ERROR_MESSAGE = "Cannot mask columns because dynamic data masking is not " +
|
||||
"enabled. You can enable it with the " +
|
||||
|
|
@ -76,20 +77,13 @@ public abstract class ColumnMask
|
|||
/** The values of the arguments of the partially applied masking function. */
|
||||
protected final ByteBuffer[] partialArgumentValues;
|
||||
|
||||
private ColumnMask(ScalarFunction function, ByteBuffer... partialArgumentValues)
|
||||
public ColumnMask(ScalarFunction function, ByteBuffer... partialArgumentValues)
|
||||
{
|
||||
assert function.argTypes().size() == partialArgumentValues.length + 1;
|
||||
this.function = function;
|
||||
this.partialArgumentValues = partialArgumentValues;
|
||||
}
|
||||
|
||||
public static ColumnMask build(ScalarFunction function, ByteBuffer... partialArgumentValues)
|
||||
{
|
||||
return function.isNative()
|
||||
? new Native((MaskingFunction) function, partialArgumentValues)
|
||||
: new Custom(function, partialArgumentValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The types of the arguments of the partially applied masking function, as an unmodifiable list.
|
||||
*/
|
||||
|
|
@ -122,23 +116,37 @@ public abstract class ColumnMask
|
|||
.build();
|
||||
Function newFunction = FunctionResolver.get(function.name().keyspace, function.name(), args, null, null, null);
|
||||
assert newFunction != null;
|
||||
return build((ScalarFunction) newFunction, partialArgumentValues);
|
||||
return new ColumnMask((ScalarFunction) newFunction, partialArgumentValues);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param protocolVersion the used version of the transport protocol
|
||||
* @param value a column value to be masked
|
||||
* @return the specified value after having been masked by the masked function
|
||||
* @param version the used version of the transport protocol
|
||||
* @return a masker instance that caches the terminal masking function arguments
|
||||
*/
|
||||
public ByteBuffer mask(ProtocolVersion protocolVersion, ByteBuffer value)
|
||||
public Masker masker(ProtocolVersion version)
|
||||
{
|
||||
if (!DatabaseDescriptor.getDynamicDataMaskingEnabled())
|
||||
return value;
|
||||
|
||||
return maskInternal(protocolVersion, value);
|
||||
return new Masker(version, function, partialArgumentValues);
|
||||
}
|
||||
|
||||
protected abstract ByteBuffer maskInternal(ProtocolVersion protocolVersion, ByteBuffer value);
|
||||
public static class Masker
|
||||
{
|
||||
private final ScalarFunction function;
|
||||
private final Arguments arguments;
|
||||
|
||||
private Masker(ProtocolVersion version, ScalarFunction function, ByteBuffer[] partialArgumentValues)
|
||||
{
|
||||
this.function = function;
|
||||
arguments = function.newArguments(version);
|
||||
for (int i = 0; i < partialArgumentValues.length; i++)
|
||||
arguments.set(i + 1, partialArgumentValues[i]);
|
||||
}
|
||||
|
||||
public ByteBuffer mask(ByteBuffer value)
|
||||
{
|
||||
arguments.set(0, value);
|
||||
return function.execute(arguments);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ensureEnabled()
|
||||
{
|
||||
|
|
@ -183,57 +191,6 @@ public abstract class ColumnMask
|
|||
builder.append(" MASKED WITH ").append(toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ColumnMask} for native masking functions.
|
||||
*/
|
||||
private static class Native extends ColumnMask
|
||||
{
|
||||
private final MaskingFunction.Masker masker;
|
||||
|
||||
public Native(MaskingFunction function, ByteBuffer... partialArgumentValues)
|
||||
{
|
||||
super(function, partialArgumentValues);
|
||||
masker = function.masker(partialArgumentValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteBuffer maskInternal(ProtocolVersion protocolVersion, ByteBuffer value)
|
||||
{
|
||||
return masker.mask(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ColumnMask} for user-defined masking functions.
|
||||
*/
|
||||
private static class Custom extends ColumnMask
|
||||
{
|
||||
public Custom(ScalarFunction function, ByteBuffer... partialArgumentValues)
|
||||
{
|
||||
super(function, partialArgumentValues);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ByteBuffer maskInternal(ProtocolVersion protocolVersion, ByteBuffer value)
|
||||
{
|
||||
List<ByteBuffer> argumentValues;
|
||||
int numPartialArgs = partialArgumentValues.length;
|
||||
if (numPartialArgs == 0)
|
||||
{
|
||||
argumentValues = Collections.singletonList(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ByteBuffer[] args = new ByteBuffer[numPartialArgs + 1];
|
||||
args[0] = value;
|
||||
System.arraycopy(partialArgumentValues, 0, args, 1, numPartialArgs);
|
||||
argumentValues = Arrays.asList(args);
|
||||
}
|
||||
|
||||
return function.execute(protocolVersion, argumentValues);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A parsed but not prepared column mask.
|
||||
*/
|
||||
|
|
@ -252,7 +209,7 @@ public abstract class ColumnMask
|
|||
{
|
||||
ScalarFunction function = findMaskingFunction(keyspace, table, column, type);
|
||||
ByteBuffer[] partialArguments = preparePartialArguments(keyspace, function);
|
||||
return ColumnMask.build(function, partialArguments);
|
||||
return new ColumnMask(function, partialArguments);
|
||||
}
|
||||
|
||||
private ScalarFunction findMaskingFunction(String keyspace, String table, ColumnIdentifier column, AbstractType<?> type)
|
||||
|
|
|
|||
|
|
@ -21,11 +21,15 @@ package org.apache.cassandra.cql3.functions.masking;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.FunctionArguments;
|
||||
import org.apache.cassandra.cql3.functions.FunctionFactory;
|
||||
import org.apache.cassandra.cql3.functions.FunctionName;
|
||||
import org.apache.cassandra.cql3.functions.FunctionParameter;
|
||||
import org.apache.cassandra.cql3.functions.NativeFunction;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
* A {@link MaskingFunction} that returns a fixed replacement value for the data type of its single argument.
|
||||
|
|
@ -40,34 +44,24 @@ public class DefaultMaskingFunction extends MaskingFunction
|
|||
{
|
||||
public static final String NAME = "default";
|
||||
|
||||
private final Masker masker;
|
||||
AbstractType<?> inputType;
|
||||
|
||||
private <T> DefaultMaskingFunction(FunctionName name, AbstractType<T> inputType)
|
||||
private DefaultMaskingFunction(FunctionName name, AbstractType<?> inputType)
|
||||
{
|
||||
super(name, inputType, inputType);
|
||||
masker = new Masker(inputType);
|
||||
this.inputType = inputType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Masker masker(ByteBuffer... parameters)
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return masker;
|
||||
return FunctionArguments.newNoopInstance(version, 1);
|
||||
}
|
||||
|
||||
private static class Masker implements MaskingFunction.Masker
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments) throws InvalidRequestException
|
||||
{
|
||||
private final ByteBuffer defaultValue;
|
||||
|
||||
private Masker(AbstractType<?> inputType)
|
||||
{
|
||||
defaultValue = inputType.getMaskedValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer mask(ByteBuffer value)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
return inputType.getMaskedValue();
|
||||
}
|
||||
|
||||
/** @return a {@link FunctionFactory} to build new {@link DefaultMaskingFunction}s. */
|
||||
|
|
|
|||
|
|
@ -22,22 +22,25 @@ import java.nio.ByteBuffer;
|
|||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.FunctionArguments;
|
||||
import org.apache.cassandra.cql3.functions.FunctionFactory;
|
||||
import org.apache.cassandra.cql3.functions.FunctionName;
|
||||
import org.apache.cassandra.cql3.functions.FunctionParameter;
|
||||
import org.apache.cassandra.cql3.functions.NativeFunction;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.BytesType;
|
||||
import org.apache.cassandra.db.marshal.StringType;
|
||||
import org.apache.cassandra.db.marshal.UTF8Type;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
/**
|
||||
|
|
@ -50,61 +53,42 @@ public class HashMaskingFunction extends MaskingFunction
|
|||
public static final String NAME = "hash";
|
||||
|
||||
/** The default hashing algorithm to be used if no other algorithm is specified in the call to the function. */
|
||||
public static final String DEFAULT_ALGORITHM = "SHA-256";
|
||||
public static final ByteBuffer DEFAULT_ALGORITHM = UTF8Type.instance.decompose("SHA-256");
|
||||
|
||||
/**
|
||||
* All the created digests that we use to generate the hash, so we don't need to get them on every call.
|
||||
* We use the serialized algorithm as key, so we don't have to deserialize it for getting a cache hit.
|
||||
*/
|
||||
private static final Map<ByteBuffer, MessageDigest> DIGESTS = new ConcurrentHashMap<>();
|
||||
|
||||
// The default message digest is lazily built to prevent a failure during server startup if the algorithm is not
|
||||
// available. That way, if the algorithm is not found only the calls to the function will fail.
|
||||
private static final Supplier<MessageDigest> DEFAULT_DIGEST = Suppliers.memoize(() -> messageDigest(DEFAULT_ALGORITHM));
|
||||
private static final AbstractType<?>[] DEFAULT_ARGUMENTS = {};
|
||||
private static final AbstractType<?>[] ARGUMENTS_WITH_ALGORITHM = new AbstractType<?>[]{ UTF8Type.instance };
|
||||
|
||||
/** The type of the supplied algorithm argument, {@code null} if that argument isn't supplied. */
|
||||
@Nullable
|
||||
private final StringType algorithmArgumentType;
|
||||
|
||||
private HashMaskingFunction(FunctionName name, AbstractType<?> inputType, @Nullable StringType algorithmArgumentType)
|
||||
private HashMaskingFunction(FunctionName name, AbstractType<?> inputType, boolean hasAlgorithmArgument)
|
||||
{
|
||||
super(name, BytesType.instance, inputType, argumentsType(algorithmArgumentType));
|
||||
this.algorithmArgumentType = algorithmArgumentType;
|
||||
}
|
||||
|
||||
private static AbstractType<?>[] argumentsType(@Nullable StringType algorithmArgumentType)
|
||||
{
|
||||
// the algorithm argument is optional, so we will have different signatures depending on whether that argument
|
||||
// is supplied or not
|
||||
return algorithmArgumentType == null
|
||||
? DEFAULT_ARGUMENTS
|
||||
: new AbstractType<?>[]{ algorithmArgumentType };
|
||||
super(name, BytesType.instance, inputType, hasAlgorithmArgument ? ARGUMENTS_WITH_ALGORITHM : DEFAULT_ARGUMENTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Masker masker(ByteBuffer... parameters)
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return new Masker(algorithmArgumentType, parameters);
|
||||
return new FunctionArguments(version,
|
||||
ArgumentDeserializer.NOOP_DESERIALIZER, // the value to be masked
|
||||
(v, b) -> messageDigest(b)); // the algorithm, if any
|
||||
}
|
||||
|
||||
private static class Masker implements MaskingFunction.Masker
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments) throws InvalidRequestException
|
||||
{
|
||||
private final MessageDigest digest;
|
||||
ByteBuffer value = arguments.get(0);
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
private Masker(StringType algorithmArgumentType, ByteBuffer... parameters)
|
||||
{
|
||||
if (algorithmArgumentType == null || parameters[0] == null)
|
||||
{
|
||||
digest = DEFAULT_DIGEST.get();
|
||||
}
|
||||
else
|
||||
{
|
||||
String algorithm = algorithmArgumentType.compose(parameters[0]);
|
||||
digest = messageDigest(algorithm);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer mask(ByteBuffer value)
|
||||
{
|
||||
return HashMaskingFunction.hash(digest, value);
|
||||
}
|
||||
MessageDigest digest = arguments.get(1);
|
||||
if (digest == null)
|
||||
digest = messageDigest(DEFAULT_ALGORITHM);
|
||||
|
||||
return HashMaskingFunction.hash(digest, value);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
|
@ -118,6 +102,19 @@ public class HashMaskingFunction extends MaskingFunction
|
|||
return BytesType.instance.compose(ByteBuffer.wrap(hash));
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static MessageDigest messageDigest(@Nullable ByteBuffer algorithm)
|
||||
{
|
||||
ByteBuffer cacheKey = algorithm == null ? DEFAULT_ALGORITHM : algorithm;
|
||||
MessageDigest digest = DIGESTS.get(cacheKey);
|
||||
if (digest == null)
|
||||
{
|
||||
digest = messageDigest(UTF8Type.instance.compose(cacheKey));
|
||||
DIGESTS.put(cacheKey.duplicate(), digest);
|
||||
}
|
||||
return digest;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static MessageDigest messageDigest(String algorithm)
|
||||
{
|
||||
|
|
@ -144,9 +141,9 @@ public class HashMaskingFunction extends MaskingFunction
|
|||
switch (argTypes.size())
|
||||
{
|
||||
case 1:
|
||||
return new HashMaskingFunction(name, argTypes.get(0), null);
|
||||
return new HashMaskingFunction(name, argTypes.get(0), false);
|
||||
case 2:
|
||||
return new HashMaskingFunction(name, argTypes.get(0), UTF8Type.instance);
|
||||
return new HashMaskingFunction(name, argTypes.get(0), true);
|
||||
default:
|
||||
throw invalidNumberOfArgumentsException();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,6 @@
|
|||
|
||||
package org.apache.cassandra.cql3.functions.masking;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ObjectArrays;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.FunctionFactory;
|
||||
|
|
@ -28,7 +25,6 @@ import org.apache.cassandra.cql3.functions.FunctionName;
|
|||
import org.apache.cassandra.cql3.functions.FunctionParameter;
|
||||
import org.apache.cassandra.cql3.functions.NativeScalarFunction;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
* A {@link NativeScalarFunction} that totally or partially replaces the original value of a column value,
|
||||
|
|
@ -56,33 +52,6 @@ public abstract class MaskingFunction extends NativeScalarFunction
|
|||
super(name.name, outputType, ObjectArrays.concat(inputType, argsType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ByteBuffer execute(ProtocolVersion protocolVersion, List<ByteBuffer> parameters)
|
||||
{
|
||||
ByteBuffer[] partialParameters = new ByteBuffer[parameters.size() - 1];
|
||||
for (int i = 0; i < partialParameters.length; i++)
|
||||
partialParameters[i] = parameters.get(i + 1);
|
||||
|
||||
return masker(partialParameters).mask(parameters.get(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link Masker} for the specified masking parameters.
|
||||
* This is meant to be used by {@link ColumnMask}, so it doesn't need to evaluate the arguments on every call.
|
||||
*
|
||||
* @param parameters the masking parameters in the function call.
|
||||
* @return a new {@link Masker} using the specified masking arguments
|
||||
*/
|
||||
public abstract Masker masker(ByteBuffer... parameters);
|
||||
|
||||
/**
|
||||
* Class that actually makes the masking of the first function parameter according to the masking arguments.
|
||||
*/
|
||||
public interface Masker
|
||||
{
|
||||
public ByteBuffer mask(ByteBuffer value);
|
||||
}
|
||||
|
||||
protected static abstract class Factory extends FunctionFactory
|
||||
{
|
||||
public Factory(String name, FunctionParameter... parameters)
|
||||
|
|
|
|||
|
|
@ -21,11 +21,15 @@ package org.apache.cassandra.cql3.functions.masking;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.FunctionArguments;
|
||||
import org.apache.cassandra.cql3.functions.FunctionFactory;
|
||||
import org.apache.cassandra.cql3.functions.FunctionName;
|
||||
import org.apache.cassandra.cql3.functions.FunctionParameter;
|
||||
import org.apache.cassandra.cql3.functions.NativeFunction;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
* A {@link MaskingFunction} that always returns a {@code null} column. The returned value is always an absent column,
|
||||
|
|
@ -37,7 +41,6 @@ import org.apache.cassandra.db.marshal.AbstractType;
|
|||
public class NullMaskingFunction extends MaskingFunction
|
||||
{
|
||||
public static final String NAME = "null";
|
||||
private static final Masker MASKER = new Masker();
|
||||
|
||||
private NullMaskingFunction(FunctionName name, AbstractType<?> inputType)
|
||||
{
|
||||
|
|
@ -45,18 +48,15 @@ public class NullMaskingFunction extends MaskingFunction
|
|||
}
|
||||
|
||||
@Override
|
||||
public Masker masker(ByteBuffer... parameters)
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return MASKER;
|
||||
return FunctionArguments.newNoopInstance(version, 1);
|
||||
}
|
||||
|
||||
private static class Masker implements MaskingFunction.Masker
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments) throws InvalidRequestException
|
||||
{
|
||||
@Override
|
||||
public ByteBuffer mask(ByteBuffer value)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return a {@link FunctionFactory} to build new {@link NullMaskingFunction}s. */
|
||||
|
|
|
|||
|
|
@ -23,12 +23,14 @@ import java.util.Collection;
|
|||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.FunctionArguments;
|
||||
import org.apache.cassandra.cql3.functions.FunctionFactory;
|
||||
import org.apache.cassandra.cql3.functions.FunctionName;
|
||||
import org.apache.cassandra.cql3.functions.FunctionParameter;
|
||||
|
|
@ -37,10 +39,13 @@ import org.apache.cassandra.db.marshal.AbstractType;
|
|||
import org.apache.cassandra.db.marshal.Int32Type;
|
||||
import org.apache.cassandra.db.marshal.UTF8Type;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
/**
|
||||
* A {@link MaskingFunction} applied to a {@link org.apache.cassandra.db.marshal.StringType} value that,
|
||||
* depending on {@link Type}:
|
||||
* depending on {@link Kind}:
|
||||
* <ul>
|
||||
* <li>Replaces each character between the supplied positions by the supplied padding character. In other words,
|
||||
* it will mask all the characters except the first m and last n.</li>
|
||||
|
|
@ -55,25 +60,38 @@ public class PartialMaskingFunction extends MaskingFunction
|
|||
public static final char DEFAULT_PADDING_CHAR = '*';
|
||||
|
||||
/** The type of partial masking to perform, inner or outer. */
|
||||
private final Type type;
|
||||
private final Kind kind;
|
||||
|
||||
/** The original type of the masked value. */
|
||||
private final AbstractType<String> inputType;
|
||||
|
||||
/** Whether a padding argument hab been supplied. */
|
||||
@Nullable
|
||||
private final boolean hasPaddingArgument;
|
||||
/** The custom argument deserializer for the padding character. */
|
||||
private final ArgumentDeserializer paddingArgumentDeserializer;
|
||||
|
||||
private PartialMaskingFunction(FunctionName name,
|
||||
Type type,
|
||||
Kind kind,
|
||||
AbstractType<String> inputType,
|
||||
boolean hasPaddingArgument)
|
||||
{
|
||||
super(name, inputType, inputType, argumentsType(hasPaddingArgument));
|
||||
|
||||
this.type = type;
|
||||
this.kind = kind;
|
||||
this.inputType = inputType;
|
||||
this.hasPaddingArgument = hasPaddingArgument;
|
||||
|
||||
paddingArgumentDeserializer = (version, buffer) -> {
|
||||
|
||||
if (buffer == null || !hasPaddingArgument)
|
||||
return null;
|
||||
|
||||
String arg = UTF8Type.instance.compose(buffer);
|
||||
if (arg.length() != 1)
|
||||
{
|
||||
throw new InvalidRequestException(format("The padding argument for function %s should " +
|
||||
"be single-character, but '%s' has %d characters.",
|
||||
name, arg, arg.length()));
|
||||
}
|
||||
return arg.charAt(0);
|
||||
};
|
||||
}
|
||||
|
||||
private static AbstractType<?>[] argumentsType(boolean hasPaddingArgument)
|
||||
|
|
@ -87,56 +105,31 @@ public class PartialMaskingFunction extends MaskingFunction
|
|||
}
|
||||
|
||||
@Override
|
||||
public Masker masker(ByteBuffer... parameters)
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return new Masker(parameters);
|
||||
return new FunctionArguments(version,
|
||||
inputType.getArgumentDeserializer(),
|
||||
Int32Type.instance.getArgumentDeserializer(),
|
||||
Int32Type.instance.getArgumentDeserializer(),
|
||||
paddingArgumentDeserializer);
|
||||
}
|
||||
|
||||
private class Masker implements MaskingFunction.Masker
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments) throws InvalidRequestException
|
||||
{
|
||||
private final int begin, end;
|
||||
private final char padding;
|
||||
String value = arguments.get(0);
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
private Masker(ByteBuffer... parameters)
|
||||
{
|
||||
// Parse the beginning and end positions. No validation is needed since the masker accepts negatives,
|
||||
// but we should consider that the arguments migh be null.
|
||||
begin = parameters[0] == null ? 0 : Int32Type.instance.compose(parameters[0]);
|
||||
end = parameters[1] == null ? 0 : Int32Type.instance.compose(parameters[1]);
|
||||
int begin = arguments.get(1) != null ? arguments.getAsInt(1) : 0;
|
||||
int end = arguments.get(2) != null ? arguments.getAsInt(2) : 0;
|
||||
char padding = arguments.get(3) == null ? DEFAULT_PADDING_CHAR : arguments.get(3);
|
||||
|
||||
// Parse the padding character. The type of the argument is a string of any length because we don't have a
|
||||
// character type in CQL, so we should verify that the passed string argument is single-character.
|
||||
if (hasPaddingArgument && parameters[2] != null)
|
||||
{
|
||||
String parameter = UTF8Type.instance.compose(parameters[2]);
|
||||
if (parameter.length() != 1)
|
||||
{
|
||||
throw new InvalidRequestException(String.format("The padding argument for function %s should " +
|
||||
"be single-character, but '%s' has %d characters.",
|
||||
name(), parameter, parameter.length()));
|
||||
}
|
||||
padding = parameter.charAt(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
padding = DEFAULT_PADDING_CHAR;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer mask(ByteBuffer value)
|
||||
{
|
||||
// Null column values aren't masked
|
||||
if (value == null)
|
||||
return null;
|
||||
|
||||
String stringValue = inputType.compose(value);
|
||||
String maskedValue = type.mask(stringValue, begin, end, padding);
|
||||
return inputType.decompose(maskedValue);
|
||||
}
|
||||
String maskedValue = kind.mask(value, begin, end, padding);
|
||||
return inputType.decompose(maskedValue);
|
||||
}
|
||||
|
||||
public enum Type
|
||||
public enum Kind
|
||||
{
|
||||
/** Masks everything except the first {@code begin} and last {@code end} characters. */
|
||||
INNER
|
||||
|
|
@ -181,14 +174,14 @@ public class PartialMaskingFunction extends MaskingFunction
|
|||
/** @return a collection of function factories to build new {@code PartialMaskingFunction} functions. */
|
||||
public static Collection<FunctionFactory> factories()
|
||||
{
|
||||
return Stream.of(Type.values())
|
||||
return Stream.of(Kind.values())
|
||||
.map(PartialMaskingFunction::factory)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private static FunctionFactory factory(Type type)
|
||||
private static FunctionFactory factory(Kind kind)
|
||||
{
|
||||
return new MaskingFunction.Factory(type.name(),
|
||||
return new MaskingFunction.Factory(kind.name(),
|
||||
FunctionParameter.string(),
|
||||
FunctionParameter.fixed(CQL3Type.Native.INT),
|
||||
FunctionParameter.fixed(CQL3Type.Native.INT),
|
||||
|
|
@ -199,7 +192,7 @@ public class PartialMaskingFunction extends MaskingFunction
|
|||
protected NativeFunction doGetOrCreateFunction(List<AbstractType<?>> argTypes, AbstractType<?> receiverType)
|
||||
{
|
||||
AbstractType<String> inputType = (AbstractType<String>) argTypes.get(0);
|
||||
return new PartialMaskingFunction(name, type, inputType, argTypes.size() == 4);
|
||||
return new PartialMaskingFunction(name, kind, inputType, argTypes.size() == 4);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,11 +21,15 @@ package org.apache.cassandra.cql3.functions.masking;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.FunctionArguments;
|
||||
import org.apache.cassandra.cql3.functions.FunctionFactory;
|
||||
import org.apache.cassandra.cql3.functions.FunctionName;
|
||||
import org.apache.cassandra.cql3.functions.FunctionParameter;
|
||||
import org.apache.cassandra.cql3.functions.NativeFunction;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
* A {@link MaskingFunction} that replaces the specified column value by a certain replacement value.
|
||||
|
|
@ -44,25 +48,15 @@ public class ReplaceMaskingFunction extends MaskingFunction
|
|||
}
|
||||
|
||||
@Override
|
||||
public Masker masker(ByteBuffer... parameters)
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return new Masker(parameters[0]);
|
||||
return FunctionArguments.newNoopInstance(version, 2);
|
||||
}
|
||||
|
||||
private static class Masker implements MaskingFunction.Masker
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments) throws InvalidRequestException
|
||||
{
|
||||
private final ByteBuffer replacement;
|
||||
|
||||
private Masker(ByteBuffer replacement)
|
||||
{
|
||||
this.replacement = replacement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer mask(ByteBuffer value)
|
||||
{
|
||||
return replacement;
|
||||
}
|
||||
return arguments.get(1);
|
||||
}
|
||||
|
||||
/** @return a {@link FunctionFactory} to build new {@link ReplaceMaskingFunction}s. */
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ package org.apache.cassandra.cql3.selection;
|
|||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
|
|
@ -28,6 +27,7 @@ import com.google.common.collect.Iterables;
|
|||
|
||||
import org.apache.commons.lang3.text.StrBuilder;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.FunctionResolver;
|
||||
import org.apache.cassandra.schema.ColumnMetadata;
|
||||
import org.apache.cassandra.schema.TableMetadata;
|
||||
|
|
@ -55,6 +55,10 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
|
|||
{
|
||||
protected Selector deserialize(DataInputPlus in, int version, TableMetadata metadata) throws IOException
|
||||
{
|
||||
// The selector will only be deserialized on the replicas for GROUP BY queries. Due to that we
|
||||
// can safely use the current protocol version.
|
||||
final ProtocolVersion protocolVersion = ProtocolVersion.CURRENT;
|
||||
|
||||
FunctionName name = new FunctionName(in.readUTF(), in.readUTF());
|
||||
|
||||
int numberOfArguments = in.readUnsignedVInt32();
|
||||
|
|
@ -74,19 +78,27 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
|
|||
.collect(joining(", "))));
|
||||
|
||||
boolean isPartial = in.readBoolean();
|
||||
// if the function is partial we need to retrieve the resolved arguments.
|
||||
// The resolved arguments are encoded as follow: [vint]([vint][bytes])*
|
||||
// The first vint contains the bitset used to determine which arguments were resolved.
|
||||
// A bit equals to one meaning a resolved argument.
|
||||
// The arguments are encoded as [vint][bytes] where the vint contains the size in bytes of the
|
||||
// argument.
|
||||
if (isPartial)
|
||||
{
|
||||
// We use a bitset to track the position of the unresolved arguments
|
||||
int bitset = in.readUnsignedVInt32();
|
||||
List<ByteBuffer> partialParameters = new ArrayList<>(numberOfArguments);
|
||||
List<ByteBuffer> partialArguments = new ArrayList<>(numberOfArguments);
|
||||
for (int i = 0; i < numberOfArguments; i++)
|
||||
{
|
||||
ByteBuffer parameter = ((bitset & 1) == 1) ? ByteBufferUtil.readWithVIntLength(in)
|
||||
: Function.UNRESOLVED;
|
||||
partialParameters.add(parameter);
|
||||
boolean isArgumentResolved = getRightMostBit(bitset) == 1;
|
||||
ByteBuffer argument = isArgumentResolved ? ByteBufferUtil.readWithVIntLength(in)
|
||||
: Function.UNRESOLVED;
|
||||
partialArguments.add(argument);
|
||||
bitset >>= 1;
|
||||
}
|
||||
|
||||
function = ((ScalarFunction) function).partialApplication(ProtocolVersion.CURRENT, partialParameters);
|
||||
function = ((ScalarFunction) function).partialApplication(protocolVersion, partialArguments);
|
||||
}
|
||||
|
||||
int numberOfRemainingArguments = in.readUnsignedVInt32();
|
||||
|
|
@ -96,10 +108,22 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
|
|||
argSelectors.add(Selector.serializer.deserialize(in, version, metadata));
|
||||
}
|
||||
|
||||
return newFunctionSelector(function, argSelectors);
|
||||
return newFunctionSelector(protocolVersion, function, argSelectors);
|
||||
}
|
||||
|
||||
protected abstract Selector newFunctionSelector(Function function, List<Selector> argSelectors);
|
||||
/**
|
||||
* Returns the value of the right most bit.
|
||||
* @param bitset the bitset
|
||||
* @return the value of the right most bit
|
||||
*/
|
||||
private int getRightMostBit(int bitset)
|
||||
{
|
||||
return bitset & 1;
|
||||
}
|
||||
|
||||
protected abstract Selector newFunctionSelector(ProtocolVersion version,
|
||||
Function function,
|
||||
List<Selector> argSelectors);
|
||||
}
|
||||
|
||||
protected final T fun;
|
||||
|
|
@ -108,7 +132,7 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
|
|||
* The list used to pass the function arguments is recycled to avoid the cost of instantiating a new list
|
||||
* with each function call.
|
||||
*/
|
||||
private final List<ByteBuffer> args;
|
||||
private final Arguments args;
|
||||
protected final List<Selector> argSelectors;
|
||||
|
||||
public static Factory newFactory(final Function fun, final SelectorFactories factories) throws InvalidRequestException
|
||||
|
|
@ -154,7 +178,7 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
|
|||
|
||||
public Selector newInstance(QueryOptions options) throws InvalidRequestException
|
||||
{
|
||||
return fun.isAggregate() ? new AggregateFunctionSelector(fun, factories.newInstances(options))
|
||||
return fun.isAggregate() ? new AggregateFunctionSelector(options.getProtocolVersion(), fun, factories.newInstances(options))
|
||||
: createScalarSelector(options, (ScalarFunction) fun, factories.newInstances(options));
|
||||
}
|
||||
|
||||
|
|
@ -179,21 +203,25 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
|
|||
}
|
||||
|
||||
if (terminalCount == 0)
|
||||
return new ScalarFunctionSelector(fun, argSelectors);
|
||||
return new ScalarFunctionSelector(version, fun, argSelectors);
|
||||
|
||||
// All terminal, reduce to a simple value if the function is pure
|
||||
if (terminalCount == argSelectors.size() && function.isPure())
|
||||
return new TermSelector(function.execute(version, terminalArgs), function.returnType());
|
||||
|
||||
// We have some terminal arguments but not all, do a partial application
|
||||
// We have some terminal arguments, do a partial application
|
||||
ScalarFunction partialFunction = function.partialApplication(version, terminalArgs);
|
||||
|
||||
// If all the arguments are terminal and the function is pure we can reduce to a simple value.
|
||||
if (terminalCount == argSelectors.size() && fun.isPure())
|
||||
{
|
||||
Arguments arguments = partialFunction.newArguments(version);
|
||||
return new TermSelector(partialFunction.execute(arguments), partialFunction.returnType());
|
||||
}
|
||||
|
||||
List<Selector> remainingSelectors = new ArrayList<>(argSelectors.size() - terminalCount);
|
||||
for (Selector selector : argSelectors)
|
||||
{
|
||||
if (!selector.isTerminal())
|
||||
remainingSelectors.add(selector);
|
||||
}
|
||||
return new ScalarFunctionSelector(partialFunction, remainingSelectors);
|
||||
return new ScalarFunctionSelector(version, partialFunction, remainingSelectors);
|
||||
}
|
||||
|
||||
public boolean isWritetimeSelectorFactory()
|
||||
|
|
@ -226,12 +254,12 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
|
|||
};
|
||||
}
|
||||
|
||||
protected AbstractFunctionSelector(Kind kind, T fun, List<Selector> argSelectors)
|
||||
protected AbstractFunctionSelector(Kind kind, ProtocolVersion version, T fun, List<Selector> argSelectors)
|
||||
{
|
||||
super(kind);
|
||||
this.fun = fun;
|
||||
this.argSelectors = argSelectors;
|
||||
this.args = Arrays.asList(new ByteBuffer[argSelectors.size()]);
|
||||
this.args = fun.newArguments(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -249,7 +277,7 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
|
|||
args.set(i, value);
|
||||
}
|
||||
|
||||
protected List<ByteBuffer> args()
|
||||
protected Arguments args()
|
||||
{
|
||||
return args;
|
||||
}
|
||||
|
|
@ -311,14 +339,14 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
|
|||
|
||||
if (isPartial)
|
||||
{
|
||||
List<ByteBuffer> partialParameters = ((PartialScalarFunction) fun).getPartialParameters();
|
||||
List<ByteBuffer> partialArguments = ((PartialScalarFunction) fun).getPartialArguments();
|
||||
|
||||
// We use a bitset to track the position of the unresolved arguments
|
||||
size += TypeSizes.sizeofUnsignedVInt(computeBitSet(partialParameters));
|
||||
size += TypeSizes.sizeofUnsignedVInt(computeBitSet(partialArguments));
|
||||
|
||||
for (int i = 0, m = partialParameters.size(); i < m; i++)
|
||||
for (int i = 0, m = partialArguments.size(); i < m; i++)
|
||||
{
|
||||
ByteBuffer buffer = partialParameters.get(i);
|
||||
ByteBuffer buffer = partialArguments.get(i);
|
||||
if (buffer != Function.UNRESOLVED)
|
||||
size += ByteBufferUtil.serializedSizeWithVIntLength(buffer);
|
||||
}
|
||||
|
|
@ -353,14 +381,14 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
|
|||
|
||||
if (isPartial)
|
||||
{
|
||||
List<ByteBuffer> partialParameters = ((PartialScalarFunction) fun).getPartialParameters();
|
||||
List<ByteBuffer> partialArguments = ((PartialScalarFunction) fun).getPartialArguments();
|
||||
|
||||
// We use a bitset to track the position of the unresolved arguments
|
||||
out.writeUnsignedVInt32(computeBitSet(partialParameters));
|
||||
out.writeUnsignedVInt32(computeBitSet(partialArguments));
|
||||
|
||||
for (int i = 0, m = partialParameters.size(); i < m; i++)
|
||||
for (int i = 0, m = partialArguments.size(); i < m; i++)
|
||||
{
|
||||
ByteBuffer buffer = partialParameters.get(i);
|
||||
ByteBuffer buffer = partialArguments.get(i);
|
||||
if (buffer != Function.UNRESOLVED)
|
||||
ByteBufferUtil.writeWithVIntLength(buffer, out);
|
||||
}
|
||||
|
|
@ -372,13 +400,13 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
|
|||
serializer.serialize(argSelectors.get(i), out, version);
|
||||
}
|
||||
|
||||
private int computeBitSet(List<ByteBuffer> partialParameters)
|
||||
private int computeBitSet(List<ByteBuffer> partialArguments)
|
||||
{
|
||||
assert partialParameters.size() <= 32 : "cannot serialize partial function with more than 32 parameters";
|
||||
assert partialArguments.size() <= 32 : "cannot serialize partial function with more than 32 arguments";
|
||||
int bitset = 0;
|
||||
for (int i = 0, m = partialParameters.size(); i < m; i++)
|
||||
for (int i = 0, m = partialArguments.size(); i < m; i++)
|
||||
{
|
||||
if (partialParameters.get(i) != Function.UNRESOLVED)
|
||||
if (partialArguments.get(i) != Function.UNRESOLVED)
|
||||
bitset |= 1 << i;
|
||||
}
|
||||
return bitset;
|
||||
|
|
|
|||
|
|
@ -27,12 +27,12 @@ import org.apache.cassandra.transport.ProtocolVersion;
|
|||
|
||||
final class AggregateFunctionSelector extends AbstractFunctionSelector<AggregateFunction>
|
||||
{
|
||||
protected static final SelectorDeserializer deserializer = new AbstractFunctionSelectorDeserializer()
|
||||
static final SelectorDeserializer deserializer = new AbstractFunctionSelectorDeserializer()
|
||||
{
|
||||
@Override
|
||||
protected Selector newFunctionSelector(Function function, List<Selector> argSelectors)
|
||||
protected Selector newFunctionSelector(ProtocolVersion version, Function function, List<Selector> argSelectors)
|
||||
{
|
||||
return new AggregateFunctionSelector(function, argSelectors);
|
||||
return new AggregateFunctionSelector(version, function, argSelectors);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ final class AggregateFunctionSelector extends AbstractFunctionSelector<Aggregate
|
|||
setArg(i, s.getOutput(protocolVersion));
|
||||
s.reset();
|
||||
}
|
||||
this.aggregate.addInput(protocolVersion, args());
|
||||
aggregate.addInput(args());
|
||||
}
|
||||
|
||||
public ByteBuffer getOutput(ProtocolVersion protocolVersion) throws InvalidRequestException
|
||||
|
|
@ -68,9 +68,9 @@ final class AggregateFunctionSelector extends AbstractFunctionSelector<Aggregate
|
|||
aggregate.reset();
|
||||
}
|
||||
|
||||
AggregateFunctionSelector(Function fun, List<Selector> argSelectors) throws InvalidRequestException
|
||||
AggregateFunctionSelector(ProtocolVersion version, Function fun, List<Selector> argSelectors) throws InvalidRequestException
|
||||
{
|
||||
super(Kind.AGGREGATE_FUNCTION_SELECTOR, (AggregateFunction) fun, argSelectors);
|
||||
super(Kind.AGGREGATE_FUNCTION_SELECTOR, version, (AggregateFunction) fun, argSelectors);
|
||||
|
||||
this.aggregate = this.fun.newAggregate();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,12 +28,12 @@ import static org.apache.cassandra.cql3.statements.RequestValidations.checkTrue;
|
|||
|
||||
final class ScalarFunctionSelector extends AbstractFunctionSelector<ScalarFunction>
|
||||
{
|
||||
protected static final SelectorDeserializer deserializer = new AbstractFunctionSelectorDeserializer()
|
||||
static final SelectorDeserializer deserializer = new AbstractFunctionSelectorDeserializer()
|
||||
{
|
||||
@Override
|
||||
protected Selector newFunctionSelector(Function function, List<Selector> argSelectors)
|
||||
protected Selector newFunctionSelector(ProtocolVersion version, Function function, List<Selector> argSelectors)
|
||||
{
|
||||
return new ScalarFunctionSelector(function, argSelectors);
|
||||
return new ScalarFunctionSelector(version, function, argSelectors);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ final class ScalarFunctionSelector extends AbstractFunctionSelector<ScalarFuncti
|
|||
setArg(i, s.getOutput(protocolVersion));
|
||||
s.reset();
|
||||
}
|
||||
return fun.execute(protocolVersion, args());
|
||||
return fun.execute(args());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -69,8 +69,8 @@ final class ScalarFunctionSelector extends AbstractFunctionSelector<ScalarFuncti
|
|||
argSelectors.get(i).validateForGroupBy();
|
||||
}
|
||||
|
||||
ScalarFunctionSelector(Function fun, List<Selector> argSelectors)
|
||||
ScalarFunctionSelector(ProtocolVersion version, Function fun, List<Selector> argSelectors)
|
||||
{
|
||||
super(Kind.SCALAR_FUNCTION_SELECTOR, (ScalarFunction) fun, argSelectors);
|
||||
super(Kind.SCALAR_FUNCTION_SELECTOR, version, (ScalarFunction) fun, argSelectors);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
|
|||
|
||||
import com.google.common.base.Objects;
|
||||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.functions.masking.ColumnMask;
|
||||
import org.apache.cassandra.schema.ColumnMetadata;
|
||||
import org.apache.cassandra.schema.TableMetadata;
|
||||
|
|
@ -46,7 +47,7 @@ public final class SimpleSelector extends Selector
|
|||
ByteBuffer columnName = ByteBufferUtil.readWithVIntLength(in);
|
||||
ColumnMetadata column = metadata.getColumn(columnName);
|
||||
int idx = in.readInt();
|
||||
return new SimpleSelector(column, idx, false);
|
||||
return new SimpleSelector(column, idx, false, ProtocolVersion.CURRENT);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -86,7 +87,7 @@ public final class SimpleSelector extends Selector
|
|||
@Override
|
||||
public Selector newInstance(QueryOptions options)
|
||||
{
|
||||
return new SimpleSelector(column, idx, useForPostOrdering);
|
||||
return new SimpleSelector(column, idx, useForPostOrdering, options.getProtocolVersion());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -119,7 +120,7 @@ public final class SimpleSelector extends Selector
|
|||
|
||||
public final ColumnMetadata column;
|
||||
private final int idx;
|
||||
private final boolean useForPostOrdering;
|
||||
private final ColumnMask.Masker masker;
|
||||
private ByteBuffer current;
|
||||
private ColumnTimestamps writetimes;
|
||||
private ColumnTimestamps ttls;
|
||||
|
|
@ -146,14 +147,14 @@ public final class SimpleSelector extends Selector
|
|||
ttls = input.getTtls(idx);
|
||||
|
||||
/*
|
||||
We apply the column mask of the column unless:
|
||||
We apply the column masker of the column unless:
|
||||
- The column doesn't have a mask
|
||||
- This selector is for a query with ORDER BY post-ordering, indicated by this.useForPostOrdering
|
||||
- The input row is for a user with UNMASK permission, indicated by input.unmask()
|
||||
- Dynamic data masking is globally disabled
|
||||
*/
|
||||
ColumnMask mask = useForPostOrdering || input.unmask() ? null : column.getMask();
|
||||
ByteBuffer value = input.getValue(idx);
|
||||
current = mask == null ? value : mask.mask(input.getProtocolVersion(), value);
|
||||
current = masker == null || input.unmask() || !DatabaseDescriptor.getDynamicDataMaskingEnabled()
|
||||
? value : masker.mask(value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -196,12 +197,19 @@ public final class SimpleSelector extends Selector
|
|||
return column.name.toString();
|
||||
}
|
||||
|
||||
private SimpleSelector(ColumnMetadata column, int idx, boolean useForPostOrdering)
|
||||
private SimpleSelector(ColumnMetadata column, int idx, boolean useForPostOrdering, ProtocolVersion version)
|
||||
{
|
||||
super(Kind.SIMPLE_SELECTOR);
|
||||
this.column = column;
|
||||
this.idx = idx;
|
||||
this.useForPostOrdering = useForPostOrdering;
|
||||
/*
|
||||
We apply the column mask of the column unless:
|
||||
- The column doesn't have a mask
|
||||
- This selector is for a query with ORDER BY post-ordering
|
||||
*/
|
||||
this.masker = useForPostOrdering || column.getMask() == null
|
||||
? null
|
||||
: column.getMask().masker(version);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@ import org.apache.cassandra.cql3.functions.FunctionName;
|
|||
import org.apache.cassandra.cql3.functions.ScalarFunction;
|
||||
import org.apache.cassandra.cql3.functions.UDAggregate;
|
||||
import org.apache.cassandra.cql3.functions.UDFunction;
|
||||
import org.apache.cassandra.cql3.functions.UDHelper;
|
||||
import org.apache.cassandra.cql3.functions.UserFunction;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.schema.UserFunctions.FunctionsDiff;
|
||||
|
|
@ -181,7 +180,7 @@ public final class CreateAggregateStatement extends AlterSchemaStatement
|
|||
String initialValueString = stateType.asCQL3Type().toCQLLiteral(initialValue, ProtocolVersion.CURRENT);
|
||||
assert Objects.equal(initialValue, Terms.asBytes(keyspaceName, initialValueString, stateType));
|
||||
|
||||
if (Constants.NULL_LITERAL != rawInitialValue && UDHelper.isNullOrEmpty(stateType, initialValue))
|
||||
if (Constants.NULL_LITERAL != rawInitialValue && isNullOrEmpty(stateType, initialValue))
|
||||
throw ire("INITCOND must not be empty for all types except TEXT, ASCII, BLOB");
|
||||
}
|
||||
|
||||
|
|
@ -228,6 +227,12 @@ public final class CreateAggregateStatement extends AlterSchemaStatement
|
|||
return schema.withAddedOrUpdated(keyspace.withSwapped(keyspace.userFunctions.withAddedOrUpdated(aggregate)));
|
||||
}
|
||||
|
||||
private static boolean isNullOrEmpty(AbstractType<?> type, ByteBuffer bb)
|
||||
{
|
||||
return bb == null ||
|
||||
(bb.remaining() == 0 && type.isEmptyValueMeaningless());
|
||||
}
|
||||
|
||||
SchemaChange schemaChangeEvent(KeyspacesDiff diff)
|
||||
{
|
||||
assert diff.altered.size() == 1;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.UUID;
|
|||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Duration;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.UUIDSerializer;
|
||||
|
|
@ -198,13 +199,13 @@ public abstract class AbstractTimeUUIDType<T> extends TemporalType<T>
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer addDuration(ByteBuffer temporal, ByteBuffer duration)
|
||||
public ByteBuffer addDuration(Number temporal, Duration duration)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer substractDuration(ByteBuffer temporal, ByteBuffer duration)
|
||||
public ByteBuffer substractDuration(Number temporal, Duration duration)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import org.apache.cassandra.cql3.AssignmentTestable;
|
|||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.ColumnSpecification;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.db.rows.Cell;
|
||||
import org.apache.cassandra.exceptions.SyntaxException;
|
||||
import org.apache.cassandra.io.util.DataInputPlus;
|
||||
|
|
@ -268,6 +269,14 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
|
|||
|
||||
public abstract TypeSerializer<T> getSerializer();
|
||||
|
||||
/**
|
||||
* @return the deserializer used to deserialize the function arguments of this type.
|
||||
*/
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return new DefaultArgumentDeserializer(this);
|
||||
}
|
||||
|
||||
/* convenience method */
|
||||
public String getString(Collection<ByteBuffer> names)
|
||||
{
|
||||
|
|
@ -723,4 +732,26 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>, Assignm
|
|||
{
|
||||
throw new UnsupportedOperationException("There isn't a defined masked value for type " + asCQL3Type());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ArgumentDeserializer} that uses the type deserialization.
|
||||
*/
|
||||
protected static class DefaultArgumentDeserializer implements ArgumentDeserializer
|
||||
{
|
||||
private final AbstractType<?> type;
|
||||
|
||||
public DefaultArgumentDeserializer(AbstractType<?> type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object deserialize(ProtocolVersion protocolVersion, ByteBuffer buffer)
|
||||
{
|
||||
if (buffer == null || (!buffer.hasRemaining() && type.isEmptyValueMeaningless()))
|
||||
return null;
|
||||
|
||||
return type.compose(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import org.apache.cassandra.cql3.Constants;
|
|||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.AsciiSerializer;
|
||||
|
|
@ -38,6 +39,7 @@ import org.apache.cassandra.utils.JsonUtils;
|
|||
public class AsciiType extends StringType
|
||||
{
|
||||
public static final AsciiType instance = new AsciiType();
|
||||
private static final ArgumentDeserializer ARGUMENT_DESERIALIZER = new DefaultArgumentDeserializer(instance);
|
||||
private static final ByteBuffer MASKED_VALUE = instance.decompose("****");
|
||||
|
||||
AsciiType() {super(ComparisonType.BYTE_ORDER);} // singleton
|
||||
|
|
@ -104,6 +106,12 @@ public class AsciiType extends StringType
|
|||
return AsciiSerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return ARGUMENT_DESERIALIZER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getMaskedValue()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ 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.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.BooleanSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
|
|
@ -32,7 +33,7 @@ import org.apache.cassandra.utils.bytecomparable.ByteSource;
|
|||
public class BooleanType extends AbstractType<Boolean>
|
||||
{
|
||||
public static final BooleanType instance = new BooleanType();
|
||||
|
||||
private static final ArgumentDeserializer ARGUMENT_DESERIALIZER = new DefaultArgumentDeserializer(instance);
|
||||
private static final ByteBuffer MASKED_VALUE = instance.decompose(false);
|
||||
|
||||
BooleanType() {super(ComparisonType.CUSTOM);} // singleton
|
||||
|
|
@ -113,6 +114,12 @@ public class BooleanType extends AbstractType<Boolean>
|
|||
return BooleanSerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return ARGUMENT_DESERIALIZER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int valueLengthIfFixed()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,9 +19,12 @@ package org.apache.cassandra.db.marshal;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableByte;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.ByteSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
|
|
@ -109,81 +112,81 @@ public class ByteType extends NumberType<Byte>
|
|||
}
|
||||
|
||||
@Override
|
||||
public byte toByte(ByteBuffer value)
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return ByteBufferUtil.toByte(value);
|
||||
return new NumberArgumentDeserializer<MutableByte>(new MutableByte())
|
||||
{
|
||||
@Override
|
||||
protected void setMutableValue(MutableByte mutable, ByteBuffer buffer)
|
||||
{
|
||||
mutable.setValue(ByteBufferUtil.toByte(buffer));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public short toShort(ByteBuffer value)
|
||||
public ByteBuffer add(Number left, Number right)
|
||||
{
|
||||
return toByte(value);
|
||||
return ByteBufferUtil.bytes((byte) (left.byteValue() + right.byteValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int toInt(ByteBuffer value)
|
||||
public ByteBuffer substract(Number left, Number right)
|
||||
{
|
||||
return toByte(value);
|
||||
}
|
||||
|
||||
public ByteBuffer add(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) (leftType.toByte(left) + rightType.toByte(right)));
|
||||
}
|
||||
|
||||
public ByteBuffer substract(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) (leftType.toByte(left) - rightType.toByte(right)));
|
||||
}
|
||||
|
||||
public ByteBuffer multiply(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) (leftType.toByte(left) * rightType.toByte(right)));
|
||||
}
|
||||
|
||||
public ByteBuffer divide(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) (leftType.toByte(left) / rightType.toByte(right)));
|
||||
}
|
||||
|
||||
public ByteBuffer mod(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) (leftType.toByte(left) % rightType.toByte(right)));
|
||||
}
|
||||
|
||||
public ByteBuffer negate(ByteBuffer input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) -toByte(input));
|
||||
return ByteBufferUtil.bytes((byte) (left.byteValue() - right.byteValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer abs(ByteBuffer input)
|
||||
public ByteBuffer multiply(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) Math.abs(toByte(input)));
|
||||
return ByteBufferUtil.bytes((byte) (left.byteValue() * right.byteValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer exp(ByteBuffer input)
|
||||
public ByteBuffer divide(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) Math.exp(toByte(input)));
|
||||
return ByteBufferUtil.bytes((byte) (left.byteValue() / right.byteValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(ByteBuffer input)
|
||||
public ByteBuffer mod(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) Math.log(toByte(input)));
|
||||
return ByteBufferUtil.bytes((byte) (left.byteValue() % right.byteValue()));
|
||||
}
|
||||
|
||||
public ByteBuffer negate(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) -input.byteValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(ByteBuffer input)
|
||||
public ByteBuffer abs(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) Math.log10(toByte(input)));
|
||||
return ByteBufferUtil.bytes((byte) Math.abs(input.byteValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(ByteBuffer input)
|
||||
public ByteBuffer exp(Number input)
|
||||
{
|
||||
return ByteBufferUtil.clone(input);
|
||||
return ByteBufferUtil.bytes((byte) Math.exp(input.byteValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) Math.log(input.byteValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((byte) Math.log10(input.byteValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(Number input)
|
||||
{
|
||||
return decompose(input.byteValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ 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.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.BytesSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
|
|
@ -97,6 +98,12 @@ public class BytesType extends AbstractType<ByteBuffer>
|
|||
return BytesSerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return ArgumentDeserializer.NOOP_DESERIALIZER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getMaskedValue()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
|
|||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.db.context.CounterContext;
|
||||
import org.apache.cassandra.serializers.CounterSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
|
|
@ -96,69 +97,74 @@ public class CounterColumnType extends NumberType<Long>
|
|||
}
|
||||
|
||||
@Override
|
||||
protected long toLong(ByteBuffer value)
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
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));
|
||||
return LongType.instance.getArgumentDeserializer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer abs(ByteBuffer input)
|
||||
public ByteBuffer add(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes(Math.abs(toLong(input)));
|
||||
return ByteBufferUtil.bytes(left.longValue() + right.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer exp(ByteBuffer input)
|
||||
public ByteBuffer substract(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((long) Math.exp(toLong(input)));
|
||||
return ByteBufferUtil.bytes(left.longValue() - right.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(ByteBuffer input)
|
||||
public ByteBuffer multiply(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((long) Math.log(toLong(input)));
|
||||
return ByteBufferUtil.bytes(left.longValue() * right.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(ByteBuffer input)
|
||||
public ByteBuffer divide(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((long) Math.log10(toLong(input)));
|
||||
return ByteBufferUtil.bytes(left.longValue() / right.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(ByteBuffer input)
|
||||
public ByteBuffer mod(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.clone(input);
|
||||
return ByteBufferUtil.bytes(left.longValue() % right.longValue());
|
||||
}
|
||||
|
||||
public ByteBuffer negate(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes(-input.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer abs(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes(Math.abs(input.longValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer exp(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((long) Math.exp(input.longValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((long) Math.log(input.longValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((long) Math.log10(input.longValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(Number input)
|
||||
{
|
||||
return decompose(input.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.TimestampSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
|
|
@ -45,7 +46,7 @@ public class DateType extends AbstractType<Date>
|
|||
private static final Logger logger = LoggerFactory.getLogger(DateType.class);
|
||||
|
||||
public static final DateType instance = new DateType();
|
||||
|
||||
private static final ArgumentDeserializer ARGUMENT_DESERIALIZER = new DefaultArgumentDeserializer(instance);
|
||||
private static final ByteBuffer MASKED_VALUE = instance.decompose(new Date(0));
|
||||
|
||||
DateType() {super(ComparisonType.BYTE_ORDER);} // singleton
|
||||
|
|
@ -136,6 +137,12 @@ public class DateType extends AbstractType<Date>
|
|||
return TimestampSerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return ARGUMENT_DESERIALIZER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int valueLengthIfFixed()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import com.google.common.primitives.Ints;
|
|||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.DecimalSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
|
|
@ -43,7 +44,10 @@ public class DecimalType extends NumberType<BigDecimal>
|
|||
{
|
||||
public static final DecimalType instance = new DecimalType();
|
||||
|
||||
private static final ArgumentDeserializer ARGUMENT_DESERIALIZER = new DefaultArgumentDeserializer(instance);
|
||||
|
||||
private static final ByteBuffer MASKED_VALUE = instance.decompose(BigDecimal.ZERO);
|
||||
|
||||
private static final int MIN_SCALE = 32;
|
||||
private static final int MIN_SIGNIFICANT_DIGITS = MIN_SCALE;
|
||||
private static final int MAX_SCALE = 1000;
|
||||
|
|
@ -316,60 +320,59 @@ public class DecimalType extends NumberType<BigDecimal>
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int toInt(ByteBuffer value)
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return ARGUMENT_DESERIALIZER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the specified number into a {@link BigDecimal}.
|
||||
*
|
||||
* @param number the value to convert
|
||||
* @return the converted value
|
||||
*/
|
||||
protected BigDecimal toBigDecimal(Number number)
|
||||
{
|
||||
if (number instanceof BigDecimal)
|
||||
return (BigDecimal) number;
|
||||
|
||||
if (number instanceof BigInteger)
|
||||
return new BigDecimal((BigInteger) number);
|
||||
|
||||
double d = number.doubleValue();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float toFloat(ByteBuffer value)
|
||||
public ByteBuffer add(Number left, Number right)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return decompose(toBigDecimal(left).add(toBigDecimal(right), MAX_PRECISION));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long toLong(ByteBuffer value)
|
||||
public ByteBuffer substract(Number left, Number right)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return decompose(toBigDecimal(left).subtract(toBigDecimal(right), MAX_PRECISION));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double toDouble(ByteBuffer value)
|
||||
public ByteBuffer multiply(Number left, Number right)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return decompose(toBigDecimal(left).multiply(toBigDecimal(right), MAX_PRECISION));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BigInteger toBigInteger(ByteBuffer value)
|
||||
public ByteBuffer divide(Number left, Number right)
|
||||
{
|
||||
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), MAX_PRECISION));
|
||||
}
|
||||
|
||||
public ByteBuffer substract(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
|
||||
{
|
||||
return decompose(leftType.toBigDecimal(left).subtract(rightType.toBigDecimal(right), MAX_PRECISION));
|
||||
}
|
||||
|
||||
public ByteBuffer multiply(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
|
||||
{
|
||||
return decompose(leftType.toBigDecimal(left).multiply(rightType.toBigDecimal(right), MAX_PRECISION));
|
||||
}
|
||||
|
||||
public ByteBuffer divide(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
|
||||
{
|
||||
BigDecimal leftOperand = leftType.toBigDecimal(left);
|
||||
BigDecimal rightOperand = rightType.toBigDecimal(right);
|
||||
BigDecimal leftOperand = toBigDecimal(left);
|
||||
BigDecimal rightOperand = toBigDecimal(right);
|
||||
|
||||
// Predict position of first significant digit in the quotient.
|
||||
// Note: it is possible to improve prediction accuracy by comparing first significant digits in operands
|
||||
|
|
@ -385,24 +388,26 @@ public class DecimalType extends NumberType<BigDecimal>
|
|||
return decompose(leftOperand.divide(rightOperand, scale, RoundingMode.HALF_UP).stripTrailingZeros());
|
||||
}
|
||||
|
||||
public ByteBuffer mod(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
|
||||
@Override
|
||||
public ByteBuffer mod(Number left, Number right)
|
||||
{
|
||||
return decompose(leftType.toBigDecimal(left).remainder(rightType.toBigDecimal(right)));
|
||||
return decompose(toBigDecimal(left).remainder(toBigDecimal(right)));
|
||||
}
|
||||
|
||||
public ByteBuffer negate(ByteBuffer input)
|
||||
@Override
|
||||
public ByteBuffer negate(Number input)
|
||||
{
|
||||
return decompose(toBigDecimal(input).negate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer abs(ByteBuffer input)
|
||||
public ByteBuffer abs(Number input)
|
||||
{
|
||||
return decompose(toBigDecimal(input).abs());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer exp(ByteBuffer input)
|
||||
public ByteBuffer exp(Number input)
|
||||
{
|
||||
return decompose(exp(toBigDecimal(input)));
|
||||
}
|
||||
|
|
@ -416,7 +421,7 @@ public class DecimalType extends NumberType<BigDecimal>
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(ByteBuffer input)
|
||||
public ByteBuffer log(Number input)
|
||||
{
|
||||
return decompose(log(toBigDecimal(input)));
|
||||
}
|
||||
|
|
@ -431,7 +436,7 @@ public class DecimalType extends NumberType<BigDecimal>
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(ByteBuffer input)
|
||||
public ByteBuffer log10(Number input)
|
||||
{
|
||||
return decompose(log10(toBigDecimal(input)));
|
||||
}
|
||||
|
|
@ -446,7 +451,7 @@ public class DecimalType extends NumberType<BigDecimal>
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(ByteBuffer input)
|
||||
public ByteBuffer round(Number input)
|
||||
{
|
||||
return DecimalType.instance.decompose(
|
||||
toBigDecimal(input).setScale(0, RoundingMode.HALF_UP));
|
||||
|
|
|
|||
|
|
@ -19,9 +19,12 @@ package org.apache.cassandra.db.marshal;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableDouble;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.DoubleSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
|
|
@ -122,6 +125,19 @@ public class DoubleType extends NumberType<Double>
|
|||
return DoubleSerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return new NumberArgumentDeserializer<MutableDouble>(new MutableDouble())
|
||||
{
|
||||
@Override
|
||||
protected void setMutableValue(MutableDouble mutable, ByteBuffer buffer)
|
||||
{
|
||||
mutable.setValue(ByteBufferUtil.toDouble(buffer));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int valueLengthIfFixed()
|
||||
{
|
||||
|
|
@ -129,87 +145,69 @@ public class DoubleType extends NumberType<Double>
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int toInt(ByteBuffer value)
|
||||
public ByteBuffer add(Number left, Number right)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return ByteBufferUtil.bytes(left.doubleValue() + right.doubleValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float toFloat(ByteBuffer value)
|
||||
public ByteBuffer substract(Number left, Number right)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return ByteBufferUtil.bytes(left.doubleValue() - right.doubleValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long toLong(ByteBuffer value)
|
||||
public ByteBuffer multiply(Number left, Number right)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return ByteBufferUtil.bytes(left.doubleValue() * right.doubleValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double toDouble(ByteBuffer value)
|
||||
public ByteBuffer divide(Number left, Number right)
|
||||
{
|
||||
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));
|
||||
return ByteBufferUtil.bytes(left.doubleValue() / right.doubleValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer abs(ByteBuffer input)
|
||||
public ByteBuffer mod(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes(Math.abs(toDouble(input)));
|
||||
return ByteBufferUtil.bytes(left.doubleValue() % right.doubleValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer exp(ByteBuffer input)
|
||||
public ByteBuffer negate(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes(Math.exp(toDouble(input)));
|
||||
return ByteBufferUtil.bytes(-input.doubleValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(ByteBuffer input)
|
||||
public ByteBuffer abs(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes(Math.log(toDouble(input)));
|
||||
return ByteBufferUtil.bytes(Math.abs(input.doubleValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(ByteBuffer input)
|
||||
public ByteBuffer exp(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes(Math.log10(toDouble(input)));
|
||||
return ByteBufferUtil.bytes(Math.exp(input.doubleValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(ByteBuffer input)
|
||||
public ByteBuffer log(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((double) Math.round(toDouble(input)));
|
||||
return ByteBufferUtil.bytes(Math.log(input.doubleValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes(Math.log10(input.doubleValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((double) Math.round(input.doubleValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import org.apache.cassandra.cql3.CQL3Type;
|
|||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Duration;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.DurationSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
|
|
@ -36,6 +37,8 @@ public class DurationType extends AbstractType<Duration>
|
|||
{
|
||||
public static final DurationType instance = new DurationType();
|
||||
|
||||
private static final ArgumentDeserializer ARGUMENT_DESERIALIZER = new DefaultArgumentDeserializer(instance);
|
||||
|
||||
private static final ByteBuffer MASKED_VALUE = instance.decompose(Duration.newInstance(0, 0, 0));
|
||||
|
||||
DurationType()
|
||||
|
|
@ -77,6 +80,12 @@ public class DurationType extends AbstractType<Duration>
|
|||
return DurationSerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return ARGUMENT_DESERIALIZER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory;
|
|||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.io.util.DataInputPlus;
|
||||
import org.apache.cassandra.io.util.DataOutputPlus;
|
||||
import org.apache.cassandra.serializers.EmptySerializer;
|
||||
|
|
@ -129,6 +130,12 @@ public class EmptyType extends AbstractType<Void>
|
|||
return EmptySerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int valueLengthIfFixed()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,9 +19,12 @@ package org.apache.cassandra.db.marshal;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableFloat;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.FloatSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
|
|
@ -123,6 +126,19 @@ public class FloatType extends NumberType<Float>
|
|||
return FloatSerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return new NumberArgumentDeserializer<MutableFloat>(new MutableFloat())
|
||||
{
|
||||
@Override
|
||||
protected void setMutableValue(MutableFloat mutable, ByteBuffer buffer)
|
||||
{
|
||||
mutable.setValue(ByteBufferUtil.toFloat(buffer));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int valueLengthIfFixed()
|
||||
{
|
||||
|
|
@ -130,81 +146,69 @@ public class FloatType extends NumberType<Float>
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int toInt(ByteBuffer value)
|
||||
public ByteBuffer add(Number left, Number right)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return ByteBufferUtil.bytes(left.floatValue() + right.floatValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float toFloat(ByteBuffer value)
|
||||
public ByteBuffer substract(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.toFloat(value);
|
||||
return ByteBufferUtil.bytes(left.floatValue() - right.floatValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double toDouble(ByteBuffer value)
|
||||
public ByteBuffer multiply(Number left, Number right)
|
||||
{
|
||||
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));
|
||||
return ByteBufferUtil.bytes(left.floatValue() * right.floatValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer abs(ByteBuffer input)
|
||||
public ByteBuffer divide(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes(Math.abs(toFloat(input)));
|
||||
return ByteBufferUtil.bytes(left.floatValue() / right.floatValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer exp(ByteBuffer input)
|
||||
public ByteBuffer mod(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((float) Math.exp(toFloat(input)));
|
||||
return ByteBufferUtil.bytes(left.floatValue() % right.floatValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(ByteBuffer input)
|
||||
public ByteBuffer negate(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((float) Math.log(toFloat(input)));
|
||||
return ByteBufferUtil.bytes(-input.floatValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(ByteBuffer input)
|
||||
public ByteBuffer abs(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((float) Math.log10(toFloat(input)));
|
||||
return ByteBufferUtil.bytes(Math.abs(input.floatValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(ByteBuffer input)
|
||||
public ByteBuffer exp(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((float) Math.round(toFloat(input)));
|
||||
return ByteBufferUtil.bytes((float) Math.exp(input.floatValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((float) Math.log(input.floatValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((float) Math.log10(input.floatValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((float) Math.round(input.floatValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.exceptions.SyntaxException;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
|
|
@ -71,4 +72,10 @@ public class FrozenType extends AbstractType<Void>
|
|||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ 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.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.InetAddressSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
|
|
@ -34,6 +35,8 @@ public class InetAddressType extends AbstractType<InetAddress>
|
|||
{
|
||||
public static final InetAddressType instance = new InetAddressType();
|
||||
|
||||
private static final ArgumentDeserializer ARGUMENT_DESERIALIZER = new DefaultArgumentDeserializer(instance);
|
||||
|
||||
private static final ByteBuffer MASKED_VALUE = instance.decompose(new InetSocketAddress(0).getAddress());
|
||||
|
||||
InetAddressType() {super(ComparisonType.BYTE_ORDER);} // singleton
|
||||
|
|
@ -98,6 +101,12 @@ public class InetAddressType extends AbstractType<InetAddress>
|
|||
return InetAddressSerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return ARGUMENT_DESERIALIZER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getMaskedValue()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,9 +20,12 @@ package org.apache.cassandra.db.marshal;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableInt;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.Int32Serializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
|
@ -129,6 +132,19 @@ public class Int32Type extends NumberType<Integer>
|
|||
return Int32Serializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return new NumberArgumentDeserializer<MutableInt>(new MutableInt())
|
||||
{
|
||||
@Override
|
||||
protected void setMutableValue(MutableInt mutable, ByteBuffer buffer)
|
||||
{
|
||||
mutable.setValue(ByteBufferUtil.toInt(buffer));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int valueLengthIfFixed()
|
||||
{
|
||||
|
|
@ -136,75 +152,69 @@ public class Int32Type extends NumberType<Integer>
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int toInt(ByteBuffer value)
|
||||
public ByteBuffer add(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.toInt(value);
|
||||
return ByteBufferUtil.bytes(left.intValue() + right.intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float toFloat(ByteBuffer value)
|
||||
public ByteBuffer substract(Number left, Number right)
|
||||
{
|
||||
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));
|
||||
return ByteBufferUtil.bytes(left.intValue() - right.intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer abs(ByteBuffer input)
|
||||
public ByteBuffer multiply(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes(Math.abs(toInt(input)));
|
||||
return ByteBufferUtil.bytes(left.intValue() * right.intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer exp(ByteBuffer input)
|
||||
public ByteBuffer divide(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((int) Math.exp(toInt(input)));
|
||||
return ByteBufferUtil.bytes(left.intValue() / right.intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(ByteBuffer input)
|
||||
public ByteBuffer mod(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((int) Math.log(toInt(input)));
|
||||
return ByteBufferUtil.bytes(left.intValue() % right.intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(ByteBuffer input)
|
||||
public ByteBuffer negate(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((int) Math.log10(toInt(input)));
|
||||
return ByteBufferUtil.bytes(-input.intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(ByteBuffer input)
|
||||
public ByteBuffer abs(Number input)
|
||||
{
|
||||
return ByteBufferUtil.clone(input);
|
||||
return ByteBufferUtil.bytes(Math.abs(input.intValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer exp(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((int) Math.exp(input.intValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((int) Math.log(input.intValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((int) Math.log10(input.intValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes(input.intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import java.util.Objects;
|
|||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.IntegerSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
|
|
@ -38,6 +39,8 @@ public final class IntegerType extends NumberType<BigInteger>
|
|||
{
|
||||
public static final IntegerType instance = new IntegerType();
|
||||
|
||||
private static final ArgumentDeserializer ARGUMENT_DESERIALIZER = new DefaultArgumentDeserializer(instance);
|
||||
|
||||
private static final ByteBuffer MASKED_VALUE = instance.decompose(BigInteger.ZERO);
|
||||
|
||||
// Constants or escaping values needed to encode/decode variable-length integers in our custom byte-ordered
|
||||
|
|
@ -497,79 +500,57 @@ public final class IntegerType extends NumberType<BigInteger>
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int toInt(ByteBuffer value)
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return ARGUMENT_DESERIALIZER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float toFloat(ByteBuffer value)
|
||||
private BigInteger toBigInteger(Number number)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
if (number instanceof BigInteger)
|
||||
return (BigInteger) number;
|
||||
|
||||
return BigInteger.valueOf(number.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long toLong(ByteBuffer value)
|
||||
public ByteBuffer add(Number left, Number right)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return decompose(toBigInteger(left).add(toBigInteger(right)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected double toDouble(ByteBuffer value)
|
||||
public ByteBuffer substract(Number left, Number right)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return decompose(toBigInteger(left).subtract(toBigInteger(right)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BigInteger toBigInteger(ByteBuffer value)
|
||||
public ByteBuffer multiply(Number left, Number right)
|
||||
{
|
||||
return compose(value);
|
||||
return decompose(toBigInteger(left).multiply(toBigInteger(right)));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BigDecimal toBigDecimal(ByteBuffer value)
|
||||
public ByteBuffer divide(Number left, Number right)
|
||||
{
|
||||
return new BigDecimal(compose(value));
|
||||
return decompose(toBigInteger(left).divide(toBigInteger(right)));
|
||||
}
|
||||
|
||||
public ByteBuffer add(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
|
||||
public ByteBuffer mod(Number left, Number right)
|
||||
{
|
||||
return decompose(leftType.toBigInteger(left).add(rightType.toBigInteger(right)));
|
||||
return decompose(toBigInteger(left).remainder(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)
|
||||
public ByteBuffer negate(Number input)
|
||||
{
|
||||
return decompose(toBigInteger(input).negate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer abs(ByteBuffer input)
|
||||
public ByteBuffer abs(Number input)
|
||||
{
|
||||
return decompose(toBigInteger(input).abs());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer exp(ByteBuffer input)
|
||||
public ByteBuffer exp(Number input)
|
||||
{
|
||||
BigInteger bi = toBigInteger(input);
|
||||
BigDecimal bd = new BigDecimal(bi);
|
||||
|
|
@ -579,7 +560,7 @@ public final class IntegerType extends NumberType<BigInteger>
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(ByteBuffer input)
|
||||
public ByteBuffer log(Number input)
|
||||
{
|
||||
BigInteger bi = toBigInteger(input);
|
||||
if (bi.compareTo(BigInteger.ZERO) <= 0) throw new ArithmeticException("Natural log of number zero or less");
|
||||
|
|
@ -590,7 +571,7 @@ public final class IntegerType extends NumberType<BigInteger>
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(ByteBuffer input)
|
||||
public ByteBuffer log10(Number input)
|
||||
{
|
||||
BigInteger bi = toBigInteger(input);
|
||||
if (bi.compareTo(BigInteger.ZERO) <= 0) throw new ArithmeticException("Log10 of number zero or less");
|
||||
|
|
@ -601,9 +582,9 @@ public final class IntegerType extends NumberType<BigInteger>
|
|||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(ByteBuffer input)
|
||||
public ByteBuffer round(Number input)
|
||||
{
|
||||
return ByteBufferUtil.clone(input);
|
||||
return decompose(toBigInteger(input));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.UUID;
|
|||
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.UUIDSerializer;
|
||||
|
|
@ -34,6 +35,8 @@ public class LexicalUUIDType extends AbstractType<UUID>
|
|||
{
|
||||
public static final LexicalUUIDType instance = new LexicalUUIDType();
|
||||
|
||||
private static final ArgumentDeserializer ARGUMENT_DESERIALIZER = new DefaultArgumentDeserializer(instance);
|
||||
|
||||
private static final ByteBuffer MASKED_VALUE = instance.decompose(UUID.fromString("00000000-0000-0000-0000-000000000000"));
|
||||
|
||||
LexicalUUIDType()
|
||||
|
|
@ -123,11 +126,18 @@ public class LexicalUUIDType extends AbstractType<UUID>
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSerializer<UUID> getSerializer()
|
||||
{
|
||||
return UUIDSerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return ARGUMENT_DESERIALIZER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int valueLengthIfFixed()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,9 +20,12 @@ package org.apache.cassandra.db.marshal;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableLong;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.LongSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
|
|
@ -147,6 +150,19 @@ public class LongType extends NumberType<Long>
|
|||
return LongSerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return new NumberArgumentDeserializer<MutableLong>(new MutableLong())
|
||||
{
|
||||
@Override
|
||||
protected void setMutableValue(MutableLong mutable, ByteBuffer buffer)
|
||||
{
|
||||
mutable.setValue(ByteBufferUtil.toLong(buffer));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int valueLengthIfFixed()
|
||||
{
|
||||
|
|
@ -154,81 +170,69 @@ public class LongType extends NumberType<Long>
|
|||
}
|
||||
|
||||
@Override
|
||||
protected int toInt(ByteBuffer value)
|
||||
public ByteBuffer add(Number left, Number right)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return ByteBufferUtil.bytes(left.longValue() + right.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected float toFloat(ByteBuffer value)
|
||||
public ByteBuffer substract(Number left, Number right)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
return ByteBufferUtil.bytes(left.longValue() - right.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long toLong(ByteBuffer value)
|
||||
public ByteBuffer multiply(Number left, Number right)
|
||||
{
|
||||
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));
|
||||
return ByteBufferUtil.bytes(left.longValue() * right.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer abs(ByteBuffer input)
|
||||
public ByteBuffer divide(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes(Math.abs(toLong(input)));
|
||||
return ByteBufferUtil.bytes(left.longValue() / right.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer exp(ByteBuffer input)
|
||||
public ByteBuffer mod(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((long) Math.exp(toLong(input)));
|
||||
return ByteBufferUtil.bytes(left.longValue() % right.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(ByteBuffer input)
|
||||
public ByteBuffer negate(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((long) Math.log(toLong(input)));
|
||||
return ByteBufferUtil.bytes(-input.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(ByteBuffer input)
|
||||
public ByteBuffer abs(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((long) Math.log10(toLong(input)));
|
||||
return ByteBufferUtil.bytes(Math.abs(input.longValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(ByteBuffer input)
|
||||
public ByteBuffer exp(Number input)
|
||||
{
|
||||
return ByteBufferUtil.clone(input);
|
||||
return ByteBufferUtil.bytes((long) Math.exp(input.longValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((long) Math.log(input.longValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((long) Math.log10(input.longValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(Number input)
|
||||
{
|
||||
return decompose(input.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -17,10 +17,13 @@
|
|||
*/
|
||||
package org.apache.cassandra.db.marshal;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.commons.lang3.mutable.Mutable;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
* Base type for the numeric types.
|
||||
*/
|
||||
|
|
@ -40,178 +43,50 @@ public abstract class NumberType<T extends Number> extends AbstractType<T>
|
|||
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);
|
||||
public abstract ByteBuffer add(Number left, Number 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);
|
||||
public abstract ByteBuffer substract(Number left, Number 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);
|
||||
public abstract ByteBuffer multiply(Number left, Number 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);
|
||||
public abstract ByteBuffer divide(Number left, Number 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);
|
||||
public abstract ByteBuffer mod(Number left, Number right);
|
||||
|
||||
/**
|
||||
* Negates the argument.
|
||||
|
|
@ -219,7 +94,7 @@ public abstract class NumberType<T extends Number> extends AbstractType<T>
|
|||
* @param input the argument to negate
|
||||
* @return the negated argument
|
||||
*/
|
||||
public abstract ByteBuffer negate(ByteBuffer input);
|
||||
public abstract ByteBuffer negate(Number input);
|
||||
|
||||
/**
|
||||
* Takes the absolute value of the argument.
|
||||
|
|
@ -228,7 +103,7 @@ public abstract class NumberType<T extends Number> extends AbstractType<T>
|
|||
* @return a ByteBuffer containing the absolute value of the argument. The type of the contents of the ByteBuffer
|
||||
* will match that of the input.
|
||||
*/
|
||||
public abstract ByteBuffer abs(ByteBuffer input);
|
||||
public abstract ByteBuffer abs(Number input);
|
||||
|
||||
/**
|
||||
* Raises e to the power of the argument.
|
||||
|
|
@ -238,7 +113,7 @@ public abstract class NumberType<T extends Number> extends AbstractType<T>
|
|||
* argument. The type of the contents of the ByteBuffer will be a double, unless the input is a DecimalType or
|
||||
* IntegerType, in which the ByteBuffer will contain a DecimalType.
|
||||
*/
|
||||
public abstract ByteBuffer exp(ByteBuffer input);
|
||||
public abstract ByteBuffer exp(Number input);
|
||||
|
||||
/**
|
||||
* Takes the natural logrithm of the argument.
|
||||
|
|
@ -248,7 +123,7 @@ public abstract class NumberType<T extends Number> extends AbstractType<T>
|
|||
* will be a double, unless the input is a DecimalType or IntegerType, in which the ByteBuffer will contain a
|
||||
* DecimalType.
|
||||
*/
|
||||
public abstract ByteBuffer log(ByteBuffer input);
|
||||
public abstract ByteBuffer log(Number input);
|
||||
|
||||
/**
|
||||
* Takes the log base 10 of the arguement.
|
||||
|
|
@ -258,7 +133,7 @@ public abstract class NumberType<T extends Number> extends AbstractType<T>
|
|||
* will be a double, unless the input is a DecimalType or IntegerType, in which the ByteBuffer will contain a
|
||||
* DecimalType.
|
||||
*/
|
||||
public abstract ByteBuffer log10(ByteBuffer input);
|
||||
public abstract ByteBuffer log10(Number input);
|
||||
|
||||
/**
|
||||
* Rounds the argument to the nearest whole number.
|
||||
|
|
@ -268,5 +143,39 @@ public abstract class NumberType<T extends Number> extends AbstractType<T>
|
|||
* a copy of the input. If the input is a float, the ByteBuffer will contain an int32. If the input is a double, the
|
||||
* output will contain a long. If the input is a DecimalType, the output will contain an IntegerType.
|
||||
*/
|
||||
public abstract ByteBuffer round(ByteBuffer input);
|
||||
public abstract ByteBuffer round(Number input);
|
||||
|
||||
/**
|
||||
* Base class for numeric type {@link ArgumentDeserializer}.
|
||||
*
|
||||
* <p>This class uses and returns a mutable wrapper instead of the Java immutable primitive wrapper. This wrapper
|
||||
* is being reused between each call to minimize the amount of objects instantiated.</p>
|
||||
*
|
||||
* @param <M> The Mutable wrapper type
|
||||
*/
|
||||
protected abstract static class NumberArgumentDeserializer<M extends Mutable<Number>> implements ArgumentDeserializer
|
||||
{
|
||||
protected final M wrapper;
|
||||
|
||||
public NumberArgumentDeserializer(M wrapper)
|
||||
{
|
||||
this.wrapper = wrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object deserialize(ProtocolVersion protocolVersion, ByteBuffer buffer)
|
||||
{
|
||||
if (buffer == null || !buffer.hasRemaining())
|
||||
return null;
|
||||
|
||||
setMutableValue(wrapper, buffer);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the mutable.
|
||||
* @param buffer the serialized value.
|
||||
*/
|
||||
protected abstract void setMutableValue(M mutable, ByteBuffer buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import java.util.Iterator;
|
|||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.db.DecoratedKey;
|
||||
import org.apache.cassandra.db.PartitionPosition;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
|
|
@ -130,11 +131,18 @@ public class PartitionerDefinedOrder extends AbstractType<ByteBuffer>
|
|||
throw new IllegalStateException("You shouldn't be validating this.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSerializer<ByteBuffer> getSerializer()
|
||||
{
|
||||
throw new UnsupportedOperationException("You can't do this with a local partitioner.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
throw new UnsupportedOperationException("You can't do this with a local partitioner.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.exceptions.ConfigurationException;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
|
|
@ -139,11 +140,18 @@ public class ReversedType<T> extends AbstractType<T>
|
|||
return baseType.asCQL3Type();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSerializer<T> getSerializer()
|
||||
{
|
||||
return baseType.getSerializer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return baseType.getArgumentDeserializer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> boolean referencesUserType(V name, ValueAccessor<V> accessor)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -20,9 +20,12 @@ package org.apache.cassandra.db.marshal;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableShort;
|
||||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.ShortSerializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
|
|
@ -111,76 +114,82 @@ public class ShortType extends NumberType<Short>
|
|||
}
|
||||
|
||||
@Override
|
||||
public short toShort(ByteBuffer value)
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return ByteBufferUtil.toShort(value);
|
||||
return new NumberArgumentDeserializer<MutableShort>(new MutableShort())
|
||||
{
|
||||
@Override
|
||||
protected void setMutableValue(MutableShort mutable, ByteBuffer buffer)
|
||||
{
|
||||
mutable.setValue(ByteBufferUtil.toShort(buffer));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int toInt(ByteBuffer value)
|
||||
public ByteBuffer add(Number left, Number right)
|
||||
{
|
||||
return toShort(value);
|
||||
return ByteBufferUtil.bytes((short) (left.shortValue() + right.shortValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer add(NumberType<?> leftType, ByteBuffer left, NumberType<?> rightType, ByteBuffer right)
|
||||
public ByteBuffer substract(Number left, Number 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));
|
||||
return ByteBufferUtil.bytes((short) (left.shortValue() - right.shortValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer abs(ByteBuffer input)
|
||||
public ByteBuffer multiply(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((short) Math.abs(toShort(input)));
|
||||
return ByteBufferUtil.bytes((short) (left.shortValue() * right.shortValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer exp(ByteBuffer input)
|
||||
public ByteBuffer divide(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((short) Math.exp(toShort(input)));
|
||||
return ByteBufferUtil.bytes((short) (left.shortValue() / right.shortValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(ByteBuffer input)
|
||||
public ByteBuffer mod(Number left, Number right)
|
||||
{
|
||||
return ByteBufferUtil.bytes((short) Math.log(toShort(input)));
|
||||
return ByteBufferUtil.bytes((short) (left.shortValue() % right.shortValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(ByteBuffer input)
|
||||
public ByteBuffer negate(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((short) Math.log10(toShort(input)));
|
||||
return ByteBufferUtil.bytes((short) -input.shortValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(ByteBuffer input)
|
||||
public ByteBuffer abs(Number input)
|
||||
{
|
||||
return ByteBufferUtil.clone(input);
|
||||
return ByteBufferUtil.bytes((short) Math.abs(input.shortValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer exp(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((short) Math.exp(input.shortValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((short) Math.log(input.shortValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer log10(Number input)
|
||||
{
|
||||
return ByteBufferUtil.bytes((short) Math.log10(input.shortValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer round(Number input)
|
||||
{
|
||||
return decompose(input.shortValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -27,14 +27,8 @@ public abstract class StringType extends AbstractType<String>
|
|||
super(comparisonType);
|
||||
}
|
||||
|
||||
public ByteBuffer concat(StringType leftType,
|
||||
ByteBuffer left,
|
||||
StringType rightType,
|
||||
ByteBuffer right)
|
||||
public ByteBuffer concat(String left, String right)
|
||||
{
|
||||
String leftS = leftType.compose(left);
|
||||
String rightS = rightType.compose(right);
|
||||
|
||||
return decompose(leftS + rightS);
|
||||
return decompose(left + right);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,11 @@ package org.apache.cassandra.db.marshal;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.apache.commons.lang3.mutable.MutableLong;
|
||||
|
||||
import org.apache.cassandra.cql3.Duration;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
import static org.apache.cassandra.utils.Clock.Global.currentTimeMillis;
|
||||
|
||||
|
|
@ -70,13 +74,11 @@ public abstract class TemporalType<T> extends AbstractType<T>
|
|||
* @param duration the duration to add
|
||||
* @return the addition result
|
||||
*/
|
||||
public ByteBuffer addDuration(ByteBuffer temporal,
|
||||
ByteBuffer duration)
|
||||
public ByteBuffer addDuration(Number temporal, Duration duration)
|
||||
{
|
||||
long timeInMillis = toTimeInMillis(temporal);
|
||||
Duration d = DurationType.instance.compose(duration);
|
||||
validateDuration(d);
|
||||
return fromTimeInMillis(d.addTo(timeInMillis));
|
||||
long timeInMillis = temporal.longValue();
|
||||
validateDuration(duration);
|
||||
return fromTimeInMillis(duration.addTo(timeInMillis));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -86,13 +88,11 @@ public abstract class TemporalType<T> extends AbstractType<T>
|
|||
* @param duration the duration to substract
|
||||
* @return the substracion result
|
||||
*/
|
||||
public ByteBuffer substractDuration(ByteBuffer temporal,
|
||||
ByteBuffer duration)
|
||||
public ByteBuffer substractDuration(Number temporal, Duration duration)
|
||||
{
|
||||
long timeInMillis = toTimeInMillis(temporal);
|
||||
Duration d = DurationType.instance.compose(duration);
|
||||
validateDuration(d);
|
||||
return fromTimeInMillis(d.substractFrom(timeInMillis));
|
||||
long timeInMillis = temporal.longValue();
|
||||
validateDuration(duration);
|
||||
return fromTimeInMillis(duration.substractFrom(timeInMillis));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -102,4 +102,23 @@ public abstract class TemporalType<T> extends AbstractType<T>
|
|||
protected void validateDuration(Duration duration)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return new ArgumentDeserializer()
|
||||
{
|
||||
private final MutableLong wrapper = new MutableLong();
|
||||
|
||||
@Override
|
||||
public Object deserialize(ProtocolVersion protocolVersion, ByteBuffer buffer)
|
||||
{
|
||||
if (buffer == null || (!buffer.hasRemaining() && isEmptyValueMeaningless()))
|
||||
return null;
|
||||
|
||||
wrapper.setValue(toTimeInMillis(buffer));
|
||||
return wrapper;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import java.time.ZoneOffset;
|
|||
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.TimeSerializer;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
|
|
@ -40,7 +41,10 @@ public class TimeType extends TemporalType<Long>
|
|||
{
|
||||
public static final TimeType instance = new TimeType();
|
||||
|
||||
private static final ArgumentDeserializer ARGUMENT_DESERIALIZER = new DefaultArgumentDeserializer(instance);
|
||||
|
||||
private static final ByteBuffer DEFAULT_MASKED_VALUE = instance.decompose(0L);
|
||||
|
||||
private TimeType() {super(ComparisonType.BYTE_ORDER);} // singleton
|
||||
|
||||
public ByteBuffer fromString(String source) throws MarshalException
|
||||
|
|
@ -93,11 +97,18 @@ public class TimeType extends TemporalType<Long>
|
|||
return CQL3Type.Native.TIME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSerializer<Long> getSerializer()
|
||||
{
|
||||
return TimeSerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return ARGUMENT_DESERIALIZER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer now()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import org.apache.cassandra.cql3.Constants;
|
|||
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.UTF8Serializer;
|
||||
|
|
@ -36,6 +37,8 @@ public class UTF8Type extends StringType
|
|||
{
|
||||
public static final UTF8Type instance = new UTF8Type();
|
||||
|
||||
private static final ArgumentDeserializer ARGUMENT_DESERIALIZER = new DefaultArgumentDeserializer(instance);
|
||||
|
||||
private static final ByteBuffer MASKED_VALUE = instance.decompose("****");
|
||||
|
||||
UTF8Type() {super(ComparisonType.BYTE_ORDER);} // singleton
|
||||
|
|
@ -80,16 +83,24 @@ public class UTF8Type extends StringType
|
|||
return this == previous || previous == AsciiType.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CQL3Type asCQL3Type()
|
||||
{
|
||||
return CQL3Type.Native.TEXT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSerializer<String> getSerializer()
|
||||
{
|
||||
return UTF8Serializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return ARGUMENT_DESERIALIZER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer getMaskedValue()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import com.google.common.primitives.UnsignedLongs;
|
|||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.Constants;
|
||||
import org.apache.cassandra.cql3.Term;
|
||||
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.UUIDSerializer;
|
||||
|
|
@ -49,6 +50,8 @@ public class UUIDType extends AbstractType<UUID>
|
|||
{
|
||||
public static final UUIDType instance = new UUIDType();
|
||||
|
||||
private static final ArgumentDeserializer ARGUMENT_DESERIALIZER = new DefaultArgumentDeserializer(instance);
|
||||
|
||||
private static final ByteBuffer MASKED_VALUE = instance.decompose(UUID.fromString("00000000-0000-0000-0000-000000000000"));
|
||||
|
||||
UUIDType()
|
||||
|
|
@ -189,11 +192,18 @@ public class UUIDType extends AbstractType<UUID>
|
|||
return CQL3Type.Native.UUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeSerializer<UUID> getSerializer()
|
||||
{
|
||||
return UUIDSerializer.instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArgumentDeserializer getArgumentDeserializer()
|
||||
{
|
||||
return ARGUMENT_DESERIALIZER;
|
||||
}
|
||||
|
||||
static final Pattern regexPattern = Pattern.compile("[A-Fa-f0-9]{8}\\-[A-Fa-f0-9]{4}\\-[A-Fa-f0-9]{4}\\-[A-Fa-f0-9]{4}\\-[A-Fa-f0-9]{12}");
|
||||
|
||||
static ByteBuffer parse(String source)
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ import org.apache.cassandra.cql3.ColumnSpecification;
|
|||
import org.apache.cassandra.cql3.QueryOptions;
|
||||
import org.apache.cassandra.cql3.QueryProcessor;
|
||||
import org.apache.cassandra.cql3.UpdateParameters;
|
||||
import org.apache.cassandra.cql3.functions.UDHelper;
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.types.UserType;
|
||||
import org.apache.cassandra.cql3.statements.ModificationStatement;
|
||||
|
|
@ -68,6 +67,7 @@ import org.apache.cassandra.schema.Views;
|
|||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
import org.apache.cassandra.utils.JavaDriverUtils;
|
||||
|
||||
import static org.apache.cassandra.utils.Clock.Global.currentTimeMillis;
|
||||
|
||||
|
|
@ -132,7 +132,7 @@ public class CQLSSTableWriter implements Closeable
|
|||
this.writer = writer;
|
||||
this.modificationStatement = modificationStatement;
|
||||
this.boundNames = boundNames;
|
||||
this.typeCodecs = boundNames.stream().map(bn -> UDHelper.codecFor(UDHelper.driverType(bn.type)))
|
||||
this.typeCodecs = boundNames.stream().map(bn -> JavaDriverUtils.codecFor(JavaDriverUtils.driverType(bn.type)))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
|
|
@ -339,7 +339,7 @@ public class CQLSSTableWriter implements Closeable
|
|||
{
|
||||
KeyspaceMetadata ksm = Schema.instance.getKeyspaceMetadata(modificationStatement.keyspace());
|
||||
org.apache.cassandra.db.marshal.UserType userType = ksm.types.getNullable(ByteBufferUtil.bytes(dataType));
|
||||
return (UserType) UDHelper.driverType(userType);
|
||||
return (UserType) JavaDriverUtils.driverType(userType);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1150,7 +1150,7 @@ public final class SchemaKeyspace
|
|||
values[i] = argumentTypes.get(i + 1).fromString(valuesAsCQL.get(i));
|
||||
}
|
||||
|
||||
mask = ColumnMask.build((ScalarFunction) function, values);
|
||||
mask = new ColumnMask((ScalarFunction) function, values);
|
||||
}
|
||||
|
||||
return new ColumnMetadata(keyspace, table, name, type, position, kind, mask);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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.utils;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.CodecRegistry;
|
||||
import org.apache.cassandra.cql3.functions.types.DataType;
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
/**
|
||||
* Utility methods to convert from {@link AbstractType} to {@link DataType} or to {@link TypeCodec}.
|
||||
*/
|
||||
public final class JavaDriverUtils
|
||||
{
|
||||
private static final CodecRegistry codecRegistry = new CodecRegistry();
|
||||
|
||||
private static final MethodHandle methodParseOne;
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
Class<?> cls = Class.forName("org.apache.cassandra.cql3.functions.types.DataTypeClassNameParser");
|
||||
Method m = cls.getDeclaredMethod("parseOne", String.class, ProtocolVersion.class, CodecRegistry.class);
|
||||
m.setAccessible(true);
|
||||
methodParseOne = MethodHandles.lookup().unreflect(m);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static TypeCodec<Object> codecFor(AbstractType<?> abstractType)
|
||||
{
|
||||
return codecFor(driverType(abstractType));
|
||||
}
|
||||
|
||||
public static TypeCodec<Object> codecFor(DataType dataType)
|
||||
{
|
||||
return codecRegistry.codecFor(dataType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Java Driver {@link DataType} for the C* internal type.
|
||||
*/
|
||||
public static DataType driverType(AbstractType<?> abstractType)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (DataType) methodParseOne.invoke(abstractType.toString(), ProtocolVersion.CURRENT, codecRegistry);
|
||||
}
|
||||
catch (RuntimeException | Error e)
|
||||
{
|
||||
// immediately rethrow these...
|
||||
throw e;
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
throw new RuntimeException("cannot parse driver type " + abstractType, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The class should never be instantiated as it contains only static methods.
|
||||
*/
|
||||
private JavaDriverUtils()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -4,29 +4,30 @@ import java.nio.ByteBuffer;
|
|||
import java.util.*;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.types.TupleValue;
|
||||
import org.apache.cassandra.cql3.functions.types.UDTValue;
|
||||
|
||||
public final class #class_name# extends JavaUDF
|
||||
{
|
||||
public #class_name#(TypeCodec<Object> returnCodec, TypeCodec<Object>[] argCodecs, UDFContext udfContext)
|
||||
public #class_name#(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnCodec, argCodecs, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
#return_type# result = #execute_internal_name#(
|
||||
#arguments#
|
||||
#arguments#
|
||||
);
|
||||
return super.decompose(protocolVersion, result);
|
||||
return decompose(arguments.getProtocolVersion(), result);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
#return_type# result = #execute_internal_name#(
|
||||
#arguments_aggregate#
|
||||
|
|
|
|||
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* 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.test.microbench;
|
||||
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.config.OverrideConfigurationLoader;
|
||||
import org.apache.cassandra.cql3.CQLTester;
|
||||
import org.apache.cassandra.cql3.UntypedResultSet;
|
||||
import org.apache.cassandra.db.ColumnFamilyStore;
|
||||
import org.apache.cassandra.db.Keyspace;
|
||||
import org.apache.cassandra.db.commitlog.CommitLog;
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Level;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.TearDown;
|
||||
import org.openjdk.jmh.annotations.Threads;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
|
||||
/**
|
||||
* Benchmarks the performance of CQL functions calls with terminal arguments.
|
||||
*/
|
||||
@BenchmarkMode(Mode.Throughput)
|
||||
@OutputTimeUnit(TimeUnit.SECONDS)
|
||||
@Warmup(iterations = 15, time = 2) // seconds
|
||||
@Measurement(iterations = 10, time = 2) // seconds
|
||||
@Fork(value = 1)
|
||||
@Threads(1)
|
||||
@State(Scope.Benchmark)
|
||||
public class FunctionWithTerminalArgsBench extends CQLTester
|
||||
{
|
||||
private static final int NUM_PARTITIONS = 10;
|
||||
private static final int NUM_CLUSTERINGS = 100;
|
||||
|
||||
// We repeat the number of times that the function call appears on the query to amplify its effect on the benchmark,
|
||||
// since its impact is relatively small in the context of a full query.
|
||||
private static final int NUM_FUNCTION_CALLS = 10;
|
||||
|
||||
private String udf;
|
||||
|
||||
@Setup(Level.Trial)
|
||||
public void setup() throws Throwable
|
||||
{
|
||||
// we disable UDF threads to avoid the overhead and better see the impact of the terminal arguments
|
||||
OverrideConfigurationLoader.override((config) -> {
|
||||
config.allow_insecure_udfs = true;
|
||||
config.user_defined_functions_threads_enabled = false;
|
||||
});
|
||||
DatabaseDescriptor.daemonInitialization();
|
||||
|
||||
CQLTester.setUpClass();
|
||||
beforeTest();
|
||||
|
||||
udf = createFunction(KEYSPACE,
|
||||
"int, text",
|
||||
" CREATE FUNCTION %s (a1 text, a2 text, a3 text, a4 text, a5 text)" +
|
||||
" CALLED ON NULL INPUT" +
|
||||
" RETURNS text" +
|
||||
" LANGUAGE java" +
|
||||
" AS 'return a1 + a2 + a3 + a4 + a5;'");
|
||||
|
||||
String table = createTable(KEYSPACE, "CREATE TABLE %s (k int, c int, v text, PRIMARY KEY(k, c))");
|
||||
ColumnFamilyStore cfs = Keyspace.open(KEYSPACE).getColumnFamilyStore(table);
|
||||
cfs.disableAutoCompaction();
|
||||
|
||||
System.out.println("Writing " + (NUM_PARTITIONS * NUM_CLUSTERINGS) + " rows...");
|
||||
int n = 0;
|
||||
for (int k = 0; k < NUM_PARTITIONS; k++)
|
||||
{
|
||||
for (int c = 0; c < NUM_CLUSTERINGS; c++)
|
||||
{
|
||||
execute("INSERT INTO %s(k, c, v) VALUES (?, ?, ?)", k, c, String.valueOf(n++));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TearDown(Level.Trial)
|
||||
public void teardown() throws InterruptedException
|
||||
{
|
||||
CommitLog.instance.shutdownBlocking();
|
||||
CQLTester.tearDownClass();
|
||||
CQLTester.cleanup();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Object none()
|
||||
{
|
||||
return execute("v");
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Object add()
|
||||
{
|
||||
return execute("v + 'abc'");
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Object udf()
|
||||
{
|
||||
return execute(udf + "(v, 'a1', 'a2', 'a3', 'a4')");
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Object maskReplace()
|
||||
{
|
||||
return execute("mask_replace(v, '***')");
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Object maskPartial()
|
||||
{
|
||||
return execute("mask_inner(v, 1, 1, '#')");
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Object maskHash()
|
||||
{
|
||||
return execute("mask_hash(v, 'MD5')");
|
||||
}
|
||||
|
||||
private UntypedResultSet execute(String functionCall)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT ");
|
||||
for (int i = 0; i < NUM_FUNCTION_CALLS; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
sb.append(", ");
|
||||
sb.append(functionCall);
|
||||
}
|
||||
sb.append(" FROM %s");
|
||||
return super.execute(sb.toString());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,151 +0,0 @@
|
|||
/*
|
||||
* 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 java.nio.ByteBuffer;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.UDHelper;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.AsciiType;
|
||||
import org.apache.cassandra.db.marshal.BooleanType;
|
||||
import org.apache.cassandra.db.marshal.ByteType;
|
||||
import org.apache.cassandra.db.marshal.BytesType;
|
||||
import org.apache.cassandra.db.marshal.CounterColumnType;
|
||||
import org.apache.cassandra.db.marshal.DateType;
|
||||
import org.apache.cassandra.db.marshal.DecimalType;
|
||||
import org.apache.cassandra.db.marshal.DoubleType;
|
||||
import org.apache.cassandra.db.marshal.FloatType;
|
||||
import org.apache.cassandra.db.marshal.InetAddressType;
|
||||
import org.apache.cassandra.db.marshal.Int32Type;
|
||||
import org.apache.cassandra.db.marshal.IntegerType;
|
||||
import org.apache.cassandra.db.marshal.LongType;
|
||||
import org.apache.cassandra.db.marshal.ReversedType;
|
||||
import org.apache.cassandra.db.marshal.ShortType;
|
||||
import org.apache.cassandra.db.marshal.SimpleDateType;
|
||||
import org.apache.cassandra.db.marshal.TimeType;
|
||||
import org.apache.cassandra.db.marshal.TimeUUIDType;
|
||||
import org.apache.cassandra.db.marshal.TimestampType;
|
||||
import org.apache.cassandra.db.marshal.UTF8Type;
|
||||
import org.apache.cassandra.db.marshal.UUIDType;
|
||||
import org.apache.cassandra.db.marshal.ValueAccessor;
|
||||
import org.apache.cassandra.serializers.MarshalException;
|
||||
import org.apache.cassandra.serializers.TypeSerializer;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
public class UDHelperTest
|
||||
{
|
||||
static class UFTestCustomType extends AbstractType<String>
|
||||
{
|
||||
protected UFTestCustomType()
|
||||
{
|
||||
super(ComparisonType.CUSTOM);
|
||||
}
|
||||
|
||||
public ByteBuffer fromString(String source) throws MarshalException
|
||||
{
|
||||
return ByteBuffer.wrap(source.getBytes());
|
||||
}
|
||||
|
||||
public Term fromJSONObject(Object parsed) throws MarshalException
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public TypeSerializer<String> getSerializer()
|
||||
{
|
||||
return UTF8Type.instance.getSerializer();
|
||||
}
|
||||
|
||||
public <VL, VR> int compareCustom(VL left, ValueAccessor<VL> accessorL, VR right, ValueAccessor<VR> accessorR)
|
||||
{
|
||||
return ValueAccessor.compare(left, accessorL, right, accessorR);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyVariableLengthTypes()
|
||||
{
|
||||
AbstractType<?>[] types = new AbstractType<?>[]{
|
||||
AsciiType.instance,
|
||||
BytesType.instance,
|
||||
UTF8Type.instance,
|
||||
new UFTestCustomType()
|
||||
};
|
||||
|
||||
for (AbstractType<?> type : types)
|
||||
{
|
||||
Assert.assertFalse("type " + type.getClass().getName(),
|
||||
UDHelper.isNullOrEmpty(type, ByteBufferUtil.EMPTY_BYTE_BUFFER));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonEmptyPrimitiveTypes()
|
||||
{
|
||||
AbstractType<?>[] types = new AbstractType<?>[]{
|
||||
TimeType.instance,
|
||||
SimpleDateType.instance,
|
||||
ByteType.instance,
|
||||
ShortType.instance
|
||||
};
|
||||
|
||||
for (AbstractType<?> type : types)
|
||||
{
|
||||
try
|
||||
{
|
||||
type.getSerializer().validate(ByteBufferUtil.EMPTY_BYTE_BUFFER);
|
||||
Assert.fail(type.getClass().getSimpleName());
|
||||
}
|
||||
catch (MarshalException e)
|
||||
{
|
||||
//
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptiableTypes()
|
||||
{
|
||||
AbstractType<?>[] types = new AbstractType<?>[]{
|
||||
BooleanType.instance,
|
||||
CounterColumnType.instance,
|
||||
DateType.instance,
|
||||
DecimalType.instance,
|
||||
DoubleType.instance,
|
||||
FloatType.instance,
|
||||
InetAddressType.instance,
|
||||
Int32Type.instance,
|
||||
IntegerType.instance,
|
||||
LongType.instance,
|
||||
TimestampType.instance,
|
||||
TimeUUIDType.instance,
|
||||
UUIDType.instance
|
||||
};
|
||||
|
||||
for (AbstractType<?> type : types)
|
||||
{
|
||||
Assert.assertTrue(type.getClass().getSimpleName(), UDHelper.isNullOrEmpty(type, ByteBufferUtil.EMPTY_BYTE_BUFFER));
|
||||
Assert.assertTrue("reversed " + type.getClass().getSimpleName(),
|
||||
UDHelper.isNullOrEmpty(ReversedType.getInstance(type), ByteBufferUtil.EMPTY_BYTE_BUFFER));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -53,9 +53,15 @@ public class FunctionFactoryTest extends CQLTester
|
|||
return new NativeScalarFunction(name.name, argTypes.get(0), argTypes.get(0))
|
||||
{
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocol, List<ByteBuffer> parameters)
|
||||
public Arguments newArguments(ProtocolVersion version)
|
||||
{
|
||||
return parameters.get(0);
|
||||
return FunctionArguments.newNoopInstance(version, 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
return arguments.containsNulls() ? null : arguments.get(0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -73,13 +79,13 @@ public class FunctionFactoryTest extends CQLTester
|
|||
return new NativeScalarFunction(name.name, UTF8Type.instance, argTypes.get(0))
|
||||
{
|
||||
@Override
|
||||
public ByteBuffer execute(ProtocolVersion protocol, List<ByteBuffer> parameters)
|
||||
public ByteBuffer execute(Arguments arguments)
|
||||
{
|
||||
ByteBuffer value = parameters.get(0);
|
||||
if (value == null)
|
||||
if (arguments.containsNulls())
|
||||
return null;
|
||||
|
||||
return UTF8Type.instance.decompose(argTypes.get(0).compose(value).toString());
|
||||
Object value = arguments.get(0);
|
||||
return UTF8Type.instance.decompose(value.toString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@ package org.apache.cassandra.cql3.functions;
|
|||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
|
@ -296,8 +294,9 @@ public class MathFctsTest
|
|||
|
||||
private static ByteBuffer executeFunction(Function function, ByteBuffer input)
|
||||
{
|
||||
List<ByteBuffer> params = Collections.singletonList(input);
|
||||
return ((ScalarFunction) function).execute(ProtocolVersion.CURRENT, params);
|
||||
Arguments arguments = function.newArguments(ProtocolVersion.CURRENT);
|
||||
arguments.set(0, input);
|
||||
return ((ScalarFunction) function).execute(arguments);
|
||||
}
|
||||
|
||||
private <T extends Number> void assertFctEquals(NativeFunction fct, T expected, NumberType<T> inputType, T inputValue)
|
||||
|
|
|
|||
|
|
@ -20,9 +20,7 @@ package org.apache.cassandra.cql3.functions;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
|
@ -185,7 +183,8 @@ public class TimeFctsTest
|
|||
|
||||
private static ByteBuffer executeFunction(Function function, ByteBuffer input)
|
||||
{
|
||||
List<ByteBuffer> params = Collections.singletonList(input);
|
||||
return ((ScalarFunction) function).execute(ProtocolVersion.CURRENT, params);
|
||||
Arguments arguments = function.newArguments(ProtocolVersion.CURRENT);
|
||||
arguments.set(0, input);
|
||||
return ((ScalarFunction) function).execute(arguments);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import com.datastax.driver.core.PreparedStatement;
|
|||
import com.datastax.driver.core.Session;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.CQL3Type;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.FunctionFactory;
|
||||
import org.apache.cassandra.cql3.functions.FunctionParameter;
|
||||
import org.apache.cassandra.cql3.functions.NativeFunction;
|
||||
|
|
@ -564,15 +565,10 @@ public class ColumnMaskTest extends ColumnMaskTester
|
|||
return new MaskingFunction(name, argTypes.get(0), argTypes.get(0))
|
||||
{
|
||||
@Override
|
||||
public Masker masker(ByteBuffer... parameters)
|
||||
public ByteBuffer execute(Arguments arguments) throws InvalidRequestException
|
||||
{
|
||||
return bb -> {
|
||||
if (bb == null)
|
||||
return null;
|
||||
|
||||
Integer value = Int32Type.instance.compose(bb) * -1;
|
||||
return Int32Type.instance.decompose(value);
|
||||
};
|
||||
Integer value = arguments.getAsInt(0) * -1;
|
||||
return Int32Type.instance.decompose(value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,11 +40,11 @@ public class PartialMaskingFunctionTest extends MaskingFunctionTester
|
|||
@Override
|
||||
protected void testMaskingOnColumn(String name, CQL3Type type, Object value) throws Throwable
|
||||
{
|
||||
testMaskingOnColumn(PartialMaskingFunction.Type.INNER, name, type, value);
|
||||
testMaskingOnColumn(PartialMaskingFunction.Type.OUTER, name, type, value);
|
||||
testMaskingOnColumn(PartialMaskingFunction.Kind.INNER, name, type, value);
|
||||
testMaskingOnColumn(PartialMaskingFunction.Kind.OUTER, name, type, value);
|
||||
}
|
||||
|
||||
protected void testMaskingOnColumn(PartialMaskingFunction.Type masker, String name, CQL3Type type, Object value) throws Throwable
|
||||
protected void testMaskingOnColumn(PartialMaskingFunction.Kind masker, String name, CQL3Type type, Object value) throws Throwable
|
||||
{
|
||||
String functionName = SchemaConstants.SYSTEM_KEYSPACE_NAME + ".mask_" + masker.name().toLowerCase();
|
||||
|
||||
|
|
@ -169,9 +169,9 @@ public class PartialMaskingFunctionTest extends MaskingFunctionTester
|
|||
String innerMaskedValue,
|
||||
String outerMaskedValue)
|
||||
{
|
||||
Assertions.assertThat(PartialMaskingFunction.Type.INNER.mask(unmaskedValue, begin, end, padding))
|
||||
Assertions.assertThat(PartialMaskingFunction.Kind.INNER.mask(unmaskedValue, begin, end, padding))
|
||||
.isIn(innerMaskedValue);
|
||||
Assertions.assertThat(PartialMaskingFunction.Type.OUTER.mask(unmaskedValue, begin, end, padding))
|
||||
Assertions.assertThat(PartialMaskingFunction.Kind.OUTER.mask(unmaskedValue, begin, end, padding))
|
||||
.isIn(outerMaskedValue);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -119,12 +119,12 @@ public class UFJavaTest extends CQLTester
|
|||
@Test
|
||||
public void testJavaFunctionInvalidReturn() throws Throwable
|
||||
{
|
||||
assertInvalidMessage("cannot convert from long to Double",
|
||||
assertInvalidMessage("cannot convert from boolean to double",
|
||||
"CREATE OR REPLACE FUNCTION " + KEYSPACE + ".jfir(val double) " +
|
||||
"RETURNS NULL ON NULL INPUT " +
|
||||
"RETURNS double " +
|
||||
"LANGUAGE JAVA\n" +
|
||||
"AS 'return 1L;';");
|
||||
"AS 'return true;';");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
|||
|
|
@ -27,9 +27,9 @@ import org.junit.Test;
|
|||
import org.apache.cassandra.config.Config;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.CQLTester;
|
||||
import org.apache.cassandra.cql3.functions.UDHelper;
|
||||
import org.apache.cassandra.exceptions.FunctionExecutionException;
|
||||
import org.apache.cassandra.service.ClientWarn;
|
||||
import org.apache.cassandra.utils.JavaDriverUtils;
|
||||
|
||||
public class UFSecurityTest extends CQLTester
|
||||
{
|
||||
|
|
@ -58,7 +58,7 @@ public class UFSecurityTest extends CQLTester
|
|||
}
|
||||
|
||||
String[] cfnSources =
|
||||
{ "try { Class.forName(\"" + UDHelper.class.getName() + "\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;",
|
||||
{ "try { Class.forName(\"" + JavaDriverUtils.class.getName() + "\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;",
|
||||
"try { Class.forName(\"sun.misc.Unsafe\"); } catch (Exception e) { throw new RuntimeException(e); } return 0d;" };
|
||||
for (String source : cfnSources)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,18 +23,14 @@ import java.util.Arrays;
|
|||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.reflect.TypeToken;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.datastax.driver.core.TypeTokens;
|
||||
import com.datastax.driver.core.UDTValue;
|
||||
import com.datastax.driver.core.exceptions.InvalidQueryException;
|
||||
import org.apache.cassandra.cql3.CQLTester;
|
||||
import org.apache.cassandra.cql3.QueryProcessor;
|
||||
import org.apache.cassandra.cql3.UntypedResultSet;
|
||||
import org.apache.cassandra.cql3.functions.FunctionName;
|
||||
import org.apache.cassandra.cql3.functions.JavaBasedUDFunction;
|
||||
import org.apache.cassandra.cql3.functions.UDFunction;
|
||||
import org.apache.cassandra.db.marshal.CollectionType;
|
||||
import org.apache.cassandra.exceptions.InvalidRequestException;
|
||||
|
|
@ -52,15 +48,6 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|||
|
||||
public class UFTest extends CQLTester
|
||||
{
|
||||
@Test
|
||||
public void testJavaSourceName()
|
||||
{
|
||||
Assert.assertEquals("String", JavaBasedUDFunction.javaSourceName(TypeToken.of(String.class)));
|
||||
Assert.assertEquals("java.util.Map<Integer, String>", JavaBasedUDFunction.javaSourceName(TypeTokens.mapOf(Integer.class, String.class)));
|
||||
Assert.assertEquals("com.datastax.driver.core.UDTValue", JavaBasedUDFunction.javaSourceName(TypeToken.of(UDTValue.class)));
|
||||
Assert.assertEquals("java.util.Set<com.datastax.driver.core.UDTValue>", JavaBasedUDFunction.javaSourceName(TypeTokens.setOf(UDTValue.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonExistingOnes() throws Throwable
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class CallClone extends JavaUDF
|
||||
{
|
||||
public CallClone(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public CallClone(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class CallFinalize extends JavaUDF
|
||||
{
|
||||
public CallFinalize(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public CallFinalize(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,30 +19,31 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.config.DatabaseDescriptor;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class CallOrgApache extends JavaUDF
|
||||
{
|
||||
public CallOrgApache(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public CallOrgApache(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
DatabaseDescriptor.getClusterName();
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class ClassWithField extends JavaUDF
|
||||
{
|
||||
public ClassWithField(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public ClassWithField(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class ClassWithInitializer extends JavaUDF
|
||||
{
|
||||
public ClassWithInitializer(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public ClassWithInitializer(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class ClassWithInitializer2 extends JavaUDF
|
||||
{
|
||||
public ClassWithInitializer2(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public ClassWithInitializer2(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class ClassWithInitializer3 extends JavaUDF
|
||||
{
|
||||
public ClassWithInitializer3(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public ClassWithInitializer3(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class ClassWithInnerClass extends JavaUDF
|
||||
{
|
||||
public ClassWithInnerClass(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public ClassWithInnerClass(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class ClassWithInnerClass2 extends JavaUDF
|
||||
{
|
||||
public ClassWithInnerClass2(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public ClassWithInnerClass2(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
// this is fine
|
||||
new Runnable() {
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class ClassWithStaticInitializer extends JavaUDF
|
||||
{
|
||||
public ClassWithStaticInitializer(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public ClassWithStaticInitializer(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class ClassWithStaticInnerClass extends JavaUDF
|
||||
{
|
||||
public ClassWithStaticInnerClass(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public ClassWithStaticInnerClass(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class GoodClass extends JavaUDF
|
||||
{
|
||||
public GoodClass(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public GoodClass(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class UseOfSynchronized extends JavaUDF
|
||||
{
|
||||
public UseOfSynchronized(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public UseOfSynchronized(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -19,29 +19,30 @@
|
|||
package org.apache.cassandra.cql3.validation.entities.udfverify;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.cassandra.cql3.functions.types.TypeCodec;
|
||||
import org.apache.cassandra.cql3.functions.Arguments;
|
||||
import org.apache.cassandra.cql3.functions.JavaUDF;
|
||||
import org.apache.cassandra.cql3.functions.UDFContext;
|
||||
import org.apache.cassandra.transport.ProtocolVersion;
|
||||
import org.apache.cassandra.cql3.functions.UDFDataType;
|
||||
|
||||
/**
|
||||
* Used by {@link org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
|
||||
*/
|
||||
public final class UseOfSynchronizedWithNotify extends JavaUDF
|
||||
{
|
||||
public UseOfSynchronizedWithNotify(TypeCodec<Object> returnDataType, TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
|
||||
public UseOfSynchronizedWithNotify(UDFDataType returnType, UDFContext udfContext)
|
||||
{
|
||||
super(returnDataType, argDataTypes, udfContext);
|
||||
super(returnType, udfContext);
|
||||
}
|
||||
|
||||
protected Object executeAggregateImpl(ProtocolVersion protocolVersion, Object firstParam, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected Object executeAggregateImpl(Object state, Arguments arguments)
|
||||
{
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
protected ByteBuffer executeImpl(ProtocolVersion protocolVersion, List<ByteBuffer> params)
|
||||
@Override
|
||||
protected ByteBuffer executeImpl(Arguments arguments)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue