/* * Copyright (C) 2012-2015 DataStax Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.datastax.driver.core.schemabuilder; import com.datastax.driver.core.CCMTestsSupport; import com.datastax.driver.core.DataType; import com.datastax.driver.core.ResultSet; import com.datastax.driver.core.Row; import com.datastax.driver.core.schemabuilder.TableOptions.CompactionOptions.DateTieredCompactionStrategyOptions.TimeStampResolution; import com.datastax.driver.core.utils.CassandraVersion; import org.testng.annotations.Test; import java.util.Iterator; import static com.datastax.driver.core.schemabuilder.SchemaBuilder.*; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; public class SchemaBuilderIT extends CCMTestsSupport { @Test(groups = "short") @CassandraVersion("2.1.2") public void should_modify_table_metadata() { // Create a table session().execute(SchemaBuilder.createTable("ks", "TableMetadata") .addPartitionKey("a", DataType.cint()) .addPartitionKey("b", DataType.cint()) .addClusteringColumn("c", DataType.cint()) .addClusteringColumn("d", DataType.cint()) .withOptions() .compactStorage() ); // Modify the table metadata session().execute(SchemaBuilder.alterTable("TableMetadata") .withOptions() .defaultTimeToLive(1337) .bloomFilterFPChance(0.42) .caching(SchemaBuilder.KeyCaching.ALL, rows(1)) .gcGraceSeconds(1234567890) .minIndexInterval(6) .indexInterval(7) .maxIndexInterval(8) .comment("Useful comment") .readRepairChance(0.123456) .speculativeRetry(percentile(50)) .dcLocalReadRepairChance(0.84) .memtableFlushPeriodInMillis(1234567890) .compactionOptions(dateTieredStrategy() .baseTimeSeconds(1) .minThreshold(2) .maxThreshold(3) .maxSSTableAgeDays(4) .timestampResolution(TimeStampResolution.MILLISECONDS)) .compressionOptions(snappy())); // Retrieve the metadata from Cassandra ResultSet rows = session().execute("SELECT " + "bloom_filter_fp_chance, " + "caching, " + "cf_id, " + "column_aliases, " + "comment, " + "compaction_strategy_class, " + "compaction_strategy_options, " + "comparator, " + "compression_parameters, " + "default_time_to_live, " + "default_validator, " + "dropped_columns, " + "gc_grace_seconds, " + "index_interval, " + "is_dense, " + "key_aliases, " + "key_validator, " + "local_read_repair_chance, " + "max_compaction_threshold, " + "max_index_interval, " + "memtable_flush_period_in_ms, " + "min_compaction_threshold, " + "min_index_interval, " + "read_repair_chance, " + "speculative_retry, " + "subcomparator, " + "type, " + "value_alias " + "FROM system.schema_columnfamilies " + "WHERE keyspace_name='ks' AND columnfamily_name='tablemetadata'"); for (Row row : rows) { // There should be only one row // Verify that every property we modified is correctly set assertThat(row.getDouble("bloom_filter_fp_chance")).isEqualTo(0.42); assertThat(row.getString("caching")).isEqualTo("{\"keys\":\"ALL\", \"rows_per_partition\":\"1\"}"); assertThat(row.getUUID("cf_id")).isNotNull(); assertThat(row.getString("column_aliases")).isEqualTo("[\"c\",\"d\"]"); assertThat(row.getString("comment")).isEqualTo("Useful comment"); assertThat(row.getString("compaction_strategy_class")) .isEqualTo("org.apache.cassandra.db.compaction.DateTieredCompactionStrategy"); assertThat(row.getString("compaction_strategy_options")).isEqualTo( "{\"base_time_seconds\":\"1\",\"timestamp_resolution\":\"MILLISECONDS\",\"max_sstable_age_days\":\"4\",\"min_threshold\":\"2\",\"max_threshold\":\"3\"}"); assertThat(row.getString("compression_parameters")) .isEqualTo("{\"sstable_compression\":\"org.apache.cassandra.io.compress.SnappyCompressor\"}"); assertThat(row.getInt("default_time_to_live")).isEqualTo(1337); assertThat(row.getInt("gc_grace_seconds")).isEqualTo(1234567890); assertThat(row.getInt("min_index_interval")).isEqualTo(6); assertThat(row.getInt("max_index_interval")).isEqualTo(8); assertThat(row.getString("key_aliases")).isEqualTo("[\"a\",\"b\"]"); assertThat(row.getDouble("local_read_repair_chance")).isEqualTo(0.84); assertThat(row.getInt("max_compaction_threshold")).isEqualTo(3); assertThat(row.getInt("memtable_flush_period_in_ms")).isEqualTo(1234567890); assertThat(row.getInt("min_compaction_threshold")).isEqualTo(2); assertThat(row.getDouble("read_repair_chance")).isEqualTo(0.123456); assertThat(row.getString("speculative_retry")).isEqualTo("50.0PERCENTILE"); } } @Test(groups = "short") @CassandraVersion("2.1.0") public void should_create_a_table_and_a_udt() { // Create a UDT and a table session().execute(SchemaBuilder.createType("MyUDT") .ifNotExists() .addColumn("x", DataType.cint()) ); UDTType myUDT = UDTType.frozen("MyUDT"); session().execute(SchemaBuilder.createTable("ks", "CreateTable") .ifNotExists() .addPartitionKey("a", DataType.cint()) .addUDTPartitionKey("b", myUDT) .addClusteringColumn("c", DataType.ascii()) .addUDTClusteringColumn("d", myUDT) .addUDTColumn("e", myUDT) .addStaticColumn("f", DataType.bigint()) .addUDTStaticColumn("g", myUDT) .addUDTListColumn("h", myUDT) .addUDTMapColumn("i", DataType.cboolean(), myUDT) .addUDTMapColumn("j", myUDT, DataType.cboolean()) .addUDTSetColumn("k", myUDT) ); // Check columns a to k ResultSet rows = session().execute( "SELECT column_name, type, validator " + "FROM system.schema_columns " + "WHERE keyspace_name='ks' AND columnfamily_name='createtable'"); Iterator<Row> iterator = rows.iterator(); verifyNextColumnDefinition(iterator, "a", "partition_key", "org.apache.cassandra.db.marshal.Int32Type"); verifyNextColumnDefinition(iterator, "b", "partition_key", "org.apache.cassandra.db.marshal.UserType"); verifyNextColumnDefinition(iterator, "c", "clustering_key", "org.apache.cassandra.db.marshal.AsciiType"); verifyNextColumnDefinition(iterator, "d", "clustering_key", "org.apache.cassandra.db.marshal.UserType"); verifyNextColumnDefinition(iterator, "e", "regular", "org.apache.cassandra.db.marshal.UserType"); verifyNextColumnDefinition(iterator, "f", "static", "org.apache.cassandra.db.marshal.LongType"); verifyNextColumnDefinition(iterator, "g", "static", "org.apache.cassandra.db.marshal.UserType"); verifyNextColumnDefinition(iterator, "h", "regular", "org.apache.cassandra.db.marshal.ListType" , "org.apache.cassandra.db.marshal.UserType"); verifyNextColumnDefinition(iterator, "i", "regular", "org.apache.cassandra.db.marshal.MapType" , "org.apache.cassandra.db.marshal.BooleanType", "org.apache.cassandra.db.marshal.UserType"); verifyNextColumnDefinition(iterator, "j", "regular", "org.apache.cassandra.db.marshal.MapType" , "org.apache.cassandra.db.marshal.UserType", "org.apache.cassandra.db.marshal.BooleanType"); verifyNextColumnDefinition(iterator, "k", "regular", "org.apache.cassandra.db.marshal.SetType" , "org.apache.cassandra.db.marshal.UserType"); } @Test(groups = "short") public void should_add_and_drop_a_column() { // Create a table, add a column to it with an alter table statement and delete that column session().execute(SchemaBuilder.createTable("ks", "DropColumn") .ifNotExists() .addPartitionKey("a", DataType.cint()) ); // Add and then drop a column session().execute(SchemaBuilder.alterTable("ks", "DropColumn") .addColumn("b") .type(DataType.cint()) ); session().execute(SchemaBuilder.alterTable("ks", "DropColumn") .dropColumn("b") ); // Check that only column a exist ResultSet rows = session().execute( "SELECT column_name, type, validator " + "FROM system.schema_columns " + "WHERE keyspace_name='ks' AND columnfamily_name='dropcolumn'"); Iterator<Row> iterator = rows.iterator(); verifyNextColumnDefinition(iterator, "a", "partition_key", "org.apache.cassandra.db.marshal.Int32Type"); assertThat(iterator.hasNext()).isFalse(); } private void verifyNextColumnDefinition(Iterator<Row> rowIterator, String columnName, String type, String... validatorFragments) { Row rowA = rowIterator.next(); assertThat(rowA.getString("column_name")).isEqualTo(columnName); assertThat(rowA.getString("type")).isEqualTo(type); for (String validatorFragment : validatorFragments) { assertThat(rowA.getString("validator")).contains(validatorFragment); } } @Test(groups = "short") public void should_drop_a_table() { // Create a table session().execute(SchemaBuilder.createTable("ks", "DropTable") .addPartitionKey("a", DataType.cint()) ); // Drop the table session().execute(SchemaBuilder.dropTable("ks", "DropTable")); session().execute(SchemaBuilder.dropTable("DropTable").ifExists()); ResultSet rows = session().execute( "SELECT columnfamily_name " + "FROM system.schema_columnfamilies " + "WHERE keyspace_name='ks' AND columnfamily_name='droptable'"); if (rows.iterator().hasNext()) { fail("This table should have been deleted"); } } @Test(groups = "short") public void should_create_an_index() { // Create a table session().execute(SchemaBuilder.createTable("ks", "CreateIndex") .addPartitionKey("a", DataType.cint()) .addClusteringColumn("b", DataType.cint()) .addColumn("c", DataType.map(DataType.cint(), DataType.cint())) ); // Create an index on a regular column of the table session().execute(SchemaBuilder.createIndex("ks_Index") .onTable("ks", "CreateIndex") .andColumn("b") ); session().execute(SchemaBuilder.createIndex("ks_IndexOnMap") .onTable("ks", "CreateIndex") .andKeysOfColumn("c") ); // Verify that the indexes exist on the right columns ResultSet rows = session().execute( "SELECT column_name, index_name, index_options, index_type, component_index " + "FROM system.schema_columns " + "WHERE keyspace_name='ks' " + "AND columnfamily_name='createindex' " + "AND column_name IN ('b', 'c')"); Iterator<Row> iterator = rows.iterator(); verifyNextIndexDefinition(iterator, "ks_Index", "{}", "COMPOSITES", 0); verifyNextIndexDefinition(iterator, "ks_IndexOnMap", "{\"index_keys\":\"\"}", "COMPOSITES", 1); assertThat(iterator.hasNext()).isFalse(); } private void verifyNextIndexDefinition(Iterator<Row> iterator, String name, String options, String type, int index) { Row nextIndex = iterator.next(); assertThat(nextIndex.getString("index_name")).isEqualTo(name); assertThat(nextIndex.getString("index_options")).isEqualTo(options); assertThat(nextIndex.getString("index_type")).isEqualTo(type); assertThat(nextIndex.getInt("component_index")).isEqualTo(index); } @Test(groups = "short") public void should_drop_an_index() { // Create a table session().execute(SchemaBuilder.createTable("ks", "DropIndex") .addPartitionKey("a", DataType.cint()) .addClusteringColumn("b", DataType.cint()) ); // Create an index // Note: we have to pick a lower-case name because Cassandra uses the CamelCase index name at creation // but a lowercase index name at deletion // See : https://issues.apache.org/jira/browse/CASSANDRA-8365 session().execute(SchemaBuilder.createIndex("ks_index") .onTable("ks", "DropIndex") .andColumn("b") ); // Verify that the PK index and the secondary indexes both exist assertThat(numberOfIndexedColumns()).isEqualTo(1); // Delete the index session().execute(SchemaBuilder.dropIndex("ks", "ks_index")); // Verify that only the PK index exists assertThat(numberOfIndexedColumns()).isEqualTo(0); } private int numberOfIndexedColumns() { ResultSet columns = session().execute( "SELECT * " + "FROM system.schema_columns " + "WHERE keyspace_name='ks' " + "AND columnfamily_name='dropindex' "); int count = 0; for (Row column : columns) { if (column.getString("index_name") != null) count += 1; } return count; } }