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
This commit is contained in:
Jacek Lewandowski 2023-10-20 12:35:33 +02:00
parent 9697be1131
commit 86e07595f7
4 changed files with 187 additions and 169 deletions

View File

@ -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)

View File

@ -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<T> extends CQLStatement.Raw implements C
@Override
public ResultMessage executeLocally(QueryState state, QueryOptions options)
{
Keyspaces keyspaces = Schema.instance.snapshot();
UUID schemaVersion = Schema.instance.getVersion();
Pair<Keyspaces, UUID> 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<T> 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<? extends T> stream = describe(state.getClientState(), keyspaces);
@ -174,7 +174,7 @@ public abstract class DescribeStatement<T> 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);

View File

@ -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<Keyspaces, UUID> 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()
{

View File

@ -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<Row> iter = rs.iterator();
assertTrue(iter.hasNext());
SimpleStatement stmt = new SimpleStatement("DESCRIBE KEYSPACES");
stmt.setFetchSize(1);
ResultSet rs = executeNet(ProtocolVersion.CURRENT, stmt);
Iterator<Row> 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<int>, list<frozen<tuple<int, text>>>, tuple<frozen<tuple<int, text>>, text>)",
"CREATE FUNCTION " + function + "(t tuple<int>, l list<frozen<tuple<int, text>>>, nt tuple<frozen<tuple<int, text>>, text>)\n" +
" CALLED ON NULL INPUT\n" +
" RETURNS tuple<int, text>\n" +
" LANGUAGE java\n" +
" AS $$throw new RuntimeException();$$;"));
assertRowsNet(executeDescribeNet("DESCRIBE FUNCTION " + function),
row(KEYSPACE_PER_TEST,
"function",
shortFunctionName(function) + "(tuple<int>, list<frozen<tuple<int, text>>>, tuple<frozen<tuple<int, text>>, text>)",
"CREATE FUNCTION " + function + "(t tuple<int>, l list<frozen<tuple<int, text>>>, nt tuple<frozen<tuple<int, text>>, text>)\n" +
" CALLED ON NULL INPUT\n" +
" RETURNS tuple<int, text>\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:
*
* <p>
* - 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.
*
* <p>
* 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()