mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-3.0' into trunk
This commit is contained in:
commit
9515fca769
|
|
@ -790,7 +790,7 @@ public final class CFMetaData
|
|||
throw new ConfigurationException("types do not match.");
|
||||
|
||||
if (!cfm.comparator.isCompatibleWith(comparator))
|
||||
throw new ConfigurationException(String.format("Column family comparators do not match or are not compatible (found %s; expected %s).", cfm.comparator.getClass().getSimpleName(), comparator.getClass().getSimpleName()));
|
||||
throw new ConfigurationException(String.format("Column family comparators do not match or are not compatible (found %s; expected %s).", cfm.comparator.toString(), comparator.toString()));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import org.apache.cassandra.db.Keyspace;
|
|||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.CollectionType;
|
||||
import org.apache.cassandra.db.marshal.CounterColumnType;
|
||||
import org.apache.cassandra.db.marshal.ReversedType;
|
||||
import org.apache.cassandra.db.view.View;
|
||||
import org.apache.cassandra.exceptions.*;
|
||||
import org.apache.cassandra.schema.IndexMetadata;
|
||||
|
|
@ -186,55 +187,25 @@ public class AlterTableStatement extends SchemaAlteringStatement
|
|||
if (def == null)
|
||||
throw new InvalidRequestException(String.format("Column %s was not found in table %s", columnName, columnFamily()));
|
||||
|
||||
AbstractType<?> validatorType = validator.getType();
|
||||
switch (def.kind)
|
||||
{
|
||||
case PARTITION_KEY:
|
||||
if (validatorType instanceof CounterColumnType)
|
||||
throw new InvalidRequestException(String.format("counter type is not supported for PRIMARY KEY part %s", columnName));
|
||||
|
||||
AbstractType<?> currentType = cfm.getKeyValidatorAsClusteringComparator().subtype(def.position());
|
||||
if (!validatorType.isValueCompatibleWith(currentType))
|
||||
throw new ConfigurationException(String.format("Cannot change %s from type %s to type %s: types are incompatible.",
|
||||
columnName,
|
||||
currentType.asCQL3Type(),
|
||||
validator));
|
||||
break;
|
||||
case CLUSTERING:
|
||||
AbstractType<?> oldType = cfm.comparator.subtype(def.position());
|
||||
// Note that CFMetaData.validateCompatibility already validate the change we're about to do. However, the error message it
|
||||
// sends is a bit cryptic for a CQL3 user, so validating here for a sake of returning a better error message
|
||||
// Do note that we need isCompatibleWith here, not just isValueCompatibleWith.
|
||||
if (!validatorType.isCompatibleWith(oldType))
|
||||
throw new ConfigurationException(String.format("Cannot change %s from type %s to type %s: types are not order-compatible.",
|
||||
columnName,
|
||||
oldType.asCQL3Type(),
|
||||
validator));
|
||||
|
||||
break;
|
||||
case REGULAR:
|
||||
case STATIC:
|
||||
// Thrift allows to change a column validator so CFMetaData.validateCompatibility will let it slide
|
||||
// if we change to an incompatible type (contrarily to the comparator case). But we don't want to
|
||||
// allow it for CQL3 (see #5882) so validating it explicitly here. We only care about value compatibility
|
||||
// though since we won't compare values (except when there is an index, but that is validated by
|
||||
// ColumnDefinition already).
|
||||
if (!validatorType.isValueCompatibleWith(def.type))
|
||||
throw new ConfigurationException(String.format("Cannot change %s from type %s to type %s: types are incompatible.",
|
||||
columnName,
|
||||
def.type.asCQL3Type(),
|
||||
validator));
|
||||
break;
|
||||
}
|
||||
AbstractType<?> validatorType = def.isReversedType() && !validator.getType().isReversed()
|
||||
? ReversedType.getInstance(validator.getType())
|
||||
: validator.getType();
|
||||
validateAlter(cfm, def, validatorType);
|
||||
// In any case, we update the column definition
|
||||
cfm.addOrReplaceColumnDefinition(def.withNewType(validatorType));
|
||||
|
||||
// We have to alter the schema of the view table as well; it doesn't affect the definition however
|
||||
// We also have to validate the view types here. If we have a view which includes a column as part of
|
||||
// the clustering key, we need to make sure that it is indeed compatible.
|
||||
for (ViewDefinition view : views)
|
||||
{
|
||||
if (!view.includes(columnName)) continue;
|
||||
ViewDefinition viewCopy = view.copy();
|
||||
viewCopy.metadata.addOrReplaceColumnDefinition(def.withNewType(validatorType));
|
||||
ColumnDefinition viewDef = view.metadata.getColumnDefinition(columnName);
|
||||
AbstractType viewType = viewDef.isReversedType() && !validator.getType().isReversed()
|
||||
? ReversedType.getInstance(validator.getType())
|
||||
: validator.getType();
|
||||
validateAlter(view.metadata, viewDef, viewType);
|
||||
viewCopy.metadata.addOrReplaceColumnDefinition(viewDef.withNewType(viewType));
|
||||
|
||||
if (viewUpdates == null)
|
||||
viewUpdates = new ArrayList<>();
|
||||
|
|
@ -361,6 +332,50 @@ public class AlterTableStatement extends SchemaAlteringStatement
|
|||
return true;
|
||||
}
|
||||
|
||||
private static void validateAlter(CFMetaData cfm, ColumnDefinition def, AbstractType<?> validatorType)
|
||||
{
|
||||
switch (def.kind)
|
||||
{
|
||||
case PARTITION_KEY:
|
||||
if (validatorType instanceof CounterColumnType)
|
||||
throw new InvalidRequestException(String.format("counter type is not supported for PRIMARY KEY part %s", def.name));
|
||||
|
||||
AbstractType<?> currentType = cfm.getKeyValidatorAsClusteringComparator().subtype(def.position());
|
||||
if (!validatorType.isValueCompatibleWith(currentType))
|
||||
throw new ConfigurationException(String.format("Cannot change %s from type %s to type %s: types are incompatible.",
|
||||
def.name,
|
||||
currentType.asCQL3Type(),
|
||||
validatorType.asCQL3Type()));
|
||||
break;
|
||||
case CLUSTERING:
|
||||
AbstractType<?> oldType = cfm.comparator.subtype(def.position());
|
||||
// Note that CFMetaData.validateCompatibility already validate the change we're about to do. However, the error message it
|
||||
// sends is a bit cryptic for a CQL3 user, so validating here for a sake of returning a better error message
|
||||
// Do note that we need isCompatibleWith here, not just isValueCompatibleWith.
|
||||
if (!validatorType.isCompatibleWith(oldType))
|
||||
{
|
||||
throw new ConfigurationException(String.format("Cannot change %s from type %s to type %s: types are not order-compatible.",
|
||||
def.name,
|
||||
oldType.asCQL3Type(),
|
||||
validatorType.asCQL3Type()));
|
||||
}
|
||||
break;
|
||||
case REGULAR:
|
||||
case STATIC:
|
||||
// Thrift allows to change a column validator so CFMetaData.validateCompatibility will let it slide
|
||||
// if we change to an incompatible type (contrarily to the comparator case). But we don't want to
|
||||
// allow it for CQL3 (see #5882) so validating it explicitly here. We only care about value compatibility
|
||||
// though since we won't compare values (except when there is an index, but that is validated by
|
||||
// ColumnDefinition already).
|
||||
if (!validatorType.isValueCompatibleWith(def.type))
|
||||
throw new ConfigurationException(String.format("Cannot change %s from type %s to type %s: types are incompatible.",
|
||||
def.name,
|
||||
def.type.asCQL3Type(),
|
||||
validatorType.asCQL3Type()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return String.format("AlterTableStatement(name=%s, type=%s, column=%s, validator=%s)",
|
||||
|
|
|
|||
|
|
@ -1456,4 +1456,80 @@ public class ViewTest extends CQLTester
|
|||
ResultSet mvRows = executeNet(protocolVersion, "SELECT a, b FROM mv1");
|
||||
assertRowsNet(protocolVersion, mvRows, row(1, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterTable() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (" +
|
||||
"a int," +
|
||||
"b text," +
|
||||
"PRIMARY KEY (a, b))");
|
||||
|
||||
executeNet(protocolVersion, "USE " + keyspace());
|
||||
|
||||
createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (b, a)");
|
||||
|
||||
alterTable("ALTER TABLE %s ALTER b TYPE blob");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterReversedTypeBaseTable() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (" +
|
||||
"a int," +
|
||||
"b text," +
|
||||
"PRIMARY KEY (a, b))" +
|
||||
"WITH CLUSTERING ORDER BY (b DESC)");
|
||||
|
||||
executeNet(protocolVersion, "USE " + keyspace());
|
||||
|
||||
createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (a, b) WITH CLUSTERING ORDER BY (b ASC)");
|
||||
|
||||
alterTable("ALTER TABLE %s ALTER b TYPE blob");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterReversedTypeViewTable() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (" +
|
||||
"a int," +
|
||||
"b text," +
|
||||
"PRIMARY KEY (a, b))");
|
||||
|
||||
executeNet(protocolVersion, "USE " + keyspace());
|
||||
|
||||
createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (a, b) WITH CLUSTERING ORDER BY (b DESC)");
|
||||
|
||||
alterTable("ALTER TABLE %s ALTER b TYPE blob");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterClusteringViewTable() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (" +
|
||||
"a int," +
|
||||
"b text," +
|
||||
"PRIMARY KEY (a))");
|
||||
|
||||
executeNet(protocolVersion, "USE " + keyspace());
|
||||
|
||||
createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (a, b) WITH CLUSTERING ORDER BY (b DESC)");
|
||||
|
||||
alterTable("ALTER TABLE %s ALTER b TYPE blob");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterViewTableValue() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (" +
|
||||
"a int," +
|
||||
"b int," +
|
||||
"PRIMARY KEY (a))");
|
||||
|
||||
executeNet(protocolVersion, "USE " + keyspace());
|
||||
|
||||
createView("mv1", "CREATE MATERIALIZED VIEW %s AS SELECT * FROM %%s WHERE a IS NOT NULL AND b IS NOT NULL PRIMARY KEY (a, b) WITH CLUSTERING ORDER BY (b DESC)");
|
||||
|
||||
assertInvalid("ALTER TABLE %s ALTER b TYPE blob");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -273,6 +273,20 @@ public class AlterTest extends CQLTester
|
|||
"ALTER TABLE %s WITH compression = { 'class' : 'SnappyCompressor', 'chunk_length_kb' : 32 , 'chunk_length_in_kb' : 32 };");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlterType() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (id text PRIMARY KEY, content text);");
|
||||
alterTable("ALTER TABLE %s ALTER content TYPE blob");
|
||||
|
||||
createTable("CREATE TABLE %s (pk int, ck text, value blob, PRIMARY KEY (pk, ck)) WITH CLUSTERING ORDER BY (ck DESC)");
|
||||
alterTable("ALTER TABLE %s ALTER ck TYPE blob");
|
||||
|
||||
createTable("CREATE TABLE %s (pk int, ck int, value blob, PRIMARY KEY (pk, ck))");
|
||||
assertThrowsConfigurationException("Cannot change value from type blob to type text: types are incompatible.",
|
||||
"ALTER TABLE %s ALTER value TYPE TEXT;");
|
||||
}
|
||||
|
||||
private void assertThrowsConfigurationException(String errorMsg, String alterStmt) throws Throwable
|
||||
{
|
||||
try
|
||||
|
|
|
|||
Loading…
Reference in New Issue