From 86e07595f744eb2a250cf6c25ee7cb09c6dbd849 Mon Sep 17 00:00:00 2001 From: Jacek Lewandowski Date: Fri, 20 Oct 2023 12:35:33 +0200 Subject: [PATCH] Retrieve keyspaces metadata and schema version concistently in DescribeStatement The fix makes the DescribeStatement to wait for the in-progress schema transformations to finish before returning the first page. This way, the metadata and schema version encoded in the result set metadata are guaranteed to be consistent. Patch by Jacek Lewandowski; reviewed by Benjamin Lerer, Ekaterina Dimitrova for CASSANDRA-18921 --- CHANGES.txt | 1 + .../cql3/statements/DescribeStatement.java | 16 +- .../org/apache/cassandra/schema/Schema.java | 11 + .../statements/DescribeStatementTest.java | 328 +++++++++--------- 4 files changed, 187 insertions(+), 169 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index 66ac892da7..bbe9c15776 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 4.0.12 + * Retrieve keyspaces metadata and schema version concistently in DescribeStatement (CASSANDRA-18921) * Gossip NPE due to shutdown event corrupting empty statuses (CASSANDRA-18913) * Synchronize CQLSSTableWriter#build on the Schema.instance object (CASSANDRA-18317) * Fix closing iterator in SecondaryIndexBuilder (CASSANDRA-18361) diff --git a/src/java/org/apache/cassandra/cql3/statements/DescribeStatement.java b/src/java/org/apache/cassandra/cql3/statements/DescribeStatement.java index 6de1d2110b..49556d729f 100644 --- a/src/java/org/apache/cassandra/cql3/statements/DescribeStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/DescribeStatement.java @@ -49,6 +49,7 @@ import org.apache.cassandra.service.pager.PagingState; import org.apache.cassandra.transport.messages.ResultMessage; import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.FBUtilities; +import org.apache.cassandra.utils.Pair; import org.apache.cassandra.utils.UUIDGen; import static java.lang.String.format; @@ -132,13 +133,12 @@ public abstract class DescribeStatement extends CQLStatement.Raw implements C @Override public ResultMessage executeLocally(QueryState state, QueryOptions options) { - Keyspaces keyspaces = Schema.instance.snapshot(); - UUID schemaVersion = Schema.instance.getVersion(); + Pair schema = Schema.instance.getSchemaBlocking(); - keyspaces = Keyspaces.builder() - .add(keyspaces) - .add(VirtualKeyspaceRegistry.instance.virtualKeyspacesMetadata()) - .build(); + Keyspaces keyspaces = Keyspaces.builder() + .add(schema.left) + .add(VirtualKeyspaceRegistry.instance.virtualKeyspacesMetadata()) + .build(); PagingState pagingState = options.getPagingState(); @@ -156,7 +156,7 @@ public abstract class DescribeStatement extends CQLStatement.Raw implements C // (vint bytes) serialized schema hash (currently the result of Keyspaces.hashCode()) // - long offset = getOffset(pagingState, schemaVersion); + long offset = getOffset(pagingState, schema.right); int pageSize = options.getPageSize(); Stream stream = describe(state.getClientState(), keyspaces); @@ -174,7 +174,7 @@ public abstract class DescribeStatement extends CQLStatement.Raw implements C if (pageSize > 0 && rows.size() == pageSize) { - result.metadata.setHasMorePages(getPagingState(offset + pageSize, schemaVersion)); + result.metadata.setHasMorePages(getPagingState(offset + pageSize, schema.right)); } return new ResultMessage.Rows(result); diff --git a/src/java/org/apache/cassandra/schema/Schema.java b/src/java/org/apache/cassandra/schema/Schema.java index 20687ae7ae..9ee220c3ca 100644 --- a/src/java/org/apache/cassandra/schema/Schema.java +++ b/src/java/org/apache/cassandra/schema/Schema.java @@ -528,8 +528,18 @@ public final class Schema implements SchemaProvider return version; } + /** + * Returns the current keyspaces metadata and version synchronouly. If the schema is in the middle of a multistep + * transformation, the method blocks until the update is completed. + */ + public synchronized Pair getSchemaBlocking() + { + return Pair.create(keyspaces, version); + } + /** * Checks whether the given schema version is the same as the current local schema. + * Note that this method is non-blocking and may use a stale schema version for comparison - see {@link #getVersion()}. */ public boolean isSameVersion(UUID schemaVersion) { @@ -538,6 +548,7 @@ public final class Schema implements SchemaProvider /** * Checks whether the current schema is empty. + * Note that this method is non-blocking and may use a stale schema version for comparison - see {@link #getVersion()}. */ public boolean isEmpty() { diff --git a/test/unit/org/apache/cassandra/cql3/statements/DescribeStatementTest.java b/test/unit/org/apache/cassandra/cql3/statements/DescribeStatementTest.java index 4285b8abeb..d28ef0a224 100644 --- a/test/unit/org/apache/cassandra/cql3/statements/DescribeStatementTest.java +++ b/test/unit/org/apache/cassandra/cql3/statements/DescribeStatementTest.java @@ -22,16 +22,14 @@ import java.util.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; - import org.apache.commons.lang3.ArrayUtils; - import org.junit.Test; +import org.junit.runner.RunWith; import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.Row; import com.datastax.driver.core.SimpleStatement; import com.datastax.driver.core.exceptions.InvalidQueryException; - import org.apache.cassandra.config.DatabaseDescriptor; import org.apache.cassandra.cql3.CQLTester; import org.apache.cassandra.dht.Token; @@ -41,36 +39,43 @@ import org.apache.cassandra.schema.Schema; import org.apache.cassandra.schema.TableId; import org.apache.cassandra.service.StorageService; import org.apache.cassandra.transport.ProtocolVersion; +import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import static java.lang.String.format; -import static org.apache.cassandra.schema.SchemaConstants.*; +import static org.apache.cassandra.schema.SchemaConstants.AUTH_KEYSPACE_NAME; +import static org.apache.cassandra.schema.SchemaConstants.DISTRIBUTED_KEYSPACE_NAME; +import static org.apache.cassandra.schema.SchemaConstants.SCHEMA_KEYSPACE_NAME; +import static org.apache.cassandra.schema.SchemaConstants.SYSTEM_KEYSPACE_NAME; +import static org.apache.cassandra.schema.SchemaConstants.TRACE_KEYSPACE_NAME; +import static org.apache.cassandra.schema.SchemaConstants.VIRTUAL_SCHEMA; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +@RunWith(BMUnitRunner.class) public class DescribeStatementTest extends CQLTester { @Test public void testSchemaChangeDuringPaging() { - SimpleStatement stmt = new SimpleStatement("DESCRIBE KEYSPACES"); - stmt.setFetchSize(1); - ResultSet rs = executeNet(ProtocolVersion.CURRENT, stmt); - Iterator iter = rs.iterator(); - assertTrue(iter.hasNext()); + SimpleStatement stmt = new SimpleStatement("DESCRIBE KEYSPACES"); + stmt.setFetchSize(1); + ResultSet rs = executeNet(ProtocolVersion.CURRENT, stmt); + Iterator iter = rs.iterator(); + assertTrue(iter.hasNext()); + iter.next(); + + createKeyspace("CREATE KEYSPACE %s WITH REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor' : 1};"); + + try + { iter.next(); - - createKeyspace("CREATE KEYSPACE %s WITH REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor' : 1};"); - - try - { - iter.next(); - fail("Expected InvalidQueryException"); - } - catch (InvalidQueryException e) - { - assertEquals(DescribeStatement.SCHEMA_CHANGED_WHILE_PAGING_MESSAGE, e.getMessage()); - } + fail("Expected InvalidQueryException"); + } + catch (InvalidQueryException e) + { + assertEquals(DescribeStatement.SCHEMA_CHANGED_WHILE_PAGING_MESSAGE, e.getMessage()); + } } @Test @@ -99,35 +104,35 @@ public class DescribeStatementTest extends CQLTester "LANGUAGE java " + "AS 'return \"Hello World\";'"); - for (String describeKeyword : new String[]{"DESCRIBE", "DESC"}) + for (String describeKeyword : new String[]{ "DESCRIBE", "DESC" }) { assertRowsNet(executeDescribeNet(describeKeyword + " FUNCTION " + fNonOverloaded), row(KEYSPACE_PER_TEST, "function", shortFunctionName(fNonOverloaded) + "()", "CREATE FUNCTION " + fNonOverloaded + "()\n" + - " CALLED ON NULL INPUT\n" + - " RETURNS int\n" + - " LANGUAGE java\n" + - " AS $$throw new RuntimeException();$$;")); + " CALLED ON NULL INPUT\n" + + " RETURNS int\n" + + " LANGUAGE java\n" + + " AS $$throw new RuntimeException();$$;")); assertRowsNet(executeDescribeNet(describeKeyword + " FUNCTION " + fOverloaded), row(KEYSPACE_PER_TEST, "function", shortFunctionName(fOverloaded) + "(int, ascii)", "CREATE FUNCTION " + fOverloaded + "(input int, other_in ascii)\n" + - " RETURNS NULL ON NULL INPUT\n" + - " RETURNS text\n" + - " LANGUAGE java\n" + - " AS $$return \"Hello World\";$$;"), + " RETURNS NULL ON NULL INPUT\n" + + " RETURNS text\n" + + " LANGUAGE java\n" + + " AS $$return \"Hello World\";$$;"), row(KEYSPACE_PER_TEST, "function", shortFunctionName(fOverloaded) + "(text, ascii)", "CREATE FUNCTION " + fOverloaded + "(input text, other_in ascii)\n" + - " RETURNS NULL ON NULL INPUT\n" + - " RETURNS text\n" + - " LANGUAGE java\n" + - " AS $$return \"Hello World\";$$;")); + " RETURNS NULL ON NULL INPUT\n" + + " RETURNS text\n" + + " LANGUAGE java\n" + + " AS $$return \"Hello World\";$$;")); assertRowsNet(executeDescribeNet(describeKeyword + " FUNCTIONS"), row(KEYSPACE_PER_TEST, @@ -159,37 +164,37 @@ public class DescribeStatementTest extends CQLTester String aNonDeterministic = createAggregate(KEYSPACE_PER_TEST, "int", format("CREATE AGGREGATE %%s(int) " + - "SFUNC %s " + - "STYPE int " + - "INITCOND 42", - shortFunctionName(fIntState))); + "SFUNC %s " + + "STYPE int " + + "INITCOND 42", + shortFunctionName(fIntState))); String aDeterministic = createAggregate(KEYSPACE_PER_TEST, "int", format("CREATE AGGREGATE %%s(int) " + - "SFUNC %s " + - "STYPE int " + - "FINALFUNC %s ", - shortFunctionName(fIntState), - shortFunctionName(fFinal))); + "SFUNC %s " + + "STYPE int " + + "FINALFUNC %s ", + shortFunctionName(fIntState), + shortFunctionName(fFinal))); - for (String describeKeyword : new String[]{"DESCRIBE", "DESC"}) + for (String describeKeyword : new String[]{ "DESCRIBE", "DESC" }) { assertRowsNet(executeDescribeNet(describeKeyword + " AGGREGATE " + aNonDeterministic), row(KEYSPACE_PER_TEST, "aggregate", shortFunctionName(aNonDeterministic) + "(int)", "CREATE AGGREGATE " + aNonDeterministic + "(int)\n" + - " SFUNC " + shortFunctionName(fIntState) + "\n" + - " STYPE int\n" + - " INITCOND 42;")); + " SFUNC " + shortFunctionName(fIntState) + "\n" + + " STYPE int\n" + + " INITCOND 42;")); assertRowsNet(executeDescribeNet(describeKeyword + " AGGREGATE " + aDeterministic), row(KEYSPACE_PER_TEST, "aggregate", shortFunctionName(aDeterministic) + "(int)", "CREATE AGGREGATE " + aDeterministic + "(int)\n" + - " SFUNC " + shortFunctionName(fIntState) + "\n" + - " STYPE int\n" + - " FINALFUNC " + shortFunctionName(fFinal) + ";")); + " SFUNC " + shortFunctionName(fIntState) + "\n" + + " STYPE int\n" + + " FINALFUNC " + shortFunctionName(fFinal) + ";")); assertRowsNet(executeDescribeNet(describeKeyword + " AGGREGATES"), row(KEYSPACE_PER_TEST, "aggregate", @@ -211,35 +216,35 @@ public class DescribeStatementTest extends CQLTester "LANGUAGE java " + "AS 'throw new RuntimeException();';"); - assertRowsNet(executeDescribeNet("DESCRIBE FUNCTION " + function), - row(KEYSPACE_PER_TEST, - "function", - shortFunctionName(function) + "(tuple, list>>, tuple>, text>)", - "CREATE FUNCTION " + function + "(t tuple, l list>>, nt tuple>, text>)\n" + - " CALLED ON NULL INPUT\n" + - " RETURNS tuple\n" + - " LANGUAGE java\n" + - " AS $$throw new RuntimeException();$$;")); + assertRowsNet(executeDescribeNet("DESCRIBE FUNCTION " + function), + row(KEYSPACE_PER_TEST, + "function", + shortFunctionName(function) + "(tuple, list>>, tuple>, text>)", + "CREATE FUNCTION " + function + "(t tuple, l list>>, nt tuple>, text>)\n" + + " CALLED ON NULL INPUT\n" + + " RETURNS tuple\n" + + " LANGUAGE java\n" + + " AS $$throw new RuntimeException();$$;")); } @Test public void testDescribeVirtualTables() throws Throwable { - assertRowsNet(executeDescribeNet("DESCRIBE ONLY KEYSPACE system_virtual_schema;"), + assertRowsNet(executeDescribeNet("DESCRIBE ONLY KEYSPACE system_virtual_schema;"), row("system_virtual_schema", "keyspace", "system_virtual_schema", - "/*\n" + + "/*\n" + "Warning: Keyspace system_virtual_schema is a virtual keyspace and cannot be recreated with CQL.\n" + "Structure, for reference:\n" + "VIRTUAL KEYSPACE system_virtual_schema;\n" + "*/")); - assertRowsNet(executeDescribeNet("DESCRIBE TABLE system_virtual_schema.columns;"), + assertRowsNet(executeDescribeNet("DESCRIBE TABLE system_virtual_schema.columns;"), row("system_virtual_schema", "table", "columns", - "/*\n" + + "/*\n" + "Warning: Table system_virtual_schema.columns is a virtual table and cannot be recreated with CQL.\n" + "Structure, for reference:\n" + "VIRTUAL TABLE system_virtual_schema.columns (\n" + @@ -277,23 +282,23 @@ public class DescribeStatementTest extends CQLTester // Test describe schema Object[][] testSchemaOutput = rows( - row(KEYSPACE, "keyspace", KEYSPACE, - "CREATE KEYSPACE " + KEYSPACE + - " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}" + - " AND durable_writes = true;"), - row(KEYSPACE_PER_TEST, "keyspace", KEYSPACE_PER_TEST, - "CREATE KEYSPACE " + KEYSPACE_PER_TEST + - " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}" + - " AND durable_writes = true;"), - row("test", "keyspace", "test", keyspaceOutput()), - row("test", "table", "has_all_types", allTypesTable()), - row("test", "table", "\"Test\"", testTableOutput()), - row("test", "index", "\"Test_col_idx\"", indexOutput("\"Test_col_idx\"", "\"Test\"", "col")), - row("test", "index", "\"Test_val_idx\"", indexOutput("\"Test_val_idx\"", "\"Test\"", "val")), - row("test", "table", "users", userTableOutput()), - row("test", "index", "myindex", indexOutput("myindex", "users", "age")), - row("test", "table", "users_mv", usersMvTableOutput()), - row("test", "materialized_view", "users_by_state", usersByStateMvOutput())); + row(KEYSPACE, "keyspace", KEYSPACE, + "CREATE KEYSPACE " + KEYSPACE + + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}" + + " AND durable_writes = true;"), + row(KEYSPACE_PER_TEST, "keyspace", KEYSPACE_PER_TEST, + "CREATE KEYSPACE " + KEYSPACE_PER_TEST + + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}" + + " AND durable_writes = true;"), + row("test", "keyspace", "test", keyspaceOutput()), + row("test", "table", "has_all_types", allTypesTable()), + row("test", "table", "\"Test\"", testTableOutput()), + row("test", "index", "\"Test_col_idx\"", indexOutput("\"Test_col_idx\"", "\"Test\"", "col")), + row("test", "index", "\"Test_val_idx\"", indexOutput("\"Test_val_idx\"", "\"Test\"", "val")), + row("test", "table", "users", userTableOutput()), + row("test", "index", "myindex", indexOutput("myindex", "users", "age")), + row("test", "table", "users_mv", usersMvTableOutput()), + row("test", "materialized_view", "users_by_state", usersByStateMvOutput())); assertRowsNet(executeDescribeNet(KEYSPACE_PER_TEST, "DESCRIBE SCHEMA"), testSchemaOutput); assertRowsNet(executeDescribeNet(KEYSPACE_PER_TEST, "DESC SCHEMA"), testSchemaOutput); @@ -310,7 +315,7 @@ public class DescribeStatementTest extends CQLTester row(VIRTUAL_SCHEMA, "keyspace", VIRTUAL_SCHEMA), row("test", "keyspace", "test")); - for (String describeKeyword : new String[]{"DESCRIBE", "DESC"}) + for (String describeKeyword : new String[]{ "DESCRIBE", "DESC" }) { assertRowsNet(executeDescribeNet(describeKeyword + " KEYSPACES"), testKeyspacesOutput); assertRowsNet(executeDescribeNet("test", describeKeyword + " KEYSPACES"), testKeyspacesOutput); @@ -329,7 +334,7 @@ public class DescribeStatementTest extends CQLTester row("test", "table", "users_mv", usersMvTableOutput()), row("test", "materialized_view", "users_by_state", usersByStateMvOutput())); - for (String describeKeyword : new String[]{"DESCRIBE", "DESC"}) + for (String describeKeyword : new String[]{ "DESCRIBE", "DESC" }) { assertRowsNet(executeDescribeNet(describeKeyword + " KEYSPACE test"), testKeyspaceOutput); assertRowsNet(executeDescribeNet(describeKeyword + " test"), testKeyspaceOutput); @@ -338,7 +343,7 @@ public class DescribeStatementTest extends CQLTester } // Test describe tables/table - for (String cmd : new String[]{"describe TABLES", "DESC tables"}) + for (String cmd : new String[]{ "describe TABLES", "DESC tables" }) assertRowsNet(executeDescribeNet("test", cmd), row("test", "table", "has_all_types"), row("test", "table", "\"Test\""), @@ -353,7 +358,7 @@ public class DescribeStatementTest extends CQLTester row("test", "index", "\"Test_val_idx\"", indexOutput("\"Test_val_idx\"", "\"Test\"", "val"))); testDescribeTable("test", "users", row("test", "table", "users", userTableOutput()), - row("test", "index", "myindex", indexOutput("myindex", "users", "age"))); + row("test", "index", "myindex", indexOutput("myindex", "users", "age"))); describeError("test", "DESCRIBE users2", "'users2' not found in keyspace 'test'"); describeError("DESCRIBE test.users2", "'users2' not found in keyspace 'test'"); @@ -379,18 +384,18 @@ public class DescribeStatementTest extends CQLTester private void testDescribeTable(String keyspace, String table, Object[]... rows) throws Throwable { - for (String describeKeyword : new String[]{"describe", "desc"}) + for (String describeKeyword : new String[]{ "describe", "desc" }) { - for (String cmd : new String[]{describeKeyword + " table " + keyspace + "." + table, - describeKeyword + " columnfamily " + keyspace + "." + table, - describeKeyword + " " + keyspace + "." + table}) + for (String cmd : new String[]{ describeKeyword + " table " + keyspace + "." + table, + describeKeyword + " columnfamily " + keyspace + "." + table, + describeKeyword + " " + keyspace + "." + table }) { assertRowsNet(executeDescribeNet(cmd), rows); } - for (String cmd : new String[]{describeKeyword + " table " + table, - describeKeyword + " columnfamily " + table, - describeKeyword + " " + table}) + for (String cmd : new String[]{ describeKeyword + " table " + table, + describeKeyword + " columnfamily " + table, + describeKeyword + " " + table }) { assertRowsNet(executeDescribeNet(keyspace, cmd), rows); } @@ -399,16 +404,16 @@ public class DescribeStatementTest extends CQLTester private void testDescribeIndex(String keyspace, String index, Object[]... rows) throws Throwable { - for (String describeKeyword : new String[]{"describe", "desc"}) + for (String describeKeyword : new String[]{ "describe", "desc" }) { - for (String cmd : new String[]{describeKeyword + " index " + keyspace + "." + index, - describeKeyword + " " + keyspace + "." + index}) + for (String cmd : new String[]{ describeKeyword + " index " + keyspace + "." + index, + describeKeyword + " " + keyspace + "." + index }) { assertRowsNet(executeDescribeNet(cmd), rows); } - for (String cmd : new String[]{describeKeyword + " index " + index, - describeKeyword + " " + index}) + for (String cmd : new String[]{ describeKeyword + " index " + index, + describeKeyword + " " + index }) { assertRowsNet(executeDescribeNet(keyspace, cmd), rows); } @@ -417,16 +422,16 @@ public class DescribeStatementTest extends CQLTester private void testDescribeMaterializedView(String keyspace, String view, Object[]... rows) throws Throwable { - for (String describeKeyword : new String[]{"describe", "desc"}) + for (String describeKeyword : new String[]{ "describe", "desc" }) { - for (String cmd : new String[]{describeKeyword + " materialized view " + keyspace + "." + view, - describeKeyword + " " + keyspace + "." + view}) + for (String cmd : new String[]{ describeKeyword + " materialized view " + keyspace + "." + view, + describeKeyword + " " + keyspace + "." + view }) { assertRowsNet(executeDescribeNet(cmd), rows); } - for (String cmd : new String[]{describeKeyword + " materialized view " + view, - describeKeyword + " " + view}) + for (String cmd : new String[]{ describeKeyword + " materialized view " + view, + describeKeyword + " " + view }) { assertRowsNet(executeDescribeNet(keyspace, cmd), rows); } @@ -436,12 +441,12 @@ public class DescribeStatementTest extends CQLTester @Test public void testDescribeCluster() throws Throwable { - for (String describeKeyword : new String[]{"DESCRIBE", "DESC"}) + for (String describeKeyword : new String[]{ "DESCRIBE", "DESC" }) { assertRowsNet(executeDescribeNet(describeKeyword + " CLUSTER"), - row("Test Cluster", - "ByteOrderedPartitioner", - DatabaseDescriptor.getEndpointSnitch().getClass().getName())); + row("Test Cluster", + "ByteOrderedPartitioner", + DatabaseDescriptor.getEndpointSnitch().getClass().getName())); assertRowsNet(executeDescribeNet("system_virtual_schema", describeKeyword + " CLUSTER"), row("Test Cluster", @@ -530,13 +535,13 @@ public class DescribeStatementTest extends CQLTester ") WITH CLUSTERING ORDER BY (ck1 ASC, ck2 DESC)\n" + " AND " + tableParametersCql(); - String mvCreateStatement ="CREATE MATERIALIZED VIEW " + KEYSPACE_PER_TEST + ".mv AS\n" + - " SELECT *\n" + - " FROM " + KEYSPACE_PER_TEST + "." + table + "\n" + - " WHERE pk2 IS NOT NULL AND pk1 IS NOT NULL AND ck2 IS NOT NULL AND ck1 IS NOT NULL\n" + - " PRIMARY KEY ((pk2, pk1), ck2, ck1)\n" + - " WITH CLUSTERING ORDER BY (ck2 DESC, ck1 ASC)\n" + - " AND " + mvParametersCql(); + String mvCreateStatement = "CREATE MATERIALIZED VIEW " + KEYSPACE_PER_TEST + ".mv AS\n" + + " SELECT *\n" + + " FROM " + KEYSPACE_PER_TEST + "." + table + "\n" + + " WHERE pk2 IS NOT NULL AND pk1 IS NOT NULL AND ck2 IS NOT NULL AND ck1 IS NOT NULL\n" + + " PRIMARY KEY ((pk2, pk1), ck2, ck1)\n" + + " WITH CLUSTERING ORDER BY (ck2 DESC, ck1 ASC)\n" + + " AND " + mvParametersCql(); try { @@ -615,7 +620,7 @@ public class DescribeStatementTest extends CQLTester execute("DROP MATERIALIZED VIEW " + KEYSPACE_PER_TEST + ".mv"); } } - + @Test public void testDescribeMissingKeyspace() throws Throwable { @@ -666,31 +671,31 @@ public class DescribeStatementTest extends CQLTester assertRowsNet(executeDescribeNet(KEYSPACE_PER_TEST, "DESCRIBE TYPE " + type2), row(KEYSPACE_PER_TEST, "type", type2, "CREATE TYPE " + KEYSPACE_PER_TEST + "." + type2 + " (\n" + - " x text,\n" + - " y text\n" + - ");")); + " x text,\n" + + " y text\n" + + ");")); assertRowsNet(executeDescribeNet(KEYSPACE_PER_TEST, "DESCRIBE TYPE " + type1), row(KEYSPACE_PER_TEST, "type", type1, "CREATE TYPE " + KEYSPACE_PER_TEST + "." + type1 + " (\n" + - " a int,\n" + - " b frozen<" + type3 + ">\n" + - ");")); + " a int,\n" + + " b frozen<" + type3 + ">\n" + + ");")); assertRowsNet(executeDescribeNet(KEYSPACE_PER_TEST, "DESCRIBE KEYSPACE " + KEYSPACE_PER_TEST), row(KEYSPACE_PER_TEST, "keyspace", KEYSPACE_PER_TEST, "CREATE KEYSPACE " + KEYSPACE_PER_TEST + - " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}" + - " AND durable_writes = true;"), + " WITH replication = {'class': 'SimpleStrategy', 'replication_factor': '1'}" + + " AND durable_writes = true;"), row(KEYSPACE_PER_TEST, "type", type2, "CREATE TYPE " + KEYSPACE_PER_TEST + "." + type2 + " (\n" + - " x text,\n" + - " y text\n" + - ");"), + " x text,\n" + + " y text\n" + + ");"), row(KEYSPACE_PER_TEST, "type", type3, "CREATE TYPE " + KEYSPACE_PER_TEST + "." + type3 + " (\n" + - " a text,\n" + - " b frozen<" + type2 + ">\n" + - ");"), + " a text,\n" + + " b frozen<" + type2 + ">\n" + + ");"), row(KEYSPACE_PER_TEST, "type", type1, "CREATE TYPE " + KEYSPACE_PER_TEST + "." + type1 + " (\n" + - " a int,\n" + - " b frozen<" + type3 + ">\n" + - ");")); + " a int,\n" + + " b frozen<" + type3 + ">\n" + + ");")); } finally { @@ -702,26 +707,26 @@ public class DescribeStatementTest extends CQLTester /** * Tests for the error reported in CASSANDRA-9064 by: - * + *

* - creating the table described in the bug report, using LCS, * - DESCRIBE-ing that table via cqlsh, then DROPping it, * - running the output of the DESCRIBE statement as a CREATE TABLE statement, and * - inserting a value into the table. - * + *

* The final two steps of the test should not fall down. If one does, that * indicates the output of DESCRIBE is not a correct CREATE TABLE statement. */ @Test public void testDescribeRoundtrip() throws Throwable { - for (String withInternals : new String[]{"", " WITH INTERNALS"}) + for (String withInternals : new String[]{ "", " WITH INTERNALS" }) { String table = createTable(KEYSPACE_PER_TEST, "CREATE TABLE %s (key int PRIMARY KEY) WITH compaction = {'class': 'LeveledCompactionStrategy'}"); String output = executeDescribeNet(KEYSPACE_PER_TEST, "DESCRIBE TABLE " + table + withInternals).all().get(0).getString("create_statement"); executeDescribeNet(KEYSPACE_PER_TEST, "CREATE MATERIALIZED VIEW " + table + "_view AS SELECT key FROM " + table - + " WHERE key IS NOT NULL PRIMARY KEY(key)"); + + " WHERE key IS NOT NULL PRIMARY KEY(key)"); String mvCreateView = executeDescribeNet(KEYSPACE_PER_TEST, "DESCRIBE MATERIALIZED VIEW " + table + "_view").all().get(0).getString("create_statement"); @@ -820,7 +825,8 @@ public class DescribeStatementTest extends CQLTester @Test public void testDescMaterializedViewShouldNotOmitQuotations() throws Throwable { - try{ + try + { execute("CREATE KEYSPACE testWithKeywords WITH REPLICATION = {'class' : 'SimpleStrategy', 'replication_factor' : 1};"); execute("CREATE TABLE testWithKeywords.users_mv (username varchar, password varchar, gender varchar, session_token varchar, " + "state varchar, birth_year bigint, \"token\" text, PRIMARY KEY (\"token\"));"); @@ -850,14 +856,14 @@ public class DescribeStatementTest extends CQLTester final String functionName = KEYSPACE_PER_TEST + ".\"token\""; createFunctionOverload(functionName, - "int, ascii", - "CREATE FUNCTION " + functionName + " (\"token\" int, other_in ascii) " + - "RETURNS NULL ON NULL INPUT " + - "RETURNS text " + - "LANGUAGE java " + - "AS 'return \"Hello World\";'"); + "int, ascii", + "CREATE FUNCTION " + functionName + " (\"token\" int, other_in ascii) " + + "RETURNS NULL ON NULL INPUT " + + "RETURNS text " + + "LANGUAGE java " + + "AS 'return \"Hello World\";'"); - for (String describeKeyword : new String[]{"DESCRIBE", "DESC"}) + for (String describeKeyword : new String[]{ "DESCRIBE", "DESC" }) { assertRowsNet(executeDescribeNet(describeKeyword + " FUNCTION " + functionName), @@ -874,24 +880,24 @@ public class DescribeStatementTest extends CQLTester final String aggregationFunctionName = KEYSPACE_PER_TEST + ".\"token\""; final String aggregationName = KEYSPACE_PER_TEST + ".\"token\""; createFunctionOverload(aggregationName, - "int, int", - "CREATE FUNCTION " + aggregationFunctionName + " (\"token\" int, add_to int) " + - "CALLED ON NULL INPUT " + - "RETURNS int " + - "LANGUAGE java " + - "AS 'return token + add_to;'"); + "int, int", + "CREATE FUNCTION " + aggregationFunctionName + " (\"token\" int, add_to int) " + + "CALLED ON NULL INPUT " + + "RETURNS int " + + "LANGUAGE java " + + "AS 'return token + add_to;'"); String aggregate = createAggregate(KEYSPACE_PER_TEST, - "int", - format("CREATE AGGREGATE %%s(int) " + - "SFUNC %s " + - "STYPE int " + - "INITCOND 42", - shortFunctionName(aggregationFunctionName))); + "int", + format("CREATE AGGREGATE %%s(int) " + + "SFUNC %s " + + "STYPE int " + + "INITCOND 42", + shortFunctionName(aggregationFunctionName))); - for (String describeKeyword : new String[]{"DESCRIBE", "DESC"}) + for (String describeKeyword : new String[]{ "DESCRIBE", "DESC" }) { assertRowsNet(executeDescribeNet(describeKeyword + " AGGREGATE " + aggregate), row(KEYSPACE_PER_TEST, @@ -975,12 +981,12 @@ public class DescribeStatementTest extends CQLTester private static String testTableOutput() { return "CREATE TABLE test.\"Test\" (\n" + - " id int,\n" + - " col int,\n" + - " val text,\n" + - " PRIMARY KEY (id, col)\n" + - ") WITH CLUSTERING ORDER BY (col ASC)\n" + - " AND " + tableParametersCql(); + " id int,\n" + + " col int,\n" + + " val text,\n" + + " PRIMARY KEY (id, col)\n" + + ") WITH CLUSTERING ORDER BY (col ASC)\n" + + " AND " + tableParametersCql(); } private static String tableParametersCql()