Author: xedin
Date: Wed Aug 17 22:17:03 2011
New Revision: 1158939
URL: http://svn.apache.org/viewvc?rev=1158939&view=rev
Log:
Validate that column names in column_metadata does not equal to key_alias on
create/update of the ColumnFamily and CQL 'ALTER' statement.
patch by Pavel Yaskevich; reviewed by Jonathan Ellis for CASSANDRA-3036
Modified:
cassandra/branches/cassandra-0.8/CHANGES.txt
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/AlterTableStatement.java
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/thrift/ThriftValidation.java
cassandra/branches/cassandra-0.8/test/system/test_cql.py
cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/thrift/ThriftValidationTest.java
Modified: cassandra/branches/cassandra-0.8/CHANGES.txt
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/CHANGES.txt?rev=1158939&r1=1158938&r2=1158939&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/CHANGES.txt (original)
+++ cassandra/branches/cassandra-0.8/CHANGES.txt Wed Aug 17 22:17:03 2011
@@ -13,7 +13,8 @@
(rows containing nothing but expired tombstones) (CASSANDRA-3039)
* work around native memory leak in com.sun.management.GarbageCollectorMXBean
(CASSANDRA-2868)
-
+ * validate that column names in column_metadata does not equal to key_alias
+ on create/update of the ColumnFamily and CQL 'ALTER' statement
(CASSANDRA-3036)
0.8.4
* include files-to-be-streamed in StreamInSession.getSources (CASSANDRA-2972)
Modified:
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/AlterTableStatement.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/AlterTableStatement.java?rev=1158939&r1=1158938&r2=1158939&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/AlterTableStatement.java
(original)
+++
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/AlterTableStatement.java
Wed Aug 17 22:17:03 2011
@@ -65,10 +65,15 @@ public class AlterTableStatement
switch (oType)
{
case ADD:
+ if (cfDef.key_alias != null &&
cfDef.key_alias.equals(columnName))
+ throw new InvalidRequestException("Invalid column name: "
+ + this.columnName
+ + ", because it equals
to key_alias.");
+
cfDef.column_metadata.add(new ColumnDefinition(columnName,
-
TypeParser.parse(validator),
- null,
-
null).deflate());
+
TypeParser.parse(validator),
+ null,
+
null).deflate());
break;
case ALTER:
Modified:
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java?rev=1158939&r1=1158938&r2=1158939&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java
(original)
+++
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/CreateColumnFamilyStatement.java
Wed Aug 17 22:17:03 2011
@@ -169,6 +169,28 @@ public class CreateColumnFamilyStatement
throw new InvalidRequestException("You must specify a PRIMARY
KEY");
else if (keyValidator.size() > 1)
throw new InvalidRequestException("You may only specify one
PRIMARY KEY");
+
+ AbstractType<?> comparator;
+
+ try
+ {
+ comparator = getComparator();
+ }
+ catch (ConfigurationException e)
+ {
+ throw new InvalidRequestException(e.toString());
+ }
+
+ for (Map.Entry<Term, String> column : columns.entrySet())
+ {
+ ByteBuffer name = column.getKey().getByteBuffer(comparator);
+
+ if (keyAlias != null && keyAlias.equals(name))
+ throw new InvalidRequestException("Invalid column name: "
+ + column.getKey().getText()
+ + ", because it equals to
the key_alias.");
+
+ }
}
/** Map a column name to a validator for its value */
@@ -215,7 +237,7 @@ public class CreateColumnFamilyStatement
{
try
{
- ByteBuffer columnName = col.getKey().getByteBuffer(comparator);
+ ByteBuffer columnName =
comparator.fromString(col.getKey().getText());
String validatorClassName =
comparators.containsKey(col.getValue()) ? comparators.get(col.getValue()) :
col.getValue();
AbstractType<?> validator =
TypeParser.parse(validatorClassName);
columnDefs.put(columnName, new ColumnDefinition(columnName,
validator, null, null));
@@ -230,7 +252,26 @@ public class CreateColumnFamilyStatement
return columnDefs;
}
-
+
+ /* If not comparator/validator is not specified, default to text
(BytesType is the wrong default for CQL
+ * since it uses hex terms). If the value specified is not found in the
comparators map, assume the user
+ * knows what they are doing (a custom comparator/validator for example),
and pass it on as-is.
+ */
+
+ private AbstractType<?> getComparator() throws ConfigurationException
+ {
+ return
TypeParser.parse((comparators.get(getPropertyString(KW_COMPARATOR, "text")) !=
null)
+ ?
comparators.get(getPropertyString(KW_COMPARATOR, "text"))
+ : getPropertyString(KW_COMPARATOR, "text"));
+ }
+
+ private AbstractType<?> getValidator() throws ConfigurationException
+ {
+ return
TypeParser.parse((comparators.get(getPropertyString(KW_DEFAULTVALIDATION,
"text")) != null)
+ ?
comparators.get(getPropertyString(KW_DEFAULTVALIDATION, "text"))
+ : getPropertyString(KW_DEFAULTVALIDATION,
"text"));
+ }
+
/**
* Returns a CFMetaData instance based on the parameters parsed from this
* <code>CREATE</code> statement, or defaults where applicable.
@@ -246,17 +287,7 @@ public class CreateColumnFamilyStatement
CFMetaData newCFMD;
try
{
- /* If not comparator/validator is not specified, default to text
(BytesType is the wrong default for CQL
- * since it uses hex terms). If the value specified is not found
in the comparators map, assume the user
- * knows what they are doing (a custom comparator/validator for
example), and pass it on as-is.
- */
- String comparatorString =
(comparators.get(getPropertyString(KW_COMPARATOR, "text")) != null)
- ?
comparators.get(getPropertyString(KW_COMPARATOR, "text"))
- : getPropertyString(KW_COMPARATOR,
"text");
- String validatorString =
(comparators.get(getPropertyString(KW_DEFAULTVALIDATION, "text")) != null)
- ?
comparators.get(getPropertyString(KW_DEFAULTVALIDATION, "text"))
- : getPropertyString(KW_DEFAULTVALIDATION,
"text");
- AbstractType<?> comparator = TypeParser.parse(comparatorString);
+ AbstractType<?> comparator = getComparator();
newCFMD = new CFMetaData(keyspace,
name,
@@ -270,7 +301,7 @@ public class CreateColumnFamilyStatement
.readRepairChance(getPropertyDouble(KW_READREPAIRCHANCE,
CFMetaData.DEFAULT_READ_REPAIR_CHANCE))
.replicateOnWrite(getPropertyBoolean(KW_REPLICATEONWRITE,
CFMetaData.DEFAULT_REPLICATE_ON_WRITE))
.gcGraceSeconds(getPropertyInt(KW_GCGRACESECONDS,
CFMetaData.DEFAULT_GC_GRACE_SECONDS))
- .defaultValidator(TypeParser.parse(validatorString))
+ .defaultValidator(getValidator())
.minCompactionThreshold(getPropertyInt(KW_MINCOMPACTIONTHRESHOLD,
CFMetaData.DEFAULT_MIN_COMPACTION_THRESHOLD))
.maxCompactionThreshold(getPropertyInt(KW_MAXCOMPACTIONTHRESHOLD,
CFMetaData.DEFAULT_MAX_COMPACTION_THRESHOLD))
.rowCacheSavePeriod(getPropertyInt(KW_ROWCACHESAVEPERIODSECS,
CFMetaData.DEFAULT_ROW_CACHE_SAVE_PERIOD_IN_SECONDS))
Modified:
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java?rev=1158939&r1=1158938&r2=1158939&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java
(original)
+++
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/cql/QueryProcessor.java
Wed Aug 17 22:17:03 2011
@@ -845,8 +845,6 @@ public class QueryProcessor
case ALTER_TABLE:
AlterTableStatement alterTable = (AlterTableStatement)
statement.statement;
- System.out.println(alterTable);
-
validateColumnFamily(keyspace, alterTable.columnFamily);
clientState.hasColumnFamilyAccess(alterTable.columnFamily,
Permission.WRITE);
validateSchemaAgreement();
Modified:
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/thrift/ThriftValidation.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/thrift/ThriftValidation.java?rev=1158939&r1=1158938&r2=1158939&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/thrift/ThriftValidation.java
(original)
+++
cassandra/branches/cassandra-0.8/src/java/org/apache/cassandra/thrift/ThriftValidation.java
Wed Aug 17 22:17:03 2011
@@ -553,22 +553,6 @@ public class ThriftValidation
}
}
- if (cf_def.key_alias != null)
- {
- if (!cf_def.key_alias.hasRemaining())
- throw new InvalidRequestException("key_alias may not be
empty");
- try
- {
- // it's hard to use a key in a select statement if we
can't type it.
- // for now let's keep it simple and require ascii.
- AsciiType.instance.validate(cf_def.key_alias);
- }
- catch (MarshalException e)
- {
- throw new InvalidRequestException("Key aliases must be
ascii");
- }
- }
-
ColumnFamilyType cfType =
ColumnFamilyType.create(cf_def.column_type);
if (cfType == null)
throw new InvalidRequestException("invalid column type " +
cf_def.column_type);
@@ -586,6 +570,18 @@ public class ThriftValidation
? TypeParser.parse(cf_def.comparator_type)
:
TypeParser.parse(cf_def.subcomparator_type);
+ if (cf_def.key_alias != null)
+ {
+ // check if any of the columns has name equal to the
cf.key_alias
+ for (ColumnDef columnDef : cf_def.column_metadata)
+ {
+ if (cf_def.key_alias.equals(columnDef.name))
+ throw new InvalidRequestException("Invalid column
name: "
+ +
AsciiType.instance.compose(cf_def.key_alias)
+ + ", because it
equals to the key_alias.");
+ }
+ }
+
// initialize a set of names NOT in the CF under consideration
Set<String> indexNames = new HashSet<String>();
for (ColumnFamilyStore cfs : ColumnFamilyStore.all())
Modified: cassandra/branches/cassandra-0.8/test/system/test_cql.py
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/test/system/test_cql.py?rev=1158939&r1=1158938&r2=1158939&view=diff
==============================================================================
--- cassandra/branches/cassandra-0.8/test/system/test_cql.py (original)
+++ cassandra/branches/cassandra-0.8/test/system/test_cql.py Wed Aug 17
22:17:03 2011
@@ -477,6 +477,9 @@ class TestCql(ThriftTester):
# Missing primary key
assert_raises(cql.ProgrammingError, cursor.execute, "CREATE
COLUMNFAMILY NewCf2")
+ # column name should not match key alias
+ assert_raises(cql.ProgrammingError, cursor.execute, "CREATE
COLUMNFAMILY NewCf2 (id 'utf8' primary key, id int)")
+
# Too many primary keys
assert_raises(cql.ProgrammingError,
cursor.execute,
@@ -1140,7 +1143,7 @@ class TestCql(ThriftTester):
cursor.execute("USE AlterTableKS;")
cursor.execute("""
- CREATE COLUMNFAMILY NewCf1 (KEY varint PRIMARY KEY) WITH
default_validation = ascii;
+ CREATE COLUMNFAMILY NewCf1 (id_key varint PRIMARY KEY) WITH
default_validation = ascii;
""")
# TODO: temporary (until this can be done with CQL).
@@ -1204,6 +1207,12 @@ class TestCql(ThriftTester):
assert_raises(cql.ProgrammingError,
cursor.execute,
"ALTER COLUMNFAMILY NewCf1 DROP name")
+
+ # should raise error when column name equals key alias
+ assert_raises(cql.ProgrammingError,
+ cursor.execute,
+ "ALTER COLUMNFAMILY NewCf1 ADD id_key utf8")
+
def test_counter_column_support(self):
"update statement should be able to work with counter columns"
Modified:
cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/thrift/ThriftValidationTest.java
URL:
http://svn.apache.org/viewvc/cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/thrift/ThriftValidationTest.java?rev=1158939&r1=1158938&r2=1158939&view=diff
==============================================================================
---
cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/thrift/ThriftValidationTest.java
(original)
+++
cassandra/branches/cassandra-0.8/test/unit/org/apache/cassandra/thrift/ThriftValidationTest.java
Wed Aug 17 22:17:03 2011
@@ -21,10 +21,17 @@ package org.apache.cassandra.thrift;
*/
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.db.marshal.AsciiType;
+import org.apache.cassandra.db.marshal.UTF8Type;
+
import org.junit.Test;
import org.apache.cassandra.CleanupHelper;
+import java.util.concurrent.Callable;
+
public class ThriftValidationTest extends CleanupHelper
{
@Test(expected=InvalidRequestException.class)
@@ -38,4 +45,46 @@ public class ThriftValidationTest extend
{
ThriftValidation.validateColumnFamily("Keyspace1", "Counter1", true);
}
+
+ @Test
+ public void testColumnNameEqualToKeyAlias()
+ {
+ CFMetaData metaData = DatabaseDescriptor.getCFMetaData("Keyspace1",
"Standard1");
+ CfDef newMetadata = CFMetaData.convertToThrift(metaData);
+
+ boolean gotException = false;
+
+ // add a key_alias = "id"
+ newMetadata.setKey_alias(AsciiType.instance.decompose("id"));
+
+ // should not throw IRE here
+ try
+ {
+ ThriftValidation.validateCfDef(newMetadata, metaData);
+ }
+ catch (InvalidRequestException e)
+ {
+ gotException = true;
+ }
+
+ assert !gotException : "got unexpected InvalidRequestException";
+
+ // add a column with name = "id"
+ newMetadata.addToColumn_metadata(new
ColumnDef(UTF8Type.instance.decompose("id"),
+
"org.apache.cassandra.db.marshal.UTF8Type"));
+
+
+ gotException = false;
+
+ try
+ {
+ ThriftValidation.validateCfDef(newMetadata, metaData);
+ }
+ catch (InvalidRequestException e)
+ {
+ gotException = true;
+ }
+
+ assert gotException : "expected InvalidRequestException but not
received.";
+ }
}