/** * Convert statement into a list of mutations to apply on the server * * @param options value for prepared statement markers * @param local if true, any requests (for collections) performed by getMutation should be done locally only. * @param now the current timestamp in microseconds to use if no timestamp is user provided. * * @return list of the mutations * @throws InvalidRequestException on invalid requests */ private Collection<? extends IMutation> getMutations(QueryOptions options, boolean local, long now) throws RequestExecutionException, RequestValidationException { List<ByteBuffer> keys = buildPartitionKeyNames(options); Composite clusteringPrefix = createClusteringPrefix(options); UpdateParameters params = makeUpdateParameters(keys, clusteringPrefix, options, local, now); Collection<IMutation> mutations = new ArrayList<IMutation>(keys.size()); for (ByteBuffer key: keys) { ThriftValidation.validateKey(cfm, key); ColumnFamily cf = ArrayBackedSortedColumns.factory.create(cfm); addUpdateForKey(cf, key, clusteringPrefix, params); Mutation mut = new Mutation(cfm.ksName, key, cf); mutations.add(isCounter() ? new CounterMutation(mut, options.getConsistency()) : mut); } return mutations; }
/** * The <code>CqlParser</code> only goes as far as extracting the keyword arguments * from these statements, so this method is responsible for processing and * validating. * * @throws InvalidRequestException if arguments are missing or unacceptable */ public void validate(ClientState state) throws RequestValidationException { ThriftValidation.validateKeyspaceNotSystem(name); // keyspace name if (!name.matches("\\w+")) throw new InvalidRequestException(String.format("\"%s\" is not a valid keyspace name", name)); if (name.length() > Schema.NAME_LENGTH) throw new InvalidRequestException(String.format("Keyspace names shouldn't be more than %s characters long (got \"%s\")", Schema.NAME_LENGTH, name)); attrs.validate(); if (attrs.getReplicationStrategyClass() == null) throw new ConfigurationException("Missing mandatory replication strategy class"); // The strategy is validated through KSMetaData.validate() in announceNewKeyspace below. // However, for backward compatibility with thrift, this doesn't validate unexpected options yet, // so doing proper validation here. AbstractReplicationStrategy.validateReplicationStrategy(name, AbstractReplicationStrategy.getClass(attrs.getReplicationStrategyClass()), StorageService.instance.getTokenMetadata(), DatabaseDescriptor.getEndpointSnitch(), attrs.getReplicationOptions()); }
/** * Convert statement into a list of mutations to apply on the server * * @param variables value for prepared statement markers * @param local if true, any requests (for collections) performed by getMutation should be done locally only. * @param cl the consistency to use for the potential reads involved in generating the mutations (for lists set/delete operations) * @param now the current timestamp in microseconds to use if no timestamp is user provided. * * @return list of the mutations * @throws InvalidRequestException on invalid requests */ public Collection<? extends IMutation> getMutations(List<ByteBuffer> variables, boolean local, ConsistencyLevel cl, long now, boolean isBatch) throws RequestExecutionException, RequestValidationException { List<ByteBuffer> keys = buildPartitionKeyNames(variables); ColumnNameBuilder clusteringPrefix = createClusteringPrefixBuilder(variables); // Some lists operation requires reading Map<ByteBuffer, ColumnGroupMap> rows = readRequiredRows(keys, clusteringPrefix, local, cl); UpdateParameters params = new UpdateParameters(cfm, variables, getTimestamp(now, variables), getTimeToLive(variables), rows); Collection<IMutation> mutations = new ArrayList<IMutation>(); for (ByteBuffer key: keys) { ThriftValidation.validateKey(cfm, key); ColumnFamily cf = updateForKey(key, clusteringPrefix, params); mutations.add(makeMutation(key, cf, cl, isBatch)); } return mutations; }
/** * The <code>CqlParser</code> only goes as far as extracting the keyword arguments * from these statements, so this method is responsible for processing and * validating. * * @throws InvalidRequestException if arguments are missing or unacceptable */ public void validate(ClientState state) throws RequestValidationException { ThriftValidation.validateKeyspaceNotSystem(name); // keyspace name if (!name.matches("\\w+")) throw new InvalidRequestException(String.format("\"%s\" is not a valid keyspace name", name)); if (name.length() > Schema.NAME_LENGTH) throw new InvalidRequestException(String.format("Keyspace names shouldn't be more than %s characters long (got \"%s\")", Schema.NAME_LENGTH, name)); attrs.validate(); if (attrs.getReplicationStrategyClass() == null) throw new ConfigurationException("Missing mandatory replication strategy class"); // The strategy is validated through KSMetaData.validate() in announceNewKeyspace below. // However, for backward compatibility with thrift, this doesn't validate unexpected options yet, // so doing proper validation here. KeyspaceParams params = attrs.asNewKeyspaceParams(); params.validate(name); if (params.replication.klass.equals(LocalStrategy.class)) throw new ConfigurationException("Unable to use given strategy class: LocalStrategy is reserved for internal use."); }
public ParsedStatement.Prepared prepare(ColumnSpecification[] boundNames) throws InvalidRequestException { CFMetaData metadata = ThriftValidation.validateColumnFamily(keyspace(), columnFamily()); type = metadata.getDefaultValidator().isCommutative() ? Type.COUNTER : Type.LOGGED; cfDef = metadata.getCfDef(); UpdateStatement.processKeys(cfDef, whereClause, processedKeys, boundNames); for (Operation.RawDeletion deletion : deletions) { CFDefinition.Name name = cfDef.get(deletion.affectedColumn()); if (name == null) throw new InvalidRequestException(String.format("Unknown identifier %s", deletion.affectedColumn())); // For compact, we only have one value except the key, so the only form of DELETE that make sense is without a column // list. However, we support having the value name for coherence with the static/sparse case if (name.kind != CFDefinition.Name.Kind.COLUMN_METADATA && name.kind != CFDefinition.Name.Kind.VALUE_ALIAS) throw new InvalidRequestException(String.format("Invalid identifier %s for deletion (should not be a PRIMARY KEY part)", name)); Operation op = deletion.prepare(name); op.collectMarkerSpecification(boundNames); toRemove.add(op); } return new ParsedStatement.Prepared(this, Arrays.<ColumnSpecification>asList(boundNames)); }
public void doVerb(MessageIn<IndexScanCommand> message, String id) { try { IndexScanCommand command = message.payload; ColumnFamilyStore cfs = Table.open(command.keyspace).getColumnFamilyStore(command.column_family); List<Row> rows = cfs.search(command.index_clause.expressions, command.range, command.index_clause.count, ThriftValidation.asIFilter(command.predicate, cfs.getComparator())); RangeSliceReply reply = new RangeSliceReply(rows); Tracing.trace("Enqueuing response to {}", message.from); MessagingService.instance().sendReply(reply.createMessage(), id, message.from); } catch (Exception ex) { throw new RuntimeException(ex); } }
/** * Convert statement into a list of mutations to apply on the server * * @param variables value for prepared statement markers * @param local if true, any requests (for collections) performed by getMutation should be done locally only. * @param cl the consistency to use for the potential reads involved in generating the mutations (for lists set/delete operations) * @param now the current timestamp in microseconds to use if no timestamp is user provided. * * @return list of the mutations * @throws InvalidRequestException on invalid requests */ public Collection<? extends IMutation> getMutations(List<ByteBuffer> variables, boolean local, ConsistencyLevel cl, long now, boolean isBatch) throws RequestExecutionException, RequestValidationException { List<ByteBuffer> keys = buildPartitionKeyNames(variables); Composite clusteringPrefix = createClusteringPrefix(variables); // Some lists operation requires reading Map<ByteBuffer, CQL3Row> rows = readRequiredRows(keys, clusteringPrefix, local, cl); UpdateParameters params = new UpdateParameters(cfm, variables, getTimestamp(now, variables), getTimeToLive(variables), rows); Collection<IMutation> mutations = new ArrayList<IMutation>(); for (ByteBuffer key: keys) { ThriftValidation.validateKey(cfm, key); ColumnFamily cf = updateForKey(key, clusteringPrefix, params); mutations.add(makeMutation(key, cf, cl, isBatch)); } return mutations; }
/** * Convert statement into a list of mutations to apply on the server * * @param variables value for prepared statement markers * @param local if true, any requests (for collections) performed by getMutation should be done locally only. * @param cl the consistency to use for the potential reads involved in generating the mutations (for lists set/delete operations) * @param now the current timestamp in microseconds to use if no timestamp is user provided. * * @return list of the mutations * @throws InvalidRequestException on invalid requests */ private Collection<? extends IMutation> getMutations(List<ByteBuffer> variables, boolean local, ConsistencyLevel cl, long now) throws RequestExecutionException, RequestValidationException { List<ByteBuffer> keys = buildPartitionKeyNames(variables); Composite clusteringPrefix = createClusteringPrefix(variables); UpdateParameters params = makeUpdateParameters(keys, clusteringPrefix, variables, local, cl, now); Collection<IMutation> mutations = new ArrayList<IMutation>(); for (ByteBuffer key: keys) { ThriftValidation.validateKey(cfm, key); ColumnFamily cf = ArrayBackedSortedColumns.factory.create(cfm); addUpdateForKey(cf, key, clusteringPrefix, params); Mutation mut = new Mutation(cfm.ksName, key, cf); mutations.add(isCounter() ? new CounterMutation(mut, cl) : mut); } return mutations; }
public void validate(ClientState state) throws RequestValidationException { ThriftValidation.validateColumnFamily(keyspace(), columnFamily()); try { TriggerExecutor.instance.loadTriggerInstance(triggerClass); } catch (Exception e) { throw new ConfigurationException(String.format("Trigger class '%s' doesn't exist", triggerClass)); } }
public ResultMessage executeWithCondition(QueryState queryState, QueryOptions options) throws RequestExecutionException, RequestValidationException { List<ByteBuffer> variables = options.getValues(); List<ByteBuffer> keys = buildPartitionKeyNames(variables); // We don't support IN for CAS operation so far if (keys.size() > 1) throw new InvalidRequestException("IN on the partition key is not supported with conditional updates"); ColumnNameBuilder clusteringPrefix = createClusteringPrefixBuilder(variables); ByteBuffer key = keys.get(0); ThriftValidation.validateKey(cfm, key); UpdateParameters updParams = new UpdateParameters(cfm, variables, queryState.getTimestamp(), getTimeToLive(variables), null); ColumnFamily updates = updateForKey(key, clusteringPrefix, updParams); // When building the conditions, we should not use the TTL. It's not useful, and if a very low ttl (1 seconds) is used, it's possible // for it to expire before actually build the conditions which would break since we would then test for the presence of tombstones. UpdateParameters condParams = new UpdateParameters(cfm, variables, queryState.getTimestamp(), 0, null); ColumnFamily expected = buildConditions(key, clusteringPrefix, condParams); ColumnFamily result = StorageProxy.cas(keyspace(), columnFamily(), key, clusteringPrefix, expected, updates, options.getSerialConsistency(), options.getConsistency()); return new ResultMessage.Rows(buildCasResultSet(key, result)); }
public void validate(ClientState state) throws RequestValidationException { CFMetaData cfm = ThriftValidation.validateColumnFamily(keyspace(), columnFamily()); ColumnDefinition cd = cfm.getColumnDefinition(columnName.key); if (cd == null) throw new InvalidRequestException("No column definition found for column " + columnName); if (cd.getIndexType() != null) { if (ifNotExists) return; else throw new InvalidRequestException("Index already exists"); } if (isCustom && indexClass == null) throw new InvalidRequestException("CUSTOM index requires specifiying the index class"); if (!isCustom && indexClass != null) throw new InvalidRequestException("Cannot specify index class for a non-CUSTOM index"); // TODO: we could lift that limitation if (cfm.getCfDef().isCompact && cd.type != ColumnDefinition.Type.REGULAR) throw new InvalidRequestException(String.format("Secondary index on %s column %s is not yet supported for compact table", cd.type, columnName)); if (cd.getValidator().isCollection() && !isCustom) throw new InvalidRequestException("Indexes on collections are no yet supported"); if (cd.type == ColumnDefinition.Type.PARTITION_KEY && cd.componentIndex == null) throw new InvalidRequestException(String.format("Cannot add secondary index to already primarily indexed column %s", columnName)); }
/** * Create a RangeSliceCommand and run it against the StorageProxy. * <p> * To match the behavior of the standard Cassandra thrift API endpoint, the * {@code nowMillis} argument should be the number of milliseconds since the * UNIX Epoch (e.g. System.currentTimeMillis() or equivalent obtained * through a {@link TimestampProvider}). This is per * {@link org.apache.cassandra.thrift.CassandraServer#get_range_slices(ColumnParent, SlicePredicate, KeyRange, ConsistencyLevel)}, * which passes the server's System.currentTimeMillis() to the * {@code RangeSliceCommand} constructor. */ private List<Row> getKeySlice(Token start, Token end, @Nullable SliceQuery sliceQuery, int pageSize, long nowMillis) throws BackendException { IPartitioner partitioner = StorageService.getPartitioner(); SliceRange columnSlice = new SliceRange(); if (sliceQuery == null) { columnSlice.setStart(ArrayUtils.EMPTY_BYTE_ARRAY) .setFinish(ArrayUtils.EMPTY_BYTE_ARRAY) .setCount(5); } else { columnSlice.setStart(sliceQuery.getSliceStart().asByteBuffer()) .setFinish(sliceQuery.getSliceEnd().asByteBuffer()) .setCount(sliceQuery.hasLimit() ? sliceQuery.getLimit() : Integer.MAX_VALUE); } /* Note: we need to fetch columns for each row as well to remove "range ghosts" */ SlicePredicate predicate = new SlicePredicate().setSlice_range(columnSlice); RowPosition startPosition = start.minKeyBound(partitioner); RowPosition endPosition = end.minKeyBound(partitioner); List<Row> rows; try { CFMetaData cfm = Schema.instance.getCFMetaData(keyspace, columnFamily); IDiskAtomFilter filter = ThriftValidation.asIFilter(predicate, cfm, null); RangeSliceCommand cmd = new RangeSliceCommand(keyspace, columnFamily, nowMillis, filter, new Bounds<RowPosition>(startPosition, endPosition), pageSize); rows = StorageProxy.getRangeSlice(cmd, ConsistencyLevel.QUORUM); } catch (Exception e) { throw new PermanentBackendException(e); } return rows; }
/** * Create a RangeSliceCommand and run it against the StorageProxy. * <p> * To match the behavior of the standard Cassandra thrift API endpoint, the * {@code nowMillis} argument should be the number of milliseconds since the * UNIX Epoch (e.g. System.currentTimeMillis() or equivalent obtained * through a {@link TimestampProvider}). This is per * {@link org.apache.cassandra.thrift.CassandraServer#get_range_slices(ColumnParent, SlicePredicate, KeyRange, ConsistencyLevel)}, * which passes the server's System.currentTimeMillis() to the * {@code RangeSliceCommand} constructor. */ private List<Row> getKeySlice(Token start, Token end, @Nullable SliceQuery sliceQuery, int pageSize, long nowMillis) throws BackendException { IPartitioner<?> partitioner = StorageService.getPartitioner(); SliceRange columnSlice = new SliceRange(); if (sliceQuery == null) { columnSlice.setStart(ArrayUtils.EMPTY_BYTE_ARRAY) .setFinish(ArrayUtils.EMPTY_BYTE_ARRAY) .setCount(5); } else { columnSlice.setStart(sliceQuery.getSliceStart().asByteBuffer()) .setFinish(sliceQuery.getSliceEnd().asByteBuffer()) .setCount(sliceQuery.hasLimit() ? sliceQuery.getLimit() : Integer.MAX_VALUE); } /* Note: we need to fetch columns for each row as well to remove "range ghosts" */ SlicePredicate predicate = new SlicePredicate().setSlice_range(columnSlice); RowPosition startPosition = start.minKeyBound(partitioner); RowPosition endPosition = end.minKeyBound(partitioner); List<Row> rows; try { CFMetaData cfm = Schema.instance.getCFMetaData(keyspace, columnFamily); IDiskAtomFilter filter = ThriftValidation.asIFilter(predicate, cfm, null); RangeSliceCommand cmd = new RangeSliceCommand(keyspace, columnFamily, nowMillis, filter, new Bounds<RowPosition>(startPosition, endPosition), pageSize); rows = StorageProxy.getRangeSlice(cmd, ConsistencyLevel.QUORUM); } catch (Exception e) { throw new PermanentBackendException(e); } return rows; }
public ParsedStatement.Prepared prepare() { VariableSpecifications boundNames = getBoundVariables(); ModificationStatement statement = prepare(boundNames); CFMetaData cfm = ThriftValidation.validateColumnFamily(keyspace(), columnFamily()); return new ParsedStatement.Prepared(statement, boundNames, boundNames.getPartitionKeyBindIndexes(cfm)); }
public ModificationStatement prepare(VariableSpecifications boundNames) { CFMetaData metadata = ThriftValidation.validateColumnFamily(keyspace(), columnFamily()); Attributes preparedAttributes = attrs.prepare(keyspace(), columnFamily()); preparedAttributes.collectMarkerSpecification(boundNames); Conditions preparedConditions = prepareConditions(metadata, boundNames); return prepareInternal(metadata, boundNames, preparedConditions, preparedAttributes); }
public void validate(ClientState state) throws RequestValidationException { CFMetaData cfm = ThriftValidation.validateColumnFamily(keyspace(), columnFamily()); if (cfm.isView()) throw new InvalidRequestException("Cannot CREATE TRIGGER against a materialized view"); try { TriggerExecutor.instance.loadTriggerInstance(triggerClass); } catch (Exception e) { throw new ConfigurationException(String.format("Trigger class '%s' doesn't exist", triggerClass)); } }
public void prepareKeyspace(ClientState state) throws InvalidRequestException { if (!functionName.hasKeyspace() && state.getRawKeyspace() != null) functionName = new FunctionName(state.getKeyspace(), functionName.name); if (!functionName.hasKeyspace()) throw new InvalidRequestException("Functions must be fully qualified with a keyspace name if a keyspace is not set for the session"); ThriftValidation.validateKeyspaceNotSystem(functionName.keyspace); stateFunc = new FunctionName(functionName.keyspace, stateFunc.name); if (finalFunc != null) finalFunc = new FunctionName(functionName.keyspace, finalFunc.name); }
public void prepareKeyspace(ClientState state) throws InvalidRequestException { if (!functionName.hasKeyspace() && state.getRawKeyspace() != null) functionName = new FunctionName(state.getKeyspace(), functionName.name); if (!functionName.hasKeyspace()) throw new InvalidRequestException("Functions must be fully qualified with a keyspace name if a keyspace is not set for the session"); ThriftValidation.validateKeyspaceNotSystem(functionName.keyspace); }
public void prepareKeyspace(ClientState state) throws InvalidRequestException { if (!functionName.hasKeyspace() && state.getRawKeyspace() != null) functionName = new FunctionName(state.getRawKeyspace(), functionName.name); if (!functionName.hasKeyspace()) throw new InvalidRequestException("Functions must be fully qualified with a keyspace name if a keyspace is not set for the session"); ThriftValidation.validateKeyspaceNotSystem(functionName.keyspace); }
@Override public void prepareKeyspace(ClientState state) throws InvalidRequestException { if (!functionName.hasKeyspace() && state.getRawKeyspace() != null) functionName = new FunctionName(state.getKeyspace(), functionName.name); if (!functionName.hasKeyspace()) throw new InvalidRequestException("Functions must be fully qualified with a keyspace name if a keyspace is not set for the session"); ThriftValidation.validateKeyspaceNotSystem(functionName.keyspace); }
@Override public void validate(ClientState state) throws RequestValidationException { CFMetaData cfm = ThriftValidation.validateColumnFamily(keyspace(), columnFamily()); CFDefinition.Name name = cfm.getCfDef().get(columnName); if (name == null) throw new InvalidRequestException("No column definition found for column " + columnName); switch (name.kind) { case KEY_ALIAS: case COLUMN_ALIAS: throw new InvalidRequestException(String.format("Cannot create index on PRIMARY KEY part %s", columnName)); case VALUE_ALIAS: throw new InvalidRequestException(String.format("Cannot create index on column %s of compact CF", columnName)); case COLUMN_METADATA: ColumnDefinition cd = cfm.getColumnDefinition(columnName.key); if (cd.getIndexType() != null) throw new InvalidRequestException("Index already exists"); if (isCustom && indexClass == null) throw new InvalidRequestException("CUSTOM index requires specifiying the index class"); if (!isCustom && indexClass != null) throw new InvalidRequestException("Cannot specify index class for a non-CUSTOM index"); if (cd.getValidator().isCollection() && !isCustom) throw new InvalidRequestException("Indexes on collections are no yet supported"); break; default: throw new AssertionError(); } }
/** * The <code>CqlParser</code> only goes as far as extracting the keyword arguments * from these statements, so this method is responsible for processing and * validating. * * @throws InvalidRequestException if arguments are missing or unacceptable */ @Override public void validate(ClientState state) throws RequestValidationException { super.validate(state); ThriftValidation.validateKeyspaceNotSystem(name); // keyspace name if (!name.matches("\\w+")) throw new InvalidRequestException(String.format("\"%s\" is not a valid keyspace name", name)); if (name.length() > Schema.NAME_LENGTH) throw new InvalidRequestException(String.format("Keyspace names shouldn't be more than %s characters long (got \"%s\")", Schema.NAME_LENGTH, name)); attrs.validate(); if (attrs.getReplicationStrategyClass() == null) throw new ConfigurationException("Missing mandatory replication strategy class"); // The strategy is validated through KSMetaData.validate() in announceNewKeyspace below. // However, for backward compatibility with thrift, this doesn't validate unexpected options yet, // so doing proper validation here. AbstractReplicationStrategy.validateReplicationStrategy(name, attrs.getReplicationStrategyClass(), StorageService.instance.getTokenMetadata(), DatabaseDescriptor.getEndpointSnitch(), attrs.getReplicationOptions()); }
public ResultMessage executeWithCondition(QueryState queryState, QueryOptions options) throws RequestExecutionException, RequestValidationException { List<ByteBuffer> variables = options.getValues(); List<ByteBuffer> keys = buildPartitionKeyNames(variables); // We don't support IN for CAS operation so far if (keys.size() > 1) throw new InvalidRequestException("IN on the partition key is not supported with conditional updates"); Composite clusteringPrefix = createClusteringPrefix(variables); ByteBuffer key = keys.get(0); ThriftValidation.validateKey(cfm, key); UpdateParameters updParams = new UpdateParameters(cfm, variables, queryState.getTimestamp(), getTimeToLive(variables), null); ColumnFamily updates = updateForKey(key, clusteringPrefix, updParams); // When building the conditions, we should not use the TTL. It's not useful, and if a very low ttl (1 seconds) is used, it's possible // for it to expire before actually build the conditions which would break since we would then test for the presence of tombstones. UpdateParameters condParams = new UpdateParameters(cfm, variables, queryState.getTimestamp(), 0, null); ColumnFamily expected = buildConditions(key, clusteringPrefix, condParams); ColumnFamily result = StorageProxy.cas(keyspace(), columnFamily(), key, clusteringPrefix, expected, updates, options.getSerialConsistency(), options.getConsistency()); return new ResultMessage.Rows(buildCasResultSet(key, result)); }
@Override public void validate(ClientState state) throws RequestValidationException { CFMetaData cfm = ThriftValidation.validateColumnFamily(keyspace(), columnFamily()); if (cfm.getDefaultValidator().isCommutative()) throw new InvalidRequestException("Secondary indexes are not supported on counter tables"); CFDefinition.Name name = cfm.getCfDef().get(columnName); if (name == null) throw new InvalidRequestException("No column definition found for column " + columnName); switch (name.kind) { case KEY_ALIAS: case COLUMN_ALIAS: throw new InvalidRequestException(String.format("Cannot create index on PRIMARY KEY part %s", columnName)); case VALUE_ALIAS: throw new InvalidRequestException(String.format("Cannot create index on column %s of compact CF", columnName)); case COLUMN_METADATA: ColumnDefinition cd = cfm.getColumnDefinition(columnName.key); if (cd.getIndexType() != null) throw new InvalidRequestException("Index already exists"); if (isCustom && indexClass == null) throw new InvalidRequestException("CUSTOM index requires specifiying the index class"); if (!isCustom && indexClass != null) throw new InvalidRequestException("Cannot specify index class for a non-CUSTOM index"); if (cd.getValidator().isCollection() && !isCustom) throw new InvalidRequestException("Indexes on collections are no yet supported"); break; default: throw new AssertionError(); } }