All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.cassandra.cql3.statements.DeleteStatement Maven / Gradle / Ivy

There is a newer version: 2.2.18-2.2.18-1.170.1-rc1
Show newest version
/*
 * 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.statements;

import java.nio.ByteBuffer;
import java.util.*;

import com.google.common.collect.Iterators;

import org.apache.cassandra.cql3.*;
import org.apache.cassandra.cql3.restrictions.Restriction;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.db.*;
import org.apache.cassandra.db.composites.Composite;
import org.apache.cassandra.exceptions.*;
import org.apache.cassandra.utils.Pair;

/**
 * A DELETE parsed from a CQL query statement.
 */
public class DeleteStatement extends ModificationStatement
{
    private DeleteStatement(StatementType type, int boundTerms, CFMetaData cfm, Attributes attrs)
    {
        super(type, boundTerms, cfm, attrs);
    }

    public boolean requireFullClusteringKey()
    {
        return false;
    }

    public void addUpdateForKey(ColumnFamily cf, ByteBuffer key, Composite prefix, UpdateParameters params)
    throws InvalidRequestException
    {
        List deletions = getOperations();

        if (deletions.isEmpty())
        {
            // We delete the slice selected by the prefix.
            // However, for performance reasons, we distinguish 2 cases:
            //   - It's a full internal row delete
            //   - It's a full cell name (i.e it's a dense layout and the prefix is full)
            if (prefix.isEmpty())
            {
                // No columns specified, delete the row
                cf.delete(new DeletionInfo(params.timestamp, params.localDeletionTime));
            }
            else if (cfm.comparator.isDense() && prefix.size() == cfm.clusteringColumns().size())
            {
                cf.addAtom(params.makeTombstone(cfm.comparator.create(prefix, null)));
            }
            else
            {
                cf.addAtom(params.makeRangeTombstone(prefix.slice()));
            }
        }
        else
        {
            for (Operation op : deletions)
                op.execute(key, cf, prefix, params);
        }
    }

    protected void validateWhereClauseForConditions() throws InvalidRequestException
    {
        boolean onlyHasConditionsOnStaticColumns = hasStaticConditions() && !hasRegularConditions();

        // In general, we can't delete specific columns if not all clustering columns have been specified.
        // However, if we delete only static colums, it's fine since we won't really use the prefix anyway.
        Iterator iterator = appliesOnlyToStaticColumns()
                                              ? cfm.partitionKeyColumns().iterator()
                                              : Iterators.concat(cfm.partitionKeyColumns().iterator(), cfm.clusteringColumns().iterator());
        while (iterator.hasNext())
        {
            ColumnDefinition def = iterator.next();
            Restriction restriction = processedKeys.get(def.name);
            if (restriction == null || !(restriction.isEQ() || restriction.isIN()))
            {
                if (onlyHasConditionsOnStaticColumns)
                {
                    for (Operation oper : getOperations())
                    {
                        if (!oper.column.isStatic())
                        {
                            throw new InvalidRequestException(String.format("Primary key column '%s' must be specified in order to delete column '%s'",
                                                                            def.name,
                                                                            oper.column.name));
                        }
                    }
                }

                throw new InvalidRequestException(
                        String.format("DELETE statements must restrict all %s KEY columns with equality relations in order " +
                                      "to use IF conditions%s, but column '%s' is not restricted",
                                      onlyHasConditionsOnStaticColumns ? "PARTITION" : "PRIMARY",
                                      onlyHasConditionsOnStaticColumns ? " on static columns" : "", def.name));
            }
        }
    }

    public static class Parsed extends ModificationStatement.Parsed
    {
        private final List deletions;
        private final List whereClause;

        public Parsed(CFName name,
                      Attributes.Raw attrs,
                      List deletions,
                      List whereClause,
                      List> conditions,
                      boolean ifExists)
        {
            super(name, attrs, conditions, false, ifExists);
            this.deletions = deletions;
            this.whereClause = whereClause;
        }

        protected ModificationStatement prepareInternal(CFMetaData cfm, VariableSpecifications boundNames, Attributes attrs) throws InvalidRequestException
        {
            DeleteStatement stmt = new DeleteStatement(ModificationStatement.StatementType.DELETE, boundNames.size(), cfm, attrs);

            for (Operation.RawDeletion deletion : deletions)
            {
                ColumnIdentifier id = deletion.affectedColumn().prepare(cfm);
                ColumnDefinition def = cfm.getColumnDefinition(id);
                if (def == null)
                    throw new InvalidRequestException(String.format("Unknown identifier %s", id));

                // 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 (def.isPrimaryKeyColumn())
                    throw new InvalidRequestException(String.format("Invalid identifier %s for deletion (should not be a PRIMARY KEY part)", def.name));

                Operation op = deletion.prepare(cfm.ksName, def);
                op.collectMarkerSpecification(boundNames);
                stmt.addOperation(op);
            }

            stmt.processWhereClause(whereClause, boundNames);
            return stmt;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy