Accord: Deterministic time integration

- now() functions must be deterministic (and derived from Accord timestamp)
 - tombstone GC and TTL evaluation must be deterministic and based on both Accord timestamp and Accord GC mechanisms (that guarantee completeness of execution)

patch by Benedict; reviewed by Alex Petrov and Ariel Weisberg for CASSANDRA-21376
This commit is contained in:
Benedict Elliott Smith 2025-11-21 15:46:58 +00:00
parent a0dc6f857b
commit 7623a59b31
136 changed files with 1201 additions and 840 deletions

View File

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

View File

@ -356,9 +356,9 @@ public final class ColumnsExpression
* Returns the key, index or fieldname specifying the selected element. * Returns the key, index or fieldname specifying the selected element.
* @return 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. * 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. * @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() 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 @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 return term == null
? (defaultUnset ? Constants.UNSET_VALUE : null) ? (defaultUnset ? Constants.UNSET_VALUE : null)
: term.bind(options); : term.bind(context);
} }
@Override @Override

View File

@ -116,9 +116,9 @@ public abstract class Operation
* Execute the operation. * Execute the operation.
* *
* @param partitionKey partition key for the update. * @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. * 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.DataStorageSpec;
import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.FunctionContext.RealTimeFunctionContext;
import org.apache.cassandra.cql3.terms.Term; import org.apache.cassandra.cql3.terms.Term;
import org.apache.cassandra.db.ConsistencyLevel; import org.apache.cassandra.db.ConsistencyLevel;
import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.db.marshal.UTF8Type;
@ -53,7 +54,7 @@ import static org.apache.cassandra.utils.ByteArrayUtil.convertToByteBufferValue;
/** /**
* Options for a query. * Options for a query.
*/ */
public abstract class QueryOptions public abstract class QueryOptions implements RealTimeFunctionContext
{ {
public static final QueryOptions DEFAULT = new DefaultQueryOptions(ConsistencyLevel.ONE, public static final QueryOptions DEFAULT = new DefaultQueryOptions(ConsistencyLevel.ONE,
Collections.emptyList(), Collections.emptyList(),
@ -378,6 +379,12 @@ public abstract class QueryOptions
} }
} }
@Override
public QueryOptions options()
{
return this;
}
static class DefaultQueryOptions extends QueryOptions static class DefaultQueryOptions extends QueryOptions
{ {
private final ConsistencyLevel consistency; private final ConsistencyLevel consistency;

View File

@ -555,7 +555,7 @@ public class QueryProcessor implements QueryHandler
.map(m -> MessagingService.instance().<ReadCommand, ReadResponse>sendWithResult(m, address)) .map(m -> MessagingService.instance().<ReadCommand, ReadResponse>sendWithResult(m, address))
.collect(Collectors.toList())); .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 -> { return future.map(list -> {
int i = 0; int i = 0;
for (Message<ReadResponse> m : list) for (Message<ReadResponse> m : list)

View File

@ -15,6 +15,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.apache.cassandra.cql3; package org.apache.cassandra.cql3;
import java.nio.ByteBuffer; 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.ColumnMetadata;
import org.apache.cassandra.schema.TableMetadata; import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.service.ClientState; import org.apache.cassandra.service.ClientState;
import org.apache.cassandra.utils.TimeUUID;
/** public abstract class RowUpdateBuilder implements FunctionContext
* Groups the parameters of an update query, and make building updates easier.
*/
public class UpdateParameters
{ {
public final TableMetadata metadata; public static class RegularRowUpdateBuilder extends RowUpdateBuilder implements RealTimeFunctionContext
public final ClientState clientState; {
public final QueryOptions options; 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; public static class NoTimeRowUpdateBuilder extends RowUpdateBuilder implements NoTimeFunctionContext
protected final long timestamp; {
private final int ttl; 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; 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. // The builder currently in use. Will alias either staticBuilder or regularBuilder, which are themselves built lazily.
private Row.Builder builder; private Row.Builder builder;
public UpdateParameters(TableMetadata metadata, protected RowUpdateBuilder(TableMetadata metadata,
ClientState clientState, ClientState clientState,
QueryOptions options, QueryOptions options,
long timestamp, long timestamp,
@ -75,21 +88,26 @@ public class UpdateParameters
Map<DecoratedKey, Partition> prefetchedRows) throws InvalidRequestException Map<DecoratedKey, Partition> prefetchedRows) throws InvalidRequestException
{ {
this.metadata = metadata; this.metadata = metadata;
this.clientState = clientState;
this.options = options; this.options = options;
this.clientState = clientState;
this.nowInSec = nowInSec; this.nowInSec = nowInSec;
this.timestamp = timestamp; this.timestamp = timestamp;
this.ttl = ttl; this.ttl = ttl;
this.deletionTime = DeletionTime.build(timestamp, nowInSec);
this.prefetchedRows = prefetchedRows; this.prefetchedRows = prefetchedRows;
// We use MIN_VALUE internally to mean the absence of of timestamp (in Selection, in sstable stats, ...), so exclude // We use MIN_VALUE internally to mean the absence of of timestamp (in Selection, in sstable stats, ...), so exclude
// it to avoid potential confusion. // it to avoid potential confusion.
if (timestamp == Long.MIN_VALUE) 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)); 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 public <V> void newRow(Clustering<V> clustering) throws InvalidRequestException
{ {
if (metadata.isCompactTable()) if (metadata.isCompactTable())
@ -208,7 +226,7 @@ public class UpdateParameters
newRow(row.clustering()); newRow(row.clustering());
addRowDeletion(row.deletion()); addRowDeletion(row.deletion());
addPrimaryKeyLivenessInfo(row.primaryKeyLivenessInfo()); addPrimaryKeyLivenessInfo(row.primaryKeyLivenessInfo());
row.iterator().forEachRemaining(cd -> { row.forEach(cd -> {
if (cd instanceof Cell<?>) if (cd instanceof Cell<?>)
{ {
builder.addCell((Cell<?>) cd); builder.addCell((Cell<?>) cd);
@ -297,11 +315,6 @@ public class UpdateParameters
return new RangeTombstone(slice, deletionTime()); return new RangeTombstone(slice, deletionTime());
} }
public byte[] nextTimeUUIDAsBytes()
{
return TimeUUID.Generator.nextTimeUUIDAsBytes();
}
/** /**
* Returns the prefetched row with the already performed modifications. * 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 * <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) return Rows.merge(prefetchedRow, pendingMutations)
.purge(DeletionPurger.PURGE_ALL, nowInSec, metadata.enforceStrictLiveness()); .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.ColumnSpecification;
import org.apache.cassandra.cql3.ColumnsExpression; import org.apache.cassandra.cql3.ColumnsExpression;
import org.apache.cassandra.cql3.FieldIdentifier; import org.apache.cassandra.cql3.FieldIdentifier;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operator; import org.apache.cassandra.cql3.Operator;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.VariableSpecifications; import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.terms.Term; import org.apache.cassandra.cql3.terms.Term;
@ -110,39 +110,39 @@ public final class ColumnCondition
values.collectMarkerSpecification(boundNames, owner); values.collectMarkerSpecification(boundNames, owner);
} }
public ColumnCondition.Bound bind(QueryOptions options) public ColumnCondition.Bound bind(FunctionContext context)
{ {
switch (columnsExpression.kind()) switch (columnsExpression.kind())
{ {
case SINGLE_COLUMN: case SINGLE_COLUMN:
return bindSingleColumn(options); return bindSingleColumn(context);
case ELEMENT: case ELEMENT:
return bindElement(options); return bindElement(context);
default: default:
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
} }
private Bound bindSingleColumn(QueryOptions options) private Bound bindSingleColumn(FunctionContext context)
{ {
ColumnMetadata column = columnsExpression.firstColumn(); ColumnMetadata column = columnsExpression.firstColumn();
TableMetadata table = columnsExpression.table(); TableMetadata table = columnsExpression.table();
if (column.type.isMultiCell()) 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(); ColumnMetadata column = columnsExpression.firstColumn();
TableMetadata table = columnsExpression.table(); TableMetadata table = columnsExpression.table();
ByteBuffer keyOrIndex = columnsExpression.element(options); ByteBuffer keyOrIndex = columnsExpression.element(context);
if (column.type.isCollection()) if (column.type.isCollection())
{ {
checkNotNull(keyOrIndex, "Invalid null value for %s element access", column.type instanceof MapType ? "map" : "list"); 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) private ByteBuffer toValue(AbstractType<?> type, List<ByteBuffer> values)
@ -157,9 +157,9 @@ public final class ColumnCondition
return value; 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 == null && operator.isIN(), "Invalid null list in IN condition");
checkFalse(buffers == Term.UNSET_LIST, "Invalid 'unset' value in condition"); checkFalse(buffers == Term.UNSET_LIST, "Invalid 'unset' value in condition");
return filterUnsetValuesIfNeeded(buffers, ByteBufferUtil.UNSET_BYTE_BUFFER); return filterUnsetValuesIfNeeded(buffers, ByteBufferUtil.UNSET_BYTE_BUFFER);

View File

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

View File

@ -19,8 +19,8 @@ package org.apache.cassandra.cql3.functions;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.exceptions.InvalidRequestException; 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. * 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. * Computes and returns the aggregate current value.
* *
* @param protocolVersion native protocol version * @param context
* @return the aggregate current value. * @return the aggregate current value.
*/ */
public ByteBuffer compute(ProtocolVersion protocolVersion) throws InvalidRequestException; public ByteBuffer compute(FunctionContext context) throws InvalidRequestException;
/** /**
* Reset this aggregate. * Reset this aggregate.

View File

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

View File

@ -20,11 +20,11 @@ package org.apache.cassandra.cql3.functions;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.apache.cassandra.cql3.CQL3Type; 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.AbstractType;
import org.apache.cassandra.db.marshal.BytesType; import org.apache.cassandra.db.marshal.BytesType;
import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.serializers.MarshalException;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.ByteBufferUtil;
public abstract class BytesConversionFcts public abstract class BytesConversionFcts
@ -49,9 +49,9 @@ public abstract class BytesConversionFcts
} }
@Override @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.commons.lang3.StringUtils;
import org.apache.cassandra.cql3.CQL3Type; 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.AbstractType;
import org.apache.cassandra.db.marshal.AsciiType; import org.apache.cassandra.db.marshal.AsciiType;
import org.apache.cassandra.db.marshal.BooleanType; 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.TimestampType;
import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.db.marshal.UUIDType; 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.toDate;
import static org.apache.cassandra.cql3.functions.TimeFcts.toTimestamp; import static org.apache.cassandra.cql3.functions.TimeFcts.toTimestamp;
@ -388,9 +388,9 @@ public final class CastFcts
} }
@Override @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); AbstractType<?> argType = argTypes.get(0);
if (buffer == null || (!buffer.hasRemaining() && argType.isEmptyValueMeaningless())) if (buffer == null || (!buffer.hasRemaining() && argType.isEmptyValueMeaningless()))
return null; return null;

View File

@ -26,13 +26,13 @@ import java.util.Set;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import org.apache.cassandra.cql3.CQL3Type; 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.AbstractType;
import org.apache.cassandra.db.marshal.CollectionType; import org.apache.cassandra.db.marshal.CollectionType;
import org.apache.cassandra.db.marshal.Int32Type; import org.apache.cassandra.db.marshal.Int32Type;
import org.apache.cassandra.db.marshal.ListType; import org.apache.cassandra.db.marshal.ListType;
import org.apache.cassandra.db.marshal.MapType; import org.apache.cassandra.db.marshal.MapType;
import org.apache.cassandra.db.marshal.SetType; import org.apache.cassandra.db.marshal.SetType;
import org.apache.cassandra.transport.ProtocolVersion;
/** /**
* Native CQL functions for collections (sets, list and maps). * Native CQL functions for collections (sets, list and maps).
@ -179,9 +179,9 @@ public class CollectionFcts
return new NativeScalarFunction(name, Int32Type.instance, inputType) return new NativeScalarFunction(name, Int32Type.instance, inputType)
{ {
@Override @Override
public Arguments newArguments(ProtocolVersion version) public Arguments newArguments(FunctionContext context)
{ {
return FunctionArguments.newNoopInstance(version, 1); return FunctionArguments.newNoopInstance(context, 1);
} }
@Override @Override
@ -359,9 +359,9 @@ public class CollectionFcts
} }
@Override @Override
public Arguments newArguments(ProtocolVersion version) public Arguments newArguments(FunctionContext context)
{ {
return FunctionArguments.newNoopInstance(version, 1); return FunctionArguments.newNoopInstance(context, 1);
} }
@Override @Override
@ -370,7 +370,7 @@ public class CollectionFcts
if (arguments.containsNulls()) if (arguments.containsNulls())
return null; return null;
Arguments args = aggregateFunction.newArguments(arguments.getProtocolVersion()); Arguments args = aggregateFunction.newArguments(arguments.context());
AggregateFunction.Aggregate aggregate = aggregateFunction.newAggregate(); AggregateFunction.Aggregate aggregate = aggregateFunction.newAggregate();
inputType.forEach(arguments.get(0), element -> { inputType.forEach(arguments.get(0), element -> {
@ -378,7 +378,7 @@ public class CollectionFcts
aggregate.addInput(args); 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.github.jamm.Unmetered;
import org.apache.cassandra.cql3.AssignmentTestable; import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.schema.Difference; import org.apache.cassandra.schema.Difference;
import org.apache.cassandra.transport.ProtocolVersion;
@Unmetered @Unmetered
public interface Function extends AssignmentTestable public interface Function extends AssignmentTestable
@ -77,10 +77,10 @@ public interface Function extends AssignmentTestable
/** /**
* Creates some new input arguments for this function. * Creates some new input arguments for this function.
* *
* @param version the protocol version * @param context
* @return some new input arguments for this function * @return some new input arguments for this function
*/ */
Arguments newArguments(ProtocolVersion version); Arguments newArguments(FunctionContext context);
public default Optional<Difference> compare(Function other) public default Optional<Difference> compare(Function other)
{ {

View File

@ -22,6 +22,7 @@ import java.nio.ByteBuffer;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.transport.ProtocolVersion; import org.apache.cassandra.transport.ProtocolVersion;
@ -30,20 +31,14 @@ import org.apache.cassandra.transport.ProtocolVersion;
*/ */
public final class FunctionArguments implements Arguments public final class FunctionArguments implements Arguments
{ {
/** public static final ArgumentDeserializer[] NO_DESERIALIZERS = new ArgumentDeserializer[0];
* An empty {@link FunctionArguments} for the current protocol.
*/
private static final FunctionArguments EMPTY = new FunctionArguments(ProtocolVersion.CURRENT);
/** /**
* The deserializer used to deserialize the columns. * The deserializer used to deserialize the columns.
*/ */
private final ArgumentDeserializer[] deserializers; private final ArgumentDeserializer[] deserializers;
/** private final FunctionContext context;
* The protocol version.
*/
private final ProtocolVersion version;
/** /**
* The deserialized arguments. * The deserialized arguments.
@ -53,93 +48,82 @@ public final class FunctionArguments implements Arguments
/** /**
* Creates a new {@link FunctionArguments} for the specified types. * Creates a new {@link FunctionArguments} for the specified types.
* *
* @param version the protocol version
* @param argTypes the argument types * @param argTypes the argument types
* @return a new {@link FunctionArguments} for the specified 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(); int size = argTypes.size();
if (size == 0) if (size == 0)
return emptyInstance(version); return context.noArguments();
ArgumentDeserializer[] deserializers = new ArgumentDeserializer[size]; ArgumentDeserializer[] deserializers = new ArgumentDeserializer[size];
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
deserializers[i] = argTypes.get(i).getArgumentDeserializer(); deserializers[i] = argTypes.get(i).getArgumentDeserializer();
return new FunctionArguments(version, deserializers); return new FunctionArguments(context, deserializers);
} }
@Override @Override
public ProtocolVersion getProtocolVersion() 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. * Creates a new {@link FunctionArguments} that does not deserialize the arguments.
* *
* @param version the protocol version
* @param numberOfArguments the number of argument * @param numberOfArguments the number of argument
* @return a new {@link FunctionArguments} for the specified types. * @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]; ArgumentDeserializer[] deserializers = new ArgumentDeserializer[numberOfArguments];
Arrays.fill(deserializers, ArgumentDeserializer.NOOP_DESERIALIZER); Arrays.fill(deserializers, ArgumentDeserializer.NOOP_DESERIALIZER);
return new FunctionArguments(version, deserializers); return new FunctionArguments(context, deserializers);
}
/**
* Creates an empty {@link FunctionArguments}.
*
* @param version the protocol version
* @return an empty {@link FunctionArguments}
*/
public static FunctionArguments emptyInstance(ProtocolVersion version)
{
if (version == ProtocolVersion.CURRENT)
return EMPTY;
return new FunctionArguments(version);
} }
/** /**
* Creates a new {@link FunctionArguments} for a native function. * Creates a new {@link FunctionArguments} for a native function.
* <p>Native functions can use different {@link ArgumentDeserializer} to avoid instanciating primitive wrappers.</p> * <p>Native functions can use different {@link ArgumentDeserializer} to avoid instanciating primitive wrappers.</p>
* *
* @param version the protocol version
* @param argTypes the argument types * @param argTypes the argument types
* @return a new {@link FunctionArguments} for the specified 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(); int size = argTypes.size();
if (size == 0) if (size == 0)
return emptyInstance(version); return context.noArguments();
ArgumentDeserializer[] deserializers = new ArgumentDeserializer[size]; ArgumentDeserializer[] deserializers = new ArgumentDeserializer[size];
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
deserializers[i] = argTypes.get(i).getArgumentDeserializer(); 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.deserializers = deserializers;
this.arguments = new Object[deserializers.length]; this.arguments = new Object[deserializers.length];
} }
public void set(int i, ByteBuffer buffer) public void set(int i, ByteBuffer buffer)
{ {
arguments[i] = deserializers[i].deserialize(version, buffer); arguments[i] = deserializers[i].deserialize(context.getProtocolVersion(), buffer);
} }
@Override @Override

View File

@ -28,7 +28,7 @@ import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.CQL3Type; import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.CqlBuilder; 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.VariableSpecifications;
import org.apache.cassandra.cql3.statements.RequestValidations; import org.apache.cassandra.cql3.statements.RequestValidations;
import org.apache.cassandra.cql3.terms.Constants; import org.apache.cassandra.cql3.terms.Constants;
@ -68,19 +68,19 @@ public class FunctionCall extends Term.NonTerminal
} }
@Override @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 @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++) for (int i = 0, m = terms.size(); i < m; i++)
{ {
Term t = terms.get(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); RequestValidations.checkBindValueSet(argument, "Invalid unset value for argument in call to function %s", fun.name().name);
arguments.set(i, argument); arguments.set(i, argument);
} }

View File

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

View File

@ -21,8 +21,8 @@ import java.util.Arrays;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.transport.ProtocolVersion;
/** /**
* Base class for our native/hardcoded functions. * Base class for our native/hardcoded functions.
@ -62,9 +62,8 @@ public abstract class NativeFunction extends AbstractFunction
} }
@Override @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. * 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 public interface PartialScalarFunction extends ScalarFunction
{ {

View File

@ -21,6 +21,7 @@ import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
import org.apache.cassandra.cql3.CqlBuilder; 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.AbstractType;
import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.transport.ProtocolVersion; 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. * 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 final class PartiallyAppliedScalarFunction extends NativeScalarFunction implements PartialScalarFunction
{ {
@ -63,9 +64,9 @@ final class PartiallyAppliedScalarFunction extends NativeScalarFunction implemen
} }
@Override @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 @Override
@ -126,9 +127,9 @@ final class PartiallyAppliedScalarFunction extends NativeScalarFunction implemen
*/ */
private final int[] mapping; 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]; mapping = new int[unresolvedCount];
int mappingIndex = 0; int mappingIndex = 0;
for (int i = 0, m = partialArguments.size(); i < m; i++) for (int i = 0, m = partialArguments.size(); i < m; i++)
@ -151,6 +152,12 @@ final class PartiallyAppliedScalarFunction extends NativeScalarFunction implemen
return arguments.getProtocolVersion(); return arguments.getProtocolVersion();
} }
@Override
public FunctionContext context()
{
return arguments.context();
}
@Override @Override
public void set(int i, ByteBuffer buffer) 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.nio.ByteBuffer;
import java.util.List; import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.transport.ProtocolVersion; 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. * Function used internally to hold the pre-computed result of another function.
* <p> * <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> * <p>
* Note : the function is cautious in keeping the protocol version used for the pre-computed value and to * 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 * 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) if (nothing.getProtocolVersion() == valueVersion)
return value; return value;
Arguments args = function.newArguments(nothing.getProtocolVersion()); Arguments args = function.newArguments(nothing.context());
for (int i = 0, m = arguments.size() ; i < m; i++) for (int i = 0, m = arguments.size() ; i < m; i++)
{ {
args.set(i, arguments.get(i));; args.set(i, arguments.get(i));;
@ -83,7 +84,7 @@ class PreComputedScalarFunction extends NativeScalarFunction implements PartialS
return function.execute(args); 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; return this;
} }

View File

@ -65,7 +65,7 @@ public interface ScalarFunction extends Function
* </pre> * </pre>
* and such that for any value of {@code b} and {@code d}, {@code bar(b, d) == foo(3, b, 'bar', d)}. * 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}. * @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 * 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 * 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() && unresolvedCount == 0)
{ {
// if isPure(), requires no FunctionContext
Arguments arguments = newArguments(protocolVersion); Arguments arguments = newArguments(protocolVersion);
for (int i = 0, m = partialArguments.size(); i < m; i++) for (int i = 0, m = partialArguments.size(); i < m; i++)
{ {

View File

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

View File

@ -22,10 +22,10 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.ByteBufferUtil;
import static java.lang.String.format; import static java.lang.String.format;
@ -55,9 +55,9 @@ public class ToJsonFct extends NativeScalarFunction
} }
@Override @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); AbstractType<?> argType = argTypes.get(0);
if (buffer == null || (!buffer.hasRemaining() && argType.isEmptyValueMeaningless())) if (buffer == null || (!buffer.hasRemaining() && argType.isEmptyValueMeaningless()))

View File

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

View File

@ -32,6 +32,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.apache.cassandra.cql3.CqlBuilder; 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.AbstractType;
import org.apache.cassandra.db.marshal.UserType; import org.apache.cassandra.db.marshal.UserType;
import org.apache.cassandra.exceptions.ConfigurationException; import org.apache.cassandra.exceptions.ConfigurationException;
@ -120,9 +121,9 @@ public class UDAggregate extends UserFunction implements AggregateFunction
} }
@Override @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) 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); maybeInit(protocolVersion);
// final function is traced in UDFunction // final function is traced in UDFunction
@ -242,7 +244,7 @@ public class UDAggregate extends UserFunction implements AggregateFunction
if (finalFunction instanceof UDFunction) if (finalFunction instanceof UDFunction)
{ {
UDFunction udf = (UDFunction)finalFunction; UDFunction udf = (UDFunction)finalFunction;
Object result = udf.executeForAggregate(state, FunctionArguments.emptyInstance(protocolVersion)); Object result = udf.executeForAggregate(state, context.noArguments());
return resultType.decompose(protocolVersion, result); return resultType.decompose(protocolVersion, result);
} }
throw new UnsupportedOperationException("UDAs only support UDFs"); 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.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.ColumnIdentifier; import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.CqlBuilder; import org.apache.cassandra.cql3.CqlBuilder;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.types.TypeCodec; import org.apache.cassandra.cql3.functions.types.TypeCodec;
import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.UserType; import org.apache.cassandra.db.marshal.UserType;
@ -232,9 +233,9 @@ public abstract class UDFunction extends UserFunction implements ScalarFunction
} }
@Override @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, public static UDFunction tryCreate(FunctionName name,

View File

@ -22,11 +22,11 @@ import java.nio.ByteBuffer;
import java.util.List; import java.util.List;
import org.apache.cassandra.cql3.CQL3Type; 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.AbstractType;
import org.apache.cassandra.db.marshal.FloatType; import org.apache.cassandra.db.marshal.FloatType;
import org.apache.cassandra.db.marshal.VectorType; import org.apache.cassandra.db.marshal.VectorType;
import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.transport.ProtocolVersion;
import io.github.jbellis.jvector.vector.VectorSimilarityFunction; import io.github.jbellis.jvector.vector.VectorSimilarityFunction;
@ -69,9 +69,9 @@ public class VectorFcts
return new NativeScalarFunction(name, FloatType.instance, type, type) return new NativeScalarFunction(name, FloatType.instance, type, type)
{ {
@Override @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),
(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.CQL3Type;
import org.apache.cassandra.cql3.ColumnIdentifier; import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.CqlBuilder; 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.Arguments;
import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.functions.FunctionName; import org.apache.cassandra.cql3.functions.FunctionName;
@ -135,20 +136,28 @@ public class ColumnMask
* @param version the used version of the transport protocol * @param version the used version of the transport protocol
* @return a masker instance that caches the terminal masking function arguments * @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 class Masker
{ {
public static final Masker NOT_A_MASKER = new Masker();
private final ScalarFunction function; private final ScalarFunction function;
private final Arguments arguments; 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; this.function = function;
arguments = function.newArguments(version); arguments = function.newArguments(context);
for (int i = 0; i < partialArgumentValues.length; i++) for (int i = 0; i < partialArgumentValues.length; i++)
arguments.set(i + 1, partialArgumentValues[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.nio.ByteBuffer;
import java.util.List; import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.Arguments; import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.FunctionArguments; import org.apache.cassandra.cql3.functions.FunctionArguments;
import org.apache.cassandra.cql3.functions.FunctionFactory; 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.cql3.functions.NativeFunction;
import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.exceptions.InvalidRequestException; 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. * 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 @Override
public Arguments newArguments(ProtocolVersion version) public Arguments newArguments(FunctionContext context)
{ {
return FunctionArguments.newNoopInstance(version, 1); return FunctionArguments.newNoopInstance(context, 1);
} }
@Override @Override

View File

@ -30,6 +30,7 @@ import javax.annotation.Nullable;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import org.apache.cassandra.cql3.CQL3Type; 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.ArgumentDeserializer;
import org.apache.cassandra.cql3.functions.Arguments; import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.FunctionArguments; 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.BytesType;
import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.ByteBufferUtil;
/** /**
@ -71,9 +71,9 @@ public class HashMaskingFunction extends MaskingFunction
} }
@Override @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 ArgumentDeserializer.NOOP_DESERIALIZER, // the value to be masked
(v, b) -> messageDigest(b)); // the algorithm, if any (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.nio.ByteBuffer;
import java.util.List; import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.Arguments; import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.FunctionArguments; import org.apache.cassandra.cql3.functions.FunctionArguments;
import org.apache.cassandra.cql3.functions.FunctionFactory; 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.cql3.functions.NativeFunction;
import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.exceptions.InvalidRequestException; 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, * 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 @Override
public Arguments newArguments(ProtocolVersion version) public Arguments newArguments(FunctionContext context)
{ {
return FunctionArguments.newNoopInstance(version, 1); return FunctionArguments.newNoopInstance(context, 1);
} }
@Override @Override

View File

@ -29,6 +29,7 @@ import com.google.common.annotations.VisibleForTesting;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.cassandra.cql3.CQL3Type; 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.ArgumentDeserializer;
import org.apache.cassandra.cql3.functions.Arguments; import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.FunctionArguments; 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.Int32Type;
import org.apache.cassandra.db.marshal.UTF8Type; import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.exceptions.InvalidRequestException; import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.transport.ProtocolVersion;
import static java.lang.String.format; import static java.lang.String.format;
@ -106,9 +106,9 @@ public class PartialMaskingFunction extends MaskingFunction
} }
@Override @Override
public Arguments newArguments(ProtocolVersion version) public Arguments newArguments(FunctionContext context)
{ {
return new FunctionArguments(version, return new FunctionArguments(context,
inputType.getArgumentDeserializer(), inputType.getArgumentDeserializer(),
Int32Type.instance.getArgumentDeserializer(), Int32Type.instance.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.nio.ByteBuffer;
import java.util.List; import java.util.List;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.Arguments; import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.FunctionArguments; import org.apache.cassandra.cql3.functions.FunctionArguments;
import org.apache.cassandra.cql3.functions.FunctionFactory; 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.cql3.functions.NativeFunction;
import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.exceptions.InvalidRequestException; 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. * A {@link MaskingFunction} that replaces the specified column value by a certain replacement value.
@ -48,9 +48,9 @@ public class ReplaceMaskingFunction extends MaskingFunction
} }
@Override @Override
public Arguments newArguments(ProtocolVersion version) public Arguments newArguments(FunctionContext context)
{ {
return FunctionArguments.newNoopInstance(version, 2); return FunctionArguments.newNoopInstance(context, 2);
} }
@Override @Override

View File

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

View File

@ -25,8 +25,8 @@ import java.util.Set;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.RangeSet; import com.google.common.collect.RangeSet;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operator; import org.apache.cassandra.cql3.Operator;
import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.Relation; import org.apache.cassandra.cql3.Relation;
import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.filter.IndexHints; import org.apache.cassandra.db.filter.IndexHints;
@ -332,31 +332,31 @@ public final class MergedRestriction implements SingleRestriction
} }
@Override @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++) 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; return values;
} }
@Override @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++) 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 @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++) 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 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.cql3.functions.Function;
import org.apache.cassandra.db.filter.IndexHints; import org.apache.cassandra.db.filter.IndexHints;
import org.apache.cassandra.db.filter.RowFilter; 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>. * 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 indexRegistry the index registry
* @param options the query options * @param context the query options
*/ */
void addToRowFilter(RowFilter filter, void addToRowFilter(RowFilter filter,
IndexRegistry indexRegistry, IndexRegistry indexRegistry,
QueryOptions options, FunctionContext context,
IndexHints indexHints); 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.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle; 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.cql3.functions.Function;
import org.apache.cassandra.db.filter.IndexHints; import org.apache.cassandra.db.filter.IndexHints;
import org.apache.cassandra.db.filter.RowFilter; import org.apache.cassandra.db.filter.RowFilter;
@ -113,10 +113,10 @@ final class RestrictionSet implements Restrictions, Iterable<SingleRestriction>
} }
@Override @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) for (Restriction restriction : this)
restriction.addToRowFilter(filter, indexRegistry, options, indexHints); restriction.addToRowFilter(filter, indexRegistry, context, indexHints);
} }
@Override @Override

View File

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

View File

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

View File

@ -21,7 +21,7 @@ import java.util.List;
import com.google.common.collect.RangeSet; 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.dht.IPartitioner;
import org.apache.cassandra.index.Index; 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}. * 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}. * @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}. * @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. * 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 rangeSet the range set to add to
* @param options the query options * @param context the query options
* @param partitioner the partitioner, used to identify MIN_TOKEN when using token restrictions * @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. * @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.commons.lang3.text.StrBuilder;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.functions.Arguments; import org.apache.cassandra.cql3.functions.Arguments;
import org.apache.cassandra.cql3.functions.Function; 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 * The list used to pass the function arguments is recycled to avoid the cost of instantiating a new list
* with each function call. * with each function call.
*/ */
private final Arguments args; private Arguments args;
protected final List<Selector> argSelectors; 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 public static Factory newFactory(final Function fun, final SelectorFactories factories) throws InvalidRequestException
{ {
if (fun.isAggregate()) if (fun.isAggregate())
@ -179,7 +188,7 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
public Selector newInstance(QueryOptions options) throws InvalidRequestException 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)); : createScalarSelector(options, (ScalarFunction) fun, factories.newInstances(options));
} }
@ -204,7 +213,7 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
} }
if (terminalCount == 0) if (terminalCount == 0)
return new ScalarFunctionSelector(version, fun, argSelectors); return new ScalarFunctionSelector(fun, argSelectors);
// We have some terminal arguments, do a partial application // We have some terminal arguments, do a partial application
ScalarFunction partialFunction = function.partialApplication(version, terminalArgs); 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 all the arguments are terminal and the function is pure we can reduce to a simple value.
if (terminalCount == argSelectors.size() && fun.isPure()) if (terminalCount == argSelectors.size() && fun.isPure())
{ {
// pure functions need no context
Arguments arguments = partialFunction.newArguments(version); Arguments arguments = partialFunction.newArguments(version);
return new TermSelector(partialFunction.execute(arguments), partialFunction.returnType()); return new TermSelector(partialFunction.execute(arguments), partialFunction.returnType());
} }
@ -222,7 +232,7 @@ abstract class AbstractFunctionSelector<T extends Function> extends Selector
if (!selector.isTerminal()) if (!selector.isTerminal())
remainingSelectors.add(selector); remainingSelectors.add(selector);
} }
return new ScalarFunctionSelector(version, partialFunction, remainingSelectors); return new ScalarFunctionSelector(partialFunction, remainingSelectors);
} }
public boolean isWritetimeSelectorFactory() 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); super(kind);
this.fun = fun; this.fun = fun;
this.argSelectors = argSelectors; this.argSelectors = argSelectors;
this.args = fun.newArguments(version);
} }
@Override @Override

View File

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

View File

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

View File

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

View File

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

View File

@ -28,6 +28,7 @@ import java.util.stream.Collectors;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.terms.Maps; import org.apache.cassandra.cql3.terms.Maps;
@ -259,7 +260,17 @@ final class MapSelector extends Selector
this.type = (MapType<?, ?>) type; this.type = (MapType<?, ?>) type;
this.elements = elements; 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 @Override
public boolean equals(Object o) public boolean equals(Object o)

View File

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

View File

@ -33,7 +33,7 @@ final class ScalarFunctionSelector extends AbstractFunctionSelector<ScalarFuncti
@Override @Override
protected Selector newFunctionSelector(ProtocolVersion version, Function function, List<Selector> argSelectors) 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(); 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 com.google.common.collect.Lists;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Json; import org.apache.cassandra.cql3.Json;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.ResultSet; import org.apache.cassandra.cql3.ResultSet;
@ -393,6 +394,8 @@ public abstract class Selection
*/ */
default boolean collectWritetimes() { return false; } default boolean collectWritetimes() { return false; }
default void prepare(FunctionContext context) {}
/** /**
* Adds the current row of the specified <code>ResultSetBuilder</code>. * 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; 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) public void addInputRow(InputRow input)
{ {
for (Selector selector : selectors) 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.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.selection.ColumnTimestamps.TimestampsType; import org.apache.cassandra.cql3.selection.ColumnTimestamps.TimestampsType;
@ -562,6 +563,8 @@ public abstract class Selector
return false; return false;
} }
public void prepare(FunctionContext context) {}
/** /**
* Checks that this selector is valid for GROUP BY clause. * 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 com.google.common.base.Objects;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.terms.Sets; import org.apache.cassandra.cql3.terms.Sets;
import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.db.TypeSizes;
@ -141,6 +142,14 @@ final class SetSelector extends Selector
this.elements = elements; this.elements = elements;
} }
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
for (Selector selector : elements)
selector.prepare(context);
}
@Override @Override
public boolean equals(Object o) 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.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.functions.masking.ColumnMask; import org.apache.cassandra.cql3.functions.masking.ColumnMask;
import org.apache.cassandra.db.TypeSizes; 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.transport.ProtocolVersion;
import org.apache.cassandra.utils.ByteBufferUtil; 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 public final class SimpleSelector extends Selector
{ {
protected static final SelectorDeserializer deserializer = new SelectorDeserializer() protected static final SelectorDeserializer deserializer = new SelectorDeserializer()
@ -47,7 +50,7 @@ public final class SimpleSelector extends Selector
ByteBuffer columnName = ByteBufferUtil.readWithVIntLength(in); ByteBuffer columnName = ByteBufferUtil.readWithVIntLength(in);
ColumnMetadata column = metadata.getColumn(columnName); ColumnMetadata column = metadata.getColumn(columnName);
int idx = in.readInt(); 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 @Override
public Selector newInstance(QueryOptions options) public Selector newInstance(QueryOptions options)
{ {
return new SimpleSelector(column, idx, useForPostOrdering, options.getProtocolVersion()); return new SimpleSelector(column, idx, useForPostOrdering);
} }
@Override @Override
@ -120,7 +123,7 @@ public final class SimpleSelector extends Selector
public final ColumnMetadata column; public final ColumnMetadata column;
private final int idx; private final int idx;
private final ColumnMask.Masker masker; private ColumnMask.Masker masker;
private ByteBuffer current; private ByteBuffer current;
private ColumnTimestamps writetimes; private ColumnTimestamps writetimes;
private ColumnTimestamps ttls; private ColumnTimestamps ttls;
@ -197,7 +200,7 @@ public final class SimpleSelector extends Selector
return column.name.toString(); 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); super(Kind.SIMPLE_SELECTOR);
this.column = column; this.column = column;
@ -207,9 +210,13 @@ public final class SimpleSelector extends Selector
- The column doesn't have a mask - The column doesn't have a mask
- This selector is for a query with ORDER BY post-ordering - This selector is for a query with ORDER BY post-ordering
*/ */
this.masker = useForPostOrdering || column.getMask() == null this.masker = useForPostOrdering || column.getMask() == null ? null : NOT_A_MASKER;
? null }
: column.getMask().masker(version);
public void prepare(FunctionContext context)
{
if (masker != null)
masker = column.getMask().masker(context.options().getProtocolVersion(), context);
} }
@Override @Override

View File

@ -24,6 +24,7 @@ import java.util.List;
import com.google.common.base.Objects; import com.google.common.base.Objects;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.terms.Tuples; import org.apache.cassandra.cql3.terms.Tuples;
import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.db.TypeSizes;
@ -140,6 +141,14 @@ final class TupleSelector extends Selector
this.elements = elements; this.elements = elements;
} }
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
for (Selector selector : elements)
selector.prepare(context);
}
@Override @Override
public boolean equals(Object o) 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.ColumnSpecification;
import org.apache.cassandra.cql3.FieldIdentifier; import org.apache.cassandra.cql3.FieldIdentifier;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.terms.UserTypes; import org.apache.cassandra.cql3.terms.UserTypes;
@ -235,6 +236,14 @@ final class UserTypeSelector extends Selector
this.fields = fields; this.fields = fields;
} }
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
for (Selector selector : fields.values())
selector.prepare(context);
}
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {

View File

@ -26,6 +26,7 @@ import java.util.Objects;
import com.google.common.base.Preconditions; import com.google.common.base.Preconditions;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.terms.Lists; import org.apache.cassandra.cql3.terms.Lists;
import org.apache.cassandra.db.filter.ColumnFilter; import org.apache.cassandra.db.filter.ColumnFilter;
@ -74,6 +75,14 @@ public class VectorSelector extends Selector
this.elements = elements; 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) 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()); 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 com.google.common.base.Objects;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.db.TypeSizes; import org.apache.cassandra.db.TypeSizes;
import org.apache.cassandra.db.filter.ColumnFilter; import org.apache.cassandra.db.filter.ColumnFilter;
@ -179,6 +180,13 @@ final class WritetimeOrTTLSelector extends Selector
this.isMultiCell = isMultiCell; this.isMultiCell = isMultiCell;
} }
@Override
public void prepare(FunctionContext context)
{
super.prepare(context);
selected.prepare(context);
}
@Override @Override
public boolean equals(Object o) public boolean equals(Object o)
{ {

View File

@ -35,8 +35,11 @@ import accord.api.Update;
import accord.primitives.Keys; import accord.primitives.Keys;
import accord.primitives.Txn; 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.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.cql3.conditions.ColumnCondition;
import org.apache.cassandra.db.Clustering; import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.Columns; import org.apache.cassandra.db.Columns;
@ -309,12 +312,12 @@ public class CQL3CasRequest implements CASRequest
return partitionUpdate; return partitionUpdate;
} }
private static class CASUpdateParameters extends UpdateParameters private static class CASUpdateBuilder extends RowUpdateBuilder implements PartialFunctionContext
{ {
final long timeUuidMsb; final long timeUuidMsb;
long timeUuidNanos; 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); super(metadata, state, options, timestamp, nowInSec, ttl, prefetchedRows);
this.timeUuidMsb = timeUuidMsb; this.timeUuidMsb = timeUuidMsb;
@ -325,6 +328,11 @@ public class CQL3CasRequest implements CASRequest
{ {
return TimeUUID.toBytes(timeUuidMsb, TimeUUIDType.signedBytesToNativeLong(timeUuidNanos++)); 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) long applyUpdates(FilteredPartition current, PartitionUpdate.Builder updateBuilder, ClientState state, long timeUuidMsb, long timeUuidNanos)
{ {
Map<DecoratedKey, Partition> map = stmt.requiresRead() ? Collections.singletonMap(key, current) : null; Map<DecoratedKey, Partition> map = stmt.requiresRead() ? Collections.singletonMap(key, current) : null;
CASUpdateParameters params = CASUpdateBuilder params =
new CASUpdateParameters(metadata, state, options, timestamp, nowInSeconds, new CASUpdateBuilder(metadata, state, options, timestamp, nowInSeconds,
stmt.getTimeToLive(options), map, timeUuidMsb, timeUuidNanos); stmt.getTimeToLive(options), map, timeUuidMsb, timeUuidNanos);
stmt.addUpdateForKey(updateBuilder, clustering, params); stmt.addUpdateForKey(updateBuilder, clustering, params);
return params.timeUuidNanos; 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 // 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; Map<DecoratedKey, Partition> map = stmt.requiresRead() ? Collections.singletonMap(key, current) : null;
UpdateParameters params = RowUpdateBuilder params =
new UpdateParameters(metadata, new NoTimeRowUpdateBuilder(metadata,
state, state,
options, options,
timestamp, timestamp,
nowInSeconds, nowInSeconds,
stmt.getTimeToLive(options), stmt.getTimeToLive(options),
map); map);
stmt.addUpdateForKey(updateBuilder, slice, params); stmt.addUpdateForKey(updateBuilder, slice, params);
} }
} }
@ -472,11 +480,11 @@ public class CQL3CasRequest implements CASRequest
super(clustering); 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) 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.Operation;
import org.apache.cassandra.cql3.Operations; import org.apache.cassandra.cql3.Operations;
import org.apache.cassandra.cql3.QualifiedName; import org.apache.cassandra.cql3.QualifiedName;
import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.cql3.StatementSource; import org.apache.cassandra.cql3.StatementSource;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.VariableSpecifications; import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.WhereClause; import org.apache.cassandra.cql3.WhereClause;
import org.apache.cassandra.cql3.conditions.ColumnCondition; import org.apache.cassandra.cql3.conditions.ColumnCondition;
@ -69,7 +69,7 @@ public class DeleteStatement extends ModificationStatement
} }
@Override @Override
public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, UpdateParameters params) public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, RowUpdateBuilder params)
throws InvalidRequestException throws InvalidRequestException
{ {
TableMetadata metadata = metadata(); TableMetadata metadata = metadata();
@ -125,7 +125,7 @@ public class DeleteStatement extends ModificationStatement
} }
@Override @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> regularDeletions = getRegularOperations();
List<Operation> staticDeletions = getStaticOperations(); 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.CQLStatement;
import org.apache.cassandra.cql3.ColumnIdentifier; import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operation; import org.apache.cassandra.cql3.Operation;
import org.apache.cassandra.cql3.Operations; import org.apache.cassandra.cql3.Operations;
import org.apache.cassandra.cql3.QualifiedName; import org.apache.cassandra.cql3.QualifiedName;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.QueryProcessor; import org.apache.cassandra.cql3.QueryProcessor;
import org.apache.cassandra.cql3.ResultSet; 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.StatementSource;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.Validation; import org.apache.cassandra.cql3.Validation;
import org.apache.cassandra.cql3.VariableSpecifications; import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.WhereClause; import org.apache.cassandra.cql3.WhereClause;
@ -330,9 +332,9 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
return restrictions; 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 @Override
public String keyspace() public String keyspace()
@ -360,9 +362,9 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
return metadata().isVirtual(); 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() public boolean isTimestampSet()
@ -370,9 +372,9 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
return attrs.isTimestampSet(); 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 @Override
@ -454,12 +456,12 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
} }
} }
public void validateTimestamp(QueryState queryState, QueryOptions options) public void validateTimestamp(QueryState queryState, FunctionContext context)
{ {
if (!isTimestampSet()) if (!isTimestampSet())
return; 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.maximumAllowableTimestamp.guard(ts, table(), false, queryState.getClientState());
Guardrails.minimumAllowableTimestamp.guard(ts, table(), false, queryState.getClientState()); Guardrails.minimumAllowableTimestamp.guard(ts, table(), false, queryState.getClientState());
} }
@ -784,13 +786,13 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
assert left.size() == 1; assert left.size() == 1;
int size = left.metadata.names.size() + right.metadata.names.size(); 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(left.metadata.names);
specs.addAll(right.metadata.names); specs.addAll(right.metadata.names);
List<List<ByteBuffer>> rows = new ArrayList<>(right.size()); List<List<ByteBuffer>> rows = new ArrayList<>(right.size());
for (int i = 0; i < right.size(); i++) 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(left.rows.get(0));
row.addAll(right.rows.get(i)); row.addAll(right.rows.get(i));
rows.add(row); rows.add(row);
@ -821,11 +823,10 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
Iterables.addAll(defs, metadata.primaryKeyColumns()); Iterables.addAll(defs, metadata.primaryKeyColumns());
Iterables.addAll(defs, columnsWithConditions); Iterables.addAll(defs, columnsWithConditions);
selection = Selection.forColumns(metadata, new ArrayList<>(defs), false); selection = Selection.forColumns(metadata, new ArrayList<>(defs), false);
} }
Selectors selectors = selection.newSelectors(options); 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) SelectStatement.forSelection(metadata, selection)
.processPartition(partition, options, builder, nowInSeconds); .processPartition(partition, options, builder, nowInSeconds);
@ -1087,7 +1088,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
if (slices.isEmpty()) if (slices.isEmpty())
return; return;
UpdateParameters params = makeUpdateParameters(keys, RowUpdateBuilder params = makeUpdateParameters(keys,
(slicesToFilter) -> new ClusteringIndexSliceFilter(slicesToFilter, false), (slicesToFilter) -> new ClusteringIndexSliceFilter(slicesToFilter, false),
slices, slices,
state, state,
@ -1120,7 +1121,7 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
if (restrictions.hasClusteringColumnsRestrictions() && clusterings.isEmpty()) if (restrictions.hasClusteringColumnsRestrictions() && clusterings.isEmpty())
return; 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) for (ByteBuffer key : keys)
{ {
@ -1171,14 +1172,14 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
return restrictions.getSlices(options); return restrictions.getSlices(options);
} }
private UpdateParameters makeUpdateParameters(Collection<ByteBuffer> keys, private RowUpdateBuilder makeUpdateBuilder(Collection<ByteBuffer> keys,
NavigableSet<Clustering<?>> clusterings, NavigableSet<Clustering<?>> clusterings,
ClientState state, ClientState state,
QueryOptions options, QueryOptions options,
boolean local, boolean local,
long timestamp, long timestamp,
long nowInSeconds, long nowInSeconds,
Dispatcher.RequestTime requestTime) Dispatcher.RequestTime requestTime)
{ {
if (clusterings.contains(Clustering.STATIC_CLUSTERING)) if (clusterings.contains(Clustering.STATIC_CLUSTERING))
return makeUpdateParameters(keys, return makeUpdateParameters(keys,
@ -1206,7 +1207,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 // filter is needed rarely, so we allocate it on demand
java.util.function.Function<F, ClusteringIndexFilter> filterBuilder, java.util.function.Function<F, ClusteringIndexFilter> filterBuilder,
F filterArg, F filterArg,
@ -1229,13 +1230,13 @@ public abstract class ModificationStatement implements CQLStatement.SingleKeyspa
nowInSeconds, nowInSeconds,
requestTime); requestTime);
return new UpdateParameters(metadata(), return new RegularRowUpdateBuilder(metadata(),
state, state,
options, options,
getTimestamp(timestamp, options), getTimestamp(timestamp, options),
nowInSeconds, nowInSeconds,
getTimeToLive(options), getTimeToLive(options),
lists); lists);
} }
public static abstract class Parsed extends QualifiedStatement public static abstract class Parsed extends QualifiedStatement

View File

@ -1081,7 +1081,7 @@ public class SelectStatement implements CQLStatement.SingleKeyspaceCqlStatement,
ClientState state) throws InvalidRequestException ClientState state) throws InvalidRequestException
{ {
GroupMaker groupMaker = aggregationSpec == null ? null : aggregationSpec.newGroupMaker(); 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()) 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.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQLStatement; import org.apache.cassandra.cql3.CQLStatement;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.ResultSet; import org.apache.cassandra.cql3.ResultSet;
import org.apache.cassandra.cql3.VariableSpecifications; 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.serializers.TableMetadatasAndKeys;
import org.apache.cassandra.service.accord.txn.AccordUpdate; import org.apache.cassandra.service.accord.txn.AccordUpdate;
import org.apache.cassandra.service.accord.txn.TxnCondition; 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.TxnDataKeyValue;
import org.apache.cassandra.service.accord.txn.TxnDataResult;
import org.apache.cassandra.service.accord.txn.TxnNamedRead; import org.apache.cassandra.service.accord.txn.TxnNamedRead;
import org.apache.cassandra.service.accord.txn.TxnQuery; import org.apache.cassandra.service.accord.txn.TxnQuery;
import org.apache.cassandra.service.accord.txn.TxnRead; 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.tcm.Epoch;
import org.apache.cassandra.transport.Dispatcher; import org.apache.cassandra.transport.Dispatcher;
import org.apache.cassandra.transport.messages.ResultMessage; import org.apache.cassandra.transport.messages.ResultMessage;
import org.apache.cassandra.utils.FBUtilities;
import org.apache.cassandra.utils.NoSpamLogger; import org.apache.cassandra.utils.NoSpamLogger;
import static accord.primitives.Txn.Kind.Read; import static accord.primitives.Txn.Kind.Read;
@ -607,31 +607,35 @@ public class TransactionStatement implements CQLStatement.CompositeCQLStatement,
if (txnResult.kind() == retry_new_protocol) if (txnResult.kind() == retry_new_protocol)
throw new InvalidRequestException(UNSUPPORTED_MIGRATION); throw new InvalidRequestException(UNSUPPORTED_MIGRATION);
TxnValidationRejection.maybeThrow(txnResult); TxnValidationRejection.maybeThrow(txnResult);
TxnDataResult data = (TxnDataResult)txnResult;
TxnData data = (TxnData)txnResult;
if (returningSelect != null) if (returningSelect != null)
{ {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
SinglePartitionReadQuery.Group<SinglePartitionReadCommand> selectQuery = (SinglePartitionReadQuery.Group<SinglePartitionReadCommand>) returningSelect.select.getQuery(options, 0); SinglePartitionReadQuery.Group<SinglePartitionReadCommand> selectQuery = (SinglePartitionReadQuery.Group<SinglePartitionReadCommand>) returningSelect.select.getQuery(options, 0);
Selection.Selectors selectors = returningSelect.select.getSelection().newSelectors(options); 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) if (selectQuery.queries.size() == 1)
{ {
TxnDataKeyValue partition = (TxnDataKeyValue)data.get(txnDataName(RETURNING)); TxnDataKeyValue partition = (TxnDataKeyValue)data.get(txnDataName(RETURNING));
boolean reversed = selectQuery.queries.get(0).isReversed(); boolean reversed = selectQuery.queries.get(0).isReversed();
if (partition != null) if (partition != null)
returningSelect.select.processPartition(partition.rowIterator(reversed), options, result, FBUtilities.nowInSeconds()); returningSelect.select.processPartition(partition.rowIterator(reversed), options, result, atSeconds);
} }
else else
{ {
long nowInSec = FBUtilities.nowInSeconds();
for (int i = 0; i < selectQuery.queries.size(); i++) for (int i = 0; i < selectQuery.queries.size(); i++)
{ {
TxnDataKeyValue partition = (TxnDataKeyValue)data.get(txnDataName(RETURNING, i)); TxnDataKeyValue partition = (TxnDataKeyValue)data.get(txnDataName(RETURNING, i));
boolean reversed = selectQuery.queries.get(i).isReversed(); boolean reversed = selectQuery.queries.get(i).isReversed();
if (partition != null) 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()); return new ResultMessage.Rows(result.build());
@ -649,7 +653,7 @@ public class TransactionStatement implements CQLStatement.CompositeCQLStatement,
columns.add(reference.column()); 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); result.newRow(options.getProtocolVersion(), null, null, columns);
for (int i = 0; i < returningReferences.size(); i++) 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.Operator;
import org.apache.cassandra.cql3.QualifiedName; import org.apache.cassandra.cql3.QualifiedName;
import org.apache.cassandra.cql3.Relation; import org.apache.cassandra.cql3.Relation;
import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.cql3.StatementSource; import org.apache.cassandra.cql3.StatementSource;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.VariableSpecifications; import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.WhereClause; import org.apache.cassandra.cql3.WhereClause;
import org.apache.cassandra.cql3.conditions.ColumnCondition; import org.apache.cassandra.cql3.conditions.ColumnCondition;
@ -96,7 +96,7 @@ public class UpdateStatement extends ModificationStatement
} }
@Override @Override
public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, UpdateParameters params) public void addUpdateForKey(PartitionUpdate.Builder updateBuilder, Clustering<?> clustering, RowUpdateBuilder params)
{ {
if (updatesRegularRows()) if (updatesRegularRows())
{ {
@ -142,7 +142,7 @@ public class UpdateStatement extends ModificationStatement
} }
@Override @Override
public void addUpdateForKey(PartitionUpdate.Builder update, Slice slice, UpdateParameters params) public void addUpdateForKey(PartitionUpdate.Builder update, Slice slice, RowUpdateBuilder builder)
{ {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -24,9 +24,9 @@ import java.nio.ByteBuffer;
import org.apache.cassandra.cql3.AssignmentTestable; import org.apache.cassandra.cql3.AssignmentTestable;
import org.apache.cassandra.cql3.CQL3Type; import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operation; import org.apache.cassandra.cql3.Operation;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.db.Clustering; import org.apache.cassandra.db.Clustering;
import org.apache.cassandra.db.DecoratedKey; import org.apache.cassandra.db.DecoratedKey;
import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AbstractType;
@ -63,9 +63,9 @@ import static java.nio.charset.StandardCharsets.US_ASCII;
*/ */
public abstract class Constants 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); Cell<?> currentCell = currentRow == null ? null : currentRow.getCell(column);
return currentCell == null ? null : currentCell.buffer(); 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. // TODO: The bind overriding should be removed. A user does not have to call bind on a Terminal.
@Override @Override
public Terminal bind(QueryOptions options) public Terminal bind(FunctionContext context)
{ {
// We return null because that makes life easier for collections // We return null because that makes life easier for collections
return null; return null;
@ -459,7 +459,7 @@ public abstract class Constants
} }
@Override @Override
public ByteBuffer bindAndGet(QueryOptions options) public ByteBuffer bindAndGet(FunctionContext context)
{ {
return bytes; return bytes;
} }
@ -478,23 +478,23 @@ public abstract class Constants
super(column, t); 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) if (value == null)
params.addTombstone(column); builder.addTombstone(column);
else if (value != ByteArrayUtil.UNSET_BYTE_ARRAY) // use reference equality and not object equality else if (value != ByteArrayUtil.UNSET_BYTE_ARRAY) // use reference equality and not object equality
params.addCell(column, value); builder.addCell(column, value);
} }
else else
{ {
ByteBuffer value = t.bindAndGet(params.options); ByteBuffer value = t.bindAndGet(builder);
if (value == null) if (value == null)
params.addTombstone(column); builder.addTombstone(column);
else if (value != ByteBufferUtil.UNSET_BYTE_BUFFER) // use reference equality and not object equality 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); 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) if (column.type instanceof CounterColumnType)
{ {
ByteBuffer bytes = t.bindAndGet(params.options); ByteBuffer bytes = t.bindAndGet(builder);
if (bytes == null) if (bytes == null)
throw new InvalidRequestException("Invalid null value for counter increment"); throw new InvalidRequestException("Invalid null value for counter increment");
if (bytes == ByteBufferUtil.UNSET_BYTE_BUFFER) if (bytes == ByteBufferUtil.UNSET_BYTE_BUFFER)
return; return;
long increment = ByteBufferUtil.toLong(bytes); long increment = ByteBufferUtil.toLong(bytes);
params.addCounter(column, increment); builder.addCounter(column, increment);
} }
else if (column.type instanceof NumberType<?>) else if (column.type instanceof NumberType<?>)
{ {
@SuppressWarnings("unchecked") NumberType<Number> type = (NumberType<Number>) column.type; @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) if (increment == null)
return; return;
ByteBuffer current = type.sanitize(getCurrentCellBuffer(column, partitionKey, params)); ByteBuffer current = type.sanitize(getCurrentCellBuffer(column, partitionKey, builder));
if (current == null) if (current == null)
return; return;
ByteBuffer newValue = type.add(type.compose(current), type.compose(increment)); ByteBuffer newValue = type.add(type.compose(current), type.compose(increment));
params.addCell(column, newValue); builder.addCell(column, newValue);
} }
else if (column.type instanceof StringType) else if (column.type instanceof StringType)
{ {
ByteBuffer append = t.bindAndGet(params.options); ByteBuffer append = t.bindAndGet(builder);
if (append == null) if (append == null)
return; return;
ByteBuffer current = getCurrentCellBuffer(column, partitionKey, params); ByteBuffer current = getCurrentCellBuffer(column, partitionKey, builder);
if (current == null) if (current == null)
return; return;
ByteBuffer newValue = ByteBuffer.allocate(current.remaining() + append.remaining()); ByteBuffer newValue = ByteBuffer.allocate(current.remaining() + append.remaining());
FastByteOperations.copy(current, current.position(), newValue, newValue.position(), current.remaining()); FastByteOperations.copy(current, current.position(), newValue, newValue.position(), current.remaining());
FastByteOperations.copy(append, append.position(), newValue, newValue.position() + current.remaining(), append.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(); 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) if (column.type instanceof CounterColumnType)
{ {
ByteBuffer bytes = t.bindAndGet(params.options); ByteBuffer bytes = t.bindAndGet(builder);
if (bytes == null) if (bytes == null)
throw new InvalidRequestException("Invalid null value for counter increment"); throw new InvalidRequestException("Invalid null value for counter increment");
if (bytes == ByteBufferUtil.UNSET_BYTE_BUFFER) if (bytes == ByteBufferUtil.UNSET_BYTE_BUFFER)
@ -579,19 +579,19 @@ public abstract class Constants
if (increment == Long.MIN_VALUE) if (increment == Long.MIN_VALUE)
throw new InvalidRequestException("The negation of " + increment + " overflows supported counter precision (signed 8 bytes integer)"); 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<?>) else if (column.type instanceof NumberType<?>)
{ {
@SuppressWarnings("unchecked") NumberType<Number> type = (NumberType<Number>) column.type; @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) if (increment == null)
return; return;
ByteBuffer current = type.sanitize(getCurrentCellBuffer(column, partitionKey, params)); ByteBuffer current = type.sanitize(getCurrentCellBuffer(column, partitionKey, builder));
if (current == null) if (current == null)
return; return;
ByteBuffer newValue = type.substract(type.compose(current), type.compose(increment)); 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); 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()) if (column.type.isMultiCell())
params.setComplexDeletionTime(column); builder.setComplexDeletionTime(column);
else 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.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnIdentifier; import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification; 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.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AbstractType;
@ -60,9 +60,9 @@ public final class InMarker extends Terms.NonTerminals
} }
@Override @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) if (values == null)
return null; return null;
@ -95,16 +95,16 @@ public final class InMarker extends Terms.NonTerminals
} }
@Override @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(); return terminals == null ? null : terminals.get();
} }
@Override @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(); 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.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnIdentifier; import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operation; import org.apache.cassandra.cql3.Operation;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.cql3.VariableSpecifications; import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.db.DecoratedKey; import org.apache.cassandra.db.DecoratedKey;
import org.apache.cassandra.db.guardrails.Guardrails; import org.apache.cassandra.db.guardrails.Guardrails;
@ -180,7 +180,7 @@ public abstract class Lists
values.add(t); values.add(t);
} }
MultiElements.DelayedValue value = new MultiElements.DelayedValue((MultiElementType<?>) receiver.type.unwrap(), values); 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 private void validateAssignableTo(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
@ -304,16 +304,16 @@ public abstract class Lists
return column.type.isMultiCell(); 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) if (value == UNSET_VALUE)
return; return;
// delete + append // delete + append
if (column.type.isMultiCell()) if (column.type.isMultiCell())
params.setComplexDeletionTimeForOverwrite(column); builder.setComplexDeletionTimeForOverwrite(column);
Appender.doAppend(value, column, params); Appender.doAppend(value, column, builder);
} }
} }
@ -349,23 +349,23 @@ public abstract class Lists
idx.collectMarkerSpecification(boundNames, owner); 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 // we should not get here for frozen lists
assert column.type.isMultiCell() : "Attempted to set an individual element on a frozen list"; assert column.type.isMultiCell() : "Attempted to set an individual element on a frozen list";
Guardrails.readBeforeWriteListOperationsEnabled 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 index = idx.bindAndGet(builder);
ByteBuffer value = t.bindAndGet(params.options); ByteBuffer value = t.bindAndGet(builder);
if (index == null) if (index == null)
throw new InvalidRequestException("Invalid null value for list index"); throw new InvalidRequestException("Invalid null value for list index");
if (index == ByteBufferUtil.UNSET_BYTE_BUFFER) if (index == ByteBufferUtil.UNSET_BYTE_BUFFER)
throw new InvalidRequestException("Invalid unset value for list index"); 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 existingSize = existingSize(existingRow, column);
int idx = ByteBufferUtil.toInt(index); int idx = ByteBufferUtil.toInt(index);
if (existingSize == 0) if (existingSize == 0)
@ -375,9 +375,9 @@ public abstract class Lists
CellPath elementPath = existingRow.getComplexColumnData(column).getCellByIndex(idx).path(); CellPath elementPath = existingRow.getComplexColumnData(column).getCellByIndex(idx).path();
if (value == null) if (value == null)
params.addTombstone(column, elementPath); builder.addTombstone(column, elementPath);
else if (value != ByteBufferUtil.UNSET_BYTE_BUFFER) 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); 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"; assert column.type.isMultiCell() : "Attempted to append to a frozen list";
Term.Terminal value = t.bind(params.options); Term.Terminal value = t.bind(builder);
doAppend(value, column, params); doAppend(value, column, builder);
} }
@Override @Override
@ -401,7 +401,7 @@ public abstract class Lists
return column.type.isMultiCell(); 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; ListType<?> type = (ListType<?>) column.type;
@ -409,7 +409,7 @@ public abstract class Lists
{ {
// for frozen lists, we're overwriting the whole cell value // for frozen lists, we're overwriting the whole cell value
if (!type.isMultiCell()) if (!type.isMultiCell())
params.addTombstone(column); builder.addTombstone(column);
// If we append null, do nothing. Note that for Setter, we've // If we append null, do nothing. Note that for Setter, we've
// already removed the previous value so we're good here too // 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 // 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 // already existent elements. This is done so to avoid read-before-write, having additional checks
// during SSTable write. // 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; int dataSize = 0;
for (ByteBuffer buffer : elements) for (ByteBuffer buffer : elements)
{ {
ByteBuffer cellPath = ByteBuffer.wrap(params.nextTimeUUIDAsBytes()); ByteBuffer cellPath = ByteBuffer.wrap(builder.nextTimeUUIDAsBytes());
Cell<?> cell = params.addCell(column, CellPath.create(cellPath), buffer); Cell<?> cell = builder.addCell(column, CellPath.create(cellPath), buffer);
dataSize += cell.dataSize(); dataSize += cell.dataSize();
} }
Guardrails.collectionListSize.guard(dataSize, column.name.toString(), false, params.clientState); Guardrails.collectionListSize.guard(dataSize, column.name.toString(), false, builder.clientState);
} }
else else
{ {
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, params.clientState); Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, builder.clientState);
Cell<?> cell = params.addCell(column, value.get()); Cell<?> cell = builder.addCell(column, value.get());
Guardrails.collectionListSize.guard(cell.dataSize(), column.name.toString(), false, params.clientState); Guardrails.collectionListSize.guard(cell.dataSize(), column.name.toString(), false, builder.clientState);
} }
} }
} }
@ -459,10 +459,10 @@ public abstract class Lists
return column.type.isMultiCell(); 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"; 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) if (value == null || value == UNSET_VALUE)
return; return;
@ -484,7 +484,7 @@ public abstract class Lists
// TODO: is this safe as part of LWTs? // TODO: is this safe as part of LWTs?
ByteBuffer uuid = ByteBuffer.wrap(atUnixMillisAsBytes(pt.millis, (pt.nanos + remainingInBatch--))); 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; 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"; assert column.type.isMultiCell() : "Attempted to delete from a frozen list";
Guardrails.readBeforeWriteListOperationsEnabled 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. // 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); ComplexColumnData complexData = existingRow == null ? null : existingRow.getComplexColumnData(column);
if (value == null || value == UNSET_VALUE || complexData == null) if (value == null || value == UNSET_VALUE || complexData == null)
return; return;
@ -525,7 +525,7 @@ public abstract class Lists
for (Cell<?> cell : complexData) for (Cell<?> cell : complexData)
{ {
if (toDiscard.contains(cell.buffer())) 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; 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"; assert column.type.isMultiCell() : "Attempted to delete an item by index from a frozen list";
Guardrails.readBeforeWriteListOperationsEnabled 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) if (index == null)
throw new InvalidRequestException("Invalid null value for list index"); throw new InvalidRequestException("Invalid null value for list index");
if (index == Constants.UNSET_VALUE) if (index == Constants.UNSET_VALUE)
return; return;
Row existingRow = params.getPrefetchedRow(partitionKey, params.currentClustering()); Row existingRow = builder.getPrefetchedRow(partitionKey, builder.currentClustering());
int existingSize = existingSize(existingRow, column); int existingSize = existingSize(existingRow, column);
int idx = ByteBufferUtil.toInt(index.get()); int idx = ByteBufferUtil.toInt(index.get());
if (existingSize == 0) if (existingSize == 0)
@ -564,7 +564,7 @@ public abstract class Lists
if (idx < 0 || idx >= existingSize) if (idx < 0 || idx >= existingSize)
throw new InvalidRequestException(String.format("List index %d out of bound, list has size %d", 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.ColumnSpecification;
import org.apache.cassandra.cql3.Operation; import org.apache.cassandra.cql3.Operation;
import org.apache.cassandra.cql3.QueryOptions; 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.cql3.VariableSpecifications;
import org.apache.cassandra.db.DecoratedKey; import org.apache.cassandra.db.DecoratedKey;
import org.apache.cassandra.db.guardrails.Guardrails; import org.apache.cassandra.db.guardrails.Guardrails;
@ -252,16 +252,16 @@ public final class Maps
super(column, t); 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) if (value == UNSET_VALUE)
return; return;
// delete + put // delete + put
if (column.type.isMultiCell()) if (column.type.isMultiCell())
params.setComplexDeletionTimeForOverwrite(column); builder.setComplexDeletionTimeForOverwrite(column);
Putter.doPut(value, column, params); Putter.doPut(value, column, builder);
} }
} }
@ -282,11 +282,11 @@ public final class Maps
k.collectMarkerSpecification(boundNames, owner); 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"; assert column.type.isMultiCell() : "Attempted to set a value for a single key on a frozen map";
ByteBuffer key = k.bindAndGet(params.options); ByteBuffer key = k.bindAndGet(builder);
ByteBuffer value = t.bindAndGet(params.options); ByteBuffer value = t.bindAndGet(builder);
if (key == null) if (key == null)
throw new InvalidRequestException("Invalid null map key"); throw new InvalidRequestException("Invalid null map key");
if (key == ByteBufferUtil.UNSET_BYTE_BUFFER) if (key == ByteBufferUtil.UNSET_BYTE_BUFFER)
@ -296,11 +296,11 @@ public final class Maps
if (value == null) if (value == null)
{ {
params.addTombstone(column, path); builder.addTombstone(column, path);
} }
else if (value != ByteBufferUtil.UNSET_BYTE_BUFFER) 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); 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"; 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) 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; MapType<?, ?> type = (MapType<?, ?>) column.type;
@ -328,7 +328,7 @@ public final class Maps
{ {
// for frozen maps, we're overwriting the whole cell // for frozen maps, we're overwriting the whole cell
if (!type.isMultiCell()) if (!type.isMultiCell())
params.addTombstone(column); builder.addTombstone(column);
return; return;
} }
@ -343,22 +343,22 @@ public final class Maps
// Guardrails about collection size are only checked for the added elements without considering // 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 // already existent elements. This is done so to avoid read-before-write, having additional checks
// during SSTable write. // 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; int dataSize = 0;
Iterator<ByteBuffer> iter = elements.iterator(); Iterator<ByteBuffer> iter = elements.iterator();
while(iter.hasNext()) 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(); dataSize += cell.dataSize();
} }
Guardrails.collectionMapSize.guard(dataSize, column.name.toString(), false, params.clientState); Guardrails.collectionMapSize.guard(dataSize, column.name.toString(), false, builder.clientState);
} }
else else
{ {
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, params.clientState); Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, builder.clientState);
Cell<?> cell = params.addCell(column, value.get()); Cell<?> cell = builder.addCell(column, value.get());
Guardrails.collectionMapSize.guard(cell.dataSize(), column.name.toString(), false, params.clientState); Guardrails.collectionMapSize.guard(cell.dataSize(), column.name.toString(), false, builder.clientState);
} }
} }
} }
@ -370,16 +370,16 @@ public final class Maps
super(column, k); 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"; 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) if (key == null)
throw new InvalidRequestException("Invalid null map key"); throw new InvalidRequestException("Invalid null map key");
if (key == Constants.UNSET_VALUE) if (key == Constants.UNSET_VALUE)
throw new InvalidRequestException("Invalid unset map key"); 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.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnSpecification; 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.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.marshal.AbstractType; 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. * 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 * <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; private final int bindIndex;
@ -72,11 +72,11 @@ public final class Marker extends Term.NonTerminal
} }
@Override @Override
public Term.Terminal bind(QueryOptions options) throws InvalidRequestException public Term.Terminal bind(FunctionContext context) throws InvalidRequestException
{ {
try try
{ {
ByteBuffer bytes = options.getValue(bindIndex); ByteBuffer bytes = context.options().getValues().get(bindIndex);
if (bytes == null) if (bytes == null)
return null; return null;
@ -97,11 +97,11 @@ public final class Marker extends Term.NonTerminal
// an optimized version without allocating interim Terminal objects // an optimized version without allocating interim Terminal objects
@Override @Override
public ByteBuffer bindAndGet(QueryOptions options) public ByteBuffer bindAndGet(FunctionContext context)
{ {
try try
{ {
ByteBuffer bytes = options.getValue(bindIndex); ByteBuffer bytes = context.options().getValue(bindIndex);
if (bytes == null) if (bytes == null)
return 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 Same logic as bind() but it returns byte[] instead of ByteBuffer and there is no Value wrapper usage
*/ */
@Override @Override
public byte[] bindAndGetByteArray(QueryOptions options) throws InvalidRequestException public byte[] bindAndGetByteArray(FunctionContext context) throws InvalidRequestException
{ {
try try
{ {
byte[] bytes = options.getByteArrayValues()[bindIndex]; byte[] bytes = context.options().getByteArrayValues()[bindIndex];
if (bytes == null) if (bytes == null)
return null; return null;

View File

@ -22,7 +22,7 @@ import java.nio.ByteBuffer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.db.marshal.MultiElementType; import org.apache.cassandra.db.marshal.MultiElementType;
@ -126,14 +126,14 @@ public final class MultiElements
} }
@Override @Override
public Terminal bind(QueryOptions options) public Terminal bind(FunctionContext context)
{ {
try try
{ {
List<ByteBuffer> buffers = new ArrayList<>(elements.size()); List<ByteBuffer> buffers = new ArrayList<>(elements.size());
for (Term t : elements) for (Term t : elements)
{ {
buffers.add(t.bindAndGet(options)); buffers.add(t.bindAndGet(context));
} }
buffers = type.filterSortAndValidateElements(buffers); 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.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnIdentifier; import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.Operation; import org.apache.cassandra.cql3.Operation;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.RowUpdateBuilder;
import org.apache.cassandra.cql3.UpdateParameters;
import org.apache.cassandra.db.DecoratedKey; import org.apache.cassandra.db.DecoratedKey;
import org.apache.cassandra.db.guardrails.Guardrails; import org.apache.cassandra.db.guardrails.Guardrails;
import org.apache.cassandra.db.marshal.AbstractType; import org.apache.cassandra.db.marshal.AbstractType;
@ -172,7 +172,7 @@ public final class Sets
values.add(t); values.add(t);
} }
MultiElements.DelayedValue value = new MultiElements.DelayedValue((MultiElementType<?>) receiver.type.unwrap(), values); 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 private void validateAssignableTo(String keyspace, ColumnSpecification receiver) throws InvalidRequestException
@ -227,16 +227,16 @@ public final class Sets
super(column, t); 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) if (value == UNSET_VALUE)
return; return;
// delete + add // delete + add
if (column.type.isMultiCell()) if (column.type.isMultiCell())
params.setComplexDeletionTimeForOverwrite(column); builder.setComplexDeletionTimeForOverwrite(column);
Adder.doAdd(value, column, params); Adder.doAdd(value, column, builder);
} }
} }
@ -247,15 +247,15 @@ public final class Sets
super(column, t); 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"; 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) 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; SetType<?> type = (SetType<?>) column.type;
@ -263,7 +263,7 @@ public final class Sets
{ {
// for frozen sets, we're overwriting the whole cell // for frozen sets, we're overwriting the whole cell
if (!type.isMultiCell()) if (!type.isMultiCell())
params.addTombstone(column); builder.addTombstone(column);
return; return;
} }
@ -278,7 +278,7 @@ public final class Sets
// Guardrails about collection size are only checked for the added elements without considering // 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 // already existent elements. This is done so to avoid read-before-write, having additional checks
// during SSTable write. // 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; int dataSize = 0;
for (ByteBuffer bb : elements) for (ByteBuffer bb : elements)
@ -286,16 +286,16 @@ public final class Sets
if (bb == ByteBufferUtil.UNSET_BYTE_BUFFER) if (bb == ByteBufferUtil.UNSET_BYTE_BUFFER)
continue; 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(); dataSize += cell.dataSize();
} }
Guardrails.collectionSetSize.guard(dataSize, column.name.toString(), false, params.clientState); Guardrails.collectionSetSize.guard(dataSize, column.name.toString(), false, builder.clientState);
} }
else else
{ {
Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, params.clientState); Guardrails.itemsPerCollection.guard(type.collectionSize(elements), column.name.toString(), false, builder.clientState);
Cell<?> cell = params.addCell(column, value.get()); Cell<?> cell = builder.addCell(column, value.get());
Guardrails.collectionSetSize.guard(cell.dataSize(), column.name.toString(), false, params.clientState); Guardrails.collectionSetSize.guard(cell.dataSize(), column.name.toString(), false, builder.clientState);
} }
} }
} }
@ -308,11 +308,11 @@ public final class Sets
super(column, t); 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"; 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) if (value == null || value == UNSET_VALUE)
return; return;
@ -320,7 +320,7 @@ public final class Sets
List<ByteBuffer> toDiscard = value.getElements(); List<ByteBuffer> toDiscard = value.getElements();
for (ByteBuffer bb : toDiscard) 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); 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"; 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) if (elt == null)
throw new InvalidRequestException("Invalid null set element"); 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.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.CqlParser; import org.apache.cassandra.cql3.CqlParser;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.VariableSpecifications; import org.apache.cassandra.cql3.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function; 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}. * 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. * 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}. * @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()}. * 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 * object between the bind and the get (note that we still want to be able
* to separate bind and get for collections). * 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 * 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() * 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; return false;
} }
@ -102,7 +103,7 @@ public interface Term
/** /**
* an allocation-optimized version of bindAndGet() method * 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, " + throw new IllegalStateException("bindAndGetByteArray() method is not implemented, " +
"isByteArrayGetSupported() must be always checked before invoking this method"); "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 * We expose it mainly because for constants it can avoid allocating a temporary
* object between the bind and the getElements. * 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. * Whether that term contains at least one bind marker.
@ -250,7 +251,7 @@ public interface Term
public void collectMarkerSpecification(VariableSpecifications boundNames, Object owner) {} public void collectMarkerSpecification(VariableSpecifications boundNames, Object owner) {}
@Override @Override
public Terminal bind(QueryOptions options) { return this; } public Terminal bind(FunctionContext context) { return this; }
@Override @Override
public void addFunctionsTo(List<Function> functions) public void addFunctionsTo(List<Function> functions)
@ -291,13 +292,13 @@ public interface Term
} }
@Override @Override
public ByteBuffer bindAndGet(QueryOptions options) public ByteBuffer bindAndGet(FunctionContext context)
{ {
return get(); return get();
} }
@Override @Override
public List<ByteBuffer> bindAndGetElements(QueryOptions options) public List<ByteBuffer> bindAndGetElements(FunctionContext context)
{ {
return getElements(); return getElements();
} }
@ -318,16 +319,16 @@ public interface Term
abstract class NonTerminal implements Term abstract class NonTerminal implements Term
{ {
@Override @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(); return t == null ? null : t.get();
} }
@Override @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(); 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.AssignmentTestable;
import org.apache.cassandra.cql3.ColumnSpecification; 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.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.terms.Term.NonTerminal; 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}. * 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. * 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. * @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()}. * A shorter for {@code bind(options).get()}.
* We expose it mainly because for constants it can avoid allocating a temporary * We expose it mainly because for constants it can avoid allocating a temporary
* object between the bind and the get. * 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; return false;
} }
default ByteBuffer bindAndGetSingleTermValue(QueryOptions options) default ByteBuffer bindAndGetSingleTermValue(FunctionContext context)
{ {
throw new IllegalStateException("bindAndGetSingleTermValue() method is not implemented, " + throw new IllegalStateException("bindAndGetSingleTermValue() method is not implemented, " +
"isSingleTerm() must be always checked before invoking this method"); "isSingleTerm() must be always checked before invoking this method");
@ -132,9 +133,10 @@ public interface Terms
* A shorter for {@code bind(options).getElements()}. * A shorter for {@code bind(options).getElements()}.
* We expose it mainly because for constants it can avoid allocating a temporary * We expose it mainly because for constants it can avoid allocating a temporary
* object between the {@code bind} and the {@code getElements}. * 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}. * Creates a {@code Terms} containing a single {@code Term}.
@ -457,19 +459,19 @@ public interface Terms
public void collectMarkerSpecification(VariableSpecifications boundNames, Object owner) {} public void collectMarkerSpecification(VariableSpecifications boundNames, Object owner) {}
@Override @Override
public final Terminals bind(QueryOptions options) public final Terminals bind(FunctionContext context)
{ {
return this; return this;
} }
@Override @Override
public List<ByteBuffer> bindAndGet(QueryOptions options) public List<ByteBuffer> bindAndGet(FunctionContext context)
{ {
return get(); return get();
} }
@Override @Override
public List<List<ByteBuffer>> bindAndGetElements(QueryOptions options) public List<List<ByteBuffer>> bindAndGetElements(FunctionContext context)
{ {
return getElements(); return getElements();
} }
@ -628,34 +630,34 @@ public interface Terms
} }
@Override @Override
public Terminals bind(QueryOptions options) public Terminals bind(FunctionContext context)
{ {
return Terminals.of(term.bind(options)); return Terminals.of(term.bind(context));
} }
@Override @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 @Override
public boolean isSingleTerm(QueryOptions options) public boolean isSingleTerm(FunctionContext context)
{ {
return true; return true;
} }
@Override @Override
public ByteBuffer bindAndGetSingleTermValue(QueryOptions options) public ByteBuffer bindAndGetSingleTermValue(FunctionContext context)
{ {
return term.bindAndGet(options); return term.bindAndGet(context);
} }
@Override @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 @Override
@ -698,40 +700,40 @@ public interface Terms
} }
@Override @Override
public Terminals bind(QueryOptions options) public Terminals bind(FunctionContext context)
{ {
int size = terms.size(); int size = terms.size();
List<Terminal> terminals = new ArrayList<>(size); List<Terminal> terminals = new ArrayList<>(size);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
Term term = terms.get(i); Term term = terms.get(i);
terminals.add(term.bind(options)); terminals.add(term.bind(context));
} }
return Terminals.of(terminals); return Terminals.of(terminals);
} }
@Override @Override
public List<ByteBuffer> bindAndGet(QueryOptions options) public List<ByteBuffer> bindAndGet(FunctionContext context)
{ {
int size = terms.size(); int size = terms.size();
List<ByteBuffer> buffers = new ArrayList<>(size); List<ByteBuffer> buffers = new ArrayList<>(size);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
Term term = terms.get(i); Term term = terms.get(i);
buffers.add(term.bindAndGet(options)); buffers.add(term.bindAndGet(context));
} }
return buffers; return buffers;
} }
@Override @Override
public List<List<ByteBuffer>> bindAndGetElements(QueryOptions options) public List<List<ByteBuffer>> bindAndGetElements(FunctionContext context)
{ {
int size = terms.size(); int size = terms.size();
List<List<ByteBuffer>> buffers = new ArrayList<>(size); List<List<ByteBuffer>> buffers = new ArrayList<>(size);
for (int i = 0; i < size; i++) for (int i = 0; i < size; i++)
{ {
Term term = terms.get(i); Term term = terms.get(i);
buffers.add(term.bindAndGetElements(options)); buffers.add(term.bindAndGetElements(context));
} }
return buffers; return buffers;
} }

View File

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

View File

@ -19,7 +19,7 @@
package org.apache.cassandra.cql3.transactions; package org.apache.cassandra.cql3.transactions;
import org.apache.cassandra.cql3.ColumnSpecification; 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.VariableSpecifications;
import org.apache.cassandra.cql3.terms.Term; import org.apache.cassandra.cql3.terms.Term;
import org.apache.cassandra.db.marshal.AbstractType; 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 class ReferenceValue
{ {
public abstract TxnReferenceValue bindAndGet(QueryOptions options); public abstract TxnReferenceValue bindAndGet(FunctionContext context);
public static abstract class Raw extends Term.Raw public static abstract class Raw extends Term.Raw
{ {
@ -48,9 +48,9 @@ public abstract class ReferenceValue
} }
@Override @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 public static class Raw extends ReferenceValue.Raw
@ -104,9 +104,9 @@ public abstract class ReferenceValue
} }
@Override @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 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.ColumnIdentifier;
import org.apache.cassandra.cql3.ColumnSpecification; import org.apache.cassandra.cql3.ColumnSpecification;
import org.apache.cassandra.cql3.FieldIdentifier; 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.VariableSpecifications;
import org.apache.cassandra.cql3.functions.Function; import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.functions.types.utils.Bytes; import org.apache.cassandra.cql3.functions.types.utils.Bytes;
@ -84,7 +84,7 @@ public class RowDataReference extends Term.NonTerminal
} }
@Override @Override
public Terminal bind(QueryOptions options) throws InvalidRequestException public Terminal bind(FunctionContext context) throws InvalidRequestException
{ {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@ -174,20 +174,20 @@ public class RowDataReference extends Term.NonTerminal
return UserTypes.fieldSpecOf(column, field); return UserTypes.fieldSpecOf(column, field);
} }
private CellPath bindCellPath(QueryOptions options) private CellPath bindCellPath(FunctionContext context)
{ {
if (fieldPath != null) if (fieldPath != null)
return fieldPath; 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(elementPath == null || column.isComplex() || column.type.isFrozenCollection());
Preconditions.checkState(fieldPath == null || column.isComplex() || column.type.isUDT()); 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() 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.concurrent.ExecutorFactory.Global.executorFactory;
import static org.apache.cassandra.config.DatabaseDescriptor.getFlushWriters; import static org.apache.cassandra.config.DatabaseDescriptor.getFlushWriters;
import static org.apache.cassandra.db.commitlog.CommitLogPosition.NONE; 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.currentTimeMillis;
import static org.apache.cassandra.utils.Clock.Global.nanoTime; import static org.apache.cassandra.utils.Clock.Global.nanoTime;
import static org.apache.cassandra.utils.Throwables.maybeFail; import static org.apache.cassandra.utils.Throwables.maybeFail;
@ -2011,9 +2012,19 @@ public class ColumnFamilyStore implements ColumnFamilyStoreMBean, Memtable.Owner
return paxosRepairHistory.get().getBallotForToken(key.getToken()); 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) 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) public RefViewFragment selectAndReference(Function<View, Iterable<SSTableReader>> filter)

View File

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

View File

@ -224,7 +224,8 @@ public abstract class GroupMaker
{ {
input.add(argument); 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); selector.addInput(input);
ByteBuffer output = selector.getOutput(ProtocolVersion.CURRENT); ByteBuffer output = selector.getOutput(ProtocolVersion.CURRENT);
selector.reset(); selector.reset();

View File

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

View File

@ -162,7 +162,6 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
public final AtomicInteger currentlyBackgroundUpgrading = new AtomicInteger(0); public final AtomicInteger currentlyBackgroundUpgrading = new AtomicInteger(0);
public static final int NO_GC = Integer.MIN_VALUE; public static final int NO_GC = Integer.MIN_VALUE;
public static final int GC_ALL = Integer.MAX_VALUE;
static static
{ {
@ -395,7 +394,7 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
} }
CompactionStrategyManager strategy = cfs.getCompactionStrategyManager(); CompactionStrategyManager strategy = cfs.getCompactionStrategyManager();
tasks = strategy.getNextBackgroundTasks(getDefaultGcBefore(cfs, FBUtilities.nowInSeconds())); tasks = strategy.getNextBackgroundTasks(cfs.getDefaultGcBefore(FBUtilities.nowInSeconds()));
if (tasks == null || tasks.isEmpty()) if (tasks == null || tasks.isEmpty())
{ {
if (DatabaseDescriptor.automaticSSTableUpgrade()) if (DatabaseDescriptor.automaticSSTableUpgrade())
@ -885,10 +884,10 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
public void execute(LifecycleTransaction txn) throws IOException public void execute(LifecycleTransaction txn) throws IOException
{ {
logger.debug("Garbage collecting {}", txn.originals()); 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 @Override
protected CompactionController getCompactionController(Set<SSTableReader> toCompact) protected CompactionController getCompactionController(Set<SSTableReader> toCompact, long gcBefore)
{ {
return new CompactionController(cfStore, toCompact, gcBefore, null, tombstoneOption); return new CompactionController(cfStore, toCompact, gcBefore, null, tombstoneOption);
} }
@ -1153,12 +1152,12 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
public void performMaximal(final ColumnFamilyStore cfStore, boolean splitOutput, int permittedParallelism) 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) 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) public List<Future<?>> submitMaximal(final ColumnFamilyStore cfStore, final long gcBefore, boolean splitOutput, int permittedParallelism)
@ -1218,7 +1217,7 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
logger.debug("No sstables found for the provided token range"); logger.debug("No sstables found for the provided token range");
return CompactionTasks.empty(); 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, try (CompactionTasks tasks = cfStore.runWithCompactionsDisabled(taskCreator,
@ -1354,7 +1353,7 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
List<Future<?>> futures = new ArrayList<>(descriptors.size()); List<Future<?>> futures = new ArrayList<>(descriptors.size());
long nowInSec = FBUtilities.nowInSeconds(); long nowInSec = FBUtilities.nowInSeconds();
for (ColumnFamilyStore cfs : descriptors.keySet()) 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); FBUtilities.waitOnFutures(futures);
} }
@ -1645,7 +1644,7 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
long nowInSec = FBUtilities.nowInSeconds(); long nowInSec = FBUtilities.nowInSeconds();
try (SSTableRewriter writer = SSTableRewriter.construct(cfs, txn, false, sstable.maxDataAge); try (SSTableRewriter writer = SSTableRewriter.construct(cfs, txn, false, sstable.maxDataAge);
ISSTableScanner scanner = cleanupStrategy.getScanner(sstable); 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)); Refs<SSTableReader> refs = Refs.ref(Collections.singleton(sstable));
CompactionIterator ci = new CompactionIterator(OperationType.CLEANUP, Collections.singletonList(scanner), controller, nowInSec, nextTimeUUID(), active, null)) CompactionIterator ci = new CompactionIterator(OperationType.CLEANUP, Collections.singletonList(scanner), controller, nowInSec, nextTimeUUID(), active, null))
{ {
@ -1992,7 +1991,7 @@ public class CompactionManager implements CompactionManagerMBean, ICompactionMan
SSTableRewriter unrepairedWriter = SSTableRewriter.constructWithoutEarlyOpening(sharedTxn, false, groupMaxDataAge); SSTableRewriter unrepairedWriter = SSTableRewriter.constructWithoutEarlyOpening(sharedTxn, false, groupMaxDataAge);
AbstractCompactionStrategy.ScannerList scanners = strategy.getScanners(txn.originals()); 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)) CompactionIterator ci = getAntiCompactionIterator(scanners.scanners, controller, nowInSec, nextTimeUUID(), active, isCancelled))
{ {
int expectedBloomFilterSize = Math.max(cfs.metadata().params.minIndexInterval, (int)(SSTableReader.getApproximateKeyCount(sstableAsSet))); int expectedBloomFilterSize = Math.max(cfs.metadata().params.minIndexInterval, (int)(SSTableReader.getApproximateKeyCount(sstableAsSet)));
@ -2178,13 +2177,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) public Future<Long> submitViewBuilder(final ViewBuilderTask task)
{ {
return submitViewBuilder(task, active); return submitViewBuilder(task, active);

View File

@ -35,6 +35,12 @@ import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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.config.DatabaseDescriptor;
import org.apache.cassandra.db.ColumnFamilyStore; import org.apache.cassandra.db.ColumnFamilyStore;
import org.apache.cassandra.db.Directories; 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.format.SSTableReader;
import org.apache.cassandra.io.sstable.metadata.MetadataCollector; import org.apache.cassandra.io.sstable.metadata.MetadataCollector;
import org.apache.cassandra.io.util.File; import org.apache.cassandra.io.util.File;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.service.ActiveRepairService; 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.SnapshotManager;
import org.apache.cassandra.service.snapshot.SnapshotOptions; import org.apache.cassandra.service.snapshot.SnapshotOptions;
import org.apache.cassandra.service.snapshot.SnapshotType; 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.TimeUUID;
import org.apache.cassandra.utils.concurrent.Refs; 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.currentTimeMillis;
import static org.apache.cassandra.utils.Clock.Global.nanoTime; 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; private static final int MEGABYTE = 1024 * 1024;
protected static final Logger logger = LoggerFactory.getLogger(CompactionTask.class); protected static final Logger logger = LoggerFactory.getLogger(CompactionTask.class);
protected final long gcBefore; protected final long gcBeforeSeconds;
protected final boolean keepOriginals; protected final boolean keepOriginals;
protected static long totalBytesCompacted = 0; protected static long totalBytesCompacted = 0;
private ActiveCompactionsTracker activeCompactions; 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); super(cfs, txn);
this.gcBefore = gcBefore; this.gcBeforeSeconds = gcBeforeSeconds;
this.keepOriginals = keepOriginals; this.keepOriginals = keepOriginals;
} }
@ -546,7 +558,33 @@ public class CompactionTask extends AbstractCompactionTask
return 0; 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); return new CompactionController(cfs, toCompact, gcBefore);
} }

View File

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

View File

@ -35,7 +35,7 @@ public class TimeWindowCompactionTask extends CompactionTask
} }
@Override @Override
public CompactionController getCompactionController(Set<SSTableReader> toCompact) public CompactionController getCompactionController(Set<SSTableReader> toCompact, long gcBefore)
{ {
return new TimeWindowCompactionController(cfs, toCompact, gcBefore, ignoreOverlaps); 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.CQL3Type;
import org.apache.cassandra.cql3.Duration; 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.Constants;
import org.apache.cassandra.cql3.terms.Term; import org.apache.cassandra.cql3.terms.Term;
import org.apache.cassandra.serializers.MarshalException; 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 org.apache.cassandra.utils.bytecomparable.ByteSourceInverse;
import static java.util.concurrent.TimeUnit.MILLISECONDS; 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 // Fully compatible with UUID, and indeed is interpreted as UUID for UDF
public abstract class AbstractTimeUUIDType<T> extends TemporalType<T> public abstract class AbstractTimeUUIDType<T> extends TemporalType<T>
@ -218,9 +218,9 @@ public abstract class AbstractTimeUUIDType<T> extends TemporalType<T>
} }
@Override @Override
public ByteBuffer now() public ByteBuffer now(FunctionContext context)
{ {
return ByteBuffer.wrap(nextTimeUUIDAsBytes()); return ByteBuffer.wrap(context.nextTimeUUIDAsBytes());
} }
@Override @Override

View File

@ -22,11 +22,10 @@ import java.nio.ByteBuffer;
import org.apache.commons.lang3.mutable.MutableLong; import org.apache.commons.lang3.mutable.MutableLong;
import org.apache.cassandra.cql3.Duration; import org.apache.cassandra.cql3.Duration;
import org.apache.cassandra.cql3.FunctionContext;
import org.apache.cassandra.cql3.functions.ArgumentDeserializer; import org.apache.cassandra.cql3.functions.ArgumentDeserializer;
import org.apache.cassandra.transport.ProtocolVersion; import org.apache.cassandra.transport.ProtocolVersion;
import static org.apache.cassandra.utils.Clock.Global.currentTimeMillis;
/** /**
* Base type for temporal types (timestamp, date ...). * Base type for temporal types (timestamp, date ...).
* *
@ -42,9 +41,9 @@ public abstract class TemporalType<T> extends AbstractType<T>
* Returns the current temporal value. * Returns the current temporal value.
* @return 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 java.time.ZoneOffset;
import org.apache.cassandra.cql3.CQL3Type; 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.ArgumentDeserializer;
import org.apache.cassandra.cql3.terms.Constants; import org.apache.cassandra.cql3.terms.Constants;
import org.apache.cassandra.cql3.terms.Term; import org.apache.cassandra.cql3.terms.Term;
@ -110,9 +111,10 @@ public class TimeType extends TemporalType<Long>
} }
@Override @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 @Override

View File

@ -130,7 +130,6 @@ public abstract class AbstractBTreePartition implements Partition, Iterable<Row>
if (rt != null && rt.deletionTime().supersedes(activeDeletion)) if (rt != null && rt.deletionTime().supersedes(activeDeletion))
activeDeletion = rt.deletionTime(); activeDeletion = rt.deletionTime();
if (row == null) if (row == null)
{ {
// this means our partition level deletion supersedes all other deletions and we don't have to keep the row deletions // 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 private static class ValidationCompactionIterator extends CompactionIterator
{ {
public ValidationCompactionIterator(List<ISSTableScanner> scanners, ValidationCompactionController controller, long nowInSec, ActiveCompactionsTracker activeCompactions, TopPartitionTracker.Collector topPartitionCollector) 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.getKeyspaceName(),
cfs.getTableName()); 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); controller = new ValidationCompactionController(cfs, gcBefore);
scanners = cfs.getCompactionStrategyManager().getScanners(sstables, ranges); scanners = cfs.getCompactionStrategyManager().getScanners(sstables, ranges);
ci = new ValidationCompactionIterator(scanners.scanners, controller, nowInSec, CompactionManager.instance.active, topPartitionCollector); 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.ColumnSpecification;
import org.apache.cassandra.cql3.QueryOptions; import org.apache.cassandra.cql3.QueryOptions;
import org.apache.cassandra.cql3.QueryProcessor; 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.TypeCodec;
import org.apache.cassandra.cql3.functions.types.UserType; import org.apache.cassandra.cql3.functions.types.UserType;
import org.apache.cassandra.cql3.statements.ModificationStatement; import org.apache.cassandra.cql3.statements.ModificationStatement;
@ -285,13 +286,13 @@ public class CQLSSTableWriter implements Closeable
long now = currentTimeMillis(); long now = currentTimeMillis();
// Note that we asks indexes to not validate values (the last 'false' arg below) because that triggers a 'Keyspace.open' // 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. // and that forces a lot of initialization that we don't want.
UpdateParameters params = new UpdateParameters(modificationStatement.metadata, RowUpdateBuilder builder = new RegularRowUpdateBuilder(modificationStatement.metadata,
ClientState.forInternalCalls(), ClientState.forInternalCalls(),
options, options,
modificationStatement.getTimestamp(TimeUnit.MILLISECONDS.toMicros(now), options), modificationStatement.getTimestamp(TimeUnit.MILLISECONDS.toMicros(now), options),
options.getNowInSec((int) TimeUnit.MILLISECONDS.toSeconds(now)), options.getNowInSec((int) TimeUnit.MILLISECONDS.toSeconds(now)),
modificationStatement.getTimeToLive(options), modificationStatement.getTimeToLive(options),
Collections.emptyMap()); null);
try try
{ {
@ -302,7 +303,7 @@ public class CQLSSTableWriter implements Closeable
for (ByteBuffer key : keys) for (ByteBuffer key : keys)
{ {
for (Slice slice : slices) for (Slice slice : slices)
modificationStatement.addUpdateForKey(writer.getUpdateFor(key), slice, params); modificationStatement.addUpdateForKey(writer.getUpdateFor(key), slice, builder);
} }
} }
else else
@ -312,7 +313,7 @@ public class CQLSSTableWriter implements Closeable
for (ByteBuffer key : keys) for (ByteBuffer key : keys)
{ {
for (Clustering clustering : clusterings) for (Clustering clustering : clusterings)
modificationStatement.addUpdateForKey(writer.getUpdateFor(key), clustering, params); modificationStatement.addUpdateForKey(writer.getUpdateFor(key), clustering, builder);
} }
} }
return this; return this;

View File

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

View File

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

View File

@ -65,9 +65,9 @@ import org.apache.cassandra.dht.Murmur3Partitioner;
import org.apache.cassandra.schema.TableId; import org.apache.cassandra.schema.TableId;
import org.apache.cassandra.service.accord.api.PartitionKey; import org.apache.cassandra.service.accord.api.PartitionKey;
import org.apache.cassandra.service.accord.api.TokenKey; 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.serializers.TableMetadatasAndKeys;
import org.apache.cassandra.service.accord.txn.AccordUpdate; 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.TxnQuery;
import org.apache.cassandra.service.accord.txn.TxnRead; import org.apache.cassandra.service.accord.txn.TxnRead;
import org.apache.cassandra.service.accord.txn.TxnWrite; import org.apache.cassandra.service.accord.txn.TxnWrite;
@ -318,7 +318,7 @@ public class AccordObjectSizes
builder.waitingOn(WaitingOn.empty(Domain.Key)); builder.waitingOn(WaitingOn.empty(Domain.Key));
if (saveStatus.known.is(Known.Outcome.Apply)) if (saveStatus.known.is(Known.Outcome.Apply))
builder.result(ResultSerializers.APPLIED); builder.result(TxnDataResult.PERSISTABLE);
return builder.build(saveStatus); return builder.build(saveStatus);
} }
@ -400,6 +400,7 @@ public class AccordObjectSizes
size += sizeNullable(command.partialDeps(), AccordObjectSizes::dependencies); size += sizeNullable(command.partialDeps(), AccordObjectSizes::dependencies);
size += sizeNullable(command.acceptedOrCommitted(), AccordObjectSizes::timestamp); size += sizeNullable(command.acceptedOrCommitted(), AccordObjectSizes::timestamp);
size += sizeNullable(command.writes(), AccordObjectSizes::writes); 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); size += sizeNullable(command.waitingOn(), AccordObjectSizes::waitingOn);
return size; 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); 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(); 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.journal.Journal;
import org.apache.cassandra.service.accord.serializers.CommandSerializers; import org.apache.cassandra.service.accord.serializers.CommandSerializers;
import org.apache.cassandra.service.accord.serializers.DepsSerializers; 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.Version;
import org.apache.cassandra.service.accord.serializers.WaitingOnSerializer; 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.anyFieldChanged;
import static accord.impl.CommandChange.describeFlags; import static accord.impl.CommandChange.describeFlags;
@ -140,7 +140,7 @@ public class CommandChangeWriter implements Journal.Writer
CommandSerializers.writes.serialize(command.writes(), out, userVersion); CommandSerializers.writes.serialize(command.writes(), out, userVersion);
break; break;
case RESULT: case RESULT:
ResultSerializers.result.serialize(command.result(), out); TxnDataResult.persistable.serialize(command.result(), out);
break; break;
case CLEANUP: case CLEANUP:
Cleanup 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.JournalKey;
import org.apache.cassandra.service.accord.serializers.CommandSerializers; import org.apache.cassandra.service.accord.serializers.CommandSerializers;
import org.apache.cassandra.service.accord.serializers.DepsSerializers; 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.Version;
import org.apache.cassandra.service.accord.serializers.WaitingOnSerializer; 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.api.Journal.Load.ALL;
import static accord.impl.CommandChange.Field.CLEANUP; import static accord.impl.CommandChange.Field.CLEANUP;
@ -205,7 +205,7 @@ public class CommandChanges extends CommandChange.Builder implements Merger
break; break;
case RESULT: case RESULT:
Invariants.require(result != null, "%s", this); Invariants.require(result != null, "%s", this);
ResultSerializers.result.serialize(result, out); TxnDataResult.persistable.serialize(result, out);
break; break;
} }
} }
@ -309,7 +309,7 @@ public class CommandChanges extends CommandChange.Builder implements Merger
cleanup = newCleanup; cleanup = newCleanup;
break; break;
case RESULT: case RESULT:
result = ResultSerializers.result.deserialize(in); result = TxnDataResult.persistable.deserialize(in);
break; break;
} }
} }
@ -355,8 +355,7 @@ public class CommandChanges extends CommandChange.Builder implements Merger
CommandSerializers.writes.skip(in, userVersion); CommandSerializers.writes.skip(in, userVersion);
break; break;
case RESULT: case RESULT:
// TODO (expected): skip TxnDataResult.persistable.skip(in);
ResultSerializers.result.skip(in);
break; break;
} }
} }

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