Search in sources :

Example 1 with DroppedColumn

use of org.apache.cassandra.schema.DroppedColumn in project cassandra by apache.

the class AlterTableStatement method announceMigration.

public Event.SchemaChange announceMigration(QueryState queryState, boolean isLocalOnly) throws RequestValidationException {
    TableMetadata current = Schema.instance.validateTable(keyspace(), columnFamily());
    if (current.isView())
        throw new InvalidRequestException("Cannot use ALTER TABLE on Materialized View");
    TableMetadata.Builder builder = current.unbuild();
    ColumnIdentifier columnName = null;
    ColumnMetadata def = null;
    CQL3Type.Raw dataType = null;
    boolean isStatic = false;
    CQL3Type validator = null;
    List<ViewMetadata> viewUpdates = new ArrayList<>();
    Iterable<ViewMetadata> views = View.findAll(keyspace(), columnFamily());
    switch(oType) {
        case ALTER:
            throw new InvalidRequestException("Altering of types is not allowed");
        case ADD:
            if (current.isDense())
                throw new InvalidRequestException("Cannot add new column to a COMPACT STORAGE table");
            for (AlterTableStatementColumn colData : colNameList) {
                columnName = colData.getColumnName().getIdentifier(current);
                def = builder.getColumn(columnName);
                dataType = colData.getColumnType();
                assert dataType != null;
                isStatic = colData.getStaticType();
                validator = dataType.prepare(keyspace());
                if (isStatic) {
                    if (!current.isCompound())
                        throw new InvalidRequestException("Static columns are not allowed in COMPACT STORAGE tables");
                    if (current.clusteringColumns().isEmpty())
                        throw new InvalidRequestException("Static columns are only useful (and thus allowed) if the table has at least one clustering column");
                }
                if (def != null) {
                    switch(def.kind) {
                        case PARTITION_KEY:
                        case CLUSTERING:
                            throw new InvalidRequestException(String.format("Invalid column name %s because it conflicts with a PRIMARY KEY part", columnName));
                        default:
                            throw new InvalidRequestException(String.format("Invalid column name %s because it conflicts with an existing column", columnName));
                    }
                }
                // Cannot re-add a dropped counter column. See #7831.
                if (current.isCounter() && current.getDroppedColumn(columnName.bytes) != null)
                    throw new InvalidRequestException(String.format("Cannot re-add previously dropped counter column %s", columnName));
                AbstractType<?> type = validator.getType();
                if (type.isCollection() && type.isMultiCell()) {
                    if (!current.isCompound())
                        throw new InvalidRequestException("Cannot use non-frozen collections in COMPACT STORAGE tables");
                    if (current.isSuper())
                        throw new InvalidRequestException("Cannot use non-frozen collections with super column families");
                    // If there used to be a non-frozen collection column with the same name (that has been dropped),
                    // we could still have some data using the old type, and so we can't allow adding a collection
                    // with the same name unless the types are compatible (see #6276).
                    DroppedColumn dropped = current.droppedColumns.get(columnName.bytes);
                    if (dropped != null && dropped.column.type instanceof CollectionType && dropped.column.type.isMultiCell() && !type.isCompatibleWith(dropped.column.type)) {
                        String message = String.format("Cannot add a collection with the name %s because a collection with the same name" + " and a different type (%s) has already been used in the past", columnName, dropped.column.type.asCQL3Type());
                        throw new InvalidRequestException(message);
                    }
                }
                builder.addColumn(isStatic ? ColumnMetadata.staticColumn(current, columnName.bytes, type) : ColumnMetadata.regularColumn(current, columnName.bytes, type));
                // as well
                if (!isStatic)
                    for (ViewMetadata view : views) if (view.includeAllColumns)
                        viewUpdates.add(view.withAddedRegularColumn(ColumnMetadata.regularColumn(view.metadata, columnName.bytes, type)));
            }
            break;
        case DROP:
            if (!current.isCQLTable())
                throw new InvalidRequestException("Cannot drop columns from a non-CQL3 table");
            for (AlterTableStatementColumn colData : colNameList) {
                columnName = colData.getColumnName().getIdentifier(current);
                def = builder.getColumn(columnName);
                if (def == null)
                    throw new InvalidRequestException(String.format("Column %s was not found in table %s", columnName, columnFamily()));
                switch(def.kind) {
                    case PARTITION_KEY:
                    case CLUSTERING:
                        throw new InvalidRequestException(String.format("Cannot drop PRIMARY KEY part %s", columnName));
                    case REGULAR:
                    case STATIC:
                        builder.removeRegularOrStaticColumn(def.name);
                        builder.recordColumnDrop(def, deleteTimestamp == null ? queryState.getTimestamp() : deleteTimestamp);
                        break;
                }
                // If the dropped column is required by any secondary indexes
                // we reject the operation, as the indexes must be dropped first
                Indexes allIndexes = current.indexes;
                if (!allIndexes.isEmpty()) {
                    ColumnFamilyStore store = Keyspace.openAndGetStore(current);
                    Set<IndexMetadata> dependentIndexes = store.indexManager.getDependentIndexes(def);
                    if (!dependentIndexes.isEmpty()) {
                        throw new InvalidRequestException(String.format("Cannot drop column %s because it has " + "dependent secondary indexes (%s)", def, dependentIndexes.stream().map(i -> i.name).collect(Collectors.joining(","))));
                    }
                }
                // If a column is dropped which is included in a view, we don't allow the drop to take place.
                boolean rejectAlter = false;
                StringBuilder viewNames = new StringBuilder();
                for (ViewMetadata view : views) {
                    if (!view.includes(columnName))
                        continue;
                    if (rejectAlter)
                        viewNames.append(',');
                    rejectAlter = true;
                    viewNames.append(view.name);
                }
                if (rejectAlter)
                    throw new InvalidRequestException(String.format("Cannot drop column %s, depended on by materialized views (%s.{%s})", columnName.toString(), keyspace(), viewNames.toString()));
            }
            break;
        case OPTS:
            if (attrs == null)
                throw new InvalidRequestException("ALTER TABLE WITH invoked, but no parameters found");
            attrs.validate();
            TableParams params = attrs.asAlteredTableParams(current.params);
            if (!Iterables.isEmpty(views) && params.gcGraceSeconds == 0) {
                throw new InvalidRequestException("Cannot alter gc_grace_seconds of the base table of a " + "materialized view to 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.");
            }
            if (current.isCounter() && params.defaultTimeToLive > 0)
                throw new InvalidRequestException("Cannot set default_time_to_live on a table with counters");
            builder.params(params);
            break;
        case RENAME:
            for (Map.Entry<ColumnMetadata.Raw, ColumnMetadata.Raw> entry : renames.entrySet()) {
                ColumnIdentifier from = entry.getKey().getIdentifier(current);
                ColumnIdentifier to = entry.getValue().getIdentifier(current);
                def = current.getColumn(from);
                if (def == null)
                    throw new InvalidRequestException(String.format("Cannot rename unknown column %s in table %s", from, current.name));
                if (current.getColumn(to) != null)
                    throw new InvalidRequestException(String.format("Cannot rename column %s to %s in table %s; another column of that name already exist", from, to, current.name));
                if (!def.isPrimaryKeyColumn())
                    throw new InvalidRequestException(String.format("Cannot rename non PRIMARY KEY part %s", from));
                if (!current.indexes.isEmpty()) {
                    ColumnFamilyStore store = Keyspace.openAndGetStore(current);
                    Set<IndexMetadata> dependentIndexes = store.indexManager.getDependentIndexes(def);
                    if (!dependentIndexes.isEmpty())
                        throw new InvalidRequestException(String.format("Cannot rename column %s because it has " + "dependent secondary indexes (%s)", from, dependentIndexes.stream().map(i -> i.name).collect(Collectors.joining(","))));
                }
                builder.renamePrimaryKeyColumn(from, to);
                // If the view includes a renamed column, it must be renamed in the view table and the definition.
                for (ViewMetadata view : views) {
                    if (!view.includes(from))
                        continue;
                    ColumnIdentifier viewFrom = entry.getKey().getIdentifier(view.metadata);
                    ColumnIdentifier viewTo = entry.getValue().getIdentifier(view.metadata);
                    viewUpdates.add(view.renamePrimaryKeyColumn(viewFrom, viewTo));
                }
            }
            break;
    }
    // FIXME: Should really be a single announce for the table and views.
    MigrationManager.announceTableUpdate(builder.build(), isLocalOnly);
    for (ViewMetadata viewUpdate : viewUpdates) MigrationManager.announceViewUpdate(viewUpdate, isLocalOnly);
    return new Event.SchemaChange(Event.SchemaChange.Change.UPDATED, Event.SchemaChange.Target.TABLE, keyspace(), columnFamily());
}
Also used : DroppedColumn(org.apache.cassandra.schema.DroppedColumn) TableParams(org.apache.cassandra.schema.TableParams) java.util(java.util) Iterables(com.google.common.collect.Iterables) ColumnMetadata(org.apache.cassandra.schema.ColumnMetadata) IndexMetadata(org.apache.cassandra.schema.IndexMetadata) QueryState(org.apache.cassandra.service.QueryState) Permission(org.apache.cassandra.auth.Permission) ClientState(org.apache.cassandra.service.ClientState) AbstractType(org.apache.cassandra.db.marshal.AbstractType) Collectors(java.util.stream.Collectors) ViewMetadata(org.apache.cassandra.schema.ViewMetadata) org.apache.cassandra.cql3(org.apache.cassandra.cql3) Indexes(org.apache.cassandra.schema.Indexes) Schema(org.apache.cassandra.schema.Schema) View(org.apache.cassandra.db.view.View) MigrationManager(org.apache.cassandra.schema.MigrationManager) ColumnFamilyStore(org.apache.cassandra.db.ColumnFamilyStore) org.apache.cassandra.exceptions(org.apache.cassandra.exceptions) TableMetadata(org.apache.cassandra.schema.TableMetadata) Keyspace(org.apache.cassandra.db.Keyspace) CollectionType(org.apache.cassandra.db.marshal.CollectionType) Event(org.apache.cassandra.transport.Event) ColumnMetadata(org.apache.cassandra.schema.ColumnMetadata) CollectionType(org.apache.cassandra.db.marshal.CollectionType) DroppedColumn(org.apache.cassandra.schema.DroppedColumn) IndexMetadata(org.apache.cassandra.schema.IndexMetadata) ViewMetadata(org.apache.cassandra.schema.ViewMetadata) TableMetadata(org.apache.cassandra.schema.TableMetadata) TableParams(org.apache.cassandra.schema.TableParams) Indexes(org.apache.cassandra.schema.Indexes) ColumnFamilyStore(org.apache.cassandra.db.ColumnFamilyStore)

Example 2 with DroppedColumn

use of org.apache.cassandra.schema.DroppedColumn in project cassandra by apache.

the class BTreeRow method filter.

public Row filter(ColumnFilter filter, DeletionTime activeDeletion, boolean setActiveDeletionToRow, TableMetadata metadata) {
    Map<ByteBuffer, DroppedColumn> droppedColumns = metadata.droppedColumns;
    boolean mayFilterColumns = !filter.fetchesAllColumns(isStatic());
    boolean mayHaveShadowed = activeDeletion.supersedes(deletion.time());
    if (!mayFilterColumns && !mayHaveShadowed && droppedColumns.isEmpty())
        return this;
    LivenessInfo newInfo = primaryKeyLivenessInfo;
    Deletion newDeletion = deletion;
    if (mayHaveShadowed) {
        if (activeDeletion.deletes(newInfo.timestamp()))
            newInfo = LivenessInfo.EMPTY;
        // note that mayHaveShadowed means the activeDeletion shadows the row deletion. So if don't have setActiveDeletionToRow,
        // the row deletion is shadowed and we shouldn't return it.
        newDeletion = setActiveDeletionToRow ? Deletion.regular(activeDeletion) : Deletion.LIVE;
    }
    Columns columns = filter.fetchedColumns().columns(isStatic());
    Predicate<ColumnMetadata> inclusionTester = columns.inOrderInclusionTester();
    Predicate<ColumnMetadata> queriedByUserTester = filter.queriedColumns().columns(isStatic()).inOrderInclusionTester();
    final LivenessInfo rowLiveness = newInfo;
    return transformAndFilter(newInfo, newDeletion, (cd) -> {
        ColumnMetadata column = cd.column();
        if (!inclusionTester.test(column))
            return null;
        DroppedColumn dropped = droppedColumns.get(column.name.bytes);
        if (column.isComplex())
            return ((ComplexColumnData) cd).filter(filter, mayHaveShadowed ? activeDeletion : DeletionTime.LIVE, dropped, rowLiveness);
        Cell cell = (Cell) cd;
        // We include the cell unless it is 1) shadowed, 2) for a dropped column or 3) skippable.
        // And a cell is skippable if it is for a column that is not queried by the user and its timestamp
        // is lower than the row timestamp (see #10657 or SerializationHelper.includes() for details).
        boolean isForDropped = dropped != null && cell.timestamp() <= dropped.droppedTime;
        boolean isShadowed = mayHaveShadowed && activeDeletion.deletes(cell);
        boolean isSkippable = !queriedByUserTester.test(column) && cell.timestamp() < rowLiveness.timestamp();
        return isForDropped || isShadowed || isSkippable ? null : cell;
    });
}
Also used : ColumnMetadata(org.apache.cassandra.schema.ColumnMetadata) DroppedColumn(org.apache.cassandra.schema.DroppedColumn) ByteBuffer(java.nio.ByteBuffer)

Aggregations

ColumnMetadata (org.apache.cassandra.schema.ColumnMetadata)2 DroppedColumn (org.apache.cassandra.schema.DroppedColumn)2 Iterables (com.google.common.collect.Iterables)1 ByteBuffer (java.nio.ByteBuffer)1 java.util (java.util)1 Collectors (java.util.stream.Collectors)1 Permission (org.apache.cassandra.auth.Permission)1 org.apache.cassandra.cql3 (org.apache.cassandra.cql3)1 ColumnFamilyStore (org.apache.cassandra.db.ColumnFamilyStore)1 Keyspace (org.apache.cassandra.db.Keyspace)1 AbstractType (org.apache.cassandra.db.marshal.AbstractType)1 CollectionType (org.apache.cassandra.db.marshal.CollectionType)1 View (org.apache.cassandra.db.view.View)1 org.apache.cassandra.exceptions (org.apache.cassandra.exceptions)1 IndexMetadata (org.apache.cassandra.schema.IndexMetadata)1 Indexes (org.apache.cassandra.schema.Indexes)1 MigrationManager (org.apache.cassandra.schema.MigrationManager)1 Schema (org.apache.cassandra.schema.Schema)1 TableMetadata (org.apache.cassandra.schema.TableMetadata)1 TableParams (org.apache.cassandra.schema.TableParams)1