public Collection<RowMutation> getMutations(
      List<ByteBuffer> variables, boolean local, ConsistencyLevel cl, long now)
      throws RequestExecutionException, RequestValidationException {
    // keys
    List<ByteBuffer> keys = UpdateStatement.buildKeyNames(cfDef, processedKeys, variables);

    // columns
    ColumnNameBuilder builder = cfDef.getColumnNameBuilder();
    CFDefinition.Name firstEmpty =
        UpdateStatement.buildColumnNames(cfDef, processedKeys, builder, variables, false);

    boolean fullKey = builder.componentCount() == cfDef.columns.size();
    boolean isRange = cfDef.isCompact ? !fullKey : (!fullKey || toRemove.isEmpty());

    if (!toRemove.isEmpty() && isRange)
      throw new InvalidRequestException(
          String.format(
              "Missing mandatory PRIMARY KEY part %s since %s specified",
              firstEmpty, toRemove.iterator().next().left));

    // Lists DISCARD operation incurs a read. Do that now.
    Set<ByteBuffer> toRead = null;
    for (Pair<CFDefinition.Name, Term> p : toRemove) {
      CFDefinition.Name name = p.left;
      Term value = p.right;

      if ((name.type instanceof ListType) && value != null) {
        if (toRead == null) toRead = new TreeSet<ByteBuffer>(UTF8Type.instance);
        toRead.add(name.name.key);
      }
    }

    Map<ByteBuffer, ColumnGroupMap> rows =
        toRead != null
            ? readRows(keys, builder, toRead, (CompositeType) cfDef.cfm.comparator, local, cl)
            : null;

    Collection<RowMutation> rowMutations = new ArrayList<RowMutation>(keys.size());
    UpdateParameters params = new UpdateParameters(variables, getTimestamp(now), -1);

    for (ByteBuffer key : keys)
      rowMutations.add(
          mutationForKey(
              cfDef, key, builder, isRange, params, rows == null ? null : rows.get(key)));

    return rowMutations;
  }
  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 (Selector column : columns) {
      CFDefinition.Name name = cfDef.get(column.id());
      if (name == null)
        throw new InvalidRequestException(String.format("Unknown identifier %s", column));

      // 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)", column));

      if (column.key() != null) {
        if (name.type instanceof ListType) {
          if (column.key().isBindMarker())
            boundNames[column.key().bindIndex] = ListOperation.indexSpecOf(name);
        } else if (name.type instanceof MapType) {
          if (column.key().isBindMarker())
            boundNames[column.key().bindIndex] = MapOperation.keySpecOf(name, (MapType) name.type);
        } else {
          throw new InvalidRequestException(
              String.format(
                  "Invalid selection %s since %s is neither a list or a map", column, column.id()));
        }
      }

      toRemove.add(Pair.create(name, column.key()));
    }

    return new ParsedStatement.Prepared(this, Arrays.<ColumnSpecification>asList(boundNames));
  }
  public void announceMigration() throws RequestValidationException {
    CFMetaData meta = validateColumnFamily(keyspace(), columnFamily());
    CFMetaData cfm = meta.clone();

    CFDefinition cfDef = meta.getCfDef();
    CFDefinition.Name name = columnName == null ? null : cfDef.get(columnName);
    switch (oType) {
      case ADD:
        if (cfDef.isCompact)
          throw new InvalidRequestException("Cannot add new column to a compact CF");
        if (name != null) {
          switch (name.kind) {
            case KEY_ALIAS:
            case COLUMN_ALIAS:
              throw new InvalidRequestException(
                  String.format(
                      "Invalid column name %s because it conflicts with a PRIMARY KEY part",
                      columnName));
            case COLUMN_METADATA:
              throw new InvalidRequestException(
                  String.format(
                      "Invalid column name %s because it conflicts with an existing column",
                      columnName));
          }
        }

        AbstractType<?> type = validator.getType();
        if (type instanceof CollectionType) {
          if (!cfDef.isComposite)
            throw new InvalidRequestException(
                "Cannot use collection types with non-composite PRIMARY KEY");
          if (cfDef.cfm.isSuper())
            throw new InvalidRequestException(
                "Cannot use collection types with Super column family");

          Map<ByteBuffer, CollectionType> collections =
              cfDef.hasCollections
                  ? new HashMap<ByteBuffer, CollectionType>(cfDef.getCollectionType().defined)
                  : new HashMap<ByteBuffer, CollectionType>();

          collections.put(columnName.key, (CollectionType) type);
          ColumnToCollectionType newColType = ColumnToCollectionType.getInstance(collections);
          List<AbstractType<?>> ctypes =
              new ArrayList<AbstractType<?>>(((CompositeType) cfm.comparator).types);
          if (cfDef.hasCollections) ctypes.set(ctypes.size() - 1, newColType);
          else ctypes.add(newColType);
          cfm.comparator = CompositeType.getInstance(ctypes);
        }

        Integer componentIndex =
            cfDef.isComposite
                ? ((CompositeType) meta.comparator).types.size() - (cfDef.hasCollections ? 2 : 1)
                : null;
        cfm.addColumnDefinition(ColumnDefinition.regularDef(columnName.key, type, componentIndex));
        break;

      case ALTER:
        if (name == null)
          throw new InvalidRequestException(
              String.format("Column %s was not found in table %s", columnName, columnFamily()));

        switch (name.kind) {
          case KEY_ALIAS:
            AbstractType<?> newType = validator.getType();
            if (newType instanceof CounterColumnType)
              throw new InvalidRequestException(
                  String.format(
                      "counter type is not supported for PRIMARY KEY part %s", columnName));
            if (cfDef.hasCompositeKey) {
              List<AbstractType<?>> newTypes =
                  new ArrayList<AbstractType<?>>(((CompositeType) cfm.getKeyValidator()).types);
              newTypes.set(name.position, newType);
              cfm.keyValidator(CompositeType.getInstance(newTypes));
            } else {
              cfm.keyValidator(newType);
            }
            break;
          case COLUMN_ALIAS:
            assert cfDef.isComposite;
            List<AbstractType<?>> newTypes =
                new ArrayList<AbstractType<?>>(((CompositeType) cfm.comparator).types);
            newTypes.set(name.position, validator.getType());
            cfm.comparator = CompositeType.getInstance(newTypes);
            break;
          case VALUE_ALIAS:
            cfm.defaultValidator(validator.getType());
            break;
          case COLUMN_METADATA:
            ColumnDefinition column = cfm.getColumnDefinition(columnName.key);
            column.setValidator(validator.getType());
            break;
        }
        break;

      case DROP:
        if (cfDef.isCompact)
          throw new InvalidRequestException("Cannot drop columns from a compact CF");
        if (name == null)
          throw new InvalidRequestException(
              String.format("Column %s was not found in table %s", columnName, columnFamily()));

        switch (name.kind) {
          case KEY_ALIAS:
          case COLUMN_ALIAS:
            throw new InvalidRequestException(
                String.format("Cannot drop PRIMARY KEY part %s", columnName));
          case COLUMN_METADATA:
            ColumnDefinition toDelete = null;
            for (ColumnDefinition columnDef : cfm.regularColumns()) {
              if (columnDef.name.equals(columnName.key)) toDelete = columnDef;
            }
            assert toDelete != null;
            cfm.removeColumnDefinition(toDelete);
            break;
        }
        break;
      case OPTS:
        if (cfProps == null)
          throw new InvalidRequestException(
              String.format("ALTER COLUMNFAMILY WITH invoked, but no parameters found"));

        cfProps.validate();
        cfProps.applyToCFMetadata(cfm);
        break;
      case RENAME:
        for (Map.Entry<ColumnIdentifier, ColumnIdentifier> entry : renames.entrySet()) {
          ColumnIdentifier from = entry.getKey();
          ColumnIdentifier to = entry.getValue();
          cfm.renameColumn(from.key, from.toString(), to.key, to.toString());
        }
        break;
    }

    MigrationManager.announceColumnFamilyUpdate(cfm, false);
  }