Reject multiple values for a key in CQL grammar. Patch by Nachiket Patil; Reviewed by Ariel Weisberg for CASSANDRA-13369
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/1a83efe2 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/1a83efe2 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/1a83efe2 Branch: refs/heads/trunk Commit: 1a83efe2047d0138725d5e102cc40774f3b14641 Parents: d56c64a Author: Nachiket Patil <nachiket_pa...@apple.com> Authored: Mon May 8 16:23:13 2017 -0400 Committer: Ariel Weisberg <aweisb...@apple.com> Committed: Mon May 8 16:25:41 2017 -0400 ---------------------------------------------------------------------- CHANGES.txt | 1 + src/antlr/Parser.g | 5 +++- .../apache/cassandra/cql3/CqlParserTest.java | 30 ++++++++++++++++++++ .../cql3/validation/operations/AlterTest.java | 19 +++++++++++++ .../cql3/validation/operations/CreateTest.java | 14 +++++++++ 5 files changed, 68 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/1a83efe2/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 6603911..3166780 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.11.0 + * Reject multiple values for a key in CQL grammar. (CASSANDRA-13369) * UDA fails without input rows (CASSANDRA-13399) * Fix compaction-stress by using daemonInitialization (CASSANDRA-13188) * V5 protocol flags decoding broken (CASSANDRA-13443) http://git-wip-us.apache.org/repos/asf/cassandra/blob/1a83efe2/src/antlr/Parser.g ---------------------------------------------------------------------- diff --git a/src/antlr/Parser.g b/src/antlr/Parser.g index 3d06dc3..e5b7584 100644 --- a/src/antlr/Parser.g +++ b/src/antlr/Parser.g @@ -127,7 +127,10 @@ options { break; } - res.put(((Constants.Literal)entry.left).getRawText(), ((Constants.Literal)entry.right).getRawText()); + if (res.put(((Constants.Literal)entry.left).getRawText(), ((Constants.Literal)entry.right).getRawText()) != null) + { + addRecognitionError(String.format("Multiple definition for property " + ((Constants.Literal)entry.left).getRawText())); + } } return res; http://git-wip-us.apache.org/repos/asf/cassandra/blob/1a83efe2/test/unit/org/apache/cassandra/cql3/CqlParserTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/CqlParserTest.java b/test/unit/org/apache/cassandra/cql3/CqlParserTest.java index 4b76dbc..4871c09 100644 --- a/test/unit/org/apache/cassandra/cql3/CqlParserTest.java +++ b/test/unit/org/apache/cassandra/cql3/CqlParserTest.java @@ -25,6 +25,7 @@ import org.antlr.runtime.CharStream; import org.antlr.runtime.CommonTokenStream; import org.antlr.runtime.RecognitionException; import org.antlr.runtime.TokenStream; +import org.apache.cassandra.cql3.statements.PropertyDefinitions; import static org.junit.Assert.*; @@ -75,6 +76,35 @@ public class CqlParserTest assertEquals(0, secondCounter.count); } + @Test + public void testDuplicateProperties() throws Exception + { + parseAndCountErrors("properties = { 'foo' : 'value1', 'bar': 'value2' };", 0, (p) -> p.properties(new PropertyDefinitions())); + parseAndCountErrors("properties = { 'foo' : 'value1', 'foo': 'value2' };", 1, (p) -> p.properties(new PropertyDefinitions())); + parseAndCountErrors("foo = 'value1' AND bar = 'value2' };", 0, (p) -> p.properties(new PropertyDefinitions())); + parseAndCountErrors("foo = 'value1' AND foo = 'value2' };", 1, (p) -> p.properties(new PropertyDefinitions())); + } + + private void parseAndCountErrors(String cql, int expectedErrors, ParserOperation operation) throws RecognitionException + { + SyntaxErrorCounter counter = new SyntaxErrorCounter(); + CharStream stream = new ANTLRStringStream(cql); + CqlLexer lexer = new CqlLexer(stream); + TokenStream tokenStream = new CommonTokenStream(lexer); + CqlParser parser = new CqlParser(tokenStream); + parser.addErrorListener(counter); + + operation.perform(parser); + + assertEquals(expectedErrors, counter.count); + } + + @FunctionalInterface + private interface ParserOperation + { + void perform(CqlParser cqlParser) throws RecognitionException; + } + private static final class SyntaxErrorCounter implements ErrorListener { private int count; http://git-wip-us.apache.org/repos/asf/cassandra/blob/1a83efe2/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java index 2d34967..b0ee566 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java @@ -229,6 +229,25 @@ public class AlterTest extends CQLTester "max_threshold", "32"))); } + @Test + public void testAlterKeyspaceWithMultipleInstancesOfSameDCThrowsSyntaxException() throws Throwable + { + try + { + // Create a keyspace + execute("CREATE KEYSPACE testABC WITH replication = {'class' : 'NetworkTopologyStrategy', 'dc1' : 2}"); + + // try modifying the keyspace + assertInvalidThrow(SyntaxException.class, "ALTER KEYSPACE testABC WITH replication = {'class' : 'NetworkTopologyStrategy', 'dc1' : 2, 'dc1' : 3 }"); + execute("ALTER KEYSPACE testABC WITH replication = {'class' : 'NetworkTopologyStrategy', 'dc1' : 3}"); + } + finally + { + // clean-up + execute("DROP KEYSPACE IF EXISTS testABC"); + } + } + /** * Test for bug of 5232, * migrated from cql_tests.py:TestCQL.alter_bug_test() http://git-wip-us.apache.org/repos/asf/cassandra/blob/1a83efe2/test/unit/org/apache/cassandra/cql3/validation/operations/CreateTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/CreateTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/CreateTest.java index bb6ead9..3eaec23 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/CreateTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/CreateTest.java @@ -499,6 +499,20 @@ public class CreateTest extends CQLTester execute("DROP KEYSPACE testXYZ"); } + @Test + public void testCreateKeyspaceWithMultipleInstancesOfSameDCThrowsException() throws Throwable + { + try + { + assertInvalidThrow(SyntaxException.class, "CREATE KEYSPACE testABC WITH replication = {'class' : 'NetworkTopologyStrategy', 'dc1' : 2, 'dc1' : 3 }"); + } + finally + { + // clean-up + execute("DROP KEYSPACE IF EXISTS testABC"); + } + } + /** * Test create and drop table * migrated from cql_tests.py:TestCQL.table_test() --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org