Add support for index implementation selection via USING for CREATE INDEX

patch by Caleb Rackliffe; reviewed by Maxwell Guo and Andres de la Peña for CASSANDRA-18615
This commit is contained in:
Caleb Rackliffe 2023-06-21 17:29:05 -05:00 committed by Caleb Rackliffe
parent b57181032d
commit 394d4b1168
22 changed files with 307 additions and 116 deletions

View File

@ -1975,6 +1975,15 @@ drop_compact_storage_enabled: false
# if zero_ttl_on_twcs_enabled is set to false, this property is irrelevant as such statements will fail.
#zero_ttl_on_twcs_warned: true
# The default secondary index implementation when CREATE INDEX does not specify one via USING.
# ex. "legacy_local_table" - (default) legacy secondary index, implemented as a hidden table
# ex. "sai" - "storage-attched" index, implemented via optimized SSTable/Memtable-attached indexes
#default_secondary_index: legacy_local_table
# Whether a default secondary index implementation is allowed. If this is "false", CREATE INDEX must
# specify an index implementation via USING.
#default_secondary_index_enabled: true
# Startup Checks are executed as part of Cassandra startup process, not all of them
# are configurable (so you can disable them) but these which are enumerated bellow.
# Uncomment the startup checks and configure them appropriately to cover your needs.

View File

@ -513,7 +513,8 @@ __Sample:__
bc(sample).
CREATE INDEX userIndex ON NerdMovies (user);
CREATE INDEX ON Mutants (abilityId);
CREATE INDEX ON users (keys(favs));
CREATE INDEX ON users (KEYS(favs));
CREATE INDEX ON users (age) USING 'sai';
CREATE CUSTOM INDEX ON users (email) USING 'path.to.the.IndexClass';
CREATE CUSTOM INDEX ON users (email) USING 'path.to.the.IndexClass' WITH OPTIONS = {'storage': '/mnt/ssd/indexes/'};
@ -521,6 +522,15 @@ The @CREATE INDEX@ statement is used to create a new (automatic) secondary index
Attempting to create an already existing index will return an error unless the @IF NOT EXISTS@ option is used. If it is used, the statement will be a no-op if the index already exists.
h4(#usingIndex). Index Types
The @USING@ keyword optionally specifies an index type. There are two built-in types:
* legacy_local_table - (default) legacy secondary index, implemented as a hidden local table
* sai - "storage-attched" index, implemented via optimized SSTable/Memtable-attached indexes
To create a custom index, a fully qualified class name must be specified.
h4(#keysIndex). Indexes on Map Keys
When creating an index on a "map column":#map, you may index either the keys or the values. If the column identifier is placed within the @keys()@ function, the index will be on the map keys, allowing you to use @CONTAINS KEY@ in @WHERE@ clauses. Otherwise, the index will be on the map values.

View File

@ -1,5 +1,6 @@
create_index_statement::= CREATE [ CUSTOM ] INDEX [ IF NOT EXISTS ] [ index_name ]
ON table_name '(' index_identifier ')'
[ USING string [ WITH OPTIONS = map_literal ] ]
[ USING index_type [ WITH OPTIONS = map_literal ] ]
index_identifier::= column_name
| ( KEYS | VALUES | ENTRIES | FULL ) '(' column_name ')'
index_type::= 'sai' | 'legacy_local_table' | fully_qualified_class_name

View File

@ -1,6 +1,7 @@
CREATE INDEX userIndex ON NerdMovies (user);
CREATE INDEX ON Mutants (abilityId);
CREATE INDEX ON users (keys(favs));
CREATE INDEX ON users (KEYS(favs));
CREATE INDEX ON users (age) USING 'sai';
CREATE CUSTOM INDEX ON users (email)
USING 'path.to.the.IndexClass';
CREATE CUSTOM INDEX ON users (email)

View File

@ -853,6 +853,11 @@ The `TRUNCATE` statement permanently removes all data from a table.
[[createIndexStmt]]
==== CREATE INDEX
The `CREATE INDEX` statement is used to create a new
secondary index for a given (existing) column in a given table. A name
for the index itself can be specified before the `ON` keyword, if
desired.
_Syntax:_
bc(syntax).. +
@ -869,20 +874,26 @@ bc(sample). +
CREATE INDEX userIndex ON NerdMovies (user); +
CREATE INDEX ON Mutants (abilityId); +
CREATE INDEX ON users (keys(favs)); +
CREATE INDEX ON users (age) USING 'sai'; +
CREATE CUSTOM INDEX ON users (email) USING `path.to.the.IndexClass'; +
CREATE CUSTOM INDEX ON users (email) USING `path.to.the.IndexClass' WITH
OPTIONS = \{storage: `/mnt/ssd/indexes/'};
The `CREATE INDEX` statement is used to create a new (automatic)
secondary index for a given (existing) column in a given table. A name
for the index itself can be specified before the `ON` keyword, if
desired. If data already exists for the column, it will be indexed
If data already exists for the column, it will be indexed
asynchronously. After the index is created, new data for the column is
indexed automatically at insertion time.
indexed automatically at insertion time. Attempting to create an already
existing index will return an error unless the `IF NOT EXISTS` option is used.
If it is used, the statement will be a no-op if the index already exists.
Attempting to create an already existing index will return an error
unless the `IF NOT EXISTS` option is used. If it is used, the statement
will be a no-op if the index already exists.
[[indexTypes]]
===== Index Types
The `USING` keyword optionally specifies an index type. There are two built-in types:
- legacy_local_table - (default) legacy secondary index, implemented as a hidden local table
- sai - "storage-attched" index, implemented via optimized SSTable/Memtable-attached indexes
To create a custom index, a fully qualified class name must be specified.
[[keysIndex]]
===== Indexes on Map Keys

View File

@ -12,30 +12,37 @@ include::example$BNF/index_name.bnf[]
[[create-index-statement]]
== CREATE INDEX
Creating a secondary index on a table uses the `CREATE INDEX` statement:
The `CREATE INDEX` statement is used to create a new
secondary index for a given (existing) column in a given table. A name
for the index itself can be specified before the `ON` keyword, if
desired.
[source,bnf]
----
include::example$BNF/create_index_statement.bnf[]
----
For instance:
If data already exists for the column, it will be indexed
asynchronously. After the index is created, new data for the column is
indexed automatically at insertion time. Attempting to create an already
existing index will return an error unless the `IF NOT EXISTS` option is used.
If it is used, the statement will be a no-op if the index already exists.
*Examples*:
[source,cql]
----
include::example$CQL/create_index.cql[]
----
The `CREATE INDEX` statement is used to create a new (automatic)
secondary index for a given (existing) column in a given table. A name
for the index itself can be specified before the `ON` keyword, if
desired. If data already exists for the column, it will be indexed
asynchronously. After the index is created, new data for the column is
indexed automatically at insertion time.
=== Index Types
Attempting to create an already existing index will return an error
unless the `IF NOT EXISTS` option is used. If it is used, the statement
will be a no-op if the index already exists.
The `USING` keyword optionally specifies an index type. There are two built-in types:
- legacy_local_table - (default) legacy secondary index, implemented as a hidden local table
- sai - "storage-attched" index, implemented via optimized SSTable/Memtable-attached indexes
To create a custom index, a fully qualified class name must be specified.
=== Indexes on Map Keys

View File

@ -38,6 +38,7 @@ import org.slf4j.LoggerFactory;
import org.apache.cassandra.audit.AuditLogOptions;
import org.apache.cassandra.db.ConsistencyLevel;
import org.apache.cassandra.fql.FullQueryLoggerOptions;
import org.apache.cassandra.index.internal.CassandraIndex;
import org.apache.cassandra.io.sstable.format.big.BigFormat;
import org.apache.cassandra.service.StartupChecks.StartupCheckType;
import org.apache.cassandra.utils.StorageCompatibilityMode;
@ -49,7 +50,7 @@ import static org.apache.cassandra.config.CassandraRelevantProperties.SKIP_PAXOS
/**
* A class that contains configuration properties for the cassandra node it runs within.
*
* <p>
* Properties declared as volatile can be mutated via JMX.
*/
public class Config
@ -864,6 +865,10 @@ public class Config
public volatile boolean drop_truncate_table_enabled = true;
public volatile boolean drop_keyspace_enabled = true;
public volatile boolean secondary_indexes_enabled = true;
public volatile String default_secondary_index = CassandraIndex.NAME;
public volatile boolean default_secondary_index_enabled = true;
public volatile boolean uncompressed_tables_enabled = true;
public volatile boolean compact_tables_enabled = true;
public volatile boolean read_before_write_list_operations_enabled = true;

View File

@ -3765,6 +3765,26 @@ public class DatabaseDescriptor
conf.sasi_indexes_enabled = enableSASIIndexes;
}
public static String getDefaultSecondaryIndex()
{
return conf.default_secondary_index;
}
public static void setDefaultSecondaryIndex(String name)
{
conf.default_secondary_index = name;
}
public static boolean getDefaultSecondaryIndexEnabled()
{
return conf.default_secondary_index_enabled;
}
public static void setDefaultSecondaryIndexEnabled(boolean enabled)
{
conf.default_secondary_index_enabled = enabled;
}
public static boolean isTransientReplicationEnabled()
{
return conf.transient_replication_enabled;

View File

@ -35,6 +35,7 @@ import org.apache.cassandra.db.Keyspace;
import org.apache.cassandra.db.guardrails.Guardrails;
import org.apache.cassandra.db.marshal.MapType;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.index.internal.CassandraIndex;
import org.apache.cassandra.index.sasi.SASIIndex;
import org.apache.cassandra.schema.*;
import org.apache.cassandra.schema.Keyspaces.KeyspacesDiff;
@ -77,6 +78,7 @@ public final class CreateIndexStatement extends AlterSchemaStatement
public static final String INDEX_DUPLICATE_OF_EXISTING = "Index %s is a duplicate of existing index %s";
public static final String KEYSPACE_DOES_NOT_MATCH_TABLE = "Keyspace name '%s' doesn't match table name '%s'";
public static final String KEYSPACE_DOES_NOT_MATCH_INDEX = "Keyspace name '%s' doesn't match index name '%s'";
public static final String MUST_SPECIFY_INDEX_IMPLEMENTATION = "Must specify index implementation via USING";
private final String indexName;
private final String tableName;
@ -316,6 +318,27 @@ public final class CreateIndexStatement extends AlterSchemaStatement
if (indexName.hasKeyspace() && !keyspaceName.equals(indexName.getKeyspace()))
throw ire(KEYSPACE_DOES_NOT_MATCH_INDEX, keyspaceName, tableName);
// Set the configured default 2i implementation if one isn't specified with USING:
if (attrs.customClass == null)
{
if (DatabaseDescriptor.getDefaultSecondaryIndexEnabled())
attrs.customClass = DatabaseDescriptor.getDefaultSecondaryIndex();
else
// However, operators may require an implementation be specified
throw ire(MUST_SPECIFY_INDEX_IMPLEMENTATION);
}
// If we explicitly specify the index type "legacy_local_table", we can just clear the custom class, and the
// non-custom 2i creation process will begin. Otherwise, if an index type has been specified with
// USING, make sure the appropriate custom index is created.
if (attrs.customClass != null)
{
if (!attrs.isCustom && attrs.customClass.equalsIgnoreCase(CassandraIndex.NAME))
attrs.customClass = null;
else
attrs.isCustom = true;
}
return new CreateIndexStatement(keyspaceName, tableName.getName(), indexName.getName(), rawIndexTargets, attrs, ifNotExists);
}

View File

@ -69,6 +69,8 @@ import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse
*/
public abstract class CassandraIndex implements Index
{
public static final String NAME = "legacy_local_table";
private static final Logger logger = LoggerFactory.getLogger(CassandraIndex.class);
public final ColumnFamilyStore baseCfs;

View File

@ -61,9 +61,9 @@ Follow the instructions to build and start Cassandra in README.asc in root folde
`CREATE TABLE person (id int, name text, age int, PRIMARY KEY (id));`
`CREATE CUSTOM INDEX ON person (name) USING 'StorageAttachedIndex' WITH OPTIONS = {'case_sensitive': false};`
`CREATE INDEX ON person (name) USING 'sai' WITH OPTIONS = {'case_sensitive': false};`
`CREATE CUSTOM INDEX ON person (age) USING 'StorageAttachedIndex';`
`CREATE INDEX ON person (age) USING 'sai';`
2.) Add some data.

View File

@ -95,6 +95,8 @@ import org.apache.cassandra.utils.concurrent.OpOrder;
public class StorageAttachedIndex implements Index
{
public static final String NAME = "sai";
private static final Logger logger = LoggerFactory.getLogger(StorageAttachedIndex.class);
private static class StorageAttachedIndexBuildingSupport implements IndexBuildingSupport

View File

@ -67,7 +67,8 @@ public final class IndexMetadata
static
{
indexNameAliases.put(StorageAttachedIndex.class.getSimpleName(), StorageAttachedIndex.class.getCanonicalName());
indexNameAliases.put(StorageAttachedIndex.NAME, StorageAttachedIndex.class.getCanonicalName());
indexNameAliases.put(StorageAttachedIndex.class.getSimpleName().toLowerCase(), StorageAttachedIndex.class.getCanonicalName());
indexNameAliases.put(SASIIndex.class.getSimpleName(), SASIIndex.class.getCanonicalName());
}
@ -154,7 +155,7 @@ public final class IndexMetadata
if (isCustom())
{
String className = options.get(IndexTarget.CUSTOM_INDEX_OPTION_NAME);
return indexNameAliases.getOrDefault(className, className);
return indexNameAliases.getOrDefault(className.toLowerCase(), className);
}
return CassandraIndex.class.getName();
}

View File

@ -25,9 +25,12 @@ import java.util.concurrent.CountDownLatch;
import com.google.common.collect.ImmutableSet;
import org.apache.commons.lang3.StringUtils;
import org.junit.BeforeClass;
import org.junit.Test;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.index.internal.CassandraIndex;
import org.apache.cassandra.index.sai.StorageAttachedIndex;
import org.apache.cassandra.schema.ColumnMetadata;
import org.apache.cassandra.schema.TableMetadata;
import org.apache.cassandra.config.DatabaseDescriptor;
@ -70,6 +73,12 @@ import static org.junit.Assert.fail;
public class SecondaryIndexTest extends CQLTester
{
public static final int TOO_BIG = 1024 * 65;
@BeforeClass
public static void setDefaultSecondaryIndex()
{
DatabaseDescriptor.setDefaultSecondaryIndex(CassandraIndex.NAME);
}
@Test
public void testCreateAndDropIndex() throws Throwable
@ -161,6 +170,43 @@ public class SecondaryIndexTest extends CQLTester
return StringUtils.remove(indexName, '\"');
}
@Test
public void shouldCreateCassandraIndexExplicitly() throws Throwable
{
createTable("CREATE TABLE %s (userid uuid PRIMARY KEY, firstname text, lastname text, age int)");
createIndex("CREATE INDEX byAge ON %s(age) USING 'legacy_local_table'");
SecondaryIndexManager indexManager = getCurrentColumnFamilyStore().indexManager;
assertTrue(indexManager.getIndexByName("byage") instanceof CassandraIndex);
UUID id1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000");
execute("INSERT INTO %s (userid, firstname, lastname, age) VALUES (?, 'Frodo', 'Baggins', 32)", id1);
assertEmpty(execute("SELECT firstname FROM %s WHERE userid = ? AND age = 33", id1));
}
@Test
public void shouldCreateCassandraIndexWhenNotDefault() throws Throwable
{
DatabaseDescriptor.setDefaultSecondaryIndex(StorageAttachedIndex.NAME);
try
{
createTable("CREATE TABLE %s (userid uuid PRIMARY KEY, firstname text, lastname text, age int)");
createIndex("CREATE INDEX byAge ON %s(age) USING 'legacy_local_table'");
SecondaryIndexManager indexManager = getCurrentColumnFamilyStore().indexManager;
assertTrue(indexManager.getIndexByName("byage") instanceof CassandraIndex);
UUID id1 = UUID.fromString("550e8400-e29b-41d4-a716-446655440000");
execute("INSERT INTO %s (userid, firstname, lastname, age) VALUES (?, 'Frodo', 'Baggins', 32)", id1);
assertEmpty(execute("SELECT firstname FROM %s WHERE userid = ? AND age = 33", id1));
}
finally
{
DatabaseDescriptor.setDefaultSecondaryIndex(CassandraIndex.NAME);
}
}
/**
* Check that you can query for an indexed column even with a key EQ clause,
* migrated from cql_tests.py:TestCQL.static_cf_test()

View File

@ -115,7 +115,7 @@ public abstract class SAITester extends CQLTester
protected static final String CREATE_TABLE_TEMPLATE = "CREATE TABLE %s (id1 TEXT PRIMARY KEY, v1 INT, v2 TEXT) WITH compaction = " +
"{'class' : 'SizeTieredCompactionStrategy', 'enabled' : false }";
protected static final String CREATE_INDEX_TEMPLATE = "CREATE CUSTOM INDEX IF NOT EXISTS ON %%s(%s) USING 'StorageAttachedIndex'";
protected static final String CREATE_INDEX_TEMPLATE = "CREATE INDEX IF NOT EXISTS ON %%s(%s) USING 'sai'";
protected static final ColumnIdentifier V1_COLUMN_IDENTIFIER = ColumnIdentifier.getInterned("v1", true);
protected static final ColumnIdentifier V2_COLUMN_IDENTIFIER = ColumnIdentifier.getInterned("v2", true);

View File

@ -28,9 +28,11 @@ import org.apache.cassandra.index.sai.SAITester;
import static org.junit.Assert.assertEquals;
// This test is primarily handling edge conditions, error conditions
// and basic functionality. Comprehensive type testing of collections
// is in the cql/types/collections package
/**
* This test is primarily handling edge conditions, error conditions
* and basic functionality. Comprehensive type testing of collections
* is in the cql/types/collections package
*/
public class CollectionIndexingTest extends SAITester
{
@Before
@ -42,28 +44,28 @@ public class CollectionIndexingTest extends SAITester
@Test
public void indexMap() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(value) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("value"));
assertEquals(2, execute("SELECT * FROM %s WHERE value CONTAINS 'v1'").size());
}
@Test
public void indexMapKeys() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(KEYS(value)) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("KEYS(value)"));
assertEquals(2, execute("SELECT * FROM %s WHERE value CONTAINS KEY 1").size());
}
@Test
public void indexMapValues() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(VALUES(value)) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("VALUES(value)"));
assertEquals(2, execute("SELECT * FROM %s WHERE value CONTAINS 'v1'").size());
}
@Test
public void indexMapEntries() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(ENTRIES(value)) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("ENTRIES(value)"));
assertEquals(2, execute("SELECT * FROM %s WHERE value[1] = 'v1'").size());
assertEquals(1, execute("SELECT * FROM %s WHERE value[1] = 'v1' AND value[2] = 'v2'").size());
}
@ -71,14 +73,14 @@ public class CollectionIndexingTest extends SAITester
@Test
public void indexFrozenList() throws Throwable
{
createPopulatedFrozenList("CREATE CUSTOM INDEX ON %s(FULL(value)) USING 'StorageAttachedIndex'");
createPopulatedFrozenList(createIndexDDL("FULL(value)"));
assertEquals(2, execute("SELECT * FROM %s WHERE value = ?", Arrays.asList(1, 2, 3)).size());
}
@Test
public void indexFrozenMap() throws Throwable
{
createPopulatedFrozenMap("CREATE CUSTOM INDEX ON %s(FULL(value)) USING 'StorageAttachedIndex'");
createPopulatedFrozenMap(createIndexDDL("FULL(value)"));
assertEquals(1, execute("SELECT * FROM %s WHERE value = ?", new HashMap<Integer, String>() {{
put(1, "v1");
put(2, "v2");
@ -89,21 +91,21 @@ public class CollectionIndexingTest extends SAITester
@Test
public void indexFrozenMapQueryKeys() throws Throwable
{
createPopulatedFrozenMap("CREATE CUSTOM INDEX ON %s(FULL(value)) USING 'StorageAttachedIndex'");
createPopulatedFrozenMap(createIndexDDL("FULL(value)"));
assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains key 1");
}
@Test
public void indexFrozenMapQueryValues() throws Throwable
{
createPopulatedFrozenMap("CREATE CUSTOM INDEX ON %s(FULL(value)) USING 'StorageAttachedIndex'");
createPopulatedFrozenMap(createIndexDDL("FULL(value)"));
assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains 'v1'");
}
@Test
public void indexFrozenMapQueryEntries() throws Throwable
{
createPopulatedFrozenMap("CREATE CUSTOM INDEX ON %s(FULL(value)) USING 'StorageAttachedIndex'");
createPopulatedFrozenMap(createIndexDDL("FULL(value)"));
assertInvalidMessage("Map-entry equality predicates on frozen map column value are not supported",
"SELECT * FROM %s WHERE value[1] = 'v1'");
}
@ -111,7 +113,7 @@ public class CollectionIndexingTest extends SAITester
@Test
public void indexMapEntriesQueryEq() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(ENTRIES(value)) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("ENTRIES(value)"));
assertInvalidMessage("Collection column 'value' (map<int, text>) cannot be restricted by a '=' relation",
"SELECT * FROM %s WHERE value = ?", Arrays.asList(1, 2));
}
@ -119,21 +121,21 @@ public class CollectionIndexingTest extends SAITester
@Test
public void indexMapEntriesQueryKeys() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(ENTRIES(value)) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("ENTRIES(value)"));
assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains key 1");
}
@Test
public void indexMapEntriesQueryValues() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(ENTRIES(value)) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("ENTRIES(value)"));
assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains 'v1'");
}
@Test
public void indexMapKeysQueryEq() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(KEYS(value)) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("KEYS(value)"));
assertInvalidMessage("Collection column 'value' (map<int, text>) cannot be restricted by a '=' relation",
"SELECT * FROM %s WHERE value = ?", Arrays.asList(1, 2));
}
@ -141,21 +143,21 @@ public class CollectionIndexingTest extends SAITester
@Test
public void indexMapKeysQueryValues() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(KEYS(value)) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("KEYS(value)"));
assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains 'v1'");
}
@Test
public void indexMapKeysQueryEntries() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(KEYS(value)) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("KEYS(value)"));
assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value[1] = 'v1'");
}
@Test
public void indexMapValuesQueryEq() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(VALUES(value)) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("VALUES(value)"));
assertInvalidMessage("Collection column 'value' (map<int, text>) cannot be restricted by a '=' relation",
"SELECT * FROM %s WHERE value = ?", Arrays.asList(1, 2));
}
@ -163,18 +165,18 @@ public class CollectionIndexingTest extends SAITester
@Test
public void indexMapValuesQueryKeys() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(VALUES(value)) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("VALUES(value)"));
assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains key 1");
}
@Test
public void indexMapValuesQueryEntries() throws Throwable
{
createPopulatedMap("CREATE CUSTOM INDEX ON %s(VALUES(value)) USING 'StorageAttachedIndex'");
createPopulatedMap(createIndexDDL("VALUES(value)"));
assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value[1] = 'v1'");
}
private void createPopulatedMap(String createIndex) throws Throwable
private void createPopulatedMap(String createIndex)
{
createTable("CREATE TABLE %s (pk int primary key, value map<int, text>)");
createIndex(createIndex);
@ -204,7 +206,7 @@ public class CollectionIndexingTest extends SAITester
}
@SuppressWarnings("SameParameterValue")
private void createPopulatedFrozenList(String createIndex) throws Throwable
private void createPopulatedFrozenList(String createIndex)
{
createTable("CREATE TABLE %s (pk int primary key, value frozen<list<int>>)");
createIndex(createIndex);
@ -220,4 +222,9 @@ public class CollectionIndexingTest extends SAITester
assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE, query, values);
assertEquals(expectedSize, execute(query + " ALLOW FILTERING").size());
}
private static String createIndexDDL(String target)
{
return "CREATE INDEX ON %s(" + target + ") USING 'sai'";
}
}

View File

@ -30,20 +30,20 @@ public class CompositePartitionKeyIndexTest extends SAITester
public void createTableAndIndex()
{
createTable("CREATE TABLE %s (pk1 int, pk2 text, val int, PRIMARY KEY((pk1, pk2)))");
createIndex("CREATE CUSTOM INDEX ON %s(pk1) USING 'StorageAttachedIndex'");
createIndex("CREATE CUSTOM INDEX ON %s(pk2) USING 'StorageAttachedIndex'");
createIndex("CREATE INDEX ON %s(pk1) USING 'sai'");
createIndex("CREATE INDEX ON %s(pk2) USING 'sai'");
disableCompaction();
}
private void insertData1() throws Throwable
private void insertData1()
{
execute("INSERT INTO %s (pk1, pk2, val) VALUES (1, '1', 1)");
execute("INSERT INTO %s (pk1, pk2, val) VALUES (2, '2', 2)");
execute("INSERT INTO %s (pk1, pk2, val) VALUES (3, '3', 3)");
}
private void insertData2() throws Throwable
private void insertData2()
{
execute("INSERT INTO %s (pk1, pk2, val) VALUES (4, '4', 4)");
execute("INSERT INTO %s (pk1, pk2, val) VALUES (5, '5', 5)");
@ -51,7 +51,7 @@ public class CompositePartitionKeyIndexTest extends SAITester
}
@Test
public void queryFromMemtable() throws Throwable
public void queryFromMemtable()
{
insertData1();
insertData2();
@ -62,7 +62,7 @@ public class CompositePartitionKeyIndexTest extends SAITester
return row(index, Integer.toString(index), index);
}
private void runQueries() throws Throwable
private void runQueries()
{
assertRowsIgnoringOrder(execute("SELECT * FROM %s WHERE pk1 = 2"),
expectedRow(2));

View File

@ -25,26 +25,26 @@ import static org.junit.Assert.assertEquals;
public class MultipleColumnIndexTest extends SAITester
{
// Note: Full testing of multiple map index types is done in the
// types/collections/maps/MultiMap*Test tests
// This is just testing that the indexes can be created
@Test
public void canCreateMultipleMapIndexesOnSameColumn()
{
// Note: Full testing of multiple map index types is done in the
// types/collections/maps/MultiMap*Test tests
// This is just testing that the indexes can be created
createTable("CREATE TABLE %s (pk int, ck int, value map<int,int>, PRIMARY KEY(pk, ck))");
createIndex("CREATE CUSTOM INDEX ON %s(KEYS(value)) USING 'StorageAttachedIndex'");
createIndex("CREATE CUSTOM INDEX ON %s(VALUES(value)) USING 'StorageAttachedIndex'");
createIndex("CREATE CUSTOM INDEX ON %s(ENTRIES(value)) USING 'StorageAttachedIndex'");
createIndex("CREATE INDEX ON %s(KEYS(value)) USING 'sai'");
createIndex("CREATE INDEX ON %s(VALUES(value)) USING 'sai'");
createIndex("CREATE INDEX ON %s(ENTRIES(value)) USING 'sai'");
}
@Test
public void indexNamedAsColumnWillCoExistWithGeneratedIndexNames() throws Throwable
public void indexNamedAsColumnWillCoExistWithGeneratedIndexNames()
{
createTable("CREATE TABLE %s(id int PRIMARY KEY, text_map map<text, text>)");
createIndex("CREATE CUSTOM INDEX text_map ON %s(keys(text_map)) USING 'StorageAttachedIndex'");
createIndex("CREATE CUSTOM INDEX ON %s(values(text_map)) USING 'StorageAttachedIndex'");
createIndex("CREATE CUSTOM INDEX ON %s(entries(text_map)) USING 'StorageAttachedIndex'");
createIndex("CREATE INDEX text_map ON %s(keys(text_map)) USING 'sai'");
createIndex("CREATE INDEX ON %s(values(text_map)) USING 'sai'");
createIndex("CREATE INDEX ON %s(entries(text_map)) USING 'sai'");
execute("INSERT INTO %s(id, text_map) values (1, {'k1':'v1', 'k2':'v2'})");
execute("INSERT INTO %s(id, text_map) values (2, {'k1':'v1', 'k3':'v3'})");

View File

@ -37,6 +37,7 @@ import com.datastax.driver.core.ResultSet;
import com.datastax.driver.core.exceptions.InvalidConfigurationInQueryException;
import com.datastax.driver.core.exceptions.InvalidQueryException;
import com.datastax.driver.core.exceptions.ReadFailureException;
import org.apache.cassandra.config.DatabaseDescriptor;
import org.apache.cassandra.cql3.CQL3Type;
import org.apache.cassandra.cql3.ColumnIdentifier;
import org.apache.cassandra.cql3.restrictions.IndexRestrictions;
@ -50,6 +51,7 @@ import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.Int32Type;
import org.apache.cassandra.db.marshal.ReversedType;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.index.Index;
import org.apache.cassandra.index.SecondaryIndexManager;
import org.apache.cassandra.index.sai.IndexContext;
@ -145,7 +147,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
try
{
executeNet(String.format("CREATE CUSTOM INDEX ON %%s(%s) USING 'StorageAttachedIndex'", cql3Type));
executeNet(String.format("CREATE INDEX ON %%s(%s) USING 'sai'", cql3Type));
assertTrue("Index creation on unsupported type " + cql3Type + " should have failed.", supported);
}
catch (RuntimeException e)
@ -161,7 +163,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
public void shouldFailCreationOnPartitionKey()
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(id) USING 'StorageAttachedIndex'"))
assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(id) USING 'sai'"))
.isInstanceOf(InvalidQueryException.class)
.hasMessageContaining(String.format(CreateIndexStatement.ONLY_PARTITION_KEY, "id"));
}
@ -171,8 +173,8 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val) USING " +
"'StorageAttachedIndex' WITH OPTIONS = { 'mode' : 'CONTAINS' }")).isInstanceOf(InvalidConfigurationInQueryException.class);
assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val) USING 'sai' " +
"WITH OPTIONS = { 'mode' : 'CONTAINS' }")).isInstanceOf(InvalidConfigurationInQueryException.class);
}
@Test
@ -180,8 +182,8 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val) " +
"USING 'StorageAttachedIndex' " +
assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val) " +
"USING 'sai' " +
"WITH OPTIONS = { 'analyzer_class' : 'org.apache.cassandra.index.sai.analyzer.NonTokenizingAnalyzer' }"))
.isInstanceOf(InvalidConfigurationInQueryException.class);
}
@ -191,8 +193,8 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val) " +
"USING 'StorageAttachedIndex' " +
assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val) " +
"USING 'sai' " +
"WITH OPTIONS = { 'case-sensitive' : true }")).isInstanceOf(InvalidConfigurationInQueryException.class);
}
@ -201,8 +203,8 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val int)");
assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val) " +
"USING 'StorageAttachedIndex' " +
assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val) " +
"USING 'sai' " +
"WITH OPTIONS = { 'case_sensitive' : true }")).isInstanceOf(InvalidQueryException.class);
}
@ -211,8 +213,8 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val int)");
assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val) " +
"USING 'StorageAttachedIndex' " +
assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val) " +
"USING 'sai' " +
"WITH OPTIONS = { 'normalize' : true }")).isInstanceOf(InvalidQueryException.class);
}
@ -222,8 +224,8 @@ public class StorageAttachedIndexDDLTest extends SAITester
String typeName = createType("CREATE TYPE %s (a text, b int, c double)");
createTable("CREATE TABLE %s (id text PRIMARY KEY, val " + typeName + ')');
assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val) " +
"USING 'StorageAttachedIndex'")).isInstanceOf(InvalidQueryException.class);
assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val) " +
"USING 'sai'")).isInstanceOf(InvalidQueryException.class);
}
@Test
@ -231,7 +233,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val tuple<text, int, double>)");
executeNet("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex'");
executeNet("CREATE INDEX ON %s(val) USING 'sai'");
TableMetadata metadata = currentTableMetadata();
AbstractType<?> tuple = metadata.getColumn(ColumnIdentifier.getInterned("val", false)).type;
@ -246,8 +248,8 @@ public class StorageAttachedIndexDDLTest extends SAITester
String invalidColumn = "/invalid";
createTable(String.format("CREATE TABLE %%s (id text PRIMARY KEY, \"%s\" text)", invalidColumn));
assertThatThrownBy(() -> executeNet(String.format("CREATE CUSTOM INDEX ON %%s(\"%s\")" +
" USING 'StorageAttachedIndex'", invalidColumn)))
assertThatThrownBy(() -> executeNet(String.format("CREATE INDEX ON %%s(\"%s\")" +
" USING 'sai'", invalidColumn)))
.isInstanceOf(InvalidQueryException.class)
.hasMessage(String.format(CreateIndexStatement.INVALID_CUSTOM_INDEX_TARGET, invalidColumn, SchemaConstants.NAME_LENGTH));
}
@ -256,20 +258,65 @@ public class StorageAttachedIndexDDLTest extends SAITester
public void shouldCreateIndexIfExists()
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
createIndex("CREATE CUSTOM INDEX IF NOT EXISTS ON %s(val) USING 'StorageAttachedIndex' ");
createIndexAsync("CREATE CUSTOM INDEX IF NOT EXISTS ON %s(val) USING 'StorageAttachedIndex' ");
createIndex("CREATE INDEX IF NOT EXISTS ON %s(val) USING 'sai' ");
createIndexAsync("CREATE INDEX IF NOT EXISTS ON %s(val) USING 'sai' ");
assertEquals(1, saiCreationCounter.get());
}
@Test
public void shouldCreateIndexCaseInsensitive()
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val1 text, val2 text)");
createIndex("CREATE INDEX mixed_case_val ON %s(val1) USING 'Sai' ");
createIndex("CREATE INDEX upper_case_val ON %s(val2) USING 'SAI' ");
assertEquals(2, saiCreationCounter.get());
}
@Test
public void shouldCreateIndexWithClassName()
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
createIndex("CREATE INDEX ON %s(val) USING 'StorageAttachedIndex' ");
assertEquals(1, saiCreationCounter.get());
}
@Test
public void shouldCreateIndexWithDefault()
{
DatabaseDescriptor.setDefaultSecondaryIndex(StorageAttachedIndex.NAME);
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
createIndex("CREATE INDEX ON %s(val)");
assertEquals(1, saiCreationCounter.get());
}
@Test
public void shouldFailWithDefaultIndexDisabled()
{
DatabaseDescriptor.setDefaultSecondaryIndex(StorageAttachedIndex.NAME);
boolean original = DatabaseDescriptor.getDefaultSecondaryIndexEnabled();
try
{
DatabaseDescriptor.setDefaultSecondaryIndexEnabled(false);
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
assertThatThrownBy(() -> createIndex("CREATE INDEX ON %s(val)")).hasRootCauseInstanceOf(InvalidRequestException.class)
.hasRootCauseMessage(CreateIndexStatement.MUST_SPECIFY_INDEX_IMPLEMENTATION);
assertEquals(0, saiCreationCounter.get());
}
finally
{
DatabaseDescriptor.setDefaultSecondaryIndexEnabled(original);
}
}
@Test
public void shouldBeCaseSensitiveByDefault()
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex'");
createIndex("CREATE INDEX ON %s(val) USING 'sai'");
execute("INSERT INTO %s (id, val) VALUES ('1', 'Camel')");
@ -283,7 +330,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex' WITH OPTIONS = { 'case_sensitive' : true }");
createIndex("CREATE INDEX ON %s(val) USING 'sai' WITH OPTIONS = { 'case_sensitive' : true }");
execute("INSERT INTO %s (id, val) VALUES ('1', 'Camel')");
@ -297,7 +344,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex' WITH OPTIONS = { 'case_sensitive' : false }");
createIndex("CREATE INDEX ON %s(val) USING 'sai' WITH OPTIONS = { 'case_sensitive' : false }");
execute("INSERT INTO %s (id, val) VALUES ('1', 'Camel')");
@ -309,7 +356,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex'");
createIndex("CREATE INDEX ON %s(val) USING 'sai'");
execute("INSERT INTO %s (id, val) VALUES ('1', 'Cam\u00E1l')");
@ -324,7 +371,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex' WITH OPTIONS = { 'normalize' : false }");
createIndex("CREATE INDEX ON %s(val) USING 'sai' WITH OPTIONS = { 'normalize' : false }");
execute("INSERT INTO %s (id, val) VALUES ('1', 'Cam\u00E1l')");
@ -339,7 +386,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex' WITH OPTIONS = { 'normalize' : true }");
createIndex("CREATE INDEX ON %s(val) USING 'sai' WITH OPTIONS = { 'normalize' : true }");
execute("INSERT INTO %s (id, val) VALUES ('1', 'Cam\u00E1l')");
@ -351,7 +398,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex' WITH OPTIONS = { 'normalize' : true, 'case_sensitive' : false}");
createIndex("CREATE INDEX ON %s(val) USING 'sai' WITH OPTIONS = { 'normalize' : true, 'case_sensitive' : false}");
execute("INSERT INTO %s (id, val) VALUES ('1', 'Cam\u00E1l')");
@ -363,7 +410,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex' WITH OPTIONS = { 'ascii' : true, 'case_sensitive' : false}");
createIndex("CREATE INDEX ON %s(val) USING 'sai' WITH OPTIONS = { 'ascii' : true, 'case_sensitive' : false}");
execute("INSERT INTO %s (id, val) VALUES ('1', 'Éppinger')");
@ -371,11 +418,11 @@ public class StorageAttachedIndexDDLTest extends SAITester
}
@Test
public void shouldCreateIndexOnReversedType() throws Throwable
public void shouldCreateIndexOnReversedType()
{
createTable("CREATE TABLE %s (id text, ck1 text, val text, PRIMARY KEY (id,ck1)) WITH CLUSTERING ORDER BY (ck1 desc)");
String indexNameCk1 = createIndex("CREATE CUSTOM INDEX ON %s(ck1) USING 'StorageAttachedIndex'");
String indexNameCk1 = createIndex("CREATE INDEX ON %s(ck1) USING 'sai'");
execute("insert into %s(id, ck1, val) values('1', '2', '3')");
execute("insert into %s(id, ck1, val) values('1', '3', '4')");
@ -392,11 +439,10 @@ public class StorageAttachedIndexDDLTest extends SAITester
}
@Test
public void shouldCreateIndexWithAlias()
public void shouldCreateIndexWithFullClassName()
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val text)");
createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex'");
createIndex("CREATE CUSTOM INDEX ON %s(val) USING 'org.apache.cassandra.index.sai.StorageAttachedIndex'");
assertEquals(1, saiCreationCounter.get());
}
@ -406,7 +452,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
* Not putting in {@link MixedIndexImplementationsTest} because it uses CQLTester which doesn't load SAI dependency.
*/
@Test
public void shouldCreateSASI() throws Throwable
public void shouldCreateSASI()
{
createTable(CREATE_TABLE_TEMPLATE);
@ -433,7 +479,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
{
createTable("CREATE TABLE %s (id text PRIMARY KEY, val1 text, val2 text)");
assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(val1, val2) USING 'StorageAttachedIndex'"))
assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(val1, val2) USING 'sai'"))
.isInstanceOf(InvalidQueryException.class)
.hasMessageContaining("storage-attached index cannot be created over multiple columns");
}
@ -445,21 +491,21 @@ public class StorageAttachedIndexDDLTest extends SAITester
execute("INSERT INTO %s (id, v1) VALUES(1, '1')");
flush();
executeNet("CREATE CUSTOM INDEX index_1 ON %s(v1) USING 'StorageAttachedIndex'");
executeNet("CREATE INDEX index_1 ON %s(v1) USING 'sai'");
waitForTableIndexesQueryable();
// same name
assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX index_1 ON %s(v1) USING 'StorageAttachedIndex'"))
assertThatThrownBy(() -> executeNet("CREATE INDEX index_1 ON %s(v1) USING 'sai'"))
.isInstanceOf(InvalidQueryException.class)
.hasMessageContaining(String.format(CreateIndexStatement.INDEX_ALREADY_EXISTS, "index_1"));
// different name, same option
assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX index_2 ON %s(v1) USING 'StorageAttachedIndex'"))
assertThatThrownBy(() -> executeNet("CREATE INDEX index_2 ON %s(v1) USING 'sai'"))
.isInstanceOf(InvalidQueryException.class)
.hasMessageContaining(String.format(CreateIndexStatement.INDEX_DUPLICATE_OF_EXISTING, "index_2", "index_1"));
// different name, different option, same target.
assertThatThrownBy(() -> executeNet("CREATE CUSTOM INDEX ON %s(v1) USING 'StorageAttachedIndex' WITH OPTIONS = { 'case_sensitive' : true }"))
assertThatThrownBy(() -> executeNet("CREATE INDEX ON %s(v1) USING 'sai' WITH OPTIONS = { 'case_sensitive' : true }"))
.isInstanceOf(InvalidQueryException.class)
.hasMessageContaining("Cannot create more than one storage-attached index on the same column: v1" );
@ -496,7 +542,7 @@ public class StorageAttachedIndexDDLTest extends SAITester
// Create the index, but do not allow the initial index build to begin:
Injections.inject(delayInitializationTask);
createIndexAsync("CREATE CUSTOM INDEX ON %s(val) USING 'StorageAttachedIndex'");
createIndexAsync("CREATE INDEX ON %s(val) USING 'sai'");
// Flush the Memtable's contents, which will feed data to the index as the SSTable is written:
flush();

View File

@ -87,7 +87,7 @@ public abstract class IndexingTypeSupport extends SAITester
if (scenario != Scenario.POST_BUILD_QUERY)
{
for (String index : dataset.decorateIndexColumn("value"))
createIndex(String.format("CREATE CUSTOM INDEX ON %%s(%s) USING 'StorageAttachedIndex'", index));
createIndex(String.format("CREATE INDEX ON %%s(%s) USING 'sai'", index));
}
insertData(this, allRows, scenario);
@ -104,14 +104,14 @@ public abstract class IndexingTypeSupport extends SAITester
case POST_BUILD_QUERY:
flush();
for (String index : dataset.decorateIndexColumn("value"))
createIndex(String.format("CREATE CUSTOM INDEX ON %%s(%s) USING 'StorageAttachedIndex'", index));
createIndex(String.format("CREATE INDEX ON %%s(%s) USING 'sai'", index));
break;
}
dataset.querySet().runQueries(this, allRows);
}
public static void insertData(SAITester tester, Object[][] allRows, Scenario scenario) throws Throwable
public static void insertData(SAITester tester, Object[][] allRows, Scenario scenario)
{
int sstableCounter = 0;
int sstableIncrement = NUMBER_OF_VALUES / 8;

View File

@ -45,7 +45,7 @@ public class GroupComponentsTest extends SAITester
public void testInvalidateWithoutObsolete()
{
createTable("CREATE TABLE %s (pk int primary key, value text)");
createIndex("CREATE CUSTOM INDEX ON %s(value) USING 'StorageAttachedIndex'");
createIndex("CREATE INDEX ON %s(value) USING 'sai'");
execute("INSERT INTO %s (pk) VALUES (1)");
flush();
@ -70,7 +70,7 @@ public class GroupComponentsTest extends SAITester
public void getLiveComponentsForEmptyIndex()
{
createTable("CREATE TABLE %s (pk int primary key, value text)");
createIndex("CREATE CUSTOM INDEX ON %s(value) USING 'StorageAttachedIndex'");
createIndex("CREATE INDEX ON %s(value) USING 'sai'");
execute("INSERT INTO %s (pk) VALUES (1)");
flush();
@ -91,7 +91,7 @@ public class GroupComponentsTest extends SAITester
public void getLiveComponentsForPopulatedIndex()
{
createTable("CREATE TABLE %s (pk int primary key, value text)");
IndexContext indexContext = createIndexContext(createIndex("CREATE CUSTOM INDEX ON %s(value) USING 'StorageAttachedIndex'"), UTF8Type.instance);
IndexContext indexContext = createIndexContext(createIndex("CREATE INDEX ON %s(value) USING 'sai'"), UTF8Type.instance);
execute("INSERT INTO %s (pk, value) VALUES (1, '1')");
flush();

View File

@ -73,7 +73,7 @@ public class SSTablesSystemViewTest extends SAITester
public void testVirtualTableThroughIndexLifeCycle() throws Throwable
{
createTable("CREATE TABLE %s (k text, c text, v1 text, v2 text, PRIMARY KEY (k, c))");
String v1IndexName = createIndex("CREATE CUSTOM INDEX ON %s(v1) USING 'StorageAttachedIndex'");
String v1IndexName = createIndex("CREATE INDEX ON %s(v1) USING 'sai'");
String insert = "INSERT INTO %s(k, c, v1, v2) VALUES (?, ?, ?, ?)";
@ -99,7 +99,7 @@ public class SSTablesSystemViewTest extends SAITester
assertRowsIgnoringOrder(execute(SELECT), row1, row2);
// create a second index, this should create a new additional entry in the table for each sstable
String v2IndexName = createIndex("CREATE CUSTOM INDEX ON %s(v2) USING 'StorageAttachedIndex'");
String v2IndexName = createIndex("CREATE INDEX ON %s(v2) USING 'sai'");
Object[] row3 = readRow(v2IndexName, id1, "v2", 1L, 0L, 0L);
Object[] row4 = readRow(v2IndexName, id2, "v2", 2L, 0L, 1L);
assertRowsIgnoringOrder(execute(SELECT), row1, row2, row3, row4);