Merge branch 'cassandra-6.0' into trunk

This commit is contained in:
Benedict Elliott Smith 2026-05-18 13:25:59 +01:00
commit 5eba832793
136 changed files with 1201 additions and 840 deletions

View File

@ -82,12 +82,12 @@ public class Attributes
return timeToLive != null;
}
public long getTimestamp(long now, QueryOptions options) throws InvalidRequestException
public long getTimestamp(long now, FunctionContext context) throws InvalidRequestException
{
if (timestamp == null)
return now;
ByteBuffer tval = timestamp.bindAndGet(options);
ByteBuffer tval = timestamp.bindAndGet(context);
if (tval == null)
throw new InvalidRequestException("Invalid null value of timestamp");
@ -106,7 +106,7 @@ public class Attributes
return LongType.instance.compose(tval);
}
public int getTimeToLive(QueryOptions options, TableMetadata metadata) throws InvalidRequestException
public int getTimeToLive(FunctionContext context, TableMetadata metadata) throws InvalidRequestException
{
if (timeToLive == null)
{
@ -114,7 +114,7 @@ public class Attributes
return metadata.params.defaultTimeToLive;
}
ByteBuffer tval = timeToLive.bindAndGet(options);
ByteBuffer tval = timeToLive.bindAndGet(context);
if (tval == null)
return 0;

View File

@ -356,9 +356,9 @@ public final class ColumnsExpression
* Returns the key, index or fieldname specifying the selected element.
* @return the key, index or fieldname specifying the selected element.
*/
public ByteBuffer element(QueryOptions options)
public ByteBuffer element(FunctionContext context)
{
return element.bindAndGet(options);
return element.bindAndGet(context);
}
/**

View File

@ -158,12 +158,12 @@ public final class ElementExpression
/**
* Returns the ByteBuffer representation of the key or index.
*
* @param options the query options
* @param context the query options
* @return the ByteBuffer representation of the key or index.
*/
public ByteBuffer bindAndGet(QueryOptions options)
public ByteBuffer bindAndGet(FunctionContext context)
{
return keyOrIndex.bindAndGet(options);
return keyOrIndex.bindAndGet(context);
}
public String toCQLString()

View File

@ -0,0 +1,96 @@
/*
* 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.time.Instant;
import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.FunctionArguments;
import org.apache.cassandra.db.marshal.TimeUUIDType;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.Clock.Global;
import org.apache.cassandra.utils.TimeUUID;
public interface FunctionContext
{
NoTimeOrQueryFunctionContext NONE = new NoTimeOrQueryFunctionContext() {};
interface RealTimeFunctionContext extends FunctionContext
{
@Override default byte[] nextTimeUUIDAsBytes() { return TimeUUID.Generator.nextTimeUUIDAsBytes(); }
@Override default Instant now() { return Global.currentTime(); }
@Override default long nowMicros() { return Global.currentTimeMicros(); }
@Override default long nowMillis() { return Global.currentTimeMillis(); }
}
interface NoTimeFunctionContext extends FunctionContext
{
@Override default byte[] nextTimeUUIDAsBytes() { throw new UnsupportedOperationException(); }
@Override default Instant now() { throw new UnsupportedOperationException(); }
@Override default long nowMicros() { throw new UnsupportedOperationException(); }
@Override default long nowMillis() { throw new UnsupportedOperationException(); }
}
interface NoTimeOrQueryFunctionContext extends NoTimeFunctionContext
{
@Override default QueryOptions options() { throw new UnsupportedOperationException(); }
}
interface PartialFunctionContext extends FunctionContext
{
default long nowMillis() { return nowMicros() / 1000; }
default Instant now()
{
long nowMicros = nowMicros();
return Instant.ofEpochSecond(nowMicros / 1000_000, (nowMicros % 1000_000) * 1000);
}
}
abstract class MicrosFunctionContext implements PartialFunctionContext
{
final long atMicros;
private long timeUuidNanos;
public MicrosFunctionContext(long atMicros)
{
this.atMicros = atMicros;
}
@Override public long nowMicros() { return atMicros; }
@Override
public byte[] nextTimeUUIDAsBytes()
{
return TimeUUID.toBytes(TimeUUID.unixMicrosToMsb(atMicros), TimeUUIDType.signedBytesToNativeLong(timeUuidNanos++));
}
}
QueryOptions options();
Instant now();
long nowMillis();
long nowMicros();
byte[] nextTimeUUIDAsBytes();
default ProtocolVersion getProtocolVersion() { return options().getProtocolVersion(); }
default Arguments noArguments()
{
return new FunctionArguments(this);
}
}

View File

@ -251,12 +251,12 @@ public final class Json
}
@Override
public Terminal bind(QueryOptions options) throws InvalidRequestException
public Terminal bind(FunctionContext context) throws InvalidRequestException
{
Term term = options.getJsonColumnValue(marker.bindIndex, column.name, marker.columns);
Term term = context.options().getJsonColumnValue(marker.bindIndex, column.name, marker.columns);
return term == null
? (defaultUnset ? Constants.UNSET_VALUE : null)
: term.bind(options);
: term.bind(context);
}
@Override

View File

@ -116,9 +116,9 @@ public abstract class Operation
* Execute the operation.
*
* @param partitionKey partition key for the update.
* @param params parameters of the update.
* @param builder parameters of the update.
*/
public abstract void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException;
public abstract void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException;
/**
* A parsed raw UPDATE operation.

View File

@ -31,6 +31,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.cassandra.config.DataStorageSpec;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.FunctionContext.RealTimeFunctionContext;
import org.apache.cassandra.cql3.terms.Term;
import org.apache.cassandra.db.ConsistencyLevel;
import org.apache.cassandra.db.marshal.UTF8Type;
@ -53,7 +54,7 @@ import static org.apache.cassandra.utils.ByteArrayUtil.convertToByteBufferValue;
/**
* Options for a query.
*/
public abstract class QueryOptions
public abstract class QueryOptions implements RealTimeFunctionContext
{
public static final QueryOptions DEFAULT = new DefaultQueryOptions(ConsistencyLevel.ONE,
Collections.emptyList(),
@ -378,6 +379,12 @@ public abstract class QueryOptions
}
}
@Override
public QueryOptions options()
{
return this;
}
static class DefaultQueryOptions extends QueryOptions
{
private final ConsistencyLevel consistency;

View File

@ -556,7 +556,7 @@ public class QueryProcessor implements QueryHandler
.map(m -> MessagingService.instance().<ReadCommand, ReadResponse>sendWithResult(m, address))
.collect(Collectors.toList()));
ResultSetBuilder result = new ResultSetBuilder(select.getResultMetadata(), select.getSelection().newSelectors(options), false);
ResultSetBuilder result = new ResultSetBuilder(select.getResultMetadata(), options, select.getSelection().newSelectors(options), false);
return future.map(list -> {
int i = 0;
for (Message<ReadResponse> m : list)

View File

@ -15,6 +15,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cassandra.cql3;
import java.nio.ByteBuffer;
@ -43,20 +44,32 @@ import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.schema.ColumnMetadata;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.utils.TimeUUID;
/**
* Groups the parameters of an update query, and make building updates easier.
*/
public class UpdateParameters
public abstract class RowUpdateBuilder implements FunctionContext
{
public final TableMetadata metadata;
public final ClientState clientState;
public final QueryOptions options;
public static class RegularRowUpdateBuilder extends RowUpdateBuilder implements RealTimeFunctionContext
{
public RegularRowUpdateBuilder(TableMetadata metadata, ClientState clientState, QueryOptions options, long timestamp, long nowInSec, int ttl, Map<DecoratedKey, Partition> prefetchedRows) throws InvalidRequestException
{
super(metadata, clientState, options, timestamp, nowInSec, ttl, prefetchedRows);
}
}
private final long nowInSec;
protected final long timestamp;
private final int ttl;
public static class NoTimeRowUpdateBuilder extends RowUpdateBuilder implements NoTimeFunctionContext
{
public NoTimeRowUpdateBuilder(TableMetadata metadata, ClientState clientState, QueryOptions options, long timestamp, long nowInSec, int ttl, Map<DecoratedKey, Partition> prefetchedRows) throws InvalidRequestException
{
super(metadata, clientState, options, timestamp, nowInSec, ttl, prefetchedRows);
}
}
public final TableMetadata metadata;
private final QueryOptions options;
public final ClientState clientState;
public final long nowInSec;
public final long timestamp;
public final int ttl;
private DeletionTime deletionTime;
@ -66,7 +79,7 @@ public class UpdateParameters
// The builder currently in use. Will alias either staticBuilder or regularBuilder, which are themselves built lazily.
private Row.Builder builder;
public UpdateParameters(TableMetadata metadata,
protected RowUpdateBuilder(TableMetadata metadata,
ClientState clientState,
QueryOptions options,
long timestamp,
@ -75,21 +88,26 @@ public class UpdateParameters
Map<DecoratedKey, Partition> prefetchedRows) throws InvalidRequestException
{
this.metadata = metadata;
this.clientState = clientState;
this.options = options;
this.clientState = clientState;
this.nowInSec = nowInSec;
this.timestamp = timestamp;
this.ttl = ttl;
this.deletionTime = DeletionTime.build(timestamp, nowInSec);
this.prefetchedRows = prefetchedRows;
// We use MIN_VALUE internally to mean the absence of of timestamp (in Selection, in sstable stats, ...), so exclude
// it to avoid potential confusion.
if (timestamp == Long.MIN_VALUE)
throw new InvalidRequestException(String.format("Out of bound timestamp, must be in [%d, %d]", Long.MIN_VALUE + 1, Long.MAX_VALUE));
}
@Override
public QueryOptions options()
{
return options;
}
public <V> void newRow(Clustering<V> clustering) throws InvalidRequestException
{
if (metadata.isCompactTable())
@ -208,7 +226,7 @@ public class UpdateParameters
newRow(row.clustering());
addRowDeletion(row.deletion());
addPrimaryKeyLivenessInfo(row.primaryKeyLivenessInfo());
row.iterator().forEachRemaining(cd -> {
row.forEach(cd -> {
if (cd instanceof Cell<?>)
{
builder.addCell((Cell<?>) cd);
@ -297,11 +315,6 @@ public class UpdateParameters
return new RangeTombstone(slice, deletionTime());
}
public byte[] nextTimeUUIDAsBytes()
{
return TimeUUID.Generator.nextTimeUUIDAsBytes();
}
/**
* Returns the prefetched row with the already performed modifications.
* <p>If no modification have yet been performed this method will return the fetched row or {@code null} if
@ -332,4 +345,5 @@ public class UpdateParameters
return Rows.merge(prefetchedRow, pendingMutations)
.purge(DeletionPurger.PURGE_ALL, nowInSec, metadata.enforceStrictLiveness());
}
}

View File

@ -29,8 +29,8 @@ import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.ColumnsExpression;
import org.apache.cassandra.cql3.FieldIdentifier;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operator;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.terms.Term;
@ -110,39 +110,39 @@ public final class ColumnCondition
values.collectMarkerSpecification(boundNames, owner);
}
public ColumnCondition.Bound bind(QueryOptions options)
public ColumnCondition.Bound bind(FunctionContext context)
{
switch (columnsExpression.kind())
{
case SINGLE_COLUMN:
return bindSingleColumn(options);
return bindSingleColumn(context);
case ELEMENT:
return bindElement(options);
return bindElement(context);
default:
throw new UnsupportedOperationException();
}
}
private Bound bindSingleColumn(QueryOptions options)
private Bound bindSingleColumn(FunctionContext context)
{
ColumnMetadata column = columnsExpression.firstColumn();
TableMetadata table = columnsExpression.table();
if (column.type.isMultiCell())
return new MultiCellBound(column, table, operator, toValue(column.type, bindAndGetTerms(options)));
return new MultiCellBound(column, table, operator, toValue(column.type, bindAndGetTerms(context)));
return new SimpleBound(column, table, operator, toValue(column.type, bindAndGetTerms(options)));
return new SimpleBound(column, table, operator, toValue(column.type, bindAndGetTerms(context)));
}
private ColumnCondition.Bound bindElement(QueryOptions options)
private ColumnCondition.Bound bindElement(FunctionContext context)
{
ColumnMetadata column = columnsExpression.firstColumn();
TableMetadata table = columnsExpression.table();
ByteBuffer keyOrIndex = columnsExpression.element(options);
ByteBuffer keyOrIndex = columnsExpression.element(context);
if (column.type.isCollection())
{
checkNotNull(keyOrIndex, "Invalid null value for %s element access", column.type instanceof MapType ? "map" : "list");
}
return new ElementOrFieldAccessBound(column, table, keyOrIndex, operator, toValue(columnsExpression.type(), bindAndGetTerms(options)));
return new ElementOrFieldAccessBound(column, table, keyOrIndex, operator, toValue(columnsExpression.type(), bindAndGetTerms(context)));
}
private ByteBuffer toValue(AbstractType<?> type, List<ByteBuffer> values)
@ -157,9 +157,9 @@ public final class ColumnCondition
return value;
}
private List<ByteBuffer> bindAndGetTerms(QueryOptions options)
private List<ByteBuffer> bindAndGetTerms(FunctionContext context)
{
List<ByteBuffer> buffers = values.bindAndGet(options);
List<ByteBuffer> buffers = values.bindAndGet(context);
checkFalse(buffers == null && operator.isIN(), "Invalid null list in IN condition");
checkFalse(buffers == Term.UNSET_LIST, "Invalid 'unset' value in condition");
return filterUnsetValuesIfNeeded(buffers, ByteBufferUtil.UNSET_BYTE_BUFFER);

View File

@ -23,6 +23,7 @@ import java.math.RoundingMode;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.ByteType;
import org.apache.cassandra.db.marshal.BytesType;
@ -35,7 +36,6 @@ import org.apache.cassandra.db.marshal.IntegerType;
import org.apache.cassandra.db.marshal.LongType;
import org.apache.cassandra.db.marshal.ShortType;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.transport.ProtocolVersion;
/**
* Factory methods for aggregate functions.
@ -119,7 +119,7 @@ public abstract class AggregateFcts
count = 0;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return LongType.instance.decompose(count);
}
@ -163,7 +163,7 @@ public abstract class AggregateFcts
sum = BigDecimal.ZERO;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return ((DecimalType) returnType()).decompose(sum);
}
@ -204,7 +204,7 @@ public abstract class AggregateFcts
avg = BigDecimal.ZERO;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return DecimalType.instance.decompose(avg);
}
@ -244,7 +244,7 @@ public abstract class AggregateFcts
sum = BigInteger.ZERO;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return ((IntegerType) returnType()).decompose(sum);
}
@ -286,7 +286,7 @@ public abstract class AggregateFcts
sum = BigInteger.ZERO;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
if (count == 0)
return IntegerType.instance.decompose(BigInteger.ZERO);
@ -329,7 +329,7 @@ public abstract class AggregateFcts
sum = 0;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return ((ByteType) returnType()).decompose(sum);
}
@ -361,7 +361,7 @@ public abstract class AggregateFcts
{
return new AvgAggregate()
{
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
public ByteBuffer compute(FunctionContext context) throws InvalidRequestException
{
return ByteType.instance.decompose((byte) computeInternal());
}
@ -389,7 +389,7 @@ public abstract class AggregateFcts
sum = 0;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return ((ShortType) returnType()).decompose(sum);
}
@ -421,7 +421,7 @@ public abstract class AggregateFcts
{
return new AvgAggregate()
{
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return ShortType.instance.decompose((short) computeInternal());
}
@ -449,7 +449,7 @@ public abstract class AggregateFcts
sum = 0;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return ((Int32Type) returnType()).decompose(sum);
}
@ -481,7 +481,7 @@ public abstract class AggregateFcts
{
return new AvgAggregate()
{
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return Int32Type.instance.decompose((int) computeInternal());
}
@ -517,7 +517,7 @@ public abstract class AggregateFcts
{
return new AvgAggregate()
{
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return LongType.instance.decompose(computeInternal());
}
@ -538,7 +538,7 @@ public abstract class AggregateFcts
{
return new FloatSumAggregate()
{
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
public ByteBuffer compute(FunctionContext context) throws InvalidRequestException
{
return FloatType.instance.decompose((float) computeInternal());
}
@ -558,7 +558,7 @@ public abstract class AggregateFcts
{
return new FloatAvgAggregate()
{
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
public ByteBuffer compute(FunctionContext context) throws InvalidRequestException
{
return FloatType.instance.decompose((float) computeInternal());
}
@ -579,7 +579,7 @@ public abstract class AggregateFcts
{
return new FloatSumAggregate()
{
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
public ByteBuffer compute(FunctionContext context) throws InvalidRequestException
{
return DoubleType.instance.decompose(computeInternal());
}
@ -730,7 +730,7 @@ public abstract class AggregateFcts
{
return new FloatAvgAggregate()
{
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
public ByteBuffer compute(FunctionContext context) throws InvalidRequestException
{
return DoubleType.instance.decompose(computeInternal());
}
@ -760,7 +760,7 @@ public abstract class AggregateFcts
{
return new AvgAggregate()
{
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
public ByteBuffer compute(FunctionContext context) throws InvalidRequestException
{
return CounterColumnType.instance.decompose(computeInternal());
}
@ -785,7 +785,7 @@ public abstract class AggregateFcts
min = null;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return min != null ? LongType.instance.decompose(min) : null;
}
@ -824,7 +824,7 @@ public abstract class AggregateFcts
max = null;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return max != null ? LongType.instance.decompose(max) : null;
}
@ -857,9 +857,9 @@ public abstract class AggregateFcts
return new NativeAggregateFunction("max", inputType, inputType)
{
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newNoopInstance(version, 1);
return FunctionArguments.newNoopInstance(context, 1);
}
@Override
@ -874,7 +874,7 @@ public abstract class AggregateFcts
max = null;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return max;
}
@ -906,9 +906,9 @@ public abstract class AggregateFcts
return new NativeAggregateFunction("min", inputType, inputType)
{
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newNoopInstance(version, 1);
return FunctionArguments.newNoopInstance(context, 1);
}
@Override
@ -923,7 +923,7 @@ public abstract class AggregateFcts
min = null;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return min;
}
@ -955,9 +955,9 @@ public abstract class AggregateFcts
return new NativeAggregateFunction("count", LongType.instance, inputType)
{
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newNoopInstance(version, 1);
return FunctionArguments.newNoopInstance(context, 1);
}
@Override
@ -972,7 +972,7 @@ public abstract class AggregateFcts
count = 0;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return ((LongType) returnType()).decompose(count);
}
@ -999,7 +999,7 @@ public abstract class AggregateFcts
sum = 0;
}
public ByteBuffer compute(ProtocolVersion protocolVersion)
public ByteBuffer compute(FunctionContext context)
{
return LongType.instance.decompose(sum);
}

View File

@ -19,8 +19,8 @@ package org.apache.cassandra.cql3.functions;
import java.nio.ByteBuffer;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.transport.ProtocolVersion;
/**
* Performs a calculation on a set of values and return a single value.
@ -49,10 +49,10 @@ public interface AggregateFunction extends Function
/**
* Computes and returns the aggregate current value.
*
* @param protocolVersion native protocol version
* @param context
* @return the aggregate current value.
*/
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException;
public ByteBuffer compute(FunctionContext context) throws InvalidRequestException;
/**
* Reset this aggregate.

View File

@ -21,6 +21,7 @@ package org.apache.cassandra.cql3.functions;
import java.nio.ByteBuffer;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.transport.ProtocolVersion;
/**
@ -29,6 +30,8 @@ import org.apache.cassandra.transport.ProtocolVersion;
*/
public interface Arguments
{
FunctionContext context();
/**
* Sets the specified value to the arguments
*

View File

@ -20,11 +20,11 @@ package org.apache.cassandra.cql3.functions;
import java.nio.ByteBuffer;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.FunctionContext;
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;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil;
public abstract class BytesConversionFcts
@ -49,9 +49,9 @@ public abstract class BytesConversionFcts
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newNoopInstance(version, 1);
return FunctionArguments.newNoopInstance(context, 1);
}
}

View File

@ -25,6 +25,7 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.AsciiType;
import org.apache.cassandra.db.marshal.BooleanType;
@ -44,7 +45,6 @@ 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.transport.ProtocolVersion;
import static org.apache.cassandra.cql3.functions.TimeFcts.toDate;
import static org.apache.cassandra.cql3.functions.TimeFcts.toTimestamp;
@ -388,9 +388,9 @@ public final class CastFcts
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return new FunctionArguments(version, (protocolVersion, buffer) -> {
return new FunctionArguments(context, (protocolVersion, buffer) -> {
AbstractType<?> argType = argTypes.get(0);
if (buffer == null || (!buffer.hasRemaining() && argType.isEmptyValueMeaningless()))
return null;

View File

@ -26,13 +26,13 @@ import java.util.Set;
import com.google.common.collect.ImmutableList;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.CollectionType;
import org.apache.cassandra.db.marshal.Int32Type;
import org.apache.cassandra.db.marshal.ListType;
import org.apache.cassandra.db.marshal.MapType;
import org.apache.cassandra.db.marshal.SetType;
import org.apache.cassandra.transport.ProtocolVersion;
/**
* Native CQL functions for collections (sets, list and maps).
@ -179,9 +179,9 @@ public class CollectionFcts
return new NativeScalarFunction(name, Int32Type.instance, inputType)
{
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newNoopInstance(version, 1);
return FunctionArguments.newNoopInstance(context, 1);
}
@Override
@ -359,9 +359,9 @@ public class CollectionFcts
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newNoopInstance(version, 1);
return FunctionArguments.newNoopInstance(context, 1);
}
@Override
@ -370,7 +370,7 @@ public class CollectionFcts
if (arguments.containsNulls())
return null;
Arguments args = aggregateFunction.newArguments(arguments.getProtocolVersion());
Arguments args = aggregateFunction.newArguments(arguments.context());
AggregateFunction.Aggregate aggregate = aggregateFunction.newAggregate();
inputType.forEach(arguments.get(0), element -> {
@ -378,7 +378,7 @@ public class CollectionFcts
aggregate.addInput(args);
});
return aggregate.compute(arguments.getProtocolVersion());
return aggregate.compute(arguments.context());
}
}
}

View File

@ -24,9 +24,9 @@ import java.util.Optional;
import org.github.jamm.Unmetered;
import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.schema.Difference;
import org.apache.cassandra.transport.ProtocolVersion;
@Unmetered
public interface Function extends AssignmentTestable
@ -77,10 +77,10 @@ public interface Function extends AssignmentTestable
/**
* Creates some new input arguments for this function.
*
* @param version the protocol version
* @param context
* @return some new input arguments for this function
*/
Arguments newArguments(ProtocolVersion version);
Arguments newArguments(FunctionContext context);
public default Optional<Difference> compare(Function other)
{

View File

@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.transport.ProtocolVersion;
@ -30,20 +31,14 @@ import org.apache.cassandra.transport.ProtocolVersion;
*/
public final class FunctionArguments implements Arguments
{
/**
* An empty {@link FunctionArguments} for the current protocol.
*/
private static final FunctionArguments EMPTY = new FunctionArguments(ProtocolVersion.CURRENT);
public static final ArgumentDeserializer[] NO_DESERIALIZERS = new ArgumentDeserializer[0];
/**
* The deserializer used to deserialize the columns.
*/
private final ArgumentDeserializer[] deserializers;
/**
* The protocol version.
*/
private final ProtocolVersion version;
private final FunctionContext context;
/**
* The deserialized arguments.
@ -53,93 +48,82 @@ public final class FunctionArguments implements 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)
public static Arguments newInstanceForUdf(FunctionContext context, List<UDFDataType> argTypes)
{
int size = argTypes.size();
if (size == 0)
return emptyInstance(version);
return context.noArguments();
ArgumentDeserializer[] deserializers = new ArgumentDeserializer[size];
for (int i = 0; i < size; i++)
deserializers[i] = argTypes.get(i).getArgumentDeserializer();
return new FunctionArguments(version, deserializers);
return new FunctionArguments(context, deserializers);
}
@Override
public ProtocolVersion getProtocolVersion()
{
return version;
return context.getProtocolVersion();
}
@Override
public FunctionContext context()
{
return context;
}
/**
* 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)
public static FunctionArguments newNoopInstance(FunctionContext context, 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);
return new FunctionArguments(context, deserializers);
}
/**
* 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)
public static Arguments newInstanceForNativeFunction(FunctionContext context, List<AbstractType<?>> argTypes)
{
int size = argTypes.size();
if (size == 0)
return emptyInstance(version);
return context.noArguments();
ArgumentDeserializer[] deserializers = new ArgumentDeserializer[size];
for (int i = 0; i < size; i++)
deserializers[i] = argTypes.get(i).getArgumentDeserializer();
return new FunctionArguments(version, deserializers);
return new FunctionArguments(context, deserializers);
}
public FunctionArguments(ProtocolVersion version, ArgumentDeserializer... deserializers)
public FunctionArguments(FunctionContext context, ArgumentDeserializer... deserializers)
{
this.version = version;
this.context = context;
this.deserializers = deserializers;
this.arguments = new Object[deserializers.length];
}
public void set(int i, ByteBuffer buffer)
{
arguments[i] = deserializers[i].deserialize(version, buffer);
arguments[i] = deserializers[i].deserialize(context.getProtocolVersion(), buffer);
}
@Override

View File

@ -28,7 +28,7 @@ import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.CqlBuilder;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.statements.RequestValidations;
import org.apache.cassandra.cql3.terms.Constants;
@ -68,19 +68,19 @@ public class FunctionCall extends Term.NonTerminal
}
@Override
public Term.Terminal bind(QueryOptions options) throws InvalidRequestException
public Term.Terminal bind(FunctionContext context) throws InvalidRequestException
{
return makeTerminal(fun, bindAndGet(options));
return makeTerminal(fun, bindAndGet(context));
}
@Override
public ByteBuffer bindAndGet(QueryOptions options) throws InvalidRequestException
public ByteBuffer bindAndGet(FunctionContext context) throws InvalidRequestException
{
Arguments arguments = fun.newArguments(options.getProtocolVersion());
Arguments arguments = fun.newArguments(context);
for (int i = 0, m = terms.size(); i < m; i++)
{
Term t = terms.get(i);
ByteBuffer argument = t.bindAndGet(options);
ByteBuffer argument = t.bindAndGet(context);
RequestValidations.checkBindValueSet(argument, "Invalid unset value for argument in call to function %s", fun.name().name);
arguments.set(i, argument);
}

View File

@ -23,11 +23,11 @@ import java.util.HashSet;
import java.util.Set;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.FunctionContext;
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 org.apache.cassandra.utils.ByteBufferUtil;
/**
@ -60,9 +60,9 @@ public class LengthFcts
{
// Do not deserialize
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newNoopInstance(version, 1);
return FunctionArguments.newNoopInstance(context, 1);
}
@Override

View File

@ -21,8 +21,8 @@ import java.util.Arrays;
import javax.annotation.Nullable;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.transport.ProtocolVersion;
/**
* Base class for our native/hardcoded functions.
@ -62,9 +62,8 @@ public abstract class NativeFunction extends AbstractFunction
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newInstanceForNativeFunction(version, argTypes);
return FunctionArguments.newInstanceForNativeFunction(context, argTypes);
}
}

View File

@ -25,7 +25,7 @@ import org.apache.cassandra.transport.ProtocolVersion;
/**
* A partial application of a function.
*
* @see ScalarFunction#partialApplication(ProtocolVersion, List)
* @see ScalarFunction#partialApplication(ProtocolVersion, org.apache.cassandra.cql3.FunctionContext, List)
*/
public interface PartialScalarFunction extends ScalarFunction
{

View File

@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.cql3.CqlBuilder;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.transport.ProtocolVersion;
@ -28,7 +29,7 @@ import org.apache.cassandra.transport.ProtocolVersion;
/**
* An internal function used to hold the partial application of another function to only some of its parameters.
*
* @see ScalarFunction#partialApplication(ProtocolVersion, List)
* @see ScalarFunction#partialApplication(FunctionContext, List)
*/
final class PartiallyAppliedScalarFunction extends NativeScalarFunction implements PartialScalarFunction
{
@ -63,9 +64,9 @@ final class PartiallyAppliedScalarFunction extends NativeScalarFunction implemen
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return new PartialFunctionArguments(version, function, partialParameters, argTypes.size());
return new PartialFunctionArguments(context, function, partialParameters, argTypes.size());
}
@Override
@ -126,9 +127,9 @@ final class PartiallyAppliedScalarFunction extends NativeScalarFunction implemen
*/
private final int[] mapping;
public PartialFunctionArguments(ProtocolVersion version, ScalarFunction function, List<ByteBuffer> partialArguments, int unresolvedCount)
public PartialFunctionArguments(FunctionContext context, ScalarFunction function, List<ByteBuffer> partialArguments, int unresolvedCount)
{
arguments = function.newArguments(version);
arguments = function.newArguments(context);
mapping = new int[unresolvedCount];
int mappingIndex = 0;
for (int i = 0, m = partialArguments.size(); i < m; i++)
@ -151,6 +152,12 @@ final class PartiallyAppliedScalarFunction extends NativeScalarFunction implemen
return arguments.getProtocolVersion();
}
@Override
public FunctionContext context()
{
return arguments.context();
}
@Override
public void set(int i, ByteBuffer buffer)
{

View File

@ -20,6 +20,7 @@ package org.apache.cassandra.cql3.functions;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.transport.ProtocolVersion;
@ -27,7 +28,7 @@ import org.apache.cassandra.transport.ProtocolVersion;
/**
* Function used internally to hold the pre-computed result of another function.
* <p>
* See {@link ScalarFunction#partialApplication(ProtocolVersion, List)} for why this is used.
* See {@link ScalarFunction#partialApplication(ProtocolVersion, FunctionContext, List)} for why this is used.
* <p>
* Note : the function is cautious in keeping the protocol version used for the pre-computed value and to
* fallback to recomputation if the version we get when {@link #execute} is called. I don't think it's truly necessary
@ -74,7 +75,7 @@ class PreComputedScalarFunction extends NativeScalarFunction implements PartialS
if (nothing.getProtocolVersion() == valueVersion)
return value;
Arguments args = function.newArguments(nothing.getProtocolVersion());
Arguments args = function.newArguments(nothing.context());
for (int i = 0, m = arguments.size() ; i < m; i++)
{
args.set(i, arguments.get(i));;
@ -83,7 +84,7 @@ class PreComputedScalarFunction extends NativeScalarFunction implements PartialS
return function.execute(args);
}
public ScalarFunction partialApplication(ProtocolVersion protocolVersion, List<ByteBuffer> nothing) throws InvalidRequestException
public ScalarFunction partialApplication(ProtocolVersion protocolVersion, FunctionContext context, List<ByteBuffer> nothing) throws InvalidRequestException
{
return this;
}

View File

@ -65,7 +65,7 @@ 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 arguments
* @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
@ -88,6 +88,7 @@ public interface ScalarFunction extends Function
if (isPure() && unresolvedCount == 0)
{
// if isPure(), requires no FunctionContext
Arguments arguments = newArguments(protocolVersion);
for (int i = 0, m = partialArguments.size(); i < m; i++)
{

View File

@ -80,7 +80,7 @@ public abstract class TimeFcts
@Override
public ByteBuffer execute(Arguments arguments)
{
return type.now();
return type.now(arguments.context());
}
@Override

View File

@ -22,10 +22,10 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
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;
import static java.lang.String.format;
@ -55,9 +55,9 @@ public class ToJsonFct extends NativeScalarFunction
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return new FunctionArguments(version, (protocolVersion, buffer) -> {
return new FunctionArguments(context, (protocolVersion, buffer) -> {
AbstractType<?> argType = argTypes.get(0);
if (buffer == null || (!buffer.hasRemaining() && argType.isEmptyValueMeaningless()))

View File

@ -22,13 +22,13 @@ import java.util.Arrays;
import java.util.List;
import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.CBuilder;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.schema.ColumnMetadata;
import org.apache.cassandra.schema.Schema;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.transport.ProtocolVersion;
public class TokenFct extends NativeScalarFunction
{
@ -41,11 +41,11 @@ public class TokenFct extends NativeScalarFunction
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
ArgumentDeserializer[] deserializers = new ArgumentDeserializer[argTypes.size()];
Arrays.fill(deserializers, ArgumentDeserializer.NOOP_DESERIALIZER);
return new FunctionArguments(version, deserializers);
return new FunctionArguments(context, deserializers);
}
private static AbstractType<?>[] getKeyTypes(TableMetadata metadata)

View File

@ -32,6 +32,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.cassandra.cql3.CqlBuilder;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.UserType;
import org.apache.cassandra.exceptions.ConfigurationException;
@ -120,9 +121,9 @@ public class UDAggregate extends UserFunction implements AggregateFunction
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newInstanceForUdf(version, argumentTypes);
return FunctionArguments.newInstanceForUdf(context, argumentTypes);
}
public boolean hasReferenceTo(Function function)
@ -230,8 +231,9 @@ public class UDAggregate extends UserFunction implements AggregateFunction
}
}
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException
public ByteBuffer compute(FunctionContext context) throws InvalidRequestException
{
ProtocolVersion protocolVersion = context.getProtocolVersion();
maybeInit(protocolVersion);
// final function is traced in UDFunction
@ -242,7 +244,7 @@ public class UDAggregate extends UserFunction implements AggregateFunction
if (finalFunction instanceof UDFunction)
{
UDFunction udf = (UDFunction)finalFunction;
Object result = udf.executeForAggregate(state, FunctionArguments.emptyInstance(protocolVersion));
Object result = udf.executeForAggregate(state, context.noArguments());
return resultType.decompose(protocolVersion, result);
}
throw new UnsupportedOperationException("UDAs only support UDFs");

View File

@ -49,6 +49,7 @@ 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.FunctionContext;
import org.apache.cassandra.cql3.functions.types.TypeCodec;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.UserType;
@ -232,9 +233,9 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newInstanceForUdf(version, argumentTypes);
return FunctionArguments.newInstanceForUdf(context, argumentTypes);
}
public static UDFunction tryCreate(FunctionName name,

View File

@ -22,11 +22,11 @@ import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.FloatType;
import org.apache.cassandra.db.marshal.VectorType;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.transport.ProtocolVersion;
import io.github.jbellis.jvector.vector.VectorSimilarityFunction;
@ -69,9 +69,9 @@ public class VectorFcts
return new NativeScalarFunction(name, FloatType.instance, type, type)
{
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return new FunctionArguments(version,
return new FunctionArguments(context,
(v, b) -> type.composeAsFloat(b),
(v, b) -> type.composeAsFloat(b));
}

View File

@ -35,6 +35,7 @@ import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.CqlBuilder;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.functions.FunctionName;
@ -135,20 +136,28 @@ public class ColumnMask
* @param version the used version of the transport protocol
* @return a masker instance that caches the terminal masking function arguments
*/
public Masker masker(ProtocolVersion version)
public Masker masker(ProtocolVersion version, FunctionContext context)
{
return new Masker(version, function, partialArgumentValues);
return new Masker(version, context, function, partialArgumentValues);
}
public static class Masker
{
public static final Masker NOT_A_MASKER = new Masker();
private final ScalarFunction function;
private final Arguments arguments;
private Masker(ProtocolVersion version, ScalarFunction function, ByteBuffer[] partialArgumentValues)
private Masker()
{
function = null;
arguments = null;
}
private Masker(ProtocolVersion version, FunctionContext context, ScalarFunction function, ByteBuffer[] partialArgumentValues)
{
this.function = function;
arguments = function.newArguments(version);
arguments = function.newArguments(context);
for (int i = 0; i < partialArgumentValues.length; i++)
arguments.set(i + 1, partialArgumentValues[i]);
}

View File

@ -21,6 +21,7 @@ package org.apache.cassandra.cql3.functions.masking;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.FunctionArguments;
import org.apache.cassandra.cql3.functions.FunctionFactory;
@ -29,7 +30,6 @@ 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.
@ -53,9 +53,9 @@ public class DefaultMaskingFunction extends MaskingFunction
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newNoopInstance(version, 1);
return FunctionArguments.newNoopInstance(context, 1);
}
@Override

View File

@ -30,6 +30,7 @@ import javax.annotation.Nullable;
import com.google.common.annotations.VisibleForTesting;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.FunctionArguments;
@ -41,7 +42,6 @@ import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.BytesType;
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;
/**
@ -71,9 +71,9 @@ public class HashMaskingFunction extends MaskingFunction
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return new FunctionArguments(version,
return new FunctionArguments(context,
ArgumentDeserializer.NOOP_DESERIALIZER, // the value to be masked
(v, b) -> messageDigest(b)); // the algorithm, if any
}

View File

@ -21,6 +21,7 @@ package org.apache.cassandra.cql3.functions.masking;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.FunctionArguments;
import org.apache.cassandra.cql3.functions.FunctionFactory;
@ -29,7 +30,6 @@ 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,
@ -48,9 +48,9 @@ public class NullMaskingFunction extends MaskingFunction
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newNoopInstance(version, 1);
return FunctionArguments.newNoopInstance(context, 1);
}
@Override

View File

@ -29,6 +29,7 @@ import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang3.StringUtils;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.FunctionArguments;
@ -40,7 +41,6 @@ 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;
@ -106,9 +106,9 @@ public class PartialMaskingFunction extends MaskingFunction
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return new FunctionArguments(version,
return new FunctionArguments(context,
inputType.getArgumentDeserializer(),
Int32Type.instance.getArgumentDeserializer(),
Int32Type.instance.getArgumentDeserializer(),

View File

@ -21,6 +21,7 @@ package org.apache.cassandra.cql3.functions.masking;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.FunctionArguments;
import org.apache.cassandra.cql3.functions.FunctionFactory;
@ -29,7 +30,6 @@ 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.
@ -48,9 +48,9 @@ public class ReplaceMaskingFunction extends MaskingFunction
}
@Override
public Arguments newArguments(ProtocolVersion version)
public Arguments newArguments(FunctionContext context)
{
return FunctionArguments.newNoopInstance(version, 2);
return FunctionArguments.newNoopInstance(context, 2);
}
@Override

View File

@ -24,6 +24,7 @@ import javax.annotation.Nullable;
import com.google.common.collect.RangeSet;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.ClusteringComparator;
@ -199,7 +200,7 @@ final class ClusteringColumnRestrictions extends RestrictionSetWrapper
@Override
public void addToRowFilter(RowFilter filter,
IndexRegistry indexRegistry,
QueryOptions options,
FunctionContext context,
IndexHints indexHints) throws InvalidRequestException
{
int position = 0;
@ -209,7 +210,7 @@ final class ClusteringColumnRestrictions extends RestrictionSetWrapper
// We ignore all the clustering columns that can be handled by slices.
if (handleInFilter(restriction, position) || restriction.hasSupportingIndex(indexRegistry, indexHints))
{
restriction.addToRowFilter(filter, indexRegistry, options, indexHints);
restriction.addToRowFilter(filter, indexRegistry, context, indexHints);
continue;
}

View File

@ -25,8 +25,8 @@ import java.util.Set;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.RangeSet;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operator;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.Relation;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.filter.IndexHints;
@ -332,31 +332,31 @@ public final class MergedRestriction implements SingleRestriction
}
@Override
public List<ClusteringElements> values(QueryOptions options)
public List<ClusteringElements> values(FunctionContext context)
{
List<ClusteringElements> values = restrictions.get(0).values(options);
List<ClusteringElements> values = restrictions.get(0).values(context);
for (int i = 1, m = restrictions.size(); i < m; i++)
{
values.retainAll(restrictions.get(i).values(options));
values.retainAll(restrictions.get(i).values(context));
}
return values;
}
@Override
public void restrict(RangeSet<ClusteringElements> rangeSet, QueryOptions options, IPartitioner partitioner)
public void restrict(RangeSet<ClusteringElements> rangeSet, FunctionContext context, IPartitioner partitioner)
{
for (int i = 0, m = restrictions.size(); i < m; i++)
{
restrictions.get(i).restrict(rangeSet, options, partitioner);
restrictions.get(i).restrict(rangeSet, context, partitioner);
}
}
@Override
public void addToRowFilter(RowFilter filter, IndexRegistry indexRegistry, QueryOptions options, IndexHints indexHints)
public void addToRowFilter(RowFilter filter, IndexRegistry indexRegistry, FunctionContext context, IndexHints indexHints)
{
for (int i = 0, m = restrictions.size(); i < m; i++)
{
restrictions.get(i).addToRowFilter(filter, indexRegistry, options, indexHints);
restrictions.get(i).addToRowFilter(filter, indexRegistry, context, indexHints);
}
}
}

View File

@ -19,7 +19,7 @@ package org.apache.cassandra.cql3.restrictions;
import java.util.List;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.filter.IndexHints;
import org.apache.cassandra.db.filter.RowFilter;
@ -109,12 +109,12 @@ public interface Restriction
/**
* Adds to the specified row filter the expressions corresponding to this <code>Restriction</code>.
*
* @param filter the row filter to add expressions to
* @param filter the row filter to add expressions to
* @param indexRegistry the index registry
* @param options the query options
* @param context the query options
*/
void addToRowFilter(RowFilter filter,
IndexRegistry indexRegistry,
QueryOptions options,
FunctionContext context,
IndexHints indexHints);
}

View File

@ -33,7 +33,7 @@ import com.google.common.collect.AbstractIterator;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.filter.IndexHints;
import org.apache.cassandra.db.filter.RowFilter;
@ -113,10 +113,10 @@ final class RestrictionSet implements Restrictions, Iterable<SingleRestriction>
}
@Override
public void addToRowFilter(RowFilter filter, IndexRegistry indexRegistry, QueryOptions options, IndexHints indexHints) throws InvalidRequestException
public void addToRowFilter(RowFilter filter, IndexRegistry indexRegistry, FunctionContext context, IndexHints indexHints) throws InvalidRequestException
{
for (Restriction restriction : this)
restriction.addToRowFilter(filter, indexRegistry, options, indexHints);
restriction.addToRowFilter(filter, indexRegistry, context, indexHints);
}
@Override

View File

@ -22,7 +22,7 @@ import java.util.List;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.filter.IndexHints;
import org.apache.cassandra.db.filter.RowFilter;
@ -48,10 +48,10 @@ class RestrictionSetWrapper implements Restrictions
public void addToRowFilter(RowFilter filter,
IndexRegistry indexRegistry,
QueryOptions options,
FunctionContext context,
IndexHints indexHints)
{
restrictions.addToRowFilter(filter, indexRegistry, options, indexHints);
restrictions.addToRowFilter(filter, indexRegistry, context, indexHints);
}
public List<ColumnMetadata> columns()

View File

@ -28,8 +28,8 @@ import java.util.stream.Collectors;
import com.google.common.collect.RangeSet;
import org.apache.cassandra.cql3.ColumnsExpression;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operator;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.Relation;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.terms.Term;
@ -248,44 +248,44 @@ public final class SimpleRestriction implements SingleRestriction
}
@Override
public List<ClusteringElements> values(QueryOptions options)
public List<ClusteringElements> values(FunctionContext context)
{
assert operator == Operator.EQ ||
operator == Operator.IN ||
operator == Operator.ANN : String.format("Unexpected operator: %s", operator);
return bindAndGetClusteringElements(options);
return bindAndGetClusteringElements(context);
}
@Override
public void restrict(RangeSet<ClusteringElements> rangeSet, QueryOptions options, IPartitioner partitioner)
public void restrict(RangeSet<ClusteringElements> rangeSet, FunctionContext context, IPartitioner partitioner)
{
assert operator.isSlice() || operator == Operator.EQ;
operator.restrict(rangeSet, bindAndGetClusteringElements(options), partitioner);
operator.restrict(rangeSet, bindAndGetClusteringElements(context), partitioner);
}
private List<ClusteringElements> bindAndGetClusteringElements(QueryOptions options)
private List<ClusteringElements> bindAndGetClusteringElements(FunctionContext context)
{
switch (columnsExpression.kind())
{
case SINGLE_COLUMN:
case TOKEN:
return bindAndGetSingleTermClusteringElements(options);
return bindAndGetSingleTermClusteringElements(context);
case MULTI_COLUMN:
return bindAndGetMultiTermClusteringElements(options);
return bindAndGetMultiTermClusteringElements(context);
default:
throw new UnsupportedOperationException();
}
}
private List<ClusteringElements> bindAndGetSingleTermClusteringElements(QueryOptions options)
private List<ClusteringElements> bindAndGetSingleTermClusteringElements(FunctionContext context)
{
if (values.isSingleTerm(options))
if (values.isSingleTerm(context))
{
ByteBuffer value = bindAndGetSingle(options);
ByteBuffer value = bindAndGetSingle(context);
return Collections.singletonList(ClusteringElements.of(columnsExpression.columnSpecification(), value, isOnToken()));
}
List<ByteBuffer> values = bindAndGet(options);
List<ByteBuffer> values = bindAndGet(context);
if (values.isEmpty())
return Collections.emptyList();
@ -301,9 +301,9 @@ public final class SimpleRestriction implements SingleRestriction
return elements;
}
private List<ClusteringElements> bindAndGetMultiTermClusteringElements(QueryOptions options)
private List<ClusteringElements> bindAndGetMultiTermClusteringElements(FunctionContext context)
{
List<List<ByteBuffer>> values = bindAndGetElements(options);
List<List<ByteBuffer>> values = bindAndGetElements(context);
if (values.isEmpty())
return Collections.emptyList();
@ -313,24 +313,24 @@ public final class SimpleRestriction implements SingleRestriction
return elements;
}
private List<ByteBuffer> bindAndGet(QueryOptions options)
private List<ByteBuffer> bindAndGet(FunctionContext context)
{
List<ByteBuffer> buffers = values.bindAndGet(options);
List<ByteBuffer> buffers = values.bindAndGet(context);
validate(buffers);
buffers.forEach(this::validate);
return buffers;
}
private ByteBuffer bindAndGetSingle(QueryOptions options)
private ByteBuffer bindAndGetSingle(FunctionContext context)
{
ByteBuffer buffer = values.bindAndGetSingleTermValue(options);
ByteBuffer buffer = values.bindAndGetSingleTermValue(context);
validate(buffer);
return buffer;
}
private List<List<ByteBuffer>> bindAndGetElements(QueryOptions options)
private List<List<ByteBuffer>> bindAndGetElements(FunctionContext context)
{
List<List<ByteBuffer>> elementsList = values.bindAndGetElements(options);
List<List<ByteBuffer>> elementsList = values.bindAndGetElements(context);
validate(elementsList);
elementsList.forEach(this::validateElements);
return elementsList;
@ -371,7 +371,7 @@ public final class SimpleRestriction implements SingleRestriction
}
@Override
public void addToRowFilter(RowFilter filter, IndexRegistry indexRegistry, QueryOptions options, IndexHints indexHints)
public void addToRowFilter(RowFilter filter, IndexRegistry indexRegistry, FunctionContext context, IndexHints indexHints)
{
if (isOnToken())
throw new UnsupportedOperationException();
@ -380,7 +380,7 @@ public final class SimpleRestriction implements SingleRestriction
switch (columnsExpression.kind())
{
case SINGLE_COLUMN:
List<ByteBuffer> buffers = bindAndGet(options);
List<ByteBuffer> buffers = bindAndGet(context);
if (operator.kind() != Operator.Kind.BINARY)
{
if (operator == Operator.IN && !column.type.isCounter())
@ -406,7 +406,7 @@ public final class SimpleRestriction implements SingleRestriction
if (isEQ())
{
List<ByteBuffer> elements = bindAndGetElements(options).get(0);
List<ByteBuffer> elements = bindAndGetElements(context).get(0);
for (int i = 0, m = columns().size(); i < m; i++)
{
@ -420,7 +420,7 @@ public final class SimpleRestriction implements SingleRestriction
// c IN (x, y, z) and we can perform filtering
if (columns().size() == 1)
{
List<ByteBuffer> values = bindAndGetElements(options).stream()
List<ByteBuffer> values = bindAndGetElements(context).stream()
.map(elements -> elements.get(0))
.collect(Collectors.toList());
@ -451,12 +451,12 @@ public final class SimpleRestriction implements SingleRestriction
}
}
ByteBuffer key = columnsExpression.element(options);
ByteBuffer key = columnsExpression.element(context);
if (key == null)
throw invalidRequest("Invalid null map key for column %s", column.name.toCQLString());
if (key == ByteBufferUtil.UNSET_BYTE_BUFFER)
throw invalidRequest("Invalid unset map key for column %s", column.name.toCQLString());
List<ByteBuffer> values = bindAndGet(options);
List<ByteBuffer> values = bindAndGet(context);
filter.addMapEquality(column, key, operator, values.get(0));
}
break;

View File

@ -21,7 +21,7 @@ import java.util.List;
import com.google.common.collect.RangeSet;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.dht.IPartitioner;
import org.apache.cassandra.index.Index;
@ -93,19 +93,19 @@ public interface SingleRestriction extends Restriction
/**
* Returns the values selected by this restriction (or by the intersection of merged restrictions) if the operator is an {@code EQ} or an {@code IN}.
*
* @param options the query options
* @param context the query options
* @return the values selected by this restriction (or by the intersection of merged restrictions) if the operator is an {@code EQ} or an {@code IN}.
* @throws UnsupportedOperationException if the operator is not an {@code EQ} or an {@code IN}.
*/
List<ClusteringElements> values(QueryOptions options);
List<ClusteringElements> values(FunctionContext context);
/**
* Removes the ranges of values not selected by this restriction from the specified {@code RangeSet} if the operator is an operator selecting ranges of data.
*
* @param rangeSet the range set to add to
* @param options the query options
* @param rangeSet the range set to add to
* @param context the query options
* @param partitioner the partitioner, used to identify MIN_TOKEN when using token restrictions
* @throws UnsupportedOperationException if the operator is not an operator selecting ranges of data.
*/
void restrict(RangeSet<ClusteringElements> rangeSet, QueryOptions options, IPartitioner partitioner);
void restrict(RangeSet<ClusteringElements> rangeSet, FunctionContext context, IPartitioner partitioner);
}

View File

@ -28,6 +28,7 @@ import com.google.common.collect.Iterables;
import org.apache.commons.lang3.text.StrBuilder;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.Function;
@ -133,9 +134,17 @@ 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 Arguments args;
private Arguments args;
protected final List<Selector> argSelectors;
@Override
public void prepare(FunctionContext context)
{
args = fun.newArguments(context);
for (Selector selector : argSelectors)
selector.prepare(context);
}
public static Factory newFactory(final Function fun, final SelectorFactories factories) throws InvalidRequestException
{
if (fun.isAggregate())
@ -179,7 +188,7 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
public Selector newInstance(QueryOptions options) throws InvalidRequestException
{
return fun.isAggregate() ? new AggregateFunctionSelector(options.getProtocolVersion(), fun, factories.newInstances(options))
return fun.isAggregate() ? new AggregateFunctionSelector(fun, factories.newInstances(options))
: createScalarSelector(options, (ScalarFunction) fun, factories.newInstances(options));
}
@ -204,7 +213,7 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
}
if (terminalCount == 0)
return new ScalarFunctionSelector(version, fun, argSelectors);
return new ScalarFunctionSelector(fun, argSelectors);
// We have some terminal arguments, do a partial application
ScalarFunction partialFunction = function.partialApplication(version, terminalArgs);
@ -212,6 +221,7 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
// If all the arguments are terminal and the function is pure we can reduce to a simple value.
if (terminalCount == argSelectors.size() && fun.isPure())
{
// pure functions need no context
Arguments arguments = partialFunction.newArguments(version);
return new TermSelector(partialFunction.execute(arguments), partialFunction.returnType());
}
@ -222,7 +232,7 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
if (!selector.isTerminal())
remainingSelectors.add(selector);
}
return new ScalarFunctionSelector(version, partialFunction, remainingSelectors);
return new ScalarFunctionSelector(partialFunction, remainingSelectors);
}
public boolean isWritetimeSelectorFactory()
@ -255,12 +265,11 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
};
}
protected AbstractFunctionSelector(Kind kind, ProtocolVersion version, T fun, List<Selector> argSelectors)
protected AbstractFunctionSelector(Kind kind, T fun, List<Selector> argSelectors)
{
super(kind);
this.fun = fun;
this.argSelectors = argSelectors;
this.args = fun.newArguments(version);
}
@Override

View File

@ -20,6 +20,7 @@ package org.apache.cassandra.cql3.selection;
import java.nio.ByteBuffer;
import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.AggregateFunction;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.exceptions.InvalidRequestException;
@ -32,10 +33,11 @@ final class AggregateFunctionSelector extends AbstractFunctionSelector<Aggregate
@Override
protected Selector newFunctionSelector(ProtocolVersion version, Function function, List<Selector> argSelectors)
{
return new AggregateFunctionSelector(version, function, argSelectors);
return new AggregateFunctionSelector(function, argSelectors);
}
};
private FunctionContext context;
private final AggregateFunction.Aggregate aggregate;
public boolean isAggregate()
@ -43,6 +45,13 @@ final class AggregateFunctionSelector extends AbstractFunctionSelector<Aggregate
return true;
}
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
this.context = context;
}
public void addInput(InputRow input)
{
ProtocolVersion protocolVersion = input.getProtocolVersion();
@ -60,7 +69,7 @@ final class AggregateFunctionSelector extends AbstractFunctionSelector<Aggregate
public ByteBuffer getOutput(ProtocolVersion protocolVersion) throws InvalidRequestException
{
return aggregate.compute(protocolVersion);
return aggregate.compute(context);
}
public void reset()
@ -68,9 +77,9 @@ final class AggregateFunctionSelector extends AbstractFunctionSelector<Aggregate
aggregate.reset();
}
AggregateFunctionSelector(ProtocolVersion version, Function fun, List<Selector> argSelectors) throws InvalidRequestException
AggregateFunctionSelector(Function fun, List<Selector> argSelectors) throws InvalidRequestException
{
super(Kind.AGGREGATE_FUNCTION_SELECTOR, version, (AggregateFunction) fun, argSelectors);
super(Kind.AGGREGATE_FUNCTION_SELECTOR, (AggregateFunction) fun, argSelectors);
this.aggregate = this.fun.newAggregate();
}

View File

@ -24,6 +24,7 @@ import com.google.common.base.Objects;
import com.google.common.collect.Range;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.selection.SimpleSelector.SimpleSelectorFactory;
import org.apache.cassandra.cql3.terms.Term;
@ -63,6 +64,13 @@ abstract class ElementsSelector extends Selector
this.type = getCollectionType(selected);
}
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
selected.prepare(context);
}
private static boolean isUnset(ByteBuffer bb)
{
return bb == ByteBufferUtil.UNSET_BYTE_BUFFER;

View File

@ -24,6 +24,7 @@ import java.util.List;
import com.google.common.base.Objects;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.db.TypeSizes;
import org.apache.cassandra.db.filter.ColumnFilter;
@ -159,6 +160,13 @@ final class FieldSelector extends Selector
this.selected = selected;
}
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
selected.prepare(context);
}
@Override
public boolean equals(Object o)
{

View File

@ -24,6 +24,7 @@ import java.util.List;
import com.google.common.base.Objects;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.terms.Lists;
import org.apache.cassandra.db.TypeSizes;
@ -139,6 +140,14 @@ final class ListSelector extends Selector
this.elements = elements;
}
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
for (Selector selector : elements)
selector.prepare(context);
}
@Override
public boolean equals(Object o)
{

View File

@ -28,6 +28,7 @@ import java.util.stream.Collectors;
import com.google.common.base.Objects;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.terms.Maps;
@ -259,7 +260,17 @@ final class MapSelector extends Selector
this.type = (MapType<?, ?>) type;
this.elements = elements;
}
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
for (Pair<Selector, Selector> selector : elements)
{
selector.left.prepare(context);
selector.right.prepare(context);
}
}
@Override
public boolean equals(Object o)

View File

@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.ResultSet;
import org.apache.cassandra.cql3.ResultSet.ResultMetadata;
import org.apache.cassandra.cql3.selection.Selection.Selectors;
@ -60,17 +61,18 @@ public final class ResultSetBuilder
private long size = 0;
private boolean sizeWarningEmitted = false;
public ResultSetBuilder(ResultMetadata metadata, Selectors selectors, boolean unmask)
public ResultSetBuilder(ResultMetadata metadata, FunctionContext context, Selectors selectors, boolean unmask)
{
this(metadata, selectors, unmask, null);
this(metadata, context, selectors, unmask, null);
}
public ResultSetBuilder(ResultMetadata metadata, Selectors selectors, boolean unmask, GroupMaker groupMaker)
public ResultSetBuilder(ResultMetadata metadata, FunctionContext context, Selectors selectors, boolean unmask, GroupMaker groupMaker)
{
this.resultSet = new ResultSet(metadata.copy(), new ArrayList<>());
this.selectors = selectors;
this.groupMaker = groupMaker;
this.unmask = unmask;
selectors.prepare(context);
}
private void addSize(List<ByteBuffer> row)

View File

@ -33,7 +33,7 @@ final class ScalarFunctionSelector extends AbstractFunctionSelector<ScalarFuncti
@Override
protected Selector newFunctionSelector(ProtocolVersion version, Function function, List<Selector> argSelectors)
{
return new ScalarFunctionSelector(version, function, argSelectors);
return new ScalarFunctionSelector(function, argSelectors);
}
};
@ -69,8 +69,8 @@ final class ScalarFunctionSelector extends AbstractFunctionSelector<ScalarFuncti
argSelectors.get(i).validateForGroupBy();
}
ScalarFunctionSelector(ProtocolVersion version, Function fun, List<Selector> argSelectors)
ScalarFunctionSelector(Function fun, List<Selector> argSelectors)
{
super(Kind.SCALAR_FUNCTION_SELECTOR, version, (ScalarFunction) fun, argSelectors);
super(Kind.SCALAR_FUNCTION_SELECTOR, (ScalarFunction) fun, argSelectors);
}
}

View File

@ -32,6 +32,7 @@ import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Json;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.ResultSet;
@ -393,6 +394,8 @@ public abstract class Selection
*/
default boolean collectWritetimes() { return false; }
default void prepare(FunctionContext context) {}
/**
* Adds the current row of the specified <code>ResultSetBuilder</code>.
*
@ -601,6 +604,13 @@ public abstract class Selection
return isJson ? rowToJson(outputRow, options.getProtocolVersion(), metadata, orderingColumns) : outputRow;
}
@Override
public void prepare(FunctionContext context)
{
for (Selector selector : selectors)
selector.prepare(context);
}
public void addInputRow(InputRow input)
{
for (Selector selector : selectors)

View File

@ -24,6 +24,7 @@ import java.util.List;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.selection.ColumnTimestamps.TimestampsType;
@ -562,6 +563,8 @@ public abstract class Selector
return false;
}
public void prepare(FunctionContext context) {}
/**
* Checks that this selector is valid for GROUP BY clause.
*/

View File

@ -26,6 +26,7 @@ import java.util.TreeSet;
import com.google.common.base.Objects;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.terms.Sets;
import org.apache.cassandra.db.TypeSizes;
@ -141,6 +142,14 @@ final class SetSelector extends Selector
this.elements = elements;
}
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
for (Selector selector : elements)
selector.prepare(context);
}
@Override
public boolean equals(Object o)
{

View File

@ -24,6 +24,7 @@ import com.google.common.base.Objects;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.functions.masking.ColumnMask;
import org.apache.cassandra.db.TypeSizes;
@ -38,6 +39,8 @@ import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil;
import static org.apache.cassandra.cql3.functions.masking.ColumnMask.Masker.NOT_A_MASKER;
public final class SimpleSelector extends Selector
{
protected static final SelectorDeserializer deserializer = new SelectorDeserializer()
@ -47,7 +50,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, ProtocolVersion.CURRENT);
return new SimpleSelector(column, idx, false);
}
};
@ -87,7 +90,7 @@ public final class SimpleSelector extends Selector
@Override
public Selector newInstance(QueryOptions options)
{
return new SimpleSelector(column, idx, useForPostOrdering, options.getProtocolVersion());
return new SimpleSelector(column, idx, useForPostOrdering);
}
@Override
@ -120,7 +123,7 @@ public final class SimpleSelector extends Selector
public final ColumnMetadata column;
private final int idx;
private final ColumnMask.Masker masker;
private ColumnMask.Masker masker;
private ByteBuffer current;
private ColumnTimestamps writetimes;
private ColumnTimestamps ttls;
@ -197,7 +200,7 @@ public final class SimpleSelector extends Selector
return column.name.toString();
}
private SimpleSelector(ColumnMetadata column, int idx, boolean useForPostOrdering, ProtocolVersion version)
private SimpleSelector(ColumnMetadata column, int idx, boolean useForPostOrdering)
{
super(Kind.SIMPLE_SELECTOR);
this.column = column;
@ -207,9 +210,13 @@ public final class SimpleSelector extends Selector
- 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);
this.masker = useForPostOrdering || column.getMask() == null ? null : NOT_A_MASKER;
}
public void prepare(FunctionContext context)
{
if (masker != null)
masker = column.getMask().masker(context.options().getProtocolVersion(), context);
}
@Override

View File

@ -24,6 +24,7 @@ import java.util.List;
import com.google.common.base.Objects;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.terms.Tuples;
import org.apache.cassandra.db.TypeSizes;
@ -140,6 +141,14 @@ final class TupleSelector extends Selector
this.elements = elements;
}
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
for (Selector selector : elements)
selector.prepare(context);
}
@Override
public boolean equals(Object o)
{

View File

@ -29,6 +29,7 @@ import com.google.common.base.Objects;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FieldIdentifier;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.terms.UserTypes;
@ -235,6 +236,14 @@ final class UserTypeSelector extends Selector
this.fields = fields;
}
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
for (Selector selector : fields.values())
selector.prepare(context);
}
@Override
public boolean equals(Object o)
{

View File

@ -26,6 +26,7 @@ import java.util.Objects;
import com.google.common.base.Preconditions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.terms.Lists;
import org.apache.cassandra.db.filter.ColumnFilter;
@ -74,6 +75,14 @@ public class VectorSelector extends Selector
this.elements = elements;
}
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
for (Selector selector : elements)
selector.prepare(context);
}
public static Factory newFactory(final AbstractType<?> type, final SelectorFactories factories)
{
assert type.isVector() : String.format("Unable to create vector selector from typs %s", type.asCQL3Type());

View File

@ -23,6 +23,7 @@ import java.nio.ByteBuffer;
import com.google.common.base.Objects;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.db.TypeSizes;
import org.apache.cassandra.db.filter.ColumnFilter;
@ -179,6 +180,13 @@ final class WritetimeOrTTLSelector extends Selector
this.isMultiCell = isMultiCell;
}
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
selected.prepare(context);
}
@Override
public boolean equals(Object o)
{

View File

@ -35,8 +35,11 @@ import accord.api.Update;
import accord.primitives.Keys;
import accord.primitives.Txn;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.FunctionContext.PartialFunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.cql3.RowUpdateBuilder.NoTimeRowUpdateBuilder;
import org.apache.cassandra.cql3.conditions.ColumnCondition;
import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.Columns;
@ -309,12 +312,12 @@ public class CQL3CasRequest implements CASRequest
return partitionUpdate;
}
private static class CASUpdateParameters extends UpdateParameters
private static class CASUpdateBuilder extends RowUpdateBuilder implements PartialFunctionContext
{
final long timeUuidMsb;
long timeUuidNanos;
public CASUpdateParameters(TableMetadata metadata, ClientState state, QueryOptions options, long timestamp, long nowInSec, int ttl, Map<DecoratedKey, Partition> prefetchedRows, long timeUuidMsb, long timeUuidNanos) throws InvalidRequestException
public CASUpdateBuilder(TableMetadata metadata, ClientState state, QueryOptions options, long timestamp, long nowInSec, int ttl, Map<DecoratedKey, Partition> prefetchedRows, long timeUuidMsb, long timeUuidNanos) throws InvalidRequestException
{
super(metadata, state, options, timestamp, nowInSec, ttl, prefetchedRows);
this.timeUuidMsb = timeUuidMsb;
@ -325,6 +328,11 @@ public class CQL3CasRequest implements CASRequest
{
return TimeUUID.toBytes(timeUuidMsb, TimeUUIDType.signedBytesToNativeLong(timeUuidNanos++));
}
public long nowMicros()
{
return timestamp;
}
}
/**
@ -353,8 +361,8 @@ public class CQL3CasRequest implements CASRequest
long applyUpdates(FilteredPartition current, PartitionUpdate.Builder updateBuilder, ClientState state, long timeUuidMsb, long timeUuidNanos)
{
Map<DecoratedKey, Partition> map = stmt.requiresRead() ? Collections.singletonMap(key, current) : null;
CASUpdateParameters params =
new CASUpdateParameters(metadata, state, options, timestamp, nowInSeconds,
CASUpdateBuilder params =
new CASUpdateBuilder(metadata, state, options, timestamp, nowInSeconds,
stmt.getTimeToLive(options), map, timeUuidMsb, timeUuidNanos);
stmt.addUpdateForKey(updateBuilder, clustering, params);
return params.timeUuidNanos;
@ -382,14 +390,14 @@ public class CQL3CasRequest implements CASRequest
{
// No slice statements currently require a read, but this maintains consistency with RowUpdate, and future proofs us
Map<DecoratedKey, Partition> map = stmt.requiresRead() ? Collections.singletonMap(key, current) : null;
UpdateParameters params =
new UpdateParameters(metadata,
state,
options,
timestamp,
nowInSeconds,
stmt.getTimeToLive(options),
map);
RowUpdateBuilder params =
new NoTimeRowUpdateBuilder(metadata,
state,
options,
timestamp,
nowInSeconds,
stmt.getTimeToLive(options),
map);
stmt.addUpdateForKey(updateBuilder, slice, params);
}
}
@ -472,11 +480,11 @@ public class CQL3CasRequest implements CASRequest
super(clustering);
}
public void addConditions(Collection<ColumnCondition> conds, QueryOptions options) throws InvalidRequestException
public void addConditions(Collection<ColumnCondition> conds, FunctionContext context) throws InvalidRequestException
{
for (ColumnCondition condition : conds)
{
conditions.add(condition.bind(options));
conditions.add(condition.bind(context));
}
}

View File

@ -28,8 +28,8 @@ import org.apache.cassandra.cql3.Attributes;
import org.apache.cassandra.cql3.Operation;
import org.apache.cassandra.cql3.Operations;
import org.apache.cassandra.cql3.QualifiedName;
import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.cql3.StatementSource;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.WhereClause;
import org.apache.cassandra.cql3.conditions.ColumnCondition;
@ -69,7 +69,7 @@ public class DeleteStatement extends ModificationStatement
}
@Override
public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, UpdateParameters params)
public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, RowUpdateBuilder params)
throws InvalidRequestException
{
TableMetadata metadata = metadata();
@ -125,7 +125,7 @@ public class DeleteStatement extends ModificationStatement
}
@Override
public void addUpdateForKey(PartitionUpdate.Builder update, Slice slice, UpdateParameters params)
public void addUpdateForKey(PartitionUpdate.Builder update, Slice slice, RowUpdateBuilder params)
{
List<Operation> regularDeletions = getRegularOperations();
List<Operation> staticDeletions = getStaticOperations();

View File

@ -48,14 +48,16 @@ import org.apache.cassandra.cql3.Attributes;
import org.apache.cassandra.cql3.CQLStatement;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operation;
import org.apache.cassandra.cql3.Operations;
import org.apache.cassandra.cql3.QualifiedName;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.QueryProcessor;
import org.apache.cassandra.cql3.ResultSet;
import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.cql3.RowUpdateBuilder.RegularRowUpdateBuilder;
import org.apache.cassandra.cql3.StatementSource;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.Validation;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.WhereClause;
@ -330,9 +332,9 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
return restrictions;
}
public abstract void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, UpdateParameters params);
public abstract void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, RowUpdateBuilder builder);
public abstract void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Slice slice, UpdateParameters params);
public abstract void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Slice slice, RowUpdateBuilder builder);
@Override
public String keyspace()
@ -360,9 +362,9 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
return metadata().isVirtual();
}
public long getTimestamp(long now, QueryOptions options) throws InvalidRequestException
public long getTimestamp(long now, FunctionContext context) throws InvalidRequestException
{
return attrs.getTimestamp(now, options);
return attrs.getTimestamp(now, context);
}
public boolean isTimestampSet()
@ -370,9 +372,9 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
return attrs.isTimestampSet();
}
public int getTimeToLive(QueryOptions options) throws InvalidRequestException
public int getTimeToLive(FunctionContext context) throws InvalidRequestException
{
return attrs.getTimeToLive(options, metadata);
return attrs.getTimeToLive(context, metadata);
}
@Override
@ -460,12 +462,12 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
}
}
public void validateTimestamp(QueryState queryState, QueryOptions options)
public void validateTimestamp(QueryState queryState, FunctionContext context)
{
if (!isTimestampSet())
return;
long ts = attrs.getTimestamp(options.getTimestamp(queryState), options);
long ts = attrs.getTimestamp(context.options().getTimestamp(queryState), context);
Guardrails.maximumAllowableTimestamp.guard(ts, table(), false, queryState.getClientState());
Guardrails.minimumAllowableTimestamp.guard(ts, table(), false, queryState.getClientState());
}
@ -790,13 +792,13 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
assert left.size() == 1;
int size = left.metadata.names.size() + right.metadata.names.size();
List<ColumnSpecification> specs = new ArrayList<ColumnSpecification>(size);
List<ColumnSpecification> specs = new ArrayList<>(size);
specs.addAll(left.metadata.names);
specs.addAll(right.metadata.names);
List<List<ByteBuffer>> rows = new ArrayList<>(right.size());
for (int i = 0; i < right.size(); i++)
{
List<ByteBuffer> row = new ArrayList<ByteBuffer>(size);
List<ByteBuffer> row = new ArrayList<>(size);
row.addAll(left.rows.get(0));
row.addAll(right.rows.get(i));
rows.add(row);
@ -827,11 +829,10 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
Iterables.addAll(defs, metadata.primaryKeyColumns());
Iterables.addAll(defs, columnsWithConditions);
selection = Selection.forColumns(metadata, new ArrayList<>(defs), false);
}
Selectors selectors = selection.newSelectors(options);
ResultSetBuilder builder = new ResultSetBuilder(selection.getResultMetadata(), selectors, false);
ResultSetBuilder builder = new ResultSetBuilder(selection.getResultMetadata(), options, selectors, false);
SelectStatement.forSelection(metadata, selection)
.processPartition(partition, options, builder, nowInSeconds);
@ -1093,7 +1094,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
if (slices.isEmpty())
return;
UpdateParameters params = makeUpdateParameters(keys,
RowUpdateBuilder params = makeUpdateParameters(keys,
(slicesToFilter) -> new ClusteringIndexSliceFilter(slicesToFilter, false),
slices,
state,
@ -1126,7 +1127,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
if (restrictions.hasClusteringColumnsRestrictions() && clusterings.isEmpty())
return;
UpdateParameters params = makeUpdateParameters(keys, clusterings, state, options, local, timestamp, nowInSeconds, requestTime);
RowUpdateBuilder params = makeUpdateBuilder(keys, clusterings, state, options, local, timestamp, nowInSeconds, requestTime);
for (ByteBuffer key : keys)
{
@ -1177,14 +1178,14 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
return restrictions.getSlices(options);
}
private UpdateParameters makeUpdateParameters(Collection<ByteBuffer> keys,
NavigableSet<Clustering<?>> clusterings,
ClientState state,
QueryOptions options,
boolean local,
long timestamp,
long nowInSeconds,
Dispatcher.RequestTime requestTime)
private RowUpdateBuilder makeUpdateBuilder(Collection<ByteBuffer> keys,
NavigableSet<Clustering<?>> clusterings,
ClientState state,
QueryOptions options,
boolean local,
long timestamp,
long nowInSeconds,
Dispatcher.RequestTime requestTime)
{
if (clusterings.contains(Clustering.STATIC_CLUSTERING))
return makeUpdateParameters(keys,
@ -1212,7 +1213,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
);
}
private <F> UpdateParameters makeUpdateParameters(Collection<ByteBuffer> keys,
private <F> RowUpdateBuilder makeUpdateParameters(Collection<ByteBuffer> keys,
// filter is needed rarely, so we allocate it on demand
java.util.function.Function<F, ClusteringIndexFilter> filterBuilder,
F filterArg,
@ -1235,13 +1236,13 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
nowInSeconds,
requestTime);
return new UpdateParameters(metadata(),
state,
options,
getTimestamp(timestamp, options),
nowInSeconds,
getTimeToLive(options),
lists);
return new RegularRowUpdateBuilder(metadata(),
state,
options,
getTimestamp(timestamp, options),
nowInSeconds,
getTimeToLive(options),
lists);
}
public static abstract class Parsed extends QualifiedStatement

View File

@ -1087,7 +1087,7 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement,
ClientState state) throws InvalidRequestException
{
GroupMaker groupMaker = aggregationSpec == null ? null : aggregationSpec.newGroupMaker();
ResultSetBuilder result = new ResultSetBuilder(getResultMetadata(), selectors, unmask, groupMaker);
ResultSetBuilder result = new ResultSetBuilder(getResultMetadata(), options, selectors, unmask, groupMaker);
while (partitions.hasNext())
{

View File

@ -51,6 +51,7 @@ import org.apache.cassandra.audit.AuditLogEntryType;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQLStatement;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.ResultSet;
import org.apache.cassandra.cql3.VariableSpecifications;
@ -80,8 +81,8 @@ import org.apache.cassandra.service.accord.serializers.TableMetadatas;
import org.apache.cassandra.service.accord.serializers.TableMetadatasAndKeys;
import org.apache.cassandra.service.accord.txn.AccordUpdate;
import org.apache.cassandra.service.accord.txn.TxnCondition;
import org.apache.cassandra.service.accord.txn.TxnData;
import org.apache.cassandra.service.accord.txn.TxnDataKeyValue;
import org.apache.cassandra.service.accord.txn.TxnDataResult;
import org.apache.cassandra.service.accord.txn.TxnNamedRead;
import org.apache.cassandra.service.accord.txn.TxnQuery;
import org.apache.cassandra.service.accord.txn.TxnRead;
@ -96,7 +97,6 @@ import org.apache.cassandra.tcm.ClusterMetadata;
import org.apache.cassandra.tcm.Epoch;
import org.apache.cassandra.transport.Dispatcher;
import org.apache.cassandra.transport.messages.ResultMessage;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.NoSpamLogger;
import static accord.primitives.Txn.Kind.Read;
@ -607,31 +607,35 @@ public class TransactionStatement implements CQLStatement.CompositeCQLStatement,
if (txnResult.kind() == retry_new_protocol)
throw new InvalidRequestException(UNSUPPORTED_MIGRATION);
TxnValidationRejection.maybeThrow(txnResult);
TxnData data = (TxnData)txnResult;
TxnDataResult data = (TxnDataResult)txnResult;
if (returningSelect != null)
{
@SuppressWarnings("unchecked")
SinglePartitionReadQuery.Group<SinglePartitionReadCommand> selectQuery = (SinglePartitionReadQuery.Group<SinglePartitionReadCommand>) returningSelect.select.getQuery(options, 0);
Selection.Selectors selectors = returningSelect.select.getSelection().newSelectors(options);
ResultSetBuilder result = new ResultSetBuilder(resultMetadata, selectors, false);
long atMicros = data.atMicros;
FunctionContext context = new FunctionContext.MicrosFunctionContext(atMicros)
{
@Override public QueryOptions options() { return options; }
};
ResultSetBuilder result = new ResultSetBuilder(resultMetadata, context, selectors, false);
long atSeconds = atMicros / 1000_000;
if (selectQuery.queries.size() == 1)
{
TxnDataKeyValue partition = (TxnDataKeyValue)data.get(txnDataName(RETURNING));
boolean reversed = selectQuery.queries.get(0).isReversed();
if (partition != null)
returningSelect.select.processPartition(partition.rowIterator(reversed), options, result, FBUtilities.nowInSeconds());
returningSelect.select.processPartition(partition.rowIterator(reversed), options, result, atSeconds);
}
else
{
long nowInSec = FBUtilities.nowInSeconds();
for (int i = 0; i < selectQuery.queries.size(); i++)
{
TxnDataKeyValue partition = (TxnDataKeyValue)data.get(txnDataName(RETURNING, i));
boolean reversed = selectQuery.queries.get(i).isReversed();
if (partition != null)
returningSelect.select.processPartition(partition.rowIterator(reversed), options, result, nowInSec);
returningSelect.select.processPartition(partition.rowIterator(reversed), options, result, atSeconds);
}
}
return new ResultMessage.Rows(result.build());
@ -649,7 +653,7 @@ public class TransactionStatement implements CQLStatement.CompositeCQLStatement,
columns.add(reference.column());
}
ResultSetBuilder result = new ResultSetBuilder(resultMetadata, Selection.noopSelector(), false);
ResultSetBuilder result = new ResultSetBuilder(resultMetadata, FunctionContext.NONE, Selection.noopSelector(), false);
result.newRow(options.getProtocolVersion(), null, null, columns);
for (int i = 0; i < returningReferences.size(); i++)

View File

@ -38,8 +38,8 @@ import org.apache.cassandra.cql3.Operations;
import org.apache.cassandra.cql3.Operator;
import org.apache.cassandra.cql3.QualifiedName;
import org.apache.cassandra.cql3.Relation;
import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.cql3.StatementSource;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.WhereClause;
import org.apache.cassandra.cql3.conditions.ColumnCondition;
@ -96,7 +96,7 @@ public class UpdateStatement extends ModificationStatement
}
@Override
public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, UpdateParameters params)
public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, RowUpdateBuilder params)
{
if (updatesRegularRows())
{
@ -142,7 +142,7 @@ public class UpdateStatement extends ModificationStatement
}
@Override
public void addUpdateForKey(PartitionUpdate.Builder update, Slice slice, UpdateParameters params)
public void addUpdateForKey(PartitionUpdate.Builder update, Slice slice, RowUpdateBuilder builder)
{
throw new UnsupportedOperationException();
}

View File

@ -24,9 +24,9 @@ import java.nio.ByteBuffer;
import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operation;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.DecoratedKey;
import org.apache.cassandra.db.marshal.AbstractType;
@ -63,9 +63,9 @@ import static java.nio.charset.StandardCharsets.US_ASCII;
*/
public abstract class Constants
{
private static ByteBuffer getCurrentCellBuffer(ColumnMetadata column, DecoratedKey key, UpdateParameters params)
private static ByteBuffer getCurrentCellBuffer(ColumnMetadata column, DecoratedKey key, RowUpdateBuilder builder)
{
Row currentRow = params.getPrefetchedRow(key, column.isStatic() ? Clustering.STATIC_CLUSTERING : params.currentClustering());
Row currentRow = builder.getPrefetchedRow(key, column.isStatic() ? Clustering.STATIC_CLUSTERING : builder.currentClustering());
Cell<?> currentCell = currentRow == null ? null : currentRow.getCell(column);
return currentCell == null ? null : currentCell.buffer();
}
@ -228,7 +228,7 @@ public abstract class Constants
{
// TODO: The bind overriding should be removed. A user does not have to call bind on a Terminal.
@Override
public Terminal bind(QueryOptions options)
public Terminal bind(FunctionContext context)
{
// We return null because that makes life easier for collections
return null;
@ -459,7 +459,7 @@ public abstract class Constants
}
@Override
public ByteBuffer bindAndGet(QueryOptions options)
public ByteBuffer bindAndGet(FunctionContext context)
{
return bytes;
}
@ -478,23 +478,23 @@ public abstract class Constants
super(column, t);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
if (t.isByteArrayGetSupported(params.options))
if (t.isByteArrayGetSupported(builder))
{
byte[] value = t.bindAndGetByteArray(params.options);
byte[] value = t.bindAndGetByteArray(builder);
if (value == null)
params.addTombstone(column);
builder.addTombstone(column);
else if (value != ByteArrayUtil.UNSET_BYTE_ARRAY) // use reference equality and not object equality
params.addCell(column, value);
builder.addCell(column, value);
}
else
{
ByteBuffer value = t.bindAndGet(params.options);
ByteBuffer value = t.bindAndGet(builder);
if (value == null)
params.addTombstone(column);
builder.addTombstone(column);
else if (value != ByteBufferUtil.UNSET_BYTE_BUFFER) // use reference equality and not object equality
params.addCell(column, value);
builder.addCell(column, value);
}
}
}
@ -511,43 +511,43 @@ public abstract class Constants
return !(column.type instanceof CounterColumnType);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
if (column.type instanceof CounterColumnType)
{
ByteBuffer bytes = t.bindAndGet(params.options);
ByteBuffer bytes = t.bindAndGet(builder);
if (bytes == null)
throw new InvalidRequestException("Invalid null value for counter increment");
if (bytes == ByteBufferUtil.UNSET_BYTE_BUFFER)
return;
long increment = ByteBufferUtil.toLong(bytes);
params.addCounter(column, increment);
builder.addCounter(column, increment);
}
else if (column.type instanceof NumberType<?>)
{
@SuppressWarnings("unchecked") NumberType<Number> type = (NumberType<Number>) column.type;
ByteBuffer increment = type.sanitize(t.bindAndGet(params.options));
ByteBuffer increment = type.sanitize(t.bindAndGet(builder));
if (increment == null)
return;
ByteBuffer current = type.sanitize(getCurrentCellBuffer(column, partitionKey, params));
ByteBuffer current = type.sanitize(getCurrentCellBuffer(column, partitionKey, builder));
if (current == null)
return;
ByteBuffer newValue = type.add(type.compose(current), type.compose(increment));
params.addCell(column, newValue);
builder.addCell(column, newValue);
}
else if (column.type instanceof StringType)
{
ByteBuffer append = t.bindAndGet(params.options);
ByteBuffer append = t.bindAndGet(builder);
if (append == null)
return;
ByteBuffer current = getCurrentCellBuffer(column, partitionKey, params);
ByteBuffer current = getCurrentCellBuffer(column, partitionKey, builder);
if (current == null)
return;
ByteBuffer newValue = ByteBuffer.allocate(current.remaining() + append.remaining());
FastByteOperations.copy(current, current.position(), newValue, newValue.position(), current.remaining());
FastByteOperations.copy(append, append.position(), newValue, newValue.position() + current.remaining(), append.remaining());
params.addCell(column, newValue);
builder.addCell(column, newValue);
}
}
}
@ -565,11 +565,11 @@ public abstract class Constants
return !column.type.isCounter();
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
if (column.type instanceof CounterColumnType)
{
ByteBuffer bytes = t.bindAndGet(params.options);
ByteBuffer bytes = t.bindAndGet(builder);
if (bytes == null)
throw new InvalidRequestException("Invalid null value for counter increment");
if (bytes == ByteBufferUtil.UNSET_BYTE_BUFFER)
@ -579,19 +579,19 @@ public abstract class Constants
if (increment == Long.MIN_VALUE)
throw new InvalidRequestException("The negation of " + increment + " overflows supported counter precision (signed 8 bytes integer)");
params.addCounter(column, -increment);
builder.addCounter(column, -increment);
}
else if (column.type instanceof NumberType<?>)
{
@SuppressWarnings("unchecked") NumberType<Number> type = (NumberType<Number>) column.type;
ByteBuffer increment = type.sanitize(t.bindAndGet(params.options));
ByteBuffer increment = type.sanitize(t.bindAndGet(builder));
if (increment == null)
return;
ByteBuffer current = type.sanitize(getCurrentCellBuffer(column, partitionKey, params));
ByteBuffer current = type.sanitize(getCurrentCellBuffer(column, partitionKey, builder));
if (current == null)
return;
ByteBuffer newValue = type.substract(type.compose(current), type.compose(increment));
params.addCell(column, newValue);
builder.addCell(column, newValue);
}
}
}
@ -605,12 +605,12 @@ public abstract class Constants
super(column, null);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
if (column.type.isMultiCell())
params.setComplexDeletionTime(column);
builder.setComplexDeletionTime(column);
else
params.addTombstone(column);
builder.addTombstone(column);
}
}
}

View File

@ -25,7 +25,7 @@ import java.util.List;
import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.marshal.AbstractType;
@ -60,9 +60,9 @@ public final class InMarker extends Terms.NonTerminals
}
@Override
public Terminals bind(QueryOptions options)
public Terminals bind(FunctionContext context)
{
ByteBuffer values = options.getValues().get(bindIndex);
ByteBuffer values = context.options().getValues().get(bindIndex);
if (values == null)
return null;
@ -95,16 +95,16 @@ public final class InMarker extends Terms.NonTerminals
}
@Override
public List<ByteBuffer> bindAndGet(QueryOptions options)
public List<ByteBuffer> bindAndGet(FunctionContext context)
{
Terminals terminals = bind(options);
Terminals terminals = bind(context);
return terminals == null ? null : terminals.get();
}
@Override
public List<List<ByteBuffer>> bindAndGetElements(QueryOptions options)
public List<List<ByteBuffer>> bindAndGetElements(FunctionContext context)
{
Terminals terminals = bind(options);
Terminals terminals = bind(context);
return terminals == null ? null : terminals.getElements();
}

View File

@ -35,9 +35,9 @@ import org.slf4j.LoggerFactory;
import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operation;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.db.DecoratedKey;
import org.apache.cassandra.db.guardrails.Guardrails;
@ -180,7 +180,7 @@ public abstract class Lists
values.add(t);
}
MultiElements.DelayedValue value = new MultiElements.DelayedValue((MultiElementType<?>) receiver.type.unwrap(), values);
return allTerminal ? value.bind(QueryOptions.DEFAULT) : value;
return allTerminal ? value.bind(FunctionContext.NONE) : value;
}
private void validateAssignableTo(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
@ -304,16 +304,16 @@ public abstract class Lists
return column.type.isMultiCell();
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
Term.Terminal value = t.bind(params.options);
Term.Terminal value = t.bind(builder);
if (value == UNSET_VALUE)
return;
// delete + append
if (column.type.isMultiCell())
params.setComplexDeletionTimeForOverwrite(column);
Appender.doAppend(value, column, params);
builder.setComplexDeletionTimeForOverwrite(column);
Appender.doAppend(value, column, builder);
}
}
@ -349,23 +349,23 @@ public abstract class Lists
idx.collectMarkerSpecification(boundNames, owner);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
// we should not get here for frozen lists
assert column.type.isMultiCell() : "Attempted to set an individual element on a frozen list";
Guardrails.readBeforeWriteListOperationsEnabled
.ensureEnabled("Setting of list items by index requiring read before write", params.clientState);
.ensureEnabled("Setting of list items by index requiring read before write", builder.clientState);
ByteBuffer index = idx.bindAndGet(params.options);
ByteBuffer value = t.bindAndGet(params.options);
ByteBuffer index = idx.bindAndGet(builder);
ByteBuffer value = t.bindAndGet(builder);
if (index == null)
throw new InvalidRequestException("Invalid null value for list index");
if (index == ByteBufferUtil.UNSET_BYTE_BUFFER)
throw new InvalidRequestException("Invalid unset value for list index");
Row existingRow = params.getPrefetchedRow(partitionKey, params.currentClustering());
Row existingRow = builder.getPrefetchedRow(partitionKey, builder.currentClustering());
int existingSize = existingSize(existingRow, column);
int idx = ByteBufferUtil.toInt(index);
if (existingSize == 0)
@ -375,9 +375,9 @@ public abstract class Lists
CellPath elementPath = existingRow.getComplexColumnData(column).getCellByIndex(idx).path();
if (value == null)
params.addTombstone(column, elementPath);
builder.addTombstone(column, elementPath);
else if (value != ByteBufferUtil.UNSET_BYTE_BUFFER)
params.addCell(column, elementPath, value);
builder.addCell(column, elementPath, value);
}
}
@ -388,11 +388,11 @@ public abstract class Lists
super(column, t);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
assert column.type.isMultiCell() : "Attempted to append to a frozen list";
Term.Terminal value = t.bind(params.options);
doAppend(value, column, params);
Term.Terminal value = t.bind(builder);
doAppend(value, column, builder);
}
@Override
@ -401,7 +401,7 @@ public abstract class Lists
return column.type.isMultiCell();
}
static void doAppend(Term.Terminal value, ColumnMetadata column, UpdateParameters params) throws InvalidRequestException
static void doAppend(Term.Terminal value, ColumnMetadata column, RowUpdateBuilder builder) throws InvalidRequestException
{
ListType<?> type = (ListType<?>) column.type;
@ -409,7 +409,7 @@ public abstract class Lists
{
// for frozen lists, we're overwriting the whole cell value
if (!type.isMultiCell())
params.addTombstone(column);
builder.addTombstone(column);
// If we append null, do nothing. Note that for Setter, we've
// already removed the previous value so we're good here too
@ -426,22 +426,22 @@ public abstract class Lists
// Guardrails about collection size are only checked for the added elements without considering
// already existent elements. This is done so to avoid read-before-write, having additional checks
// during SSTable write.
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, params.clientState);
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, builder.clientState);
int dataSize = 0;
for (ByteBuffer buffer : elements)
{
ByteBuffer cellPath = ByteBuffer.wrap(params.nextTimeUUIDAsBytes());
Cell<?> cell = params.addCell(column, CellPath.create(cellPath), buffer);
ByteBuffer cellPath = ByteBuffer.wrap(builder.nextTimeUUIDAsBytes());
Cell<?> cell = builder.addCell(column, CellPath.create(cellPath), buffer);
dataSize += cell.dataSize();
}
Guardrails.collectionListSize.guard(dataSize, column.name.toString(), false, params.clientState);
Guardrails.collectionListSize.guard(dataSize, column.name.toString(), false, builder.clientState);
}
else
{
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, params.clientState);
Cell<?> cell = params.addCell(column, value.get());
Guardrails.collectionListSize.guard(cell.dataSize(), column.name.toString(), false, params.clientState);
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, builder.clientState);
Cell<?> cell = builder.addCell(column, value.get());
Guardrails.collectionListSize.guard(cell.dataSize(), column.name.toString(), false, builder.clientState);
}
}
}
@ -459,10 +459,10 @@ public abstract class Lists
return column.type.isMultiCell();
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
assert column.type.isMultiCell() : "Attempted to prepend to a frozen list";
Term.Terminal value = t.bind(params.options);
Term.Terminal value = t.bind(builder);
if (value == null || value == UNSET_VALUE)
return;
@ -484,7 +484,7 @@ public abstract class Lists
// TODO: is this safe as part of LWTs?
ByteBuffer uuid = ByteBuffer.wrap(atUnixMillisAsBytes(pt.millis, (pt.nanos + remainingInBatch--)));
params.addCell(column, CellPath.create(uuid), toAdd.get(i));
builder.addCell(column, CellPath.create(uuid), toAdd.get(i));
}
}
}
@ -502,17 +502,17 @@ public abstract class Lists
return true;
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
assert column.type.isMultiCell() : "Attempted to delete from a frozen list";
Guardrails.readBeforeWriteListOperationsEnabled
.ensureEnabled("Removal of list items requiring read before write", params.clientState);
.ensureEnabled("Removal of list items requiring read before write", builder.clientState);
// We want to call bind before possibly returning to reject queries where the value provided is not a list.
Term.Terminal value = t.bind(params.options);
Term.Terminal value = t.bind(builder);
Row existingRow = params.getPrefetchedRow(partitionKey, params.currentClustering());
Row existingRow = builder.getPrefetchedRow(partitionKey, builder.currentClustering());
ComplexColumnData complexData = existingRow == null ? null : existingRow.getComplexColumnData(column);
if (value == null || value == UNSET_VALUE || complexData == null)
return;
@ -525,7 +525,7 @@ public abstract class Lists
for (Cell<?> cell : complexData)
{
if (toDiscard.contains(cell.buffer()))
params.addTombstone(column, cell.path());
builder.addTombstone(column, cell.path());
}
}
}
@ -543,20 +543,20 @@ public abstract class Lists
return true;
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
assert column.type.isMultiCell() : "Attempted to delete an item by index from a frozen list";
Guardrails.readBeforeWriteListOperationsEnabled
.ensureEnabled("Removal of list items by index requiring read before write", params.clientState);
.ensureEnabled("Removal of list items by index requiring read before write", builder.clientState);
Term.Terminal index = t.bind(params.options);
Term.Terminal index = t.bind(builder);
if (index == null)
throw new InvalidRequestException("Invalid null value for list index");
if (index == Constants.UNSET_VALUE)
return;
Row existingRow = params.getPrefetchedRow(partitionKey, params.currentClustering());
Row existingRow = builder.getPrefetchedRow(partitionKey, builder.currentClustering());
int existingSize = existingSize(existingRow, column);
int idx = ByteBufferUtil.toInt(index.get());
if (existingSize == 0)
@ -564,7 +564,7 @@ public abstract class Lists
if (idx < 0 || idx >= existingSize)
throw new InvalidRequestException(String.format("List index %d out of bound, list has size %d", idx, existingSize));
params.addTombstone(column, existingRow.getComplexColumnData(column).getCellByIndex(idx).path());
builder.addTombstone(column, existingRow.getComplexColumnData(column).getCellByIndex(idx).path());
}
}
}

View File

@ -30,7 +30,7 @@ import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.Operation;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.db.DecoratedKey;
import org.apache.cassandra.db.guardrails.Guardrails;
@ -252,16 +252,16 @@ public final class Maps
super(column, t);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
Term.Terminal value = t.bind(params.options);
Term.Terminal value = t.bind(builder);
if (value == UNSET_VALUE)
return;
// delete + put
if (column.type.isMultiCell())
params.setComplexDeletionTimeForOverwrite(column);
Putter.doPut(value, column, params);
builder.setComplexDeletionTimeForOverwrite(column);
Putter.doPut(value, column, builder);
}
}
@ -282,11 +282,11 @@ public final class Maps
k.collectMarkerSpecification(boundNames, owner);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
assert column.type.isMultiCell() : "Attempted to set a value for a single key on a frozen map";
ByteBuffer key = k.bindAndGet(params.options);
ByteBuffer value = t.bindAndGet(params.options);
ByteBuffer key = k.bindAndGet(builder);
ByteBuffer value = t.bindAndGet(builder);
if (key == null)
throw new InvalidRequestException("Invalid null map key");
if (key == ByteBufferUtil.UNSET_BYTE_BUFFER)
@ -296,11 +296,11 @@ public final class Maps
if (value == null)
{
params.addTombstone(column, path);
builder.addTombstone(column, path);
}
else if (value != ByteBufferUtil.UNSET_BYTE_BUFFER)
{
params.addCell(column, path, value);
builder.addCell(column, path, value);
}
}
}
@ -312,15 +312,15 @@ public final class Maps
super(column, t);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
assert column.type.isMultiCell() : "Attempted to add items to a frozen map";
Term.Terminal value = t.bind(params.options);
Term.Terminal value = t.bind(builder);
if (value != UNSET_VALUE)
doPut(value, column, params);
doPut(value, column, builder);
}
static void doPut(Term.Terminal value, ColumnMetadata column, UpdateParameters params) throws InvalidRequestException
static void doPut(Term.Terminal value, ColumnMetadata column, RowUpdateBuilder builder) throws InvalidRequestException
{
MapType<?, ?> type = (MapType<?, ?>) column.type;
@ -328,7 +328,7 @@ public final class Maps
{
// for frozen maps, we're overwriting the whole cell
if (!type.isMultiCell())
params.addTombstone(column);
builder.addTombstone(column);
return;
}
@ -343,22 +343,22 @@ public final class Maps
// Guardrails about collection size are only checked for the added elements without considering
// already existent elements. This is done so to avoid read-before-write, having additional checks
// during SSTable write.
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, params.clientState);
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, builder.clientState);
int dataSize = 0;
Iterator<ByteBuffer> iter = elements.iterator();
while(iter.hasNext())
{
Cell<?> cell = params.addCell(column, CellPath.create(iter.next()), iter.next());
Cell<?> cell = builder.addCell(column, CellPath.create(iter.next()), iter.next());
dataSize += cell.dataSize();
}
Guardrails.collectionMapSize.guard(dataSize, column.name.toString(), false, params.clientState);
Guardrails.collectionMapSize.guard(dataSize, column.name.toString(), false, builder.clientState);
}
else
{
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, params.clientState);
Cell<?> cell = params.addCell(column, value.get());
Guardrails.collectionMapSize.guard(cell.dataSize(), column.name.toString(), false, params.clientState);
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, builder.clientState);
Cell<?> cell = builder.addCell(column, value.get());
Guardrails.collectionMapSize.guard(cell.dataSize(), column.name.toString(), false, builder.clientState);
}
}
}
@ -370,16 +370,16 @@ public final class Maps
super(column, k);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
assert column.type.isMultiCell() : "Attempted to delete a single key in a frozen map";
Term.Terminal key = t.bind(params.options);
Term.Terminal key = t.bind(builder);
if (key == null)
throw new InvalidRequestException("Invalid null map key");
if (key == Constants.UNSET_VALUE)
throw new InvalidRequestException("Invalid unset map key");
params.addTombstone(column, CellPath.create(key.get()));
builder.addTombstone(column, CellPath.create(key.get()));
}
}
}

View File

@ -22,7 +22,7 @@ import java.util.List;
import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.marshal.AbstractType;
@ -42,7 +42,7 @@ public final class Marker extends Term.NonTerminal
/**
* The index of the bind variable within the query options.
* <p>When a query is executed the value of this placeholder is retrieved from the query options values using
* the bindIndex. (see {@link Marker#bind(QueryOptions)}</p>
* the bindIndex. (see {@link Term#bind(FunctionContext)}</p>
*/
private final int bindIndex;
@ -72,11 +72,11 @@ public final class Marker extends Term.NonTerminal
}
@Override
public Term.Terminal bind(QueryOptions options) throws InvalidRequestException
public Term.Terminal bind(FunctionContext context) throws InvalidRequestException
{
try
{
ByteBuffer bytes = options.getValue(bindIndex);
ByteBuffer bytes = context.options().getValues().get(bindIndex);
if (bytes == null)
return null;
@ -97,11 +97,11 @@ public final class Marker extends Term.NonTerminal
// an optimized version without allocating interim Terminal objects
@Override
public ByteBuffer bindAndGet(QueryOptions options)
public ByteBuffer bindAndGet(FunctionContext context)
{
try
{
ByteBuffer bytes = options.getValue(bindIndex);
ByteBuffer bytes = context.options().getValue(bindIndex);
if (bytes == null)
return null;
@ -122,20 +122,20 @@ public final class Marker extends Term.NonTerminal
}
}
public boolean isByteArrayGetSupported(QueryOptions options)
public boolean isByteArrayGetSupported(FunctionContext context)
{
return options.isByteArrayValuesGetSupported();
return context.options().isByteArrayValuesGetSupported();
}
/*
Same logic as bind() but it returns byte[] instead of ByteBuffer and there is no Value wrapper usage
*/
@Override
public byte[] bindAndGetByteArray(QueryOptions options) throws InvalidRequestException
public byte[] bindAndGetByteArray(FunctionContext context) throws InvalidRequestException
{
try
{
byte[] bytes = options.getByteArrayValues()[bindIndex];
byte[] bytes = context.options().getByteArrayValues()[bindIndex];
if (bytes == null)
return null;

View File

@ -22,7 +22,7 @@ import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.marshal.MultiElementType;
@ -126,14 +126,14 @@ public final class MultiElements
}
@Override
public Terminal bind(QueryOptions options)
public Terminal bind(FunctionContext context)
{
try
{
List<ByteBuffer> buffers = new ArrayList<>(elements.size());
for (Term t : elements)
{
buffers.add(t.bindAndGet(options));
buffers.add(t.bindAndGet(context));
}
buffers = type.filterSortAndValidateElements(buffers);

View File

@ -30,9 +30,9 @@ import java.util.stream.StreamSupport;
import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operation;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.db.DecoratedKey;
import org.apache.cassandra.db.guardrails.Guardrails;
import org.apache.cassandra.db.marshal.AbstractType;
@ -172,7 +172,7 @@ public final class Sets
values.add(t);
}
MultiElements.DelayedValue value = new MultiElements.DelayedValue((MultiElementType<?>) receiver.type.unwrap(), values);
return allTerminal ? value.bind(QueryOptions.DEFAULT) : value;
return allTerminal ? value.bind(FunctionContext.NONE) : value;
}
private void validateAssignableTo(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
@ -227,16 +227,16 @@ public final class Sets
super(column, t);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
Term.Terminal value = t.bind(params.options);
Term.Terminal value = t.bind(builder);
if (value == UNSET_VALUE)
return;
// delete + add
if (column.type.isMultiCell())
params.setComplexDeletionTimeForOverwrite(column);
Adder.doAdd(value, column, params);
builder.setComplexDeletionTimeForOverwrite(column);
Adder.doAdd(value, column, builder);
}
}
@ -247,15 +247,15 @@ public final class Sets
super(column, t);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
assert column.type.isMultiCell() : "Attempted to add items to a frozen set";
Term.Terminal value = t.bind(params.options);
Term.Terminal value = t.bind(builder);
if (value != UNSET_VALUE)
doAdd(value, column, params);
doAdd(value, column, builder);
}
static void doAdd(Term.Terminal value, ColumnMetadata column, UpdateParameters params) throws InvalidRequestException
static void doAdd(Term.Terminal value, ColumnMetadata column, RowUpdateBuilder builder) throws InvalidRequestException
{
SetType<?> type = (SetType<?>) column.type;
@ -263,7 +263,7 @@ public final class Sets
{
// for frozen sets, we're overwriting the whole cell
if (!type.isMultiCell())
params.addTombstone(column);
builder.addTombstone(column);
return;
}
@ -278,7 +278,7 @@ public final class Sets
// Guardrails about collection size are only checked for the added elements without considering
// already existent elements. This is done so to avoid read-before-write, having additional checks
// during SSTable write.
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, params.clientState);
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, builder.clientState);
int dataSize = 0;
for (ByteBuffer bb : elements)
@ -286,16 +286,16 @@ public final class Sets
if (bb == ByteBufferUtil.UNSET_BYTE_BUFFER)
continue;
Cell<?> cell = params.addCell(column, CellPath.create(bb), ByteBufferUtil.EMPTY_BYTE_BUFFER);
Cell<?> cell = builder.addCell(column, CellPath.create(bb), ByteBufferUtil.EMPTY_BYTE_BUFFER);
dataSize += cell.dataSize();
}
Guardrails.collectionSetSize.guard(dataSize, column.name.toString(), false, params.clientState);
Guardrails.collectionSetSize.guard(dataSize, column.name.toString(), false, builder.clientState);
}
else
{
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, params.clientState);
Cell<?> cell = params.addCell(column, value.get());
Guardrails.collectionSetSize.guard(cell.dataSize(), column.name.toString(), false, params.clientState);
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, builder.clientState);
Cell<?> cell = builder.addCell(column, value.get());
Guardrails.collectionSetSize.guard(cell.dataSize(), column.name.toString(), false, builder.clientState);
}
}
}
@ -308,11 +308,11 @@ public final class Sets
super(column, t);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
assert column.type.isMultiCell() : "Attempted to remove items from a frozen set";
Term.Terminal value = t.bind(params.options);
Term.Terminal value = t.bind(builder);
if (value == null || value == UNSET_VALUE)
return;
@ -320,7 +320,7 @@ public final class Sets
List<ByteBuffer> toDiscard = value.getElements();
for (ByteBuffer bb : toDiscard)
params.addTombstone(column, CellPath.create(bb));
builder.addTombstone(column, CellPath.create(bb));
}
}
@ -331,14 +331,14 @@ public final class Sets
super(column, k);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
assert column.type.isMultiCell() : "Attempted to delete a single element in a frozen set";
Term.Terminal elt = t.bind(params.options);
Term.Terminal elt = t.bind(builder);
if (elt == null)
throw new InvalidRequestException("Invalid null set element");
params.addTombstone(column, CellPath.create(elt.get()));
builder.addTombstone(column, CellPath.create(elt.get()));
}
}
}

View File

@ -27,6 +27,7 @@ import org.apache.cassandra.cql3.CQLFragmentParser;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.CqlParser;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function;
@ -77,10 +78,10 @@ public interface Term
* Bind the values in this term to the values contained in the {@code options}.
* This is obviously a no-op if the term is Terminal.
*
* @param options the values to bind markers to.
* @param context the values to bind markers to.
* @return the {@code Terminal} resulting of binding the values contained in the {@code options}.
*/
Terminal bind(QueryOptions options);
Terminal bind(FunctionContext context);
/**
* A shorter for {@code bind(options).get()}.
@ -88,13 +89,13 @@ public interface Term
* object between the bind and the get (note that we still want to be able
* to separate bind and get for collections).
*/
ByteBuffer bindAndGet(QueryOptions options);
ByteBuffer bindAndGet(FunctionContext context);
/**
* return true if an optimized bindAndGetByteArray() method is implemented and can be used for this type of Term
* to retrieve a value as byte[] instead of default ByteBuffer provided by bindAndGet()
*/
default boolean isByteArrayGetSupported(QueryOptions options)
default boolean isByteArrayGetSupported(FunctionContext context)
{
return false;
}
@ -102,7 +103,7 @@ public interface Term
/**
* an allocation-optimized version of bindAndGet() method
*/
default byte[] bindAndGetByteArray(QueryOptions options) throws InvalidRequestException
default byte[] bindAndGetByteArray(FunctionContext context) throws InvalidRequestException
{
throw new IllegalStateException("bindAndGetByteArray() method is not implemented, " +
"isByteArrayGetSupported() must be always checked before invoking this method");
@ -113,7 +114,7 @@ public interface Term
* We expose it mainly because for constants it can avoid allocating a temporary
* object between the bind and the getElements.
*/
List<ByteBuffer> bindAndGetElements(QueryOptions options);
List<ByteBuffer> bindAndGetElements(FunctionContext context);
/**
* Whether that term contains at least one bind marker.
@ -250,7 +251,7 @@ public interface Term
public void collectMarkerSpecification(VariableSpecifications boundNames, Object owner) {}
@Override
public Terminal bind(QueryOptions options) { return this; }
public Terminal bind(FunctionContext context) { return this; }
@Override
public void addFunctionsTo(List<Function> functions)
@ -291,13 +292,13 @@ public interface Term
}
@Override
public ByteBuffer bindAndGet(QueryOptions options)
public ByteBuffer bindAndGet(FunctionContext context)
{
return get();
}
@Override
public List<ByteBuffer> bindAndGetElements(QueryOptions options)
public List<ByteBuffer> bindAndGetElements(FunctionContext context)
{
return getElements();
}
@ -318,16 +319,16 @@ public interface Term
abstract class NonTerminal implements Term
{
@Override
public ByteBuffer bindAndGet(QueryOptions options) throws InvalidRequestException
public ByteBuffer bindAndGet(FunctionContext context) throws InvalidRequestException
{
Terminal t = bind(options);
Terminal t = bind(context);
return t == null ? null : t.get();
}
@Override
public List<ByteBuffer> bindAndGetElements(QueryOptions options)
public List<ByteBuffer> bindAndGetElements(FunctionContext context)
{
Terminal t = bind(options);
Terminal t = bind(context);
return t == null ? Collections.emptyList() : t.getElements();
}
}

View File

@ -28,7 +28,7 @@ import com.google.common.collect.ImmutableList;
import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.terms.Term.NonTerminal;
@ -104,25 +104,26 @@ public interface Terms
* Bind the values in these terms to the values contained in {@code options}.
* This is obviously a no-op if this {@code Terms} are Terminals.
*
* @param options the query options containing the values to bind markers to.
* @param context the query options containing the values to bind markers to.
* @return the result of binding all the variables of these NonTerminals.
*/
Terminals bind(QueryOptions options);
Terminals bind(FunctionContext context);
/**
* A shorter for {@code bind(options).get()}.
* We expose it mainly because for constants it can avoid allocating a temporary
* object between the bind and the get.
* @param options the query options containing the values to bind markers to.
*
* @param context the query options containing the values to bind markers to.
*/
List<ByteBuffer> bindAndGet(QueryOptions options);
List<ByteBuffer> bindAndGet(FunctionContext context);
default boolean isSingleTerm(QueryOptions options)
default boolean isSingleTerm(FunctionContext context)
{
return false;
}
default ByteBuffer bindAndGetSingleTermValue(QueryOptions options)
default ByteBuffer bindAndGetSingleTermValue(FunctionContext context)
{
throw new IllegalStateException("bindAndGetSingleTermValue() method is not implemented, " +
"isSingleTerm() must be always checked before invoking this method");
@ -132,9 +133,10 @@ public interface Terms
* A shorter for {@code bind(options).getElements()}.
* We expose it mainly because for constants it can avoid allocating a temporary
* object between the {@code bind} and the {@code getElements}.
* @param options the query options containing the values to bind markers to.
*
* @param context the query options containing the values to bind markers to.
*/
List<List<ByteBuffer>> bindAndGetElements(QueryOptions options);
List<List<ByteBuffer>> bindAndGetElements(FunctionContext context);
/**
* Creates a {@code Terms} containing a single {@code Term}.
@ -457,19 +459,19 @@ public interface Terms
public void collectMarkerSpecification(VariableSpecifications boundNames, Object owner) {}
@Override
public final Terminals bind(QueryOptions options)
public final Terminals bind(FunctionContext context)
{
return this;
}
@Override
public List<ByteBuffer> bindAndGet(QueryOptions options)
public List<ByteBuffer> bindAndGet(FunctionContext context)
{
return get();
}
@Override
public List<List<ByteBuffer>> bindAndGetElements(QueryOptions options)
public List<List<ByteBuffer>> bindAndGetElements(FunctionContext context)
{
return getElements();
}
@ -628,34 +630,34 @@ public interface Terms
}
@Override
public Terminals bind(QueryOptions options)
public Terminals bind(FunctionContext context)
{
return Terminals.of(term.bind(options));
return Terminals.of(term.bind(context));
}
@Override
public List<ByteBuffer> bindAndGet(QueryOptions options)
public List<ByteBuffer> bindAndGet(FunctionContext context)
{
return Collections.singletonList(term.bindAndGet(options));
return Collections.singletonList(term.bindAndGet(context));
}
@Override
public boolean isSingleTerm(QueryOptions options)
public boolean isSingleTerm(FunctionContext context)
{
return true;
}
@Override
public ByteBuffer bindAndGetSingleTermValue(QueryOptions options)
public ByteBuffer bindAndGetSingleTermValue(FunctionContext context)
{
return term.bindAndGet(options);
return term.bindAndGet(context);
}
@Override
public List<List<ByteBuffer>> bindAndGetElements(QueryOptions options)
public List<List<ByteBuffer>> bindAndGetElements(FunctionContext context)
{
return Collections.singletonList(term.bindAndGetElements(options));
return Collections.singletonList(term.bindAndGetElements(context));
}
@Override
@ -698,40 +700,40 @@ public interface Terms
}
@Override
public Terminals bind(QueryOptions options)
public Terminals bind(FunctionContext context)
{
int size = terms.size();
List<Terminal> terminals = new ArrayList<>(size);
for (int i = 0; i < size; i++)
{
Term term = terms.get(i);
terminals.add(term.bind(options));
terminals.add(term.bind(context));
}
return Terminals.of(terminals);
}
@Override
public List<ByteBuffer> bindAndGet(QueryOptions options)
public List<ByteBuffer> bindAndGet(FunctionContext context)
{
int size = terms.size();
List<ByteBuffer> buffers = new ArrayList<>(size);
for (int i = 0; i < size; i++)
{
Term term = terms.get(i);
buffers.add(term.bindAndGet(options));
buffers.add(term.bindAndGet(context));
}
return buffers;
}
@Override
public List<List<ByteBuffer>> bindAndGetElements(QueryOptions options)
public List<List<ByteBuffer>> bindAndGetElements(FunctionContext context)
{
int size = terms.size();
List<List<ByteBuffer>> buffers = new ArrayList<>(size);
for (int i = 0; i < size; i++)
{
Term term = terms.get(i);
buffers.add(term.bindAndGetElements(options));
buffers.add(term.bindAndGetElements(context));
}
return buffers;
}

View File

@ -25,7 +25,7 @@ import java.util.stream.StreamSupport;
import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.ReversedType;
import org.apache.cassandra.db.marshal.TupleType;
@ -88,7 +88,7 @@ public final class Tuples
}
MultiElements.DelayedValue value = new MultiElements.DelayedValue(tupleType, values);
return allTerminal ? value.bind(QueryOptions.DEFAULT) : value;
return allTerminal ? value.bind(FunctionContext.NONE) : value;
}
public TestResult testAssignment(String keyspace, ColumnSpecification receiver)

View File

@ -28,9 +28,9 @@ import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FieldIdentifier;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operation;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.db.DecoratedKey;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.UserType;
@ -170,7 +170,7 @@ public final class UserTypes
}
MultiElements.DelayedValue value = new MultiElements.DelayedValue(((UserType)receiver.type.unwrap()), values);
return allTerminal ? value.bind(QueryOptions.DEFAULT) : value;
return allTerminal ? value.bind(FunctionContext.NONE) : value;
}
private void validateAssignableTo(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
@ -220,9 +220,9 @@ public final class UserTypes
super(column, t);
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
Term.Terminal value = t.bind(params.options);
Term.Terminal value = t.bind(builder);
if (value == UNSET_VALUE)
return;
@ -230,7 +230,7 @@ public final class UserTypes
if (type.isMultiCell())
{
// setting a whole UDT at once means we overwrite all cells, so delete existing cells
params.setComplexDeletionTimeForOverwrite(column);
builder.setComplexDeletionTimeForOverwrite(column);
if (value == null)
return;
@ -243,16 +243,16 @@ public final class UserTypes
continue;
CellPath fieldPath = type.cellPathForField(fieldName);
params.addCell(column, fieldPath, buffer);
builder.addCell(column, fieldPath, buffer);
}
}
else
{
// for frozen UDTs, we're overwriting the whole cell value
if (value == null)
params.addTombstone(column);
builder.addTombstone(column);
else
params.addCell(column, value.get());
builder.addCell(column, value.get());
}
}
}
@ -267,20 +267,20 @@ public final class UserTypes
this.field = field;
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
// we should not get here for frozen UDTs
assert column.type.isMultiCell() : "Attempted to set an individual field on a frozen UDT";
Term.Terminal value = t.bind(params.options);
Term.Terminal value = t.bind(builder);
if (value == UNSET_VALUE)
return;
CellPath fieldPath = ((UserType) column.type).cellPathForField(field);
if (value == null)
params.addTombstone(column, fieldPath);
builder.addTombstone(column, fieldPath);
else
params.addCell(column, fieldPath, value.get());
builder.addCell(column, fieldPath, value.get());
}
}
@ -294,13 +294,13 @@ public final class UserTypes
this.field = field;
}
public void execute(DecoratedKey partitionKey, UpdateParameters params) throws InvalidRequestException
public void execute(DecoratedKey partitionKey, RowUpdateBuilder builder) throws InvalidRequestException
{
// we should not get here for frozen UDTs
assert column.type.isMultiCell() : "Attempted to delete a single field from a frozen UDT";
CellPath fieldPath = ((UserType) column.type).cellPathForField(field);
params.addTombstone(column, fieldPath);
builder.addTombstone(column, fieldPath);
}
}
}

View File

@ -28,7 +28,7 @@ import java.util.stream.Collectors;
import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.VectorType;
import org.apache.cassandra.exceptions.InvalidRequestException;
@ -139,7 +139,7 @@ public final class Vectors
values.add(t);
}
MultiElements.DelayedValue value = new MultiElements.DelayedValue(type, values);
return allTerminal ? value.bind(QueryOptions.DEFAULT) : value;
return allTerminal ? value.bind(FunctionContext.NONE) : value;
}
@Override

View File

@ -19,7 +19,7 @@
package org.apache.cassandra.cql3.transactions;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.terms.Term;
import org.apache.cassandra.db.marshal.AbstractType;
@ -31,7 +31,7 @@ import static org.apache.cassandra.cql3.statements.RequestValidations.checkTrue;
public abstract class ReferenceValue
{
public abstract TxnReferenceValue bindAndGet(QueryOptions options);
public abstract TxnReferenceValue bindAndGet(FunctionContext context);
public static abstract class Raw extends Term.Raw
{
@ -48,9 +48,9 @@ public abstract class ReferenceValue
}
@Override
public TxnReferenceValue bindAndGet(QueryOptions options)
public TxnReferenceValue bindAndGet(FunctionContext context)
{
return new TxnReferenceValue.Constant(term.bindAndGet(options));
return new TxnReferenceValue.Constant(term.bindAndGet(context));
}
public static class Raw extends ReferenceValue.Raw
@ -104,9 +104,9 @@ public abstract class ReferenceValue
}
@Override
public TxnReferenceValue bindAndGet(QueryOptions options)
public TxnReferenceValue bindAndGet(FunctionContext context)
{
return new TxnReferenceValue.Substitution(reference.toTxnReference(options).asColumn());
return new TxnReferenceValue.Substitution(reference.toTxnReference(context).asColumn());
}
public static class Raw extends ReferenceValue.Raw

View File

@ -27,7 +27,7 @@ import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FieldIdentifier;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.functions.types.utils.Bytes;
@ -84,7 +84,7 @@ public class RowDataReference extends Term.NonTerminal
}
@Override
public Terminal bind(QueryOptions options) throws InvalidRequestException
public Terminal bind(FunctionContext context) throws InvalidRequestException
{
throw new UnsupportedOperationException();
}
@ -174,20 +174,20 @@ public class RowDataReference extends Term.NonTerminal
return UserTypes.fieldSpecOf(column, field);
}
private CellPath bindCellPath(QueryOptions options)
private CellPath bindCellPath(FunctionContext context)
{
if (fieldPath != null)
return fieldPath;
return elementPath != null ? CellPath.create(elementPath.bindAndGet(options)) : null;
return elementPath != null ? CellPath.create(elementPath.bindAndGet(context)) : null;
}
public TxnReference toTxnReference(QueryOptions options)
public TxnReference toTxnReference(FunctionContext context)
{
Preconditions.checkState(elementPath == null || column.isComplex() || column.type.isFrozenCollection());
Preconditions.checkState(fieldPath == null || column.isComplex() || column.type.isUDT());
return TxnReference.columnOrRow(txnDataName, table, column, bindCellPath(options));
return TxnReference.columnOrRow(txnDataName, table, column, bindCellPath(context));
}
public ColumnIdentifier getFullyQualifiedName()

View File

@ -177,6 +177,7 @@ import org.apache.cassandra.utils.concurrent.UncheckedInterruptedException;
import static org.apache.cassandra.concurrent.ExecutorFactory.Global.executorFactory;
import static org.apache.cassandra.config.DatabaseDescriptor.getFlushWriters;
import static org.apache.cassandra.db.commitlog.CommitLogPosition.NONE;
import static org.apache.cassandra.db.compaction.CompactionManager.NO_GC;
import static org.apache.cassandra.utils.Clock.Global.currentTimeMillis;
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
import static org.apache.cassandra.utils.Throwables.maybeFail;
@ -2016,9 +2017,19 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean, Memtable.Owner
return paxosRepairHistory.get().getBallotForToken(key.getToken());
}
public long getDefaultGcBefore(long nowInSec)
{
// 2ndary indexes have ExpiringColumns too, so we need to purge tombstones deleted before now. We do not need to
// add any GcGrace however since 2ndary indexes are local to a node.
return isIndex() ? nowInSec : gcBefore(nowInSec);
}
public long gcBefore(long nowInSec)
{
return nowInSec - metadata().params.gcGraceSeconds;
TableMetadata metadata = metadata();
if (metadata.isAccordEnabled())
return NO_GC;
return nowInSec - metadata.params.gcGraceSeconds;
}
public RefViewFragment selectAndReference(Function<View, Iterable<SSTableReader>> filter)

View File

@ -961,6 +961,9 @@ public abstract class ReadCommand extends AbstractReadQuery
ColumnFamilyStore cfs,
ReadExecutionController controller)
{
if (nowInSec() == 0)
return iterator;
class WithoutPurgeableTombstones extends PurgeFunction
{
public WithoutPurgeableTombstones()

View File

@ -224,7 +224,8 @@ public abstract class GroupMaker
{
input.add(argument);
// For computing groups we do not need to use the client protocol version.
// For computing groups we do not need to use the specific client protocol version.
selector.prepare(ProtocolVersion.CURRENT);
selector.addInput(input);
ByteBuffer output = selector.getOutput(ProtocolVersion.CURRENT);
selector.reset();

View File

@ -195,7 +195,7 @@ public class CompactionIterator extends CompactionInfo.Holder implements Unfilte
private static IAccordService accord(AbstractCompactionController controller)
{
IAccordService accord = AccordService.tryGetUnsafe();
Invariants.require(accord != null || (!isAccordJournal(controller.cfs) && !isAccordCommandsForKey(controller.cfs)));
Invariants.require(accord != null || !isAccordSystemTable(controller.cfs.metadata()));
return accord;
}
@ -261,19 +261,28 @@ public class CompactionIterator extends CompactionInfo.Holder implements Unfilte
private Transformation<UnfilteredRowIterator> purger(ColumnFamilyStore cfs, Supplier<AccordCompactionInfos> compactionInfos, Supplier<Version> version)
{
if (isPaxos(cfs) && paxosStatePurging() != legacy)
TableMetadata metadata = cfs.metadata.get();
if (isPaxos(metadata) && paxosStatePurging() != legacy)
return new PaxosPurger();
// Topologies uses regular deletion so it can use a regular Purger
if (!requiresAccordSpecificPurger(cfs))
return new Purger(controller, nowInSec);
if (isAccordSystemTable(metadata))
{
if (isAccordJournal(metadata))
return new AccordJournalPurger(compactionInfos.get(), version.get(), cfs);
if (isAccordCommandsForKey(metadata))
return new AccordCommandsForKeyPurger(AccordKeyspace.CFKAccessor, compactionInfos);
if (isAccordJournal(cfs))
return new AccordJournalPurger(compactionInfos.get(), version.get(), cfs);
if (isAccordCommandsForKey(cfs))
return new AccordCommandsForKeyPurger(AccordKeyspace.CFKAccessor, compactionInfos);
// at time of writing there are no other accord system tables,
// but unless otherwise stated additional tables should be treated as normal
}
throw new IllegalArgumentException("Unhandled accord table: " + cfs.keyspace.getName() + '.' + cfs.name);
long nowInSec = this.nowInSec;
if (metadata.isAccordEnabled() || metadata.migratingFromAccord())
nowInSec = controller.gcBefore;
return new Purger(controller, nowInSec);
}
public TableMetadata metadata()
@ -907,7 +916,7 @@ public class CompactionIterator extends CompactionInfo.Holder implements Unfilte
switch (key.type)
{
case COMMAND_DIFF:
compactor = new AccordCommandRowCompactor(infos, userVersion, nowInSec);
compactor = new AccordCommandRowCompactor(infos, userVersion);
break;
case TOPOLOGY_UPDATE:
compactor = new TopologyCompactor(userVersion, infos.minEpoch);
@ -1112,20 +1121,18 @@ public class CompactionIterator extends CompactionInfo.Holder implements Unfilte
final AccordCompactionInfos infos;
final Version userVersion;
final ColumnData userVersionCell;
final long nowInSec;
final CommandChanges mainBuilder = new CommandChanges();
final List<AccordCommandRowEntry> entries = new ArrayList<>();
final ArrayDeque<AccordCommandRowEntry> reuseEntries = new ArrayDeque<>();
AccordCompactionInfo info;
AccordCommandRowCompactor(AccordCompactionInfos infos, Version userVersion, long nowInSec)
AccordCommandRowCompactor(AccordCompactionInfos infos, Version userVersion)
{
super((CommandChangeSerializer) JournalKey.Type.COMMAND_DIFF.serializer);
this.infos = infos;
this.userVersion = userVersion;
this.userVersionCell = BufferCell.live(AccordKeyspace.JournalColumns.user_version, timestamp, Int32Type.instance.decompose(userVersion.version));
this.nowInSec = nowInSec;
}
@Override
@ -1258,30 +1265,23 @@ public class CompactionIterator extends CompactionInfo.Holder implements Unfilte
}
}
private static boolean isPaxos(ColumnFamilyStore cfs)
private static boolean isPaxos(TableMetadata metadata)
{
return cfs.name.equals(SystemKeyspace.PAXOS) && cfs.getKeyspaceName().equals(SchemaConstants.SYSTEM_KEYSPACE_NAME);
return metadata.name.equals(SystemKeyspace.PAXOS) && metadata.keyspace.equals(SchemaConstants.SYSTEM_KEYSPACE_NAME);
}
private static boolean requiresAccordSpecificPurger(ColumnFamilyStore cfs)
private static boolean isAccordSystemTable(TableMetadata metadata)
{
return cfs.getKeyspaceName().equals(SchemaConstants.ACCORD_KEYSPACE_NAME) &&
(cfs.getTableName().contains(AccordKeyspace.JOURNAL) ||
AccordKeyspace.COMMANDS_FOR_KEY.equals(cfs.getTableName()));
return metadata.keyspace.equals(SchemaConstants.ACCORD_KEYSPACE_NAME);
}
private static boolean isAccordTable(ColumnFamilyStore cfs, String name)
private static boolean isAccordJournal(TableMetadata metadata)
{
return cfs.name.equals(name) && cfs.getKeyspaceName().equals(SchemaConstants.ACCORD_KEYSPACE_NAME);
return metadata.name.startsWith(AccordKeyspace.JOURNAL) && metadata.keyspace.equals(SchemaConstants.ACCORD_KEYSPACE_NAME);
}
private static boolean isAccordJournal(ColumnFamilyStore cfs)
private static boolean isAccordCommandsForKey(TableMetadata metadata)
{
return cfs.getKeyspaceName().equals(SchemaConstants.ACCORD_KEYSPACE_NAME) && cfs.name.startsWith(AccordKeyspace.JOURNAL);
}
private static boolean isAccordCommandsForKey(ColumnFamilyStore cfs)
{
return isAccordTable(cfs, AccordKeyspace.COMMANDS_FOR_KEY);
return metadata.name.equals(AccordKeyspace.COMMANDS_FOR_KEY) && metadata.keyspace.equals(SchemaConstants.ACCORD_KEYSPACE_NAME);
}
}

View File

@ -161,7 +161,6 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
public final AtomicInteger currentlyBackgroundUpgrading = new AtomicInteger(0);
public static final int NO_GC = Integer.MIN_VALUE;
public static final int GC_ALL = Integer.MAX_VALUE;
static
{
@ -394,7 +393,7 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
}
CompactionStrategyManager strategy = cfs.getCompactionStrategyManager();
tasks = strategy.getNextBackgroundTasks(getDefaultGcBefore(cfs, FBUtilities.nowInSeconds()));
tasks = strategy.getNextBackgroundTasks(cfs.getDefaultGcBefore(FBUtilities.nowInSeconds()));
if (tasks == null || tasks.isEmpty())
{
if (DatabaseDescriptor.automaticSSTableUpgrade())
@ -906,10 +905,10 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
public void execute(LifecycleTransaction txn)
{
logger.debug("Garbage collecting {}", txn.originals());
CompactionTask task = new CompactionTask(cfStore, txn, getDefaultGcBefore(cfStore, FBUtilities.nowInSeconds()))
CompactionTask task = new CompactionTask(cfStore, txn, cfStore.getDefaultGcBefore(FBUtilities.nowInSeconds()))
{
@Override
protected CompactionController getCompactionController(Set<SSTableReader> toCompact)
protected CompactionController getCompactionController(Set<SSTableReader> toCompact, long gcBefore)
{
return new CompactionController(cfStore, toCompact, gcBefore, null, tombstoneOption);
}
@ -1174,12 +1173,12 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
public void performMaximal(final ColumnFamilyStore cfStore, boolean splitOutput, int permittedParallelism)
{
FBUtilities.waitOnFutures(submitMaximal(cfStore, getDefaultGcBefore(cfStore, FBUtilities.nowInSeconds()), splitOutput, permittedParallelism));
FBUtilities.waitOnFutures(submitMaximal(cfStore, cfStore.getDefaultGcBefore(FBUtilities.nowInSeconds()), splitOutput, permittedParallelism));
}
public List<Future<?>> submitMaximal(final ColumnFamilyStore cfStore, boolean splitOutput, int permittedParallelism)
{
return submitMaximal(cfStore, getDefaultGcBefore(cfStore, FBUtilities.nowInSeconds()), splitOutput, permittedParallelism);
return submitMaximal(cfStore, cfStore.getDefaultGcBefore(FBUtilities.nowInSeconds()), splitOutput, permittedParallelism);
}
public List<Future<?>> submitMaximal(final ColumnFamilyStore cfStore, final long gcBefore, boolean splitOutput, int permittedParallelism)
@ -1239,7 +1238,7 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
logger.debug("No sstables found for the provided token range");
return CompactionTasks.empty();
}
return cfStore.getCompactionStrategyManager().getUserDefinedTasks(sstables, getDefaultGcBefore(cfStore, FBUtilities.nowInSeconds()));
return cfStore.getCompactionStrategyManager().getUserDefinedTasks(sstables, cfStore.getDefaultGcBefore(FBUtilities.nowInSeconds()));
};
try (CompactionTasks tasks = cfStore.runWithCompactionsDisabled(taskCreator,
@ -1360,7 +1359,7 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
List<Future<?>> futures = new ArrayList<>(descriptors.size());
long nowInSec = FBUtilities.nowInSeconds();
for (ColumnFamilyStore cfs : descriptors.keySet())
futures.add(submitUserDefined(cfs, descriptors.get(cfs), getDefaultGcBefore(cfs, nowInSec)));
futures.add(submitUserDefined(cfs, descriptors.get(cfs), cfs.getDefaultGcBefore(nowInSec)));
FBUtilities.waitOnFutures(futures);
}
@ -1651,7 +1650,7 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
long nowInSec = FBUtilities.nowInSeconds();
try (SSTableRewriter writer = SSTableRewriter.construct(cfs, txn, false, sstable.maxDataAge);
ISSTableScanner scanner = cleanupStrategy.getScanner(sstable);
CompactionController controller = new CompactionController(cfs, txn.originals(), getDefaultGcBefore(cfs, nowInSec));
CompactionController controller = new CompactionController(cfs, txn.originals(), cfs.getDefaultGcBefore(nowInSec));
Refs<SSTableReader> refs = Refs.ref(Collections.singleton(sstable));
CompactionIterator ci = new CompactionIterator(OperationType.CLEANUP, Collections.singletonList(scanner), controller, nowInSec, nextTimeUUID(), active, null))
{
@ -1998,7 +1997,7 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
SSTableRewriter unrepairedWriter = SSTableRewriter.constructWithoutEarlyOpening(sharedTxn, false, groupMaxDataAge);
AbstractCompactionStrategy.ScannerList scanners = strategy.getScanners(txn.originals());
CompactionController controller = new CompactionController(cfs, sstableAsSet, getDefaultGcBefore(cfs, nowInSec));
CompactionController controller = new CompactionController(cfs, sstableAsSet, cfs.getDefaultGcBefore(nowInSec));
CompactionIterator ci = getAntiCompactionIterator(scanners.scanners, controller, nowInSec, nextTimeUUID(), active, isCancelled))
{
int expectedBloomFilterSize = Math.max(cfs.metadata().params.minIndexInterval, (int)(SSTableReader.getApproximateKeyCount(sstableAsSet)));
@ -2184,13 +2183,6 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
}
}
public static long getDefaultGcBefore(ColumnFamilyStore cfs, long nowInSec)
{
// 2ndary indexes have ExpiringColumns too, so we need to purge tombstones deleted before now. We do not need to
// add any GcGrace however since 2ndary indexes are local to a node.
return cfs.isIndex() ? nowInSec : cfs.gcBefore(nowInSec);
}
public Future<Long> submitViewBuilder(final ViewBuilderTask task)
{
return submitViewBuilder(task, active);

View File

@ -35,6 +35,12 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import accord.local.CommandStores;
import accord.local.CommandStores.StoreFinder;
import accord.local.Node;
import accord.primitives.Ranges;
import accord.utils.Invariants;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.db.ColumnFamilyStore;
import org.apache.cassandra.db.Directories;
@ -55,7 +61,11 @@ import org.apache.cassandra.io.sstable.ISSTableScanner;
import org.apache.cassandra.io.sstable.format.SSTableReader;
import org.apache.cassandra.io.sstable.metadata.MetadataCollector;
import org.apache.cassandra.io.util.File;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.service.ActiveRepairService;
import org.apache.cassandra.service.accord.AccordService;
import org.apache.cassandra.service.accord.TokenRange;
import org.apache.cassandra.service.accord.api.TokenKey;
import org.apache.cassandra.service.snapshot.SnapshotManager;
import org.apache.cassandra.service.snapshot.SnapshotOptions;
import org.apache.cassandra.service.snapshot.SnapshotType;
@ -63,6 +73,8 @@ import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.TimeUUID;
import org.apache.cassandra.utils.concurrent.Refs;
import static accord.local.RedundantStatus.Property.LOCALLY_APPLIED;
import static org.apache.cassandra.db.compaction.CompactionManager.NO_GC;
import static org.apache.cassandra.utils.Clock.Global.currentTimeMillis;
import static org.apache.cassandra.utils.Clock.Global.nanoTime;
@ -71,20 +83,20 @@ public class CompactionTask extends AbstractCompactionTask
private static final int MEGABYTE = 1024 * 1024;
protected static final Logger logger = LoggerFactory.getLogger(CompactionTask.class);
protected final long gcBefore;
protected final long gcBeforeSeconds;
protected final boolean keepOriginals;
protected static long totalBytesCompacted = 0;
private ActiveCompactionsTracker activeCompactions;
public CompactionTask(ColumnFamilyStore cfs, ILifecycleTransaction txn, long gcBefore)
public CompactionTask(ColumnFamilyStore cfs, ILifecycleTransaction txn, long gcBeforeSeconds)
{
this(cfs, txn, gcBefore, false);
this(cfs, txn, gcBeforeSeconds, false);
}
public CompactionTask(ColumnFamilyStore cfs, ILifecycleTransaction txn, long gcBefore, boolean keepOriginals)
public CompactionTask(ColumnFamilyStore cfs, ILifecycleTransaction txn, long gcBeforeSeconds, boolean keepOriginals)
{
super(cfs, txn);
this.gcBefore = gcBefore;
this.gcBeforeSeconds = gcBeforeSeconds;
this.keepOriginals = keepOriginals;
}
@ -546,7 +558,33 @@ public class CompactionTask extends AbstractCompactionTask
return 0;
}
protected CompactionController getCompactionController(Set<SSTableReader> toCompact)
protected final CompactionController getCompactionController(Set<SSTableReader> toCompact)
{
long gcBeforeSeconds = this.gcBeforeSeconds;
TableMetadata metadata = cfs.metadata();
if (metadata.isAccordEnabled())
{
Invariants.expect(gcBeforeSeconds <= 0);
TokenRange[] rs = new TokenRange[toCompact.size()];
int i = 0;
for (SSTableReader reader : toCompact)
rs[i++] = TokenRange.create(TokenKey.before(metadata.id, reader.getFirst().getToken()), TokenKey.after(metadata.id, reader.getLast().getToken()));
Ranges ranges = Ranges.of(rs);
Node node = AccordService.unsafeInstance().node();
// TODO (expected): we shouldn't need to limit to universalBefore, but this is a safety margin esp. against bugs with repairing tombstones or incomplete information in CommandStore;
// we should impose stronger guarantees on incoming streams (that they don't contain tombstones), and validate our CommandStore-derived bounds
gcBeforeSeconds = node.durableBefore().foldlWithDefault(ranges, (e, v) -> e == null ? NO_GC : Math.min(e.universal.hlc(), v), null, Long.MAX_VALUE);
CommandStores.StoreSelector selector = StoreFinder.selector(ranges, Long.MIN_VALUE, Long.MAX_VALUE);
gcBeforeSeconds = node.commandStores().mapReduceUnsafe(selector, commandStore -> commandStore.unsafeGetRedundantBefore().foldl(ranges, (bs, v) -> bs.maxBound(LOCALLY_APPLIED).hlc(), Long.MAX_VALUE), Math::min, gcBeforeSeconds);
if (gcBeforeSeconds == Long.MAX_VALUE)
gcBeforeSeconds = NO_GC;
else
gcBeforeSeconds = TimeUnit.MICROSECONDS.toSeconds(gcBeforeSeconds);
}
return getCompactionController(toCompact, gcBeforeSeconds);
}
protected CompactionController getCompactionController(Set<SSTableReader> toCompact, long gcBefore)
{
return new CompactionController(cfs, toCompact, gcBefore);
}

View File

@ -56,7 +56,7 @@ public class SSTableSplitter
}
@Override
protected CompactionController getCompactionController(Set<SSTableReader> toCompact)
protected CompactionController getCompactionController(Set<SSTableReader> toCompact, long gcBefore)
{
return new SplitController(cfs);
}

View File

@ -35,7 +35,7 @@ public class TimeWindowCompactionTask extends CompactionTask
}
@Override
public CompactionController getCompactionController(Set<SSTableReader> toCompact)
public CompactionController getCompactionController(Set<SSTableReader> toCompact, long gcBefore)
{
return new TimeWindowCompactionController(cfs, toCompact, gcBefore, ignoreOverlaps);
}

View File

@ -22,6 +22,7 @@ import java.util.UUID;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.Duration;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.terms.Constants;
import org.apache.cassandra.cql3.terms.Term;
import org.apache.cassandra.serializers.MarshalException;
@ -32,7 +33,6 @@ import org.apache.cassandra.utils.bytecomparable.ByteSource;
import org.apache.cassandra.utils.bytecomparable.ByteSourceInverse;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static org.apache.cassandra.utils.TimeUUID.Generator.nextTimeUUIDAsBytes;
// Fully compatible with UUID, and indeed is interpreted as UUID for UDF
public abstract class AbstractTimeUUIDType<T> extends TemporalType<T>
@ -218,9 +218,9 @@ public abstract class AbstractTimeUUIDType<T> extends TemporalType<T>
}
@Override
public ByteBuffer now()
public ByteBuffer now(FunctionContext context)
{
return ByteBuffer.wrap(nextTimeUUIDAsBytes());
return ByteBuffer.wrap(context.nextTimeUUIDAsBytes());
}
@Override

View File

@ -22,11 +22,10 @@ import java.nio.ByteBuffer;
import org.apache.commons.lang3.mutable.MutableLong;
import org.apache.cassandra.cql3.Duration;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
import org.apache.cassandra.transport.ProtocolVersion;
import static org.apache.cassandra.utils.Clock.Global.currentTimeMillis;
/**
* Base type for temporal types (timestamp, date ...).
*
@ -42,9 +41,9 @@ public abstract class TemporalType<T> extends AbstractType<T>
* Returns the current temporal value.
* @return the current temporal value.
*/
public ByteBuffer now()
public ByteBuffer now(FunctionContext context)
{
return fromTimeInMillis(currentTimeMillis());
return fromTimeInMillis(context.nowMillis());
}
/**

View File

@ -22,6 +22,7 @@ import java.time.LocalTime;
import java.time.ZoneOffset;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
import org.apache.cassandra.cql3.terms.Constants;
import org.apache.cassandra.cql3.terms.Term;
@ -110,9 +111,10 @@ public class TimeType extends TemporalType<Long>
}
@Override
public ByteBuffer now()
public ByteBuffer now(FunctionContext context)
{
return decompose(LocalTime.now(ZoneOffset.UTC).toNanoOfDay());
long nanoOfDay = LocalTime.ofInstant(context.now(), ZoneOffset.UTC).toNanoOfDay();
return decompose(nanoOfDay);
}
@Override

View File

@ -130,7 +130,6 @@ public abstract class AbstractBTreePartition implements Partition, Iterable<Row>
if (rt != null && rt.deletionTime().supersedes(activeDeletion))
activeDeletion = rt.deletionTime();
if (row == null)
{
// this means our partition level deletion supersedes all other deletions and we don't have to keep the row deletions

View File

@ -99,13 +99,6 @@ public class CassandraValidationIterator extends ValidationPartitionIterator
}
}
public static long getDefaultGcBefore(ColumnFamilyStore cfs, long nowInSec)
{
// 2ndary indexes have ExpiringColumns too, so we need to purge tombstones deleted before now. We do not need to
// add any GcGrace however since 2ndary indexes are local to a node.
return cfs.isIndex() ? nowInSec : cfs.gcBefore(nowInSec);
}
private static class ValidationCompactionIterator extends CompactionIterator
{
public ValidationCompactionIterator(List<ISSTableScanner> scanners, ValidationCompactionController controller, long nowInSec, ActiveCompactionsTracker activeCompactions, TopPartitionTracker.Collector topPartitionCollector)
@ -219,7 +212,7 @@ public class CassandraValidationIterator extends ValidationPartitionIterator
cfs.getKeyspaceName(),
cfs.getTableName());
long gcBefore = dontPurgeTombstones ? Long.MIN_VALUE : getDefaultGcBefore(cfs, nowInSec);
long gcBefore = dontPurgeTombstones ? Long.MIN_VALUE : cfs.getDefaultGcBefore(nowInSec);
controller = new ValidationCompactionController(cfs, gcBefore);
scanners = cfs.getCompactionStrategyManager().getScanners(sstables, ranges);
ci = new ValidationCompactionIterator(scanners.scanners, controller, nowInSec, CompactionManager.instance.active, topPartitionCollector);

View File

@ -46,7 +46,8 @@ import org.apache.cassandra.config.DatabaseDescriptor;
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.RowUpdateBuilder;
import org.apache.cassandra.cql3.RowUpdateBuilder.RegularRowUpdateBuilder;
import org.apache.cassandra.cql3.functions.types.TypeCodec;
import org.apache.cassandra.cql3.functions.types.UserType;
import org.apache.cassandra.cql3.statements.ModificationStatement;
@ -285,13 +286,13 @@ public class CQLSSTableWriter implements Closeable
long now = currentTimeMillis();
// Note that we asks indexes to not validate values (the last 'false' arg below) because that triggers a 'Keyspace.open'
// and that forces a lot of initialization that we don't want.
UpdateParameters params = new UpdateParameters(modificationStatement.metadata,
ClientState.forInternalCalls(),
options,
modificationStatement.getTimestamp(TimeUnit.MILLISECONDS.toMicros(now), options),
options.getNowInSec((int) TimeUnit.MILLISECONDS.toSeconds(now)),
modificationStatement.getTimeToLive(options),
Collections.emptyMap());
RowUpdateBuilder builder = new RegularRowUpdateBuilder(modificationStatement.metadata,
ClientState.forInternalCalls(),
options,
modificationStatement.getTimestamp(TimeUnit.MILLISECONDS.toMicros(now), options),
options.getNowInSec((int) TimeUnit.MILLISECONDS.toSeconds(now)),
modificationStatement.getTimeToLive(options),
null);
try
{
@ -302,7 +303,7 @@ public class CQLSSTableWriter implements Closeable
for (ByteBuffer key : keys)
{
for (Slice slice : slices)
modificationStatement.addUpdateForKey(writer.getUpdateFor(key), slice, params);
modificationStatement.addUpdateForKey(writer.getUpdateFor(key), slice, builder);
}
}
else
@ -312,7 +313,7 @@ public class CQLSSTableWriter implements Closeable
for (ByteBuffer key : keys)
{
for (Clustering clustering : clusterings)
modificationStatement.addUpdateForKey(writer.getUpdateFor(key), clustering, params);
modificationStatement.addUpdateForKey(writer.getUpdateFor(key), clustering, builder);
}
}
return this;

View File

@ -123,6 +123,7 @@ public class RepairSession extends AsyncFuture<RepairSessionResult> implements I
public final boolean isIncremental;
public final boolean allReplicas;
public final PreviewKind previewKind;
// TODO (expected): introduce forceRepairData and ignore repairData for Accord tables
public final boolean repairData;
public final boolean repairPaxos;
public final boolean repairAccord;

View File

@ -200,7 +200,6 @@ abstract class AccordExecutorAbstractLockLoop extends AccordExecutorAbstractLoop
@Override
public void run()
{
Thread self = Thread.currentThread();
int count = 0;
Task task = null;
while (true)

View File

@ -65,9 +65,9 @@ import org.apache.cassandra.dht.Murmur3Partitioner;
import org.apache.cassandra.schema.TableId;
import org.apache.cassandra.service.accord.api.PartitionKey;
import org.apache.cassandra.service.accord.api.TokenKey;
import org.apache.cassandra.service.accord.serializers.ResultSerializers;
import org.apache.cassandra.service.accord.serializers.TableMetadatasAndKeys;
import org.apache.cassandra.service.accord.txn.AccordUpdate;
import org.apache.cassandra.service.accord.txn.TxnDataResult;
import org.apache.cassandra.service.accord.txn.TxnQuery;
import org.apache.cassandra.service.accord.txn.TxnRead;
import org.apache.cassandra.service.accord.txn.TxnWrite;
@ -318,7 +318,7 @@ public class AccordObjectSizes
builder.waitingOn(WaitingOn.empty(Domain.Key));
if (saveStatus.known.is(Known.Outcome.Apply))
builder.result(ResultSerializers.APPLIED);
builder.result(TxnDataResult.PERSISTABLE);
return builder.build(saveStatus);
}
@ -400,6 +400,7 @@ public class AccordObjectSizes
size += sizeNullable(command.partialDeps(), AccordObjectSizes::dependencies);
size += sizeNullable(command.acceptedOrCommitted(), AccordObjectSizes::timestamp);
size += sizeNullable(command.writes(), AccordObjectSizes::writes);
// no need to measure command.results(), as should always be a sentinel value
size += sizeNullable(command.waitingOn(), AccordObjectSizes::waitingOn);
return size;
}

View File

@ -261,6 +261,11 @@ public final class TokenKey extends AccordRoutableKey implements RoutingKey, Ran
return new TokenKey(table, BEFORE_TOKEN_SENTINEL, token);
}
public static TokenKey after(TableId table, Token token)
{
return new TokenKey(table, AFTER_TOKEN_SENTINEL, token);
}
public static final NoTableSerializer noTableSerializer = new NoTableSerializer();

View File

@ -35,9 +35,9 @@ import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.journal.Journal;
import org.apache.cassandra.service.accord.serializers.CommandSerializers;
import org.apache.cassandra.service.accord.serializers.DepsSerializers;
import org.apache.cassandra.service.accord.serializers.ResultSerializers;
import org.apache.cassandra.service.accord.serializers.Version;
import org.apache.cassandra.service.accord.serializers.WaitingOnSerializer;
import org.apache.cassandra.service.accord.txn.TxnDataResult;
import static accord.impl.CommandChange.anyFieldChanged;
import static accord.impl.CommandChange.describeFlags;
@ -140,7 +140,7 @@ public class CommandChangeWriter implements Journal.Writer
CommandSerializers.writes.serialize(command.writes(), out, userVersion);
break;
case RESULT:
ResultSerializers.result.serialize(command.result(), out);
TxnDataResult.persistable.serialize(command.result(), out);
break;
case CLEANUP:
Cleanup cleanup;

View File

@ -41,9 +41,9 @@ import org.apache.cassandra.io.util.DataOutputPlus;
import org.apache.cassandra.service.accord.JournalKey;
import org.apache.cassandra.service.accord.serializers.CommandSerializers;
import org.apache.cassandra.service.accord.serializers.DepsSerializers;
import org.apache.cassandra.service.accord.serializers.ResultSerializers;
import org.apache.cassandra.service.accord.serializers.Version;
import org.apache.cassandra.service.accord.serializers.WaitingOnSerializer;
import org.apache.cassandra.service.accord.txn.TxnDataResult;
import static accord.api.Journal.Load.ALL;
import static accord.impl.CommandChange.Field.CLEANUP;
@ -205,7 +205,7 @@ public class CommandChanges extends CommandChange.Builder implements Merger
break;
case RESULT:
Invariants.require(result != null, "%s", this);
ResultSerializers.result.serialize(result, out);
TxnDataResult.persistable.serialize(result, out);
break;
}
}
@ -309,7 +309,7 @@ public class CommandChanges extends CommandChange.Builder implements Merger
cleanup = newCleanup;
break;
case RESULT:
result = ResultSerializers.result.deserialize(in);
result = TxnDataResult.persistable.deserialize(in);
break;
}
}
@ -355,8 +355,7 @@ public class CommandChanges extends CommandChange.Builder implements Merger
CommandSerializers.writes.skip(in, userVersion);
break;
case RESULT:
// TODO (expected): skip
ResultSerializers.result.skip(in);
TxnDataResult.persistable.skip(in);
break;
}
}

Some files were not shown because too many files have changed in this diff Show More