Search in sources :

Example 11 with org.apache.cassandra.cql3.statements

use of org.apache.cassandra.cql3.statements in project cassandra by apache.

the class CreateViewStatement method announceMigration.

public Event.SchemaChange announceMigration(QueryState queryState, boolean isLocalOnly) throws RequestValidationException {
    // We need to make sure that:
    //  - primary key includes all columns in base table's primary key
    //  - make sure that the select statement does not have anything other than columns
    //    and their names match the base table's names
    //  - make sure that primary key does not include any collections
    //  - make sure there is no where clause in the select statement
    //  - make sure there is not currently a table or view
    //  - make sure baseTable gcGraceSeconds > 0
    properties.validate();
    if (properties.useCompactStorage)
        throw new InvalidRequestException("Cannot use 'COMPACT STORAGE' when defining a materialized view");
    // specific replica would break
    if (!baseName.getKeyspace().equals(keyspace()))
        throw new InvalidRequestException("Cannot create a materialized view on a table in a separate keyspace");
    TableMetadata metadata = Schema.instance.validateTable(baseName.getKeyspace(), baseName.getColumnFamily());
    if (metadata.isCounter())
        throw new InvalidRequestException("Materialized views are not supported on counter tables");
    if (metadata.isView())
        throw new InvalidRequestException("Materialized views cannot be created against other materialized views");
    if (metadata.params.gcGraceSeconds == 0) {
        throw new InvalidRequestException(String.format("Cannot create materialized view '%s' for base table " + "'%s' with gc_grace_seconds of 0, since this value is " + "used to TTL undelivered updates. Setting gc_grace_seconds" + " too low might cause undelivered updates to expire " + "before being replayed.", cfName.getColumnFamily(), baseName.getColumnFamily()));
    }
    Set<ColumnIdentifier> included = Sets.newHashSetWithExpectedSize(selectClause.size());
    for (RawSelector selector : selectClause) {
        Selectable.Raw selectable = selector.selectable;
        if (selectable instanceof Selectable.WithFieldSelection.Raw)
            throw new InvalidRequestException("Cannot select out a part of type when defining a materialized view");
        if (selectable instanceof Selectable.WithFunction.Raw)
            throw new InvalidRequestException("Cannot use function when defining a materialized view");
        if (selectable instanceof Selectable.WritetimeOrTTL.Raw)
            throw new InvalidRequestException("Cannot use function when defining a materialized view");
        if (selector.alias != null)
            throw new InvalidRequestException("Cannot use alias when defining a materialized view");
        Selectable s = selectable.prepare(metadata);
        if (s instanceof Term.Raw)
            throw new InvalidRequestException("Cannot use terms in selection when defining a materialized view");
        ColumnMetadata cdef = (ColumnMetadata) s;
        included.add(cdef.name);
    }
    Set<ColumnMetadata.Raw> targetPrimaryKeys = new HashSet<>();
    for (ColumnMetadata.Raw identifier : Iterables.concat(partitionKeys, clusteringKeys)) {
        if (!targetPrimaryKeys.add(identifier))
            throw new InvalidRequestException("Duplicate entry found in PRIMARY KEY: " + identifier);
        ColumnMetadata cdef = identifier.prepare(metadata);
        if (cdef.type.isMultiCell())
            throw new InvalidRequestException(String.format("Cannot use MultiCell column '%s' in PRIMARY KEY of materialized view", identifier));
        if (cdef.isStatic())
            throw new InvalidRequestException(String.format("Cannot use Static column '%s' in PRIMARY KEY of materialized view", identifier));
        if (cdef.type instanceof DurationType)
            throw new InvalidRequestException(String.format("Cannot use Duration column '%s' in PRIMARY KEY of materialized view", identifier));
    }
    // build the select statement
    Map<ColumnMetadata.Raw, Boolean> orderings = Collections.emptyMap();
    List<ColumnMetadata.Raw> groups = Collections.emptyList();
    SelectStatement.Parameters parameters = new SelectStatement.Parameters(orderings, groups, false, true, false);
    SelectStatement.RawStatement rawSelect = new SelectStatement.RawStatement(baseName, parameters, selectClause, whereClause, null, null);
    ClientState state = ClientState.forInternalCalls();
    state.setKeyspace(keyspace());
    rawSelect.prepareKeyspace(state);
    rawSelect.setBoundVariables(getBoundVariables());
    ParsedStatement.Prepared prepared = rawSelect.prepare(true);
    SelectStatement select = (SelectStatement) prepared.statement;
    StatementRestrictions restrictions = select.getRestrictions();
    if (!prepared.boundNames.isEmpty())
        throw new InvalidRequestException("Cannot use query parameters in CREATE MATERIALIZED VIEW statements");
    String whereClauseText = View.relationsToWhereClause(whereClause.relations);
    Set<ColumnIdentifier> basePrimaryKeyCols = new HashSet<>();
    for (ColumnMetadata definition : Iterables.concat(metadata.partitionKeyColumns(), metadata.clusteringColumns())) basePrimaryKeyCols.add(definition.name);
    List<ColumnIdentifier> targetClusteringColumns = new ArrayList<>();
    List<ColumnIdentifier> targetPartitionKeys = new ArrayList<>();
    // This is only used as an intermediate state; this is to catch whether multiple non-PK columns are used
    boolean hasNonPKColumn = false;
    for (ColumnMetadata.Raw raw : partitionKeys) hasNonPKColumn |= getColumnIdentifier(metadata, basePrimaryKeyCols, hasNonPKColumn, raw, targetPartitionKeys, restrictions);
    for (ColumnMetadata.Raw raw : clusteringKeys) hasNonPKColumn |= getColumnIdentifier(metadata, basePrimaryKeyCols, hasNonPKColumn, raw, targetClusteringColumns, restrictions);
    // We need to include all of the primary key columns from the base table in order to make sure that we do not
    // overwrite values in the view. We cannot support "collapsing" the base table into a smaller number of rows in
    // the view because if we need to generate a tombstone, we have no way of knowing which value is currently being
    // used in the view and whether or not to generate a tombstone. In order to not surprise our users, we require
    // that they include all of the columns. We provide them with a list of all of the columns left to include.
    boolean missingClusteringColumns = false;
    StringBuilder columnNames = new StringBuilder();
    List<ColumnIdentifier> includedColumns = new ArrayList<>();
    for (ColumnMetadata def : metadata.columns()) {
        ColumnIdentifier identifier = def.name;
        boolean includeDef = included.isEmpty() || included.contains(identifier);
        if (includeDef && def.isStatic()) {
            throw new InvalidRequestException(String.format("Unable to include static column '%s' which would be included by Materialized View SELECT * statement", identifier));
        }
        boolean defInTargetPrimaryKey = targetClusteringColumns.contains(identifier) || targetPartitionKeys.contains(identifier);
        if (includeDef && !defInTargetPrimaryKey) {
            includedColumns.add(identifier);
        }
        if (!def.isPrimaryKeyColumn())
            continue;
        if (!defInTargetPrimaryKey) {
            if (missingClusteringColumns)
                columnNames.append(',');
            else
                missingClusteringColumns = true;
            columnNames.append(identifier);
        }
    }
    if (missingClusteringColumns)
        throw new InvalidRequestException(String.format("Cannot create Materialized View %s without primary key columns from base %s (%s)", columnFamily(), baseName.getColumnFamily(), columnNames.toString()));
    if (targetPartitionKeys.isEmpty())
        throw new InvalidRequestException("Must select at least a column for a Materialized View");
    if (targetClusteringColumns.isEmpty())
        throw new InvalidRequestException("No columns are defined for Materialized View other than primary key");
    TableParams params = properties.properties.asNewTableParams();
    if (params.defaultTimeToLive > 0) {
        throw new InvalidRequestException("Cannot set default_time_to_live for a materialized view. " + "Data in a materialized view always expire at the same time than " + "the corresponding data in the parent table.");
    }
    TableMetadata.Builder builder = TableMetadata.builder(keyspace(), columnFamily(), properties.properties.getId()).isView(true).params(params);
    add(metadata, targetPartitionKeys, builder::addPartitionKeyColumn);
    add(metadata, targetClusteringColumns, builder::addClusteringColumn);
    add(metadata, includedColumns, builder::addRegularColumn);
    ViewMetadata definition = new ViewMetadata(keyspace(), columnFamily(), metadata.id, metadata.name, included.isEmpty(), rawSelect, whereClauseText, builder.build());
    try {
        MigrationManager.announceNewView(definition, isLocalOnly);
        return new Event.SchemaChange(Event.SchemaChange.Change.CREATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
    } catch (AlreadyExistsException e) {
        if (ifNotExists)
            return null;
        throw e;
    }
}
Also used : ClientState(org.apache.cassandra.service.ClientState) RawSelector(org.apache.cassandra.cql3.selection.RawSelector) ColumnMetadata(org.apache.cassandra.schema.ColumnMetadata) Selectable(org.apache.cassandra.cql3.selection.Selectable) InvalidRequestException(org.apache.cassandra.exceptions.InvalidRequestException) StatementRestrictions(org.apache.cassandra.cql3.restrictions.StatementRestrictions) ViewMetadata(org.apache.cassandra.schema.ViewMetadata) TableMetadata(org.apache.cassandra.schema.TableMetadata) DurationType(org.apache.cassandra.db.marshal.DurationType) TableParams(org.apache.cassandra.schema.TableParams) AlreadyExistsException(org.apache.cassandra.exceptions.AlreadyExistsException)

Example 12 with org.apache.cassandra.cql3.statements

use of org.apache.cassandra.cql3.statements in project cassandra by apache.

the class BatchMessage method execute.

@Override
protected Message.Response execute(QueryState state, long queryStartNanoTime, boolean traceRequest) {
    List<QueryHandler.Prepared> prepared = null;
    try {
        if (traceRequest)
            traceQuery(state);
        QueryHandler handler = ClientState.getCQLQueryHandler();
        prepared = new ArrayList<>(queryOrIdList.size());
        for (int i = 0; i < queryOrIdList.size(); i++) {
            Object query = queryOrIdList.get(i);
            QueryHandler.Prepared p;
            if (query instanceof String) {
                p = QueryProcessor.parseAndPrepare((String) query, state.getClientState().cloneWithKeyspaceIfSet(options.getKeyspace()), false);
            } else {
                p = handler.getPrepared((MD5Digest) query);
                if (null == p)
                    throw new PreparedQueryNotFoundException((MD5Digest) query);
            }
            List<ByteBuffer> queryValues = values.get(i);
            if (queryValues.size() != p.statement.getBindVariables().size())
                throw new InvalidRequestException(String.format("There were %d markers(?) in CQL but %d bound variables", p.statement.getBindVariables().size(), queryValues.size()));
            prepared.add(p);
        }
        BatchQueryOptions batchOptions = BatchQueryOptions.withPerStatementVariables(options, values, queryOrIdList);
        List<ModificationStatement> statements = new ArrayList<>(prepared.size());
        List<String> queries = QueryEvents.instance.hasListeners() ? new ArrayList<>(prepared.size()) : null;
        for (int i = 0; i < prepared.size(); i++) {
            CQLStatement statement = prepared.get(i).statement;
            if (queries != null)
                queries.add(prepared.get(i).rawCQLStatement);
            batchOptions.prepareStatement(i, statement.getBindVariables());
            if (!(statement instanceof ModificationStatement))
                throw new InvalidRequestException("Invalid statement in batch: only UPDATE, INSERT and DELETE statements are allowed.");
            statements.add((ModificationStatement) statement);
        }
        // Note: It's ok at this point to pass a bogus value for the number of bound terms in the BatchState ctor
        // (and no value would be really correct, so we prefer passing a clearly wrong one).
        BatchStatement batch = new BatchStatement(batchType, VariableSpecifications.empty(), statements, Attributes.none());
        long queryTime = currentTimeMillis();
        Message.Response response = handler.processBatch(batch, state, batchOptions, getCustomPayload(), queryStartNanoTime);
        if (queries != null)
            QueryEvents.instance.notifyBatchSuccess(batchType, statements, queries, values, options, state, queryTime, response);
        return response;
    } catch (Exception e) {
        QueryEvents.instance.notifyBatchFailure(prepared, batchType, queryOrIdList, values, options, state, e);
        JVMStabilityInspector.inspectThrowable(e);
        return ErrorMessage.fromException(e);
    }
}
Also used : CQLStatement(org.apache.cassandra.cql3.CQLStatement) QueryHandler(org.apache.cassandra.cql3.QueryHandler) Message(org.apache.cassandra.transport.Message) BatchQueryOptions(org.apache.cassandra.cql3.BatchQueryOptions) ModificationStatement(org.apache.cassandra.cql3.statements.ModificationStatement) ArrayList(java.util.ArrayList) PreparedQueryNotFoundException(org.apache.cassandra.exceptions.PreparedQueryNotFoundException) ByteBuffer(java.nio.ByteBuffer) PreparedQueryNotFoundException(org.apache.cassandra.exceptions.PreparedQueryNotFoundException) InvalidRequestException(org.apache.cassandra.exceptions.InvalidRequestException) ProtocolException(org.apache.cassandra.transport.ProtocolException) MD5Digest(org.apache.cassandra.utils.MD5Digest) BatchStatement(org.apache.cassandra.cql3.statements.BatchStatement) InvalidRequestException(org.apache.cassandra.exceptions.InvalidRequestException)

Example 13 with org.apache.cassandra.cql3.statements

use of org.apache.cassandra.cql3.statements in project cassandra by apache.

the class UFIdentificationTest method testBatchStatementWithConditions.

@Test
public void testBatchStatementWithConditions() throws Throwable {
    List<ModificationStatement> statements = new ArrayList<>();
    statements.add(modificationStatement(cql("UPDATE %s SET i_val = %s WHERE key=0 AND i_cc=0 and t_cc='foo' IF l_val = %s", functionCall(iFunc, "0"), functionCall(lFunc, "[1]"))));
    statements.add(modificationStatement(cql("UPDATE %s SET i_val = %s WHERE key=0 AND i_cc=1 and t_cc='foo' IF s_val = %s", functionCall(iFunc, "0"), functionCall(sFunc, "{1}"))));
    BatchStatement batch = new BatchStatement(BatchStatement.Type.LOGGED, VariableSpecifications.empty(), statements, Attributes.none());
    assertFunctions(batch, iFunc, lFunc, sFunc);
}
Also used : ModificationStatement(org.apache.cassandra.cql3.statements.ModificationStatement) BatchStatement(org.apache.cassandra.cql3.statements.BatchStatement) Test(org.junit.Test)

Example 14 with org.apache.cassandra.cql3.statements

use of org.apache.cassandra.cql3.statements in project cassandra by apache.

the class UFAuthTest method testBatchStatement.

@Test
public void testBatchStatement() throws Throwable {
    List<ModificationStatement> statements = new ArrayList<>();
    List<String> functions = new ArrayList<>();
    for (int i = 0; i < 3; i++) {
        String functionName = createSimpleFunction();
        ModificationStatement stmt = (ModificationStatement) getStatement(String.format("INSERT INTO %s (k, v1, v2) " + "VALUES (%s, %s, %s)", KEYSPACE + "." + currentTable(), i, i, functionCall(functionName)));
        functions.add(functionName);
        statements.add(stmt);
    }
    BatchStatement batch = new BatchStatement(BatchStatement.Type.LOGGED, VariableSpecifications.empty(), statements, Attributes.none());
    assertUnauthorized(batch, functions);
    grantExecuteOnFunction(functions.get(0));
    assertUnauthorized(batch, functions.subList(1, functions.size()));
    grantExecuteOnFunction(functions.get(1));
    assertUnauthorized(batch, functions.subList(2, functions.size()));
    grantExecuteOnFunction(functions.get(2));
    batch.authorize(clientState);
}
Also used : ModificationStatement(org.apache.cassandra.cql3.statements.ModificationStatement) BatchStatement(org.apache.cassandra.cql3.statements.BatchStatement) Test(org.junit.Test)

Aggregations

BatchStatement (org.apache.cassandra.cql3.statements.BatchStatement)8 ArrayList (java.util.ArrayList)6 ModificationStatement (org.apache.cassandra.cql3.statements.ModificationStatement)6 Test (org.junit.Test)6 InvalidRequestException (org.apache.cassandra.exceptions.InvalidRequestException)4 ByteBuffer (java.nio.ByteBuffer)3 UUID (java.util.UUID)2 CQLStatement (org.apache.cassandra.cql3.CQLStatement)2 UntypedResultSet (org.apache.cassandra.cql3.UntypedResultSet)2 PreparedQueryNotFoundException (org.apache.cassandra.exceptions.PreparedQueryNotFoundException)2 ClientState (org.apache.cassandra.service.ClientState)2 MD5Digest (org.apache.cassandra.utils.MD5Digest)2 SimpleStatement (com.datastax.driver.core.SimpleStatement)1 Statement (com.datastax.driver.core.Statement)1 ImmutableMap (com.google.common.collect.ImmutableMap)1 List (java.util.List)1 AssignmentTestable (org.apache.cassandra.cql3.AssignmentTestable)1 BatchQueryOptions (org.apache.cassandra.cql3.BatchQueryOptions)1 QueryHandler (org.apache.cassandra.cql3.QueryHandler)1 FunctionName (org.apache.cassandra.cql3.functions.FunctionName)1