mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-2.2' into cassandra-3.0
This commit is contained in:
commit
e6f23e63c5
|
|
@ -13,6 +13,7 @@ Merged from 2.2:
|
|||
* Defer default role manager setup until all nodes are on 2.2+ (CASSANDRA-9761)
|
||||
* Handle missing RoleManager in config after upgrade to 2.2 (CASSANDRA-10209)
|
||||
Merged from 2.1:
|
||||
* Prevent ALTER TYPE from creating circular references (CASSANDRA-10339)
|
||||
* Fix cache handling of 2i and base tables (CASSANDRA-10155, 10359)
|
||||
* Fix NPE in nodetool compactionhistory (CASSANDRA-9758)
|
||||
* (Pig) support BulkOutputFormat as a URL parameter (CASSANDRA-7410)
|
||||
|
|
|
|||
|
|
@ -264,9 +264,13 @@ public abstract class AlterTypeStatement extends SchemaAlteringStatement
|
|||
newNames.addAll(toUpdate.fieldNames());
|
||||
newNames.add(fieldName.bytes);
|
||||
|
||||
AbstractType<?> addType = type.prepare(keyspace()).getType();
|
||||
if (addType.references(toUpdate))
|
||||
throw new InvalidRequestException(String.format("Cannot add new field %s of type %s to type %s as this would create a circular reference", fieldName, type, name));
|
||||
|
||||
List<AbstractType<?>> newTypes = new ArrayList<>(toUpdate.size() + 1);
|
||||
newTypes.addAll(toUpdate.fieldTypes());
|
||||
newTypes.add(type.prepare(keyspace()).getType());
|
||||
newTypes.add(addType);
|
||||
|
||||
return new UserType(toUpdate.keyspace, toUpdate.name, newNames, newTypes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -400,6 +400,14 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>
|
|||
ByteBufferUtil.skipWithVIntLength(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this type or any of the types this type contains references the given type.
|
||||
*/
|
||||
public boolean references(AbstractType<?> check)
|
||||
{
|
||||
return this.equals(check);
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be overriden by subclasses if necessary so that for any
|
||||
* AbstractType, this == TypeParser.parse(toString()).
|
||||
|
|
|
|||
|
|
@ -116,6 +116,17 @@ public class CompositeType extends AbstractCompositeType
|
|||
this.types = ImmutableList.copyOf(types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean references(AbstractType<?> check)
|
||||
{
|
||||
if (super.references(check))
|
||||
return true;
|
||||
for (AbstractType<?> type : types)
|
||||
if (type.references(check))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected AbstractType<?> getComparator(int i, ByteBuffer bb)
|
||||
{
|
||||
try
|
||||
|
|
|
|||
|
|
@ -74,6 +74,12 @@ public class ListType<T> extends CollectionType<List<T>>
|
|||
this.isMultiCell = isMultiCell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean references(AbstractType<?> check)
|
||||
{
|
||||
return super.references(check) || elements.references(check);
|
||||
}
|
||||
|
||||
public AbstractType<T> getElementsType()
|
||||
{
|
||||
return elements;
|
||||
|
|
|
|||
|
|
@ -74,6 +74,12 @@ public class MapType<K, V> extends CollectionType<Map<K, V>>
|
|||
this.isMultiCell = isMultiCell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean references(AbstractType<?> check)
|
||||
{
|
||||
return super.references(check) || keys.references(check) || values.references(check);
|
||||
}
|
||||
|
||||
public AbstractType<K> getKeysType()
|
||||
{
|
||||
return keys;
|
||||
|
|
|
|||
|
|
@ -135,6 +135,11 @@ public class ReversedType<T> extends AbstractType<T>
|
|||
return baseType.getSerializer();
|
||||
}
|
||||
|
||||
public boolean references(AbstractType<?> check)
|
||||
{
|
||||
return super.references(check) || baseType.references(check);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int valueLengthIfFixed()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -68,6 +68,12 @@ public class SetType<T> extends CollectionType<Set<T>>
|
|||
this.isMultiCell = isMultiCell;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean references(AbstractType<?> check)
|
||||
{
|
||||
return super.references(check) || elements.references(check);
|
||||
}
|
||||
|
||||
public AbstractType<T> getElementsType()
|
||||
{
|
||||
return elements;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,17 @@ public class TupleType extends AbstractType<ByteBuffer>
|
|||
return new TupleType(types);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean references(AbstractType<?> check)
|
||||
{
|
||||
if (super.references(check))
|
||||
return true;
|
||||
for (AbstractType<?> type : types)
|
||||
if (type.references(check))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public AbstractType<?> type(int i)
|
||||
{
|
||||
return types.get(i);
|
||||
|
|
|
|||
|
|
@ -402,4 +402,53 @@ public class UserTypesTest extends CQLTester
|
|||
execute("ALTER TYPE " + keyspace() + "." + typeName + " ADD foomap map <int,text>");
|
||||
execute("INSERT INTO %s (key, data) VALUES (1, {fooint: 1, fooset: {'2'}, foomap: {3 : 'bar'}})");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCircularReferences() throws Throwable
|
||||
{
|
||||
String type1 = createType("CREATE TYPE %s (foo int)");
|
||||
|
||||
String typeX = createType("CREATE TYPE %s (bar frozen<" + typeWithKs(type1) + ">)");
|
||||
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
|
||||
|
||||
typeX = createType("CREATE TYPE %s (bar frozen<list<" + typeWithKs(type1) + ">>)");
|
||||
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
|
||||
|
||||
typeX = createType("CREATE TYPE %s (bar frozen<set<" + typeWithKs(type1) + ">>)");
|
||||
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
|
||||
|
||||
typeX = createType("CREATE TYPE %s (bar frozen<map<text, " + typeWithKs(type1) + ">>)");
|
||||
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
|
||||
|
||||
typeX = createType("CREATE TYPE %s (bar frozen<map<" + typeWithKs(type1) + ", text>>)");
|
||||
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
|
||||
|
||||
//
|
||||
|
||||
String type2 = createType("CREATE TYPE %s (foo frozen<" + typeWithKs(type1) + ">)");
|
||||
|
||||
typeX = createType("CREATE TYPE %s (bar frozen<" + keyspace() + '.' + type2 + ">)");
|
||||
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
|
||||
|
||||
typeX = createType("CREATE TYPE %s (bar frozen<list<" + keyspace() + '.' + type2 + ">>)");
|
||||
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
|
||||
|
||||
typeX = createType("CREATE TYPE %s (bar frozen<set<" + keyspace() + '.' + type2 + ">>)");
|
||||
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
|
||||
|
||||
typeX = createType("CREATE TYPE %s (bar frozen<map<text, " + keyspace() + '.' + type2 + ">>)");
|
||||
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
|
||||
|
||||
typeX = createType("CREATE TYPE %s (bar frozen<map<" + keyspace() + '.' + type2 + ", text>>)");
|
||||
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
|
||||
|
||||
//
|
||||
|
||||
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<list<" + typeWithKs(type1) + ">>");
|
||||
}
|
||||
|
||||
private String typeWithKs(String type1)
|
||||
{
|
||||
return keyspace() + '.' + type1;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue