Ejemplo n.º 1
0
  public CFDefinition(CFMetaData cfm) {
    this.cfm = cfm;

    if (cfm.getKeyValidator() instanceof CompositeType) {
      this.hasCompositeKey = true;
      CompositeType keyComposite = (CompositeType) cfm.getKeyValidator();
      assert keyComposite.types.size() > 1;
      for (int i = 0; i < keyComposite.types.size(); i++) {
        ColumnIdentifier id = getKeyId(cfm, i);
        this.keys.put(
            id,
            new Name(
                cfm.ksName, cfm.cfName, id, Name.Kind.KEY_ALIAS, i, keyComposite.types.get(i)));
      }
    } else {
      this.hasCompositeKey = false;
      ColumnIdentifier id = getKeyId(cfm, 0);
      this.keys.put(
          id, new Name(cfm.ksName, cfm.cfName, id, Name.Kind.KEY_ALIAS, 0, cfm.getKeyValidator()));
    }

    if (cfm.comparator instanceof CompositeType) {
      this.isComposite = true;
      CompositeType composite = (CompositeType) cfm.comparator;
      /*
       * We are a "sparse" composite, i.e. a non-compact one, if either:
       *   - the last type of the composite is a ColumnToCollectionType
       *   - or we have one less alias than of composite types and the last type is UTF8Type.
       *
       * Note that this is not perfect: if someone upgrading from thrift "renames" all but
       * the last column alias, the cf will be considered "sparse" and he will be stuck with
       * that even though that might not be what he wants. But the simple workaround is
       * for that user to rename all the aliases at the same time in the first place.
       */
      int last = composite.types.size() - 1;
      AbstractType<?> lastType = composite.types.get(last);
      if (lastType instanceof ColumnToCollectionType
          || (cfm.getColumnAliases().size() == last && lastType instanceof UTF8Type)) {
        // "sparse" composite
        this.isCompact = false;
        this.value = null;
        assert cfm.getValueAlias() == null;
        // check for collection type
        if (lastType instanceof ColumnToCollectionType) {
          --last;
          this.hasCollections = true;
        } else {
          this.hasCollections = false;
        }

        for (int i = 0; i < last; i++) {
          ColumnIdentifier id = getColumnId(cfm, i);
          this.columns.put(
              id,
              new Name(
                  cfm.ksName, cfm.cfName, id, Name.Kind.COLUMN_ALIAS, i, composite.types.get(i)));
        }

        for (Map.Entry<ByteBuffer, ColumnDefinition> def : cfm.getColumn_metadata().entrySet()) {
          ColumnIdentifier id =
              new ColumnIdentifier(def.getKey(), cfm.getColumnDefinitionComparator(def.getValue()));
          this.metadata.put(
              id,
              new Name(
                  cfm.ksName,
                  cfm.cfName,
                  id,
                  Name.Kind.COLUMN_METADATA,
                  def.getValue().getValidator()));
        }
      } else {
        // "dense" composite
        this.isCompact = true;
        this.hasCollections = false;
        for (int i = 0; i < composite.types.size(); i++) {
          ColumnIdentifier id = getColumnId(cfm, i);
          this.columns.put(
              id,
              new Name(
                  cfm.ksName, cfm.cfName, id, Name.Kind.COLUMN_ALIAS, i, composite.types.get(i)));
        }
        this.value = createValue(cfm);
      }
    } else {
      this.isComposite = false;
      this.hasCollections = false;
      if (!cfm.getColumnAliases().isEmpty() || cfm.getColumn_metadata().isEmpty()) {
        // dynamic CF
        this.isCompact = true;
        ColumnIdentifier id = getColumnId(cfm, 0);
        Name name = new Name(cfm.ksName, cfm.cfName, id, Name.Kind.COLUMN_ALIAS, 0, cfm.comparator);
        this.columns.put(id, name);
        this.value = createValue(cfm);
      } else {
        // static CF
        this.isCompact = false;
        this.value = null;
        assert cfm.getValueAlias() == null;
        assert cfm.getColumnAliases() == null || cfm.getColumnAliases().isEmpty();
        for (Map.Entry<ByteBuffer, ColumnDefinition> def : cfm.getColumn_metadata().entrySet()) {
          ColumnIdentifier id =
              new ColumnIdentifier(def.getKey(), cfm.getColumnDefinitionComparator(def.getValue()));
          this.metadata.put(
              id,
              new Name(
                  cfm.ksName,
                  cfm.cfName,
                  id,
                  Name.Kind.COLUMN_METADATA,
                  def.getValue().getValidator()));
        }
      }
    }
    assert value == null || metadata.isEmpty();
  }
  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");

          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(
            new ColumnDefinition(columnName.key, type, null, null, null, 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());
            cfm.addColumnDefinition(column);
            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.getColumn_metadata().values()) {
              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()) {
          CFDefinition.Name from = cfDef.get(entry.getKey());
          ColumnIdentifier to = entry.getValue();
          if (from == null)
            throw new InvalidRequestException(
                String.format(
                    "Column %s was not found in table %s", entry.getKey(), columnFamily()));

          CFDefinition.Name exists = cfDef.get(to);
          if (exists != null)
            throw new InvalidRequestException(
                String.format(
                    "Cannot rename column %s in table %s to %s; another column of that name already exist",
                    from, columnFamily(), to));

          switch (from.kind) {
            case KEY_ALIAS:
              cfm.keyAliases(rename(from.position, to, cfm.getKeyAliases()));
              break;
            case COLUMN_ALIAS:
              cfm.columnAliases(rename(from.position, to, cfm.getColumnAliases()));
              break;
            case VALUE_ALIAS:
              cfm.valueAlias(to.key);
              break;
            case COLUMN_METADATA:
              throw new InvalidRequestException(
                  String.format("Cannot rename non PRIMARY KEY part %s", from));
          }
        }
        break;
    }

    MigrationManager.announceColumnFamilyUpdate(cfm);
  }