http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java index 15a090b,84c6958..3b7504f --- a/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java +++ b/src/java/org/apache/cassandra/cql3/restrictions/StatementRestrictions.java @@@ -37,7 -37,7 +38,6 @@@ import org.apache.cassandra.exceptions. import org.apache.cassandra.index.Index; import org.apache.cassandra.index.SecondaryIndexManager; import org.apache.cassandra.net.MessagingService; --import org.apache.cassandra.utils.ByteBufferUtil; import org.apache.cassandra.utils.btree.BTreeSet; import static org.apache.cassandra.cql3.statements.RequestValidations.checkFalse; @@@ -163,20 -159,12 +163,23 @@@ public final class StatementRestriction for (ColumnDefinition def : relation.toRestriction(cfm, boundNames).getColumnDefs()) this.notNullColumns.add(def); } + else if (relation.isLIKE()) + { + Restriction restriction = relation.toRestriction(cfm, boundNames); + + if (!type.allowUseOfSecondaryIndices() || !restriction.hasSupportingIndex(secondaryIndexManager)) + throw new InvalidRequestException(String.format("LIKE restriction is only supported on properly " + + "indexed columns. %s is not valid.", + relation.toString())); + + addRestriction(restriction); + } else { - addRestriction(relation.toRestriction(cfm, boundNames)); + if (cfm.isSuper() && cfm.isDense() && !relation.onToken()) + addRestriction(relation.toSuperColumnAdapter().toRestriction(cfm, boundNames)); + else + addRestriction(relation.toRestriction(cfm, boundNames)); } } @@@ -250,11 -237,18 +253,18 @@@ Joiner.on(", ").join(nonPrimaryKeyColumns)); } if (hasQueriableIndex) + { usesSecondaryIndexing = true; - else if (!allowFiltering) + } + else if (!allowFiltering && !cfm.isSuper()) + { throw invalidRequest(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE); + } + + checkFalse(clusteringColumnsRestrictions.isEmpty() && cfm.isSuper(), + "Filtering is not supported on SuperColumn tables"); - indexRestrictions.add(nonPrimaryKeyRestrictions); + filterRestrictions.add(nonPrimaryKeyRestrictions); } if (usesSecondaryIndexing) @@@ -824,18 -852,21 +834,29 @@@ public boolean hasAllPKColumnsRestrictedByEqualities() { return !isPartitionKeyRestrictionsOnToken() - && !hasUnrestrictedPartitionKeyComponents() - && (partitionKeyRestrictions.isEQ() || partitionKeyRestrictions.isIN()) - && !hasUnrestrictedClusteringColumns() - && (clusteringColumnsRestrictions.isEQ() || clusteringColumnsRestrictions.isIN()); + && !partitionKeyRestrictions.hasUnrestrictedPartitionKeyComponents(cfm) + && (partitionKeyRestrictions.hasOnlyEqualityRestrictions()) + && !hasUnrestrictedClusteringColumns() + && (clusteringColumnsRestrictions.hasOnlyEqualityRestrictions()); } + /** + * Checks if one of the restrictions applies to a regular column. + * @return {@code true} if one of the restrictions applies to a regular column, {@code false} otherwise. + */ + public boolean hasRegularColumnsRestrictions() + { + return hasRegularColumnsRestrictions; + } + + private SuperColumnCompatibility.SuperColumnRestrictions cached; + public SuperColumnCompatibility.SuperColumnRestrictions getSuperColumnRestrictions() + { + assert cfm.isSuper() && cfm.isDense(); + + if (cached == null) - cached = new SuperColumnCompatibility.SuperColumnRestrictions(Iterators.concat(((PrimaryKeyRestrictionSet) clusteringColumnsRestrictions).iterator(), ++ cached = new SuperColumnCompatibility.SuperColumnRestrictions(Iterators.concat(clusteringColumnsRestrictions.iterator(), + nonPrimaryKeyRestrictions.iterator())); + return cached; + } }
http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/cql3/restrictions/TermSlice.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/cql3/statements/CreateViewStatement.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java index 26b25de,a0919d7..a343fb4 --- a/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/DeleteStatement.java @@@ -139,17 -139,25 +139,25 @@@ public class DeleteStatement extends Mo { Operations operations = new Operations(type); - for (Operation.RawDeletion deletion : deletions) + if (cfm.isSuper() && cfm.isDense()) { - ColumnDefinition def = getColumnDefinition(cfm, deletion.affectedColumn()); - - // For compact, we only have one value except the key, so the only form of DELETE that make sense is without a column - // list. However, we support having the value name for coherence with the static/sparse case - checkFalse(def.isPrimaryKeyColumn(), "Invalid identifier %s for deletion (should not be a PRIMARY KEY part)", def.name); - - Operation op = deletion.prepare(cfm.ksName, def, cfm); - op.collectMarkerSpecification(boundNames); - operations.add(op); + conditions = SuperColumnCompatibility.rebuildLWTColumnConditions(conditions, cfm, whereClause); + whereClause = SuperColumnCompatibility.prepareDeleteOperations(cfm, whereClause, boundNames, operations); + } + else + { + for (Operation.RawDeletion deletion : deletions) + { + ColumnDefinition def = getColumnDefinition(cfm, deletion.affectedColumn()); + + // For compact, we only have one value except the key, so the only form of DELETE that make sense is without a column + // list. However, we support having the value name for coherence with the static/sparse case + checkFalse(def.isPrimaryKeyColumn(), "Invalid identifier %s for deletion (should not be a PRIMARY KEY part)", def.name); + - Operation op = deletion.prepare(cfm.ksName, def); ++ Operation op = deletion.prepare(cfm.ksName, def, cfm); + op.collectMarkerSpecification(boundNames); + operations.add(op); + } } StatementRestrictions restrictions = newRestrictions(cfm, http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java index c925128,28fc90f..c8c7570 --- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java @@@ -549,19 -544,25 +549,28 @@@ public abstract class ModificationState defs.addAll(cfm.partitionKeyColumns()); defs.addAll(cfm.clusteringColumns()); } - for (ColumnDefinition def : columnsWithConditions) - defs.add(def); - selection = Selection.forColumns(cfm, new ArrayList<>(defs)); + + if (cfm.isSuper() && cfm.isDense()) + { + defs.add(cfm.superColumnValueColumn()); + } + else + { + for (ColumnDefinition def : columnsWithConditions) + defs.add(def); + } + + selection = Selection.forColumns(cfm, new ArrayList<>(defs)); } - Selection.ResultSetBuilder builder = selection.resultSetBuilder(false); - SelectStatement.forSelection(cfm, selection).processPartition(partition, options, builder, FBUtilities.nowInSeconds()); + Selection.ResultSetBuilder builder = selection.resultSetBuilder(options, false); + SelectStatement.forSelection(cfm, selection).processPartition(partition, + options, + builder, + FBUtilities.nowInSeconds()); - return builder.build(options.getProtocolVersion()); + return builder.build(); } public ResultMessage executeInternal(QueryState queryState, QueryOptions options) throws RequestValidationException, RequestExecutionException http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql3/statements/SelectStatement.java index 85efafb,2e090fa..33a69e7 --- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java @@@ -18,10 -18,20 +18,19 @@@ package org.apache.cassandra.cql3.statements; import java.nio.ByteBuffer; - import java.util.*; + import java.util.ArrayList; + import java.util.Collection; + import java.util.Collections; + import java.util.Comparator; + import java.util.HashMap; + import java.util.Iterator; + import java.util.List; + import java.util.Map; + import java.util.NavigableSet; + import java.util.SortedSet; -import com.google.common.base.Objects; -import com.google.common.base.Predicate; -import com.google.common.collect.Iterables; +import com.google.common.base.MoreObjects; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@@ -33,9 -53,25 +52,26 @@@ import org.apache.cassandra.cql3.functi import org.apache.cassandra.cql3.restrictions.StatementRestrictions; import org.apache.cassandra.cql3.selection.RawSelector; import org.apache.cassandra.cql3.selection.Selection; +import org.apache.cassandra.db.*; +import org.apache.cassandra.db.aggregation.AggregationSpecification; - import org.apache.cassandra.db.filter.*; + import org.apache.cassandra.db.Clustering; + import org.apache.cassandra.db.ColumnFamilyStore; + import org.apache.cassandra.db.ConsistencyLevel; + import org.apache.cassandra.db.DataRange; + import org.apache.cassandra.db.DecoratedKey; + import org.apache.cassandra.db.Keyspace; + import org.apache.cassandra.db.PartitionPosition; + import org.apache.cassandra.db.PartitionRangeReadCommand; -import org.apache.cassandra.db.ReadOrderGroup; + import org.apache.cassandra.db.ReadQuery; + import org.apache.cassandra.db.SinglePartitionReadCommand; + import org.apache.cassandra.db.Slice; + import org.apache.cassandra.db.Slices; + import org.apache.cassandra.db.filter.ClusteringIndexFilter; + import org.apache.cassandra.db.filter.ClusteringIndexNamesFilter; + import org.apache.cassandra.db.filter.ClusteringIndexSliceFilter; + import org.apache.cassandra.db.filter.ColumnFilter; + import org.apache.cassandra.db.filter.DataLimits; + import org.apache.cassandra.db.filter.RowFilter; import org.apache.cassandra.db.marshal.CollectionType; import org.apache.cassandra.db.marshal.CompositeType; import org.apache.cassandra.db.marshal.Int32Type; @@@ -46,7 -81,11 +82,10 @@@ import org.apache.cassandra.db.rows.Row import org.apache.cassandra.db.rows.RowIterator; import org.apache.cassandra.db.view.View; import org.apache.cassandra.dht.AbstractBounds; - import org.apache.cassandra.exceptions.*; + import org.apache.cassandra.exceptions.InvalidRequestException; + import org.apache.cassandra.exceptions.RequestExecutionException; + import org.apache.cassandra.exceptions.RequestValidationException; + import org.apache.cassandra.exceptions.UnauthorizedException; -import org.apache.cassandra.exceptions.UnrecognizedEntityException; import org.apache.cassandra.index.SecondaryIndexManager; import org.apache.cassandra.serializers.MarshalException; import org.apache.cassandra.service.ClientState; @@@ -778,7 -771,13 +818,13 @@@ public class SelectStatement implement void processPartition(RowIterator partition, QueryOptions options, Selection.ResultSetBuilder result, int nowInSec) throws InvalidRequestException { + if (cfm.isSuper() && cfm.isDense()) + { + SuperColumnCompatibility.processPartition(cfm, selection, partition, result, options.getProtocolVersion(), restrictions.getSuperColumnRestrictions(), options); + return; + } + - int protocolVersion = options.getProtocolVersion(); + ProtocolVersion protocolVersion = options.getProtocolVersion(); ByteBuffer[] keyComponents = getComponents(cfm, partition.partitionKey()); http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java index 6bcfd9c,641b6bb..6638752 --- a/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/UpdateStatement.java @@@ -155,24 -155,33 +155,33 @@@ public class UpdateStatement extends Mo Operations operations = new Operations(type); boolean hasClusteringColumnsSet = false; - for (int i = 0; i < columnNames.size(); i++) + if (cfm.isSuper() && cfm.isDense()) { - ColumnDefinition def = getColumnDefinition(cfm, columnNames.get(i)); - - if (def.isClusteringColumn()) - hasClusteringColumnsSet = true; - - Term.Raw value = columnValues.get(i); - - if (def.isPrimaryKeyColumn()) - { - whereClause.add(new SingleColumnRelation(columnNames.get(i), Operator.EQ, value)); - } - else + // SuperColumn familiy updates are always row-level + hasClusteringColumnsSet = true; + SuperColumnCompatibility.prepareInsertOperations(cfm, columnNames, whereClause, columnValues, boundNames, operations); + } + else + { + for (int i = 0; i < columnNames.size(); i++) { - Operation operation = new Operation.SetValue(value).prepare(cfm, def); - operation.collectMarkerSpecification(boundNames); - operations.add(operation); + ColumnDefinition def = getColumnDefinition(cfm, columnNames.get(i)); + + if (def.isClusteringColumn()) + hasClusteringColumnsSet = true; + + Term.Raw value = columnValues.get(i); + + if (def.isPrimaryKeyColumn()) + { + whereClause.add(new SingleColumnRelation(columnNames.get(i), Operator.EQ, value)); + } + else + { - Operation operation = new Operation.SetValue(value).prepare(cfm.ksName, def); ++ Operation operation = new Operation.SetValue(value).prepare(cfm, def); + operation.collectMarkerSpecification(boundNames); + operations.add(operation); + } } } @@@ -227,25 -234,33 +236,42 @@@ Operations operations = new Operations(type); boolean hasClusteringColumnsSet = false; + if (cfm.isSuper() && cfm.isDense()) + { + hasClusteringColumnsSet = true; + SuperColumnCompatibility.prepareInsertJSONOperations(cfm, defs, boundNames, prepared, whereClause, operations); + } + else + { - for (ColumnDefinition def : defs) - { - if (def.isClusteringColumn()) - hasClusteringColumnsSet = true; + - Term.Raw raw = prepared.getRawTermForColumn(def); - if (def.isPrimaryKeyColumn()) - { - whereClause.add(new SingleColumnRelation(new ColumnIdentifier.ColumnIdentifierValue(def.name), Operator.EQ, raw)); - } - else - { - Operation operation = new Operation.SetValue(raw).prepare(cfm.ksName, def); - operation.collectMarkerSpecification(boundNames); - operations.add(operation); - } ++ ++ ++// TODO: indent ++ + for (ColumnDefinition def : defs) + { + if (def.isClusteringColumn()) + hasClusteringColumnsSet = true; + + Term.Raw raw = prepared.getRawTermForColumn(def, defaultUnset); + if (def.isPrimaryKeyColumn()) + { + whereClause.add(new SingleColumnRelation(ColumnDefinition.Raw.forColumn(def), Operator.EQ, raw)); } + else + { + Operation operation = new Operation.SetValue(raw).prepare(cfm, def); + operation.collectMarkerSpecification(boundNames); + operations.add(operation); + } + } + ++ ++ ++ + } + - boolean applyOnlyToStaticColumns = appliesOnlyToStaticColumns(operations, conditions) && !hasClusteringColumnsSet; + boolean applyOnlyToStaticColumns = !hasClusteringColumnsSet && appliesOnlyToStaticColumns(operations, conditions); StatementRestrictions restrictions = new StatementRestrictions(type, cfm, @@@ -269,8 -284,8 +295,8 @@@ public static class ParsedUpdate extends ModificationStatement.Parsed { // Provided for an UPDATE - private final List<Pair<ColumnIdentifier.Raw, Operation.RawUpdate>> updates; + private final List<Pair<ColumnDefinition.Raw, Operation.RawUpdate>> updates; - private final WhereClause whereClause; + private WhereClause whereClause; /** * Creates a new UpdateStatement from a column family name, columns map, consistency @@@ -302,17 -317,25 +328,25 @@@ { Operations operations = new Operations(type); - for (Pair<ColumnDefinition.Raw, Operation.RawUpdate> entry : updates) + if (cfm.isSuper() && cfm.isDense()) + { + conditions = SuperColumnCompatibility.rebuildLWTColumnConditions(conditions, cfm, whereClause); + whereClause = SuperColumnCompatibility.prepareUpdateOperations(cfm, whereClause, updates, boundNames, operations); + } + else { - ColumnDefinition def = getColumnDefinition(cfm, entry.left); - for (Pair<ColumnIdentifier.Raw, Operation.RawUpdate> entry : updates) ++ for (Pair<ColumnDefinition.Raw, Operation.RawUpdate> entry : updates) + { + ColumnDefinition def = getColumnDefinition(cfm, entry.left); - checkFalse(def.isPrimaryKeyColumn(), "PRIMARY KEY part %s found in SET part", def.name); + checkFalse(def.isPrimaryKeyColumn(), "PRIMARY KEY part %s found in SET part", def.name); - Operation operation = entry.right.prepare(cfm, def); - operation.collectMarkerSpecification(boundNames); - operations.add(operation); - Operation operation = entry.right.prepare(cfm.ksName, def); ++ Operation operation = entry.right.prepare(cfm, def); + operation.collectMarkerSpecification(boundNames); + operations.add(operation); + } } - + StatementRestrictions restrictions = newRestrictions(cfm, boundNames, operations, http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/db/Columns.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/db/LegacyLayout.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/db/LegacyLayout.java index 10fa021,40b9fd3..77aa59a --- a/src/java/org/apache/cassandra/db/LegacyLayout.java +++ b/src/java/org/apache/cassandra/db/LegacyLayout.java @@@ -24,7 -24,7 +24,8 @@@ import java.nio.ByteBuffer import java.security.MessageDigest; import java.util.*; + import org.apache.cassandra.cql3.SuperColumnCompatibility; +import org.apache.cassandra.config.SchemaConstants; import org.apache.cassandra.utils.AbstractIterator; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/db/SerializationHeader.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java index 97d60d5,01c5e3e..04d5f4e --- a/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java +++ b/src/java/org/apache/cassandra/schema/LegacySchemaMigrator.java @@@ -29,8 -29,8 +29,9 @@@ import org.slf4j.LoggerFactory import org.apache.cassandra.config.*; import org.apache.cassandra.cql3.ColumnIdentifier; +import org.apache.cassandra.cql3.FieldIdentifier; import org.apache.cassandra.cql3.QueryProcessor; + import org.apache.cassandra.cql3.SuperColumnCompatibility; import org.apache.cassandra.cql3.UntypedResultSet; import org.apache.cassandra.cql3.functions.FunctionName; import org.apache.cassandra.cql3.functions.UDAggregate; http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/thrift/CassandraServer.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/src/java/org/apache/cassandra/thrift/ThriftConversion.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/test/unit/org/apache/cassandra/SchemaLoader.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/SchemaLoader.java index 2bf4805,1686973..567da19 --- a/test/unit/org/apache/cassandra/SchemaLoader.java +++ b/test/unit/org/apache/cassandra/SchemaLoader.java @@@ -407,28 -391,17 +406,22 @@@ public class SchemaLoade { return superCFMD(ksName, cfName, BytesType.instance, subcc); } + public static CFMetaData superCFMD(String ksName, String cfName, AbstractType cc, AbstractType subcc) { - return superCFMD(ksName, cfName, "cols", cc, subcc); - } - public static CFMetaData superCFMD(String ksName, String cfName, String ccName, AbstractType cc, AbstractType subcc) - { - //This is busted - // return CFMetaData.Builder.createSuper(ksName, cfName, false) - // .addPartitionKey("0", BytesType.instance) - // .addClusteringColumn("1", cc) - // .addClusteringColumn("2", subcc) - // .addRegularColumn("3", AsciiType.instance) - // .build(); - return standardCFMD(ksName, cfName); + return CFMetaData.Builder.createSuper(ksName, cfName, false) + .addPartitionKey("key", BytesType.instance) + .addClusteringColumn("column1", cc) + .addRegularColumn("", MapType.getInstance(AsciiType.instance, subcc, true)) + .build(); } - public static CFMetaData compositeIndexCFMD(String ksName, String cfName, boolean withIndex) throws ConfigurationException + public static CFMetaData compositeIndexCFMD(String ksName, String cfName, boolean withRegularIndex) throws ConfigurationException + { + return compositeIndexCFMD(ksName, cfName, withRegularIndex, false); + } + + public static CFMetaData compositeIndexCFMD(String ksName, String cfName, boolean withRegularIndex, boolean withStaticIndex) throws ConfigurationException { // the withIndex flag exists to allow tests index creation // on existing columns http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/test/unit/org/apache/cassandra/cql3/ViewTest.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/cql3/ViewTest.java index 8428e42,4a4fe1a..7717a4d --- a/test/unit/org/apache/cassandra/cql3/ViewTest.java +++ b/test/unit/org/apache/cassandra/cql3/ViewTest.java @@@ -45,9 -47,12 +47,13 @@@ import org.apache.cassandra.db.ColumnFa import org.apache.cassandra.db.Keyspace; import org.apache.cassandra.db.SystemKeyspace; import org.apache.cassandra.db.compaction.CompactionManager; + import org.apache.cassandra.db.marshal.AsciiType; + import org.apache.cassandra.schema.KeyspaceParams; +import org.apache.cassandra.transport.ProtocolVersion; import org.apache.cassandra.utils.FBUtilities; + import static org.junit.Assert.assertEquals; + import static org.junit.Assert.assertTrue; public class ViewTest extends CQLTester { http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/test/unit/org/apache/cassandra/cql3/validation/ThriftIntegrationTest.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/cql3/validation/ThriftIntegrationTest.java index 0000000,def489e..7e89228 mode 000000,100644..100644 --- a/test/unit/org/apache/cassandra/cql3/validation/ThriftIntegrationTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/ThriftIntegrationTest.java @@@ -1,0 -1,942 +1,942 @@@ + /* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 org.apache.cassandra.cql3.validation; + + import java.nio.ByteBuffer; + import java.util.Arrays; + import java.util.Collections; + import java.util.List; + import java.util.concurrent.atomic.AtomicInteger; + + import org.junit.After; + import org.junit.Before; + import org.junit.Test; + + import org.apache.cassandra.cql3.ColumnIdentifier; + import org.apache.cassandra.cql3.UntypedResultSet; + import org.apache.cassandra.cql3.validation.operations.ThriftCQLTester; + import org.apache.cassandra.db.Keyspace; + import org.apache.cassandra.db.marshal.AsciiType; + import org.apache.cassandra.db.marshal.CounterColumnType; + import org.apache.cassandra.db.marshal.Int32Type; + import org.apache.cassandra.db.marshal.LongType; + import org.apache.cassandra.locator.SimpleStrategy; + import org.apache.cassandra.service.StorageService; + import org.apache.cassandra.thrift.Cassandra; + import org.apache.cassandra.thrift.CfDef; + import org.apache.cassandra.thrift.Column; + import org.apache.cassandra.thrift.ColumnDef; + import org.apache.cassandra.thrift.ColumnOrSuperColumn; + import org.apache.cassandra.thrift.ColumnParent; + import org.apache.cassandra.thrift.ColumnPath; + import org.apache.cassandra.thrift.CounterColumn; + import org.apache.cassandra.thrift.CounterSuperColumn; + import org.apache.cassandra.thrift.Deletion; + import org.apache.cassandra.thrift.KsDef; + import org.apache.cassandra.thrift.Mutation; + import org.apache.cassandra.thrift.SlicePredicate; + import org.apache.cassandra.thrift.SliceRange; + import org.apache.cassandra.thrift.SuperColumn; + import org.apache.cassandra.utils.ByteBufferUtil; + import org.apache.cassandra.utils.FBUtilities; + + import static org.apache.cassandra.thrift.ConsistencyLevel.ONE; + import static org.junit.Assert.assertEquals; + + public class ThriftIntegrationTest extends ThriftCQLTester + { + final static AtomicInteger seqNumber = new AtomicInteger(); + final String KEYSPACE = "thrift_compact_table_with_supercolumns_test_" + seqNumber.incrementAndGet(); + + @Before + public void setupSuperColumnFamily() throws Throwable + { + StorageService.instance.setRpcReady(true); + + final String denseTableName = createTableName(); + final String sparseTableName = currentSparseTable(); + final String counterTableName = currentCounterTable(); + + CfDef cfDef = new CfDef().setColumn_type("Super") + .setSubcomparator_type(Int32Type.instance.toString()) + .setComparator_type(AsciiType.instance.toString()) + .setDefault_validation_class(AsciiType.instance.toString()) + .setKey_validation_class(AsciiType.instance.toString()) + .setKeyspace(KEYSPACE) + .setName(denseTableName); + + CfDef sparseCfDef = new CfDef().setColumn_type("Super") + .setComparator_type(AsciiType.instance.toString()) + .setSubcomparator_type(AsciiType.instance.toString()) + .setKey_validation_class(AsciiType.instance.toString()) + .setColumn_metadata(Arrays.asList(new ColumnDef(ByteBufferUtil.bytes("col1"), LongType.instance.toString()), + new ColumnDef(ByteBufferUtil.bytes("col2"), LongType.instance.toString()))) + .setKeyspace(KEYSPACE) + .setName(sparseTableName); + + CfDef counterCfDef = new CfDef().setColumn_type("Super") + .setSubcomparator_type(AsciiType.instance.toString()) + .setComparator_type(AsciiType.instance.toString()) + .setDefault_validation_class(CounterColumnType.instance.toString()) + .setKey_validation_class(AsciiType.instance.toString()) + .setKeyspace(KEYSPACE) + .setName(counterTableName); + + KsDef ksDef = new KsDef(KEYSPACE, + SimpleStrategy.class.getName(), + Arrays.asList(cfDef, sparseCfDef, counterCfDef)); + + ksDef.setStrategy_options(Collections.singletonMap("replication_factor", "1")); + + Cassandra.Client client = getClient(); + client.system_add_keyspace(ksDef); + client.set_keyspace(KEYSPACE); + } + + @After + public void tearDown() throws Throwable + { + getClient().send_system_drop_keyspace(KEYSPACE); + } + + @Test + public void testCounterTableReads() throws Throwable + { + populateCounterTable(); + beforeAndAfterFlush(this::testCounterTableReadsInternal); + } + + private void testCounterTableReadsInternal() throws Throwable + { + UntypedResultSet resultSet = execute(String.format("select * from %s.%s", KEYSPACE, currentCounterTable())); + assertRows(resultSet, + row("key1", "ck1", "counter1", 10L), + row("key1", "ck1", "counter2", 5L), + row("key2", "ck1", "counter1", 10L), + row("key2", "ck1", "counter2", 5L)); + } + + @Test + public void testCounterTableThriftUpdates() throws Throwable + { + populateCounterTable(); + + Cassandra.Client client = getClient(); + Mutation mutation = new Mutation(); + ColumnOrSuperColumn csoc = new ColumnOrSuperColumn(); + csoc.setCounter_super_column(new CounterSuperColumn(ByteBufferUtil.bytes("ck1"), + Arrays.asList(new CounterColumn(ByteBufferUtil.bytes("counter1"), 1)))); + mutation.setColumn_or_supercolumn(csoc); + + Mutation mutation2 = new Mutation(); + ColumnOrSuperColumn csoc2 = new ColumnOrSuperColumn(); + csoc2.setCounter_super_column(new CounterSuperColumn(ByteBufferUtil.bytes("ck1"), + Arrays.asList(new CounterColumn(ByteBufferUtil.bytes("counter1"), 100)))); + mutation2.setColumn_or_supercolumn(csoc2); + client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key1"), + Collections.singletonMap(currentCounterTable(), Arrays.asList(mutation))), + ONE); + client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key2"), + Collections.singletonMap(currentCounterTable(), Arrays.asList(mutation2))), + ONE); + + beforeAndAfterFlush(() -> { + UntypedResultSet resultSet = execute(String.format("select * from %s.%s", KEYSPACE, currentCounterTable())); + assertRows(resultSet, + row("key1", "ck1", "counter1", 11L), + row("key1", "ck1", "counter2", 5L), + row("key2", "ck1", "counter1", 110L), + row("key2", "ck1", "counter2", 5L)); + }); + } + + @Test + public void testCounterTableCqlUpdates() throws Throwable + { + populateCounterTable(); + + execute(String.format("UPDATE %s.%s set value = value + 1 WHERE key = ? AND column1 = ? AND column2 = ?", KEYSPACE, currentCounterTable()), + "key1", "ck1", "counter1"); + execute(String.format("UPDATE %s.%s set value = value + 100 WHERE key = 'key2' AND column1 = 'ck1' AND column2 = 'counter1'", KEYSPACE, currentCounterTable())); + + execute(String.format("UPDATE %s.%s set value = value - ? WHERE key = 'key1' AND column1 = 'ck1' AND column2 = 'counter2'", KEYSPACE, currentCounterTable()), 2L); + execute(String.format("UPDATE %s.%s set value = value - ? WHERE key = 'key2' AND column1 = 'ck1' AND column2 = 'counter2'", KEYSPACE, currentCounterTable()), 100L); + + beforeAndAfterFlush(() -> { + UntypedResultSet resultSet = execute(String.format("select * from %s.%s", KEYSPACE, currentCounterTable())); + assertRows(resultSet, + row("key1", "ck1", "counter1", 11L), + row("key1", "ck1", "counter2", 3L), + row("key2", "ck1", "counter1", 110L), + row("key2", "ck1", "counter2", -95L)); + }); + } + + @Test + public void testCounterTableCqlDeletes() throws Throwable + { + populateCounterTable(); + + assertRows(execute(String.format("select * from %s.%s", KEYSPACE, currentCounterTable())), + row("key1", "ck1", "counter1", 10L), + row("key1", "ck1", "counter2", 5L), + row("key2", "ck1", "counter1", 10L), + row("key2", "ck1", "counter2", 5L)); + + execute(String.format("DELETE value FROM %s.%s WHERE key = ? AND column1 = ? AND column2 = ?", KEYSPACE, currentCounterTable()), + "key1", "ck1", "counter1"); + + assertRows(execute(String.format("select * from %s.%s", KEYSPACE, currentCounterTable())), + row("key1", "ck1", "counter2", 5L), + row("key2", "ck1", "counter1", 10L), + row("key2", "ck1", "counter2", 5L)); + + execute(String.format("DELETE FROM %s.%s WHERE key = ? AND column1 = ?", KEYSPACE, currentCounterTable()), + "key1", "ck1"); + + assertRows(execute(String.format("select * from %s.%s", KEYSPACE, currentCounterTable())), + row("key2", "ck1", "counter1", 10L), + row("key2", "ck1", "counter2", 5L)); + + execute(String.format("DELETE FROM %s.%s WHERE key = ?", KEYSPACE, currentCounterTable()), + "key2"); + + assertEmpty(execute(String.format("select * from %s.%s", KEYSPACE, currentCounterTable()))); + } + + @Test + public void testDenseTableAlter() throws Throwable + { + populateDenseTable(); + + alterTable(String.format("ALTER TABLE %s.%s RENAME column1 TO renamed_column1", KEYSPACE, currentDenseTable())); + alterTable(String.format("ALTER TABLE %s.%s RENAME column2 TO renamed_column2", KEYSPACE, currentDenseTable())); + alterTable(String.format("ALTER TABLE %s.%s RENAME key TO renamed_key", KEYSPACE, currentDenseTable())); + alterTable(String.format("ALTER TABLE %s.%s RENAME value TO renamed_value", KEYSPACE, currentDenseTable())); + + beforeAndAfterFlush(() -> { + UntypedResultSet resultSet = execute(String.format("select * from %s.%s", KEYSPACE, currentDenseTable())); + assertEquals("renamed_key", resultSet.metadata().get(0).name.toString()); + assertEquals("renamed_column1", resultSet.metadata().get(1).name.toString()); + assertEquals("renamed_column2", resultSet.metadata().get(2).name.toString()); + assertEquals("renamed_value", resultSet.metadata().get(3).name.toString()); + assertRows(resultSet, + row("key1", "val1", 1, "value1"), + row("key1", "val1", 2, "value2"), + row("key1", "val2", 4, "value4"), + row("key1", "val2", 5, "value5"), + row("key2", "val1", 1, "value1"), + row("key2", "val1", 2, "value2"), + row("key2", "val2", 4, "value4"), + row("key2", "val2", 5, "value5")); + }); + } + + @Test + public void testDenseTableReads() throws Throwable + { + populateDenseTable(); + beforeAndAfterFlush(this::testDenseTableReadsInternal); + } + + private void testDenseTableReadsInternal() throws Throwable + { + UntypedResultSet resultSet = execute(String.format("select * from %s.%s", KEYSPACE, currentDenseTable())); + assertEquals("key", resultSet.metadata().get(0).name.toString()); + assertEquals("column1", resultSet.metadata().get(1).name.toString()); + assertEquals("column2", resultSet.metadata().get(2).name.toString()); + assertEquals("value", resultSet.metadata().get(3).name.toString()); + + + assertRows(resultSet, + row("key1", "val1", 1, "value1"), + row("key1", "val1", 2, "value2"), + row("key1", "val2", 4, "value4"), + row("key1", "val2", 5, "value5"), + row("key2", "val1", 1, "value1"), + row("key2", "val1", 2, "value2"), + row("key2", "val2", 4, "value4"), + row("key2", "val2", 5, "value5")); + + assertRows(execute(String.format("select * from %s.%s LIMIT 5", KEYSPACE, currentDenseTable())), + row("key1", "val1", 1, "value1"), + row("key1", "val1", 2, "value2"), + row("key1", "val2", 4, "value4"), + row("key1", "val2", 5, "value5"), + row("key2", "val1", 1, "value1")); + + assertRows(execute(String.format("select value, column2, column1, key from %s.%s", KEYSPACE, currentDenseTable())), + row("value1", 1, "val1", "key1"), + row("value2", 2, "val1", "key1"), + row("value4", 4, "val2", "key1"), + row("value5", 5, "val2", "key1"), + row("value1", 1, "val1", "key2"), + row("value2", 2, "val1", "key2"), + row("value4", 4, "val2", "key2"), + row("value5", 5, "val2", "key2")); + + assertRows(execute(String.format("select * from %s.%s WHERE key = ? AND column1 = ?", KEYSPACE, currentDenseTable()), "key1", "val2"), + row("key1", "val2", 4, "value4"), + row("key1", "val2", 5, "value5")); + + assertRows(execute(String.format("select * from %s.%s where key IN ('key1', 'key2') and column1 = 'val1' and column2 = 2", KEYSPACE, currentDenseTable())), + row("key1", "val1", 2, "value2"), + row("key2", "val1", 2, "value2")); + assertRows(execute(String.format("select * from %s.%s where key IN ('key1', 'key2') and column1 = 'val1' and column2 > 1", KEYSPACE, currentDenseTable())), + row("key1", "val1", 2, "value2"), + row("key2", "val1", 2, "value2")); + assertRows(execute(String.format("select * from %s.%s where key IN ('key1', 'key2') and column1 = 'val1' and column2 >= 2", KEYSPACE, currentDenseTable())), + row("key1", "val1", 2, "value2"), + row("key2", "val1", 2, "value2")); + assertEmpty(execute(String.format("select * from %s.%s where key IN ('key1', 'key2') and column1 = 'val1' and column2 > 2", KEYSPACE, currentDenseTable()))); + + assertRows(execute(String.format("select column2, key from %s.%s WHERE key = ? AND column1 = ? and column2 = 5", KEYSPACE, currentDenseTable()), "key1", "val2"), + row(5, "key1")); + assertRows(execute(String.format("select * from %s.%s WHERE key = ? AND column1 = ? and column2 >= ?", KEYSPACE, currentDenseTable()), "key1", "val2", 5), + row("key1", "val2", 5, "value5")); + assertRows(execute(String.format("select * from %s.%s WHERE key = ? AND column1 = ? and column2 > ?", KEYSPACE, currentDenseTable()), "key1", "val2", 4), + row("key1", "val2", 5, "value5")); + assertRows(execute(String.format("select * from %s.%s WHERE key = ? AND column1 = ? and column2 < ?", KEYSPACE, currentDenseTable()), "key1", "val2", 5), + row("key1", "val2", 4, "value4")); + assertRows(execute(String.format("select * from %s.%s WHERE key = ? AND column1 = ? and column2 <= ?", KEYSPACE, currentDenseTable()), "key1", "val2", 5), + row("key1", "val2", 4, "value4"), + row("key1", "val2", 5, "value5")); + + assertRows(execute(String.format("select * from %s.%s where key = 'key1' and column1 in ('val1', 'val2') and column2 IN (1, 4)", KEYSPACE, currentDenseTable())), + row("key1", "val1", 1, "value1"), + row("key1", "val2", 4, "value4")); + + assertRows(execute(String.format("select * from %s.%s where key = 'key1' and column1 in ('val1', 'val2')", KEYSPACE, currentDenseTable())), + row("key1", "val1", 1, "value1"), + row("key1", "val1", 2, "value2"), + row("key1", "val2", 4, "value4"), + row("key1", "val2", 5, "value5")); + + assertRows(execute(String.format("select * from %s.%s where key = 'key1' and column1 in ('val1', 'val2') and column2 = 1", KEYSPACE, currentDenseTable())), + row("key1", "val1", 1, "value1")); + + assertRows(execute(String.format("select * from %s.%s where key = 'key1' and (column1, column2) = ('val2', 4)", KEYSPACE, currentDenseTable())), + row("key1", "val2", 4, "value4")); + + assertRows(execute(String.format("select * from %s.%s where key = 'key1' and (column1, column2) >= ('val2', 4)", KEYSPACE, currentDenseTable())), + row("key1", "val2", 4, "value4"), + row("key1", "val2", 5, "value5")); + + assertRows(execute(String.format("select * from %s.%s where key = 'key1' and (column1, column2) > ('val1', 1)", KEYSPACE, currentDenseTable())), + row("key1", "val1", 2, "value2"), + row("key1", "val2", 4, "value4"), + row("key1", "val2", 5, "value5")); + + assertRows(execute(String.format("select * from %s.%s where key = 'key1' and (column1, column2) > ('val2', 1)", KEYSPACE, currentDenseTable())), + row("key1", "val2", 4, "value4"), + row("key1", "val2", 5, "value5")); + + resultSet = execute(String.format("select key as a, column1 as b, column2 as c, value as d " + + "from %s.%s WHERE key = ? AND column1 = ?", KEYSPACE, currentDenseTable()), "key1", "val2"); + assertRows(resultSet, + row("key1", "val2", 4, "value4"), + row("key1", "val2", 5, "value5")); + assertEquals(resultSet.metadata().get(2).type, Int32Type.instance); + assertEquals(resultSet.metadata().get(3).type, AsciiType.instance); + + assertRows(execute(String.format("select column2, value from %s.%s WHERE key = ? AND column1 = ?", KEYSPACE, currentDenseTable()), "key1", "val2"), + row(4, "value4"), + row(5, "value5")); + + assertRows(execute(String.format("select column1, value from %s.%s WHERE key = ? AND column1 = ?", KEYSPACE, currentDenseTable()), "key2", "val1"), + row("val1", "value1"), + row("val1", "value2")); + + assertInvalidMessage("Secondary indexes are not supported on COMPACT STORAGE tables that have clustering columns", + String.format("CREATE INDEX ON %s.%s (column2)", KEYSPACE, currentDenseTable())); + assertInvalidMessage("Secondary indexes are not supported on COMPACT STORAGE tables that have clustering columns", + String.format("CREATE INDEX ON %s.%s (value)", KEYSPACE, currentDenseTable())); + + assertRows(execute(String.format("SELECT JSON * FROM %s.%s WHERE key = ? AND column1 = ?", KEYSPACE, currentDenseTable()), "key1", "val2"), + row("{\"key\": \"key1\", \"column1\": \"val2\", \"column2\": 4, \"value\": \"value4\"}"), + row("{\"key\": \"key1\", \"column1\": \"val2\", \"column2\": 5, \"value\": \"value5\"}")); + } + + @Test + public void testDenseTablePartialCqlInserts() throws Throwable + { + assertInvalidMessage("Column value is mandatory for SuperColumn tables", + String.format("INSERT INTO %s.%s (key, column1, column2) VALUES ('key1', 'val1', 1)", KEYSPACE, currentDenseTable())); + + // That's slightly different from 2.X, since null map keys are not allowed + assertInvalidMessage("Column key is mandatory for SuperColumn tables", + String.format("INSERT INTO %s.%s (key, column1, value) VALUES ('key1', 'val1', 'value1')", KEYSPACE, currentDenseTable())); + + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key1', 'val1', 1, NULL)", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key1', 'val1', 1, ?)", KEYSPACE, currentDenseTable()), unset()); + assertEmpty(execute(String.format("select * from %s.%s", KEYSPACE, currentDenseTable()))); + } + + @Test + public void testDenseTableCqlInserts() throws Throwable + { + Cassandra.Client client = getClient(); + + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES (?, ?, ?, ?)", KEYSPACE, currentDenseTable()), + "key1", "val1", 1, "value1"); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES (?, ?, 2, ?)", KEYSPACE, currentDenseTable()), + "key1", "val1", "value2"); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key1', 'val2', 4, 'value4')", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key1', 'val2', 5, 'value5')", KEYSPACE, currentDenseTable())); + + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key2', 'val1', 1, 'value1')", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key2', 'val1', 2, 'value2')", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key2', 'val2', 4, 'value4')", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key2', 'val2', 5, 'value5')", KEYSPACE, currentDenseTable())); + + ColumnPath path = new ColumnPath(currentDenseTable()); + path.setSuper_column(ByteBufferUtil.bytes("val1")); + + ColumnOrSuperColumn cosc = client.get(ByteBufferUtil.bytes("key1"), path, ONE); + assertEquals(cosc.getSuper_column().columns.get(0).name, ByteBufferUtil.bytes(1)); + assertEquals(cosc.getSuper_column().columns.get(0).value, ByteBufferUtil.bytes("value1")); + assertEquals(cosc.getSuper_column().columns.get(1).name, ByteBufferUtil.bytes(2)); + assertEquals(cosc.getSuper_column().columns.get(1).value, ByteBufferUtil.bytes("value2")); + } + + @Test + public void testDenseTableCqlUpdates() throws Throwable + { + assertInvalidMessage("Column key is mandatory for SuperColumn tables", + String.format("UPDATE %s.%s SET column2 = 1, value = 'value1' WHERE key = 'key1' AND column1 = 'val1'", KEYSPACE, currentDenseTable())); + assertInvalidMessage("Column `column2` of type `int` found in SET part", + String.format("UPDATE %s.%s SET column2 = 1, value = 'value1' WHERE key = 'key1' AND column1 = 'val1' AND column2 = 1", KEYSPACE, currentDenseTable())); + assertInvalidMessage("Some clustering keys are missing: column1", + String.format("UPDATE %s.%s SET value = 'value1' WHERE key = 'key1' AND column2 = 1", KEYSPACE, currentDenseTable())); + + execute(String.format("UPDATE %s.%s SET value = 'value1' WHERE key = 'key1' AND column1 = 'val1' AND column2 = 1", KEYSPACE, currentDenseTable())); + execute(String.format("UPDATE %s.%s SET value = 'value2' WHERE key = 'key1' AND column1 = 'val1' AND column2 = 2", KEYSPACE, currentDenseTable())); + + execute(String.format("UPDATE %s.%s SET value = ? WHERE key = ? AND column1 = ? AND column2 = ?", KEYSPACE, currentDenseTable()), + "value1", "key2", "val2", 1); + execute(String.format("UPDATE %s.%s SET value = 'value2' WHERE key = 'key2' AND column1 = ? AND column2 = ?", KEYSPACE, currentDenseTable()), + "val2", 2); + + Cassandra.Client client = getClient(); + ColumnPath path = new ColumnPath(currentDenseTable()); + path.setSuper_column(ByteBufferUtil.bytes("val1")); + + ColumnOrSuperColumn cosc = client.get(ByteBufferUtil.bytes("key1"), path, ONE); + assertEquals(cosc.getSuper_column().columns.get(0).name, ByteBufferUtil.bytes(1)); + assertEquals(cosc.getSuper_column().columns.get(0).value, ByteBufferUtil.bytes("value1")); + assertEquals(cosc.getSuper_column().columns.get(1).name, ByteBufferUtil.bytes(2)); + assertEquals(cosc.getSuper_column().columns.get(1).value, ByteBufferUtil.bytes("value2")); + + path = new ColumnPath(currentDenseTable()); + path.setSuper_column(ByteBufferUtil.bytes("val2")); + + cosc = client.get(ByteBufferUtil.bytes("key2"), path, ONE); + assertEquals(cosc.getSuper_column().columns.get(0).name, ByteBufferUtil.bytes(1)); + assertEquals(cosc.getSuper_column().columns.get(0).value, ByteBufferUtil.bytes("value1")); + assertEquals(cosc.getSuper_column().columns.get(1).name, ByteBufferUtil.bytes(2)); + assertEquals(cosc.getSuper_column().columns.get(1).value, ByteBufferUtil.bytes("value2")); + } + + + @Test + public void testDenseTableCqlDeletes() throws Throwable + { + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key1', 'val1', 1, 'value1')", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key1', 'val1', 2, 'value2')", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key1', 'val2', 4, 'value4')", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key1', 'val2', 5, 'value5')", KEYSPACE, currentDenseTable())); + + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key2', 'val1', 1, 'value1')", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key2', 'val1', 2, 'value2')", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key2', 'val2', 4, 'value4')", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key2', 'val2', 5, 'value5')", KEYSPACE, currentDenseTable())); + + execute(String.format("DELETE FROM %s.%s WHERE key = 'key1' AND column1 = 'val2' AND column2 = 5", KEYSPACE, currentDenseTable())); + assertRows(execute(String.format("SELECT * FROM %s.%s WHERE key = 'key1'", KEYSPACE, currentDenseTable())), + row("key1", "val1", 1, "value1"), + row("key1", "val1", 2, "value2"), + row("key1", "val2", 4, "value4")); + execute(String.format("DELETE FROM %s.%s WHERE key = 'key1' AND column1 = 'val2'", KEYSPACE, currentDenseTable())); + assertRows(execute(String.format("SELECT * FROM %s.%s WHERE key = 'key1'", KEYSPACE, currentDenseTable())), + row("key1", "val1", 1, "value1"), + row("key1", "val1", 2, "value2")); + execute(String.format("DELETE FROM %s.%s WHERE key = 'key1'", KEYSPACE, currentDenseTable())); + assertEmpty(execute(String.format("SELECT * FROM %s.%s WHERE key = 'key1'", KEYSPACE, currentDenseTable()))); + + Cassandra.Client client = getClient(); + + Mutation mutation1 = new Mutation(); + SlicePredicate slicePredicate = new SlicePredicate(); + slicePredicate.setSlice_range(new SliceRange(ByteBufferUtil.bytes("val1"), ByteBufferUtil.bytes("val1"), false, 1)); + Deletion deletion1 = new Deletion(); + deletion1.setTimestamp(FBUtilities.timestampMicros()); + deletion1.setPredicate(slicePredicate); + mutation1.setDeletion(deletion1); + client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key2"), + Collections.singletonMap(currentDenseTable(), Arrays.asList(mutation1))), + ONE); + assertRows(execute(String.format("SELECT * FROM %s.%s WHERE key = 'key2'", KEYSPACE, currentDenseTable())), + row("key2", "val2", 4, "value4"), + row("key2", "val2", 5, "value5")); + + Mutation mutation2 = new Mutation(); + Deletion deletion2 = new Deletion(); + deletion2.setTimestamp(FBUtilities.timestampMicros()); + deletion2.setSuper_column(ByteBufferUtil.bytes("val2")); + mutation2.setDeletion(deletion2); + client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key2"), + Collections.singletonMap(currentDenseTable(), Arrays.asList(mutation2))), + ONE); + + assertEmpty(execute(String.format("SELECT * FROM %s.%s WHERE key = 'key2'", KEYSPACE, currentDenseTable()))); + + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key1', 'val1', 1, 'value1')", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key2', 'val1', 1, 'value1')", KEYSPACE, currentDenseTable())); + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES ('key3', 'val1', 1, 'value1')", KEYSPACE, currentDenseTable())); + + execute(String.format("DELETE FROM %s.%s WHERE key IN ('key1', 'key2')", KEYSPACE, currentDenseTable())); + assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentDenseTable())), + row("key3", "val1", 1, "value1")); + + assertInvalidMessage("Multi-column relations cannot be used in WHERE clauses for UPDATE and DELETE statements", + String.format("DELETE FROM %s.%s WHERE key = 'key3' AND (column1, column2) = ('val1', 1)", KEYSPACE, currentDenseTable())); + + assertInvalidMessage("Token relations cannot be used in WHERE clauses for UPDATE and DELETE statements: token(key) > token('key3')", + String.format("DELETE FROM %s.%s WHERE token(key) > token('key3')", KEYSPACE, currentDenseTable())); + } + + @Test + public void testSparseTableAlter() throws Throwable + { + populateSparseTable(); + + alterTable(String.format("ALTER TABLE %s.%s RENAME column1 TO renamed_column1", KEYSPACE, currentSparseTable())); + alterTable(String.format("ALTER TABLE %s.%s RENAME key TO renamed_key", KEYSPACE, currentSparseTable())); + assertInvalidMessage("Cannot rename non PRIMARY KEY part col1", + String.format("ALTER TABLE %s.%s RENAME col1 TO renamed_col1", KEYSPACE, currentSparseTable())); + assertInvalidMessage("Cannot rename non PRIMARY KEY part col2", + String.format("ALTER TABLE %s.%s RENAME col2 TO renamed_col2", KEYSPACE, currentSparseTable())); + assertInvalidMessage("Cannot rename unknown column column2 in keyspace", + String.format("ALTER TABLE %s.%s RENAME column2 TO renamed_column2", KEYSPACE, currentSparseTable())); + assertInvalidMessage("Cannot rename unknown column value in keyspace", + String.format("ALTER TABLE %s.%s RENAME value TO renamed_value", KEYSPACE, currentSparseTable())); + + + UntypedResultSet resultSet = execute(String.format("select * from %s.%s", KEYSPACE, currentSparseTable())); + assertEquals("renamed_key", resultSet.metadata().get(0).name.toString()); + assertEquals("renamed_column1", resultSet.metadata().get(1).name.toString()); + assertEquals("col1", resultSet.metadata().get(2).name.toString()); + assertEquals("col2", resultSet.metadata().get(3).name.toString()); + + assertRows(resultSet, + row("key1", "val1", 3L, 4L), + row("key1", "val2", 3L, 4L), + row("key2", "val1", 3L, 4L), + row("key2", "val2", 3L, 4L)); + } + + @Test + public void testSparseTableCqlReads() throws Throwable + { + populateSparseTable(); + beforeAndAfterFlush(this::testSparseTableCqlReadsInternal); + } + + private void testSparseTableCqlReadsInternal() throws Throwable + { + UntypedResultSet resultSet = execute(String.format("select * from %s.%s", KEYSPACE, currentSparseTable())); + assertEquals("key", resultSet.metadata().get(0).name.toString()); + assertEquals("column1", resultSet.metadata().get(1).name.toString()); + assertEquals("col1", resultSet.metadata().get(2).name.toString()); + assertEquals("col2", resultSet.metadata().get(3).name.toString()); + + assertRows(resultSet, + row("key1", "val1", 3L, 4L), + row("key1", "val2", 3L, 4L), + row("key2", "val1", 3L, 4L), + row("key2", "val2", 3L, 4L)); + + assertRows(execute(String.format("select col1, col2, column1, key from %s.%s", KEYSPACE, currentSparseTable())), + row(3L, 4L, "val1", "key1"), + row(3L, 4L, "val2", "key1"), + row(3L, 4L, "val1", "key2"), + row(3L, 4L, "val2", "key2")); + - assertInvalidMessage("Undefined name value in selection clause", ++ assertInvalidMessage("Undefined column name value", + String.format("select value from %s.%s", KEYSPACE, currentSparseTable())); + + assertRows(execute(String.format("select * from %s.%s WHERE key = ? AND column1 = ?", KEYSPACE, currentSparseTable()), "key1", "val2"), + row("key1", "val2", 3L, 4L)); + + resultSet = execute(String.format("select col1 as a, col2 as b, column1 as c, key as d from %s.%s WHERE key = ? AND column1 = ?", KEYSPACE, currentSparseTable()), "key1", "val2"); + assertRows(resultSet, + row(3L, 4L, "val2", "key1")); + assertEquals(resultSet.metadata().get(0).name, ColumnIdentifier.getInterned("a", true)); + assertEquals(resultSet.metadata().get(1).name, ColumnIdentifier.getInterned("b", true)); + assertEquals(resultSet.metadata().get(2).name, ColumnIdentifier.getInterned("c", true)); + assertEquals(resultSet.metadata().get(3).name, ColumnIdentifier.getInterned("d", true)); + + assertRows(execute(String.format("select col1, col2 from %s.%s WHERE key = ? AND column1 = ?", KEYSPACE, currentSparseTable()), "key1", "val2"), + row(3L, 4L)); + + assertInvalidMessage("Secondary indexes are not supported on COMPACT STORAGE tables that have clustering columns", + String.format("CREATE INDEX ON %s.%s (column1)", KEYSPACE, currentSparseTable())); + assertInvalidMessage("Secondary indexes are not supported on COMPACT STORAGE tables that have clustering columns", + String.format("CREATE INDEX ON %s.%s (col1)", KEYSPACE, currentSparseTable())); + + assertRows(execute(String.format("SELECT JSON * FROM %s.%s WHERE key = ? AND column1 = ?", KEYSPACE, currentSparseTable()), "key1", "val2"), + row("{\"key\": \"key1\", \"column1\": \"val2\", \"col1\": 3, \"col2\": 4}")); + } + + @Test + public void testSparseTableCqlInserts() throws Throwable + { + execute(String.format("insert into %s.%s (key, column1, col1, col2) values ('key1', 'val1', 1, 2)", KEYSPACE, currentSparseTable())); + execute(String.format("insert into %s.%s (key, column1, col1, col2) values ('key1', 'val2', 3, 4)", KEYSPACE, currentSparseTable())); + execute(String.format("insert into %s.%s (key, column1, col1, col2) values ('key2', 'val1', 5, 6)", KEYSPACE, currentSparseTable())); + execute(String.format("insert into %s.%s (key, column1, col1, col2) values ('key2', 'val2', 7, 8)", KEYSPACE, currentSparseTable())); + + assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentSparseTable())), + row("key1", "val1", 1L, 2L), + row("key1", "val2", 3L, 4L), + row("key2", "val1", 5L, 6L), + row("key2", "val2", 7L, 8L)); + + execute(String.format("truncate %s.%s", KEYSPACE, currentSparseTable())); + + execute(String.format("insert into %s.%s (key, column1) values ('key1', 'val1')", KEYSPACE, currentSparseTable())); + assertRows(execute(String.format("select * from %s.%s", KEYSPACE, currentSparseTable()))); + + execute(String.format("insert into %s.%s (key, column1, col1) values ('key1', 'val1', 1)", KEYSPACE, currentSparseTable())); + execute(String.format("insert into %s.%s (key, column1, col2) values ('key1', 'val1', 2)", KEYSPACE, currentSparseTable())); + assertRows(execute(String.format("select * from %s.%s", KEYSPACE, currentSparseTable())), + row("key1", "val1", 1L, 2L)); + + Cassandra.Client client = getClient(); + ColumnPath path = new ColumnPath(currentSparseTable()); + path.setSuper_column(ByteBufferUtil.bytes("val1")); + + ColumnOrSuperColumn cosc = client.get(ByteBufferUtil.bytes("key1"), path, ONE); + assertEquals(cosc.getSuper_column().columns.get(0).value, ByteBufferUtil.bytes(1L)); + assertEquals(cosc.getSuper_column().columns.get(0).name, ByteBufferUtil.bytes("col1")); + assertEquals(cosc.getSuper_column().columns.get(1).value, ByteBufferUtil.bytes(2L)); + assertEquals(cosc.getSuper_column().columns.get(1).name, ByteBufferUtil.bytes("col2")); + } + + @Test + public void testSparseTableCqlUpdates() throws Throwable + { + execute(String.format("UPDATE %s.%s set col1 = 1, col2 = 2 WHERE key = 'key1' AND column1 = 'val1'", KEYSPACE, currentSparseTable())); + execute(String.format("UPDATE %s.%s set col1 = 3, col2 = 4 WHERE key = 'key1' AND column1 = 'val2'", KEYSPACE, currentSparseTable())); + execute(String.format("UPDATE %s.%s set col1 = 5, col2 = 6 WHERE key = 'key2' AND column1 = 'val1'", KEYSPACE, currentSparseTable())); + execute(String.format("UPDATE %s.%s set col1 = 7, col2 = 8 WHERE key = 'key2' AND column1 = 'val2'", KEYSPACE, currentSparseTable())); + + assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentSparseTable())), + row("key1", "val1", 1L, 2L), + row("key1", "val2", 3L, 4L), + row("key2", "val1", 5L, 6L), + row("key2", "val2", 7L, 8L)); + + Cassandra.Client client = getClient(); + ColumnPath path = new ColumnPath(currentSparseTable()); + path.setSuper_column(ByteBufferUtil.bytes("val1")); + + ColumnOrSuperColumn cosc = client.get(ByteBufferUtil.bytes("key1"), path, ONE); + assertEquals(cosc.getSuper_column().columns.get(0).value, ByteBufferUtil.bytes(1L)); + assertEquals(cosc.getSuper_column().columns.get(0).name, ByteBufferUtil.bytes("col1")); + assertEquals(cosc.getSuper_column().columns.get(1).value, ByteBufferUtil.bytes(2L)); + assertEquals(cosc.getSuper_column().columns.get(1).name, ByteBufferUtil.bytes("col2")); + } + + @Test + public void testSparseTableCqlDeletes() throws Throwable + { + execute(String.format("insert into %s.%s (key, column1, col1, col2) values ('key1', 'val1', 1, 2)", KEYSPACE, currentSparseTable())); + execute(String.format("insert into %s.%s (key, column1, col1, col2) values ('key1', 'val2', 3, 4)", KEYSPACE, currentSparseTable())); + execute(String.format("insert into %s.%s (key, column1, col1, col2) values ('key2', 'val1', 5, 6)", KEYSPACE, currentSparseTable())); + execute(String.format("insert into %s.%s (key, column1, col1, col2) values ('key2', 'val2', 7, 8)", KEYSPACE, currentSparseTable())); + + execute(String.format("DELETE col1 FROM %s.%s WHERE key = 'key1' AND column1 = 'val1'", KEYSPACE, currentSparseTable())); + + assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentSparseTable())), + row("key1", "val1", null, 2L), + row("key1", "val2", 3L, 4L), + row("key2", "val1", 5L, 6L), + row("key2", "val2", 7L, 8L)); + + execute(String.format("DELETE FROM %s.%s WHERE key = 'key1' AND column1 = 'val2'", KEYSPACE, currentSparseTable())); + + assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentSparseTable())), + row("key1", "val1", null, 2L), + row("key2", "val1", 5L, 6L), + row("key2", "val2", 7L, 8L)); + + execute(String.format("DELETE FROM %s.%s WHERE key = 'key2'", KEYSPACE, currentSparseTable())); + + assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentSparseTable())), + row("key1", "val1", null, 2L)); + } + + @Test + public void testInsertJson() throws Throwable + { + execute(String.format("INSERT INTO %s.%s JSON ?", KEYSPACE, currentDenseTable()), + "{\"key\": \"key5\", \"column1\": \"val2\", \"column2\": 4, \"value\": \"value4\"}"); + assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentDenseTable())), + row("key5", "val2", 4, "value4")); + + execute(String.format("INSERT INTO %s.%s JSON ?", KEYSPACE, currentSparseTable()), + "{\"key\": \"key1\", \"column1\": \"val1\", \"col1\": 1, \"col2\": 2}"); + assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentSparseTable())), + row("key1", "val1", 1L, 2L)); + } + + @Test + public void testFiltering() throws Throwable + { + assertInvalidMessage("Filtering is not supported on SuperColumn tables", + String.format("select * from %s.%s WHERE value = ?", KEYSPACE, currentDenseTable()), + "value5"); + assertInvalidMessage("Filtering is not supported on SuperColumn tables", + String.format("select * from %s.%s WHERE value = ? ALLOW FILTERING", KEYSPACE, currentDenseTable()), + "value5"); + assertInvalidMessage("Filtering is not supported on SuperColumn tables", + String.format("SELECT * FROM %s.%s WHERE value = 'value2' ALLOW FILTERING", KEYSPACE, currentDenseTable())); + assertInvalidMessage("Filtering is not supported on SuperColumn tables", + String.format("SELECT * FROM %s.%s WHERE column2 = 1 ALLOW FILTERING", KEYSPACE, currentDenseTable())); + } + + @Test + public void testLwt() throws Throwable + { + assertRows(execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES (?, ?, ?, ?) IF NOT EXISTS", KEYSPACE, currentDenseTable()), + "key1", "val1", 1, "value1"), + row(true)); + assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentDenseTable())), + row("key1", "val1", 1, "value1")); + assertRows(execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES (?, ?, ?, ?) IF NOT EXISTS", KEYSPACE, currentDenseTable()), + "key1", "val1", 1, "value1"), + row(false, "key1", "val1", 1, "value1")); + + // in 2.2 this query was a no-op + assertInvalidMessage("Lightweight transactions on SuperColumn tables are only supported with supplied SuperColumn key", + String.format("UPDATE %s.%s SET value = 'changed' WHERE key = ? AND column1 = ? IF value = ?", KEYSPACE, currentDenseTable())); + + assertRows(execute(String.format("UPDATE %s.%s SET value = 'changed' WHERE key = ? AND column1 = ? AND column2 = ? IF value = ?", KEYSPACE, currentDenseTable()), + "key1", "val1", 1, "value1"), + row(true)); + assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentDenseTable())), + row("key1", "val1", 1, "changed")); + assertRows(execute(String.format("UPDATE %s.%s SET value = 'changed' WHERE key = ? AND column1 = ? AND column2 = ? IF value = ?", KEYSPACE, currentDenseTable()), + "key1", "val1", 1, "value1"), + row(false, "changed")); + + assertRows(execute(String.format("UPDATE %s.%s SET value = 'changed2' WHERE key = ? AND column1 = ? AND column2 = ? IF value > ?", KEYSPACE, currentDenseTable()), + "key1", "val1", 1, "a"), + row(true)); + assertRows(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentDenseTable())), + row("key1", "val1", 1, "changed2")); + assertRows(execute(String.format("UPDATE %s.%s SET value = 'changed2' WHERE key = ? AND column1 = ? AND column2 = ? IF value < ?", KEYSPACE, currentDenseTable()), + "key1", "val1", 1, "a"), + row(false, "changed2")); + + assertInvalidMessage("PRIMARY KEY column 'column2' cannot have IF conditions", + String.format("UPDATE %s.%s SET value = 'changed2' WHERE key = ? AND column1 = ? AND column2 = ? IF value > ? AND column2 = ?", KEYSPACE, currentDenseTable())); + + assertInvalidMessage("Lightweight transactions on SuperColumn tables are only supported with supplied SuperColumn key", + String.format("UPDATE %s.%s SET value = 'changed2' WHERE key = ? AND column1 = ? IF value > ?", KEYSPACE, currentDenseTable())); + + execute(String.format("DELETE FROM %s.%s WHERE key = 'key1' AND column1 = 'val1' AND column2 = 1 IF EXISTS", KEYSPACE, currentDenseTable())); + assertEmpty(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentDenseTable()))); + + execute(String.format("INSERT INTO %s.%s (key, column1, column2, value) VALUES (?, ?, ?, ?)", KEYSPACE, currentDenseTable()), + "key1", "val1", 1, "value1"); + + assertRows(execute(String.format("DELETE FROM %s.%s WHERE key = 'key1' AND column1 = 'val1' AND column2 = 1 IF value = 'value1'", KEYSPACE, currentDenseTable())), + row(true)); + assertEmpty(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentDenseTable()))); + + assertRows(execute(String.format("DELETE FROM %s.%s WHERE key = 'key1' AND column1 = 'val1' AND column2 = 1 IF value = 'value1'", KEYSPACE, currentDenseTable())), + row(false)); + assertEmpty(execute(String.format("SELECT * FROM %s.%s", KEYSPACE, currentDenseTable()))); + } + + @Test + public void testCqlAggregateFunctions() throws Throwable + { + populateDenseTable(); + populateSparseTable(); + + assertRows(execute(String.format("select count(*) from %s.%s", KEYSPACE, currentDenseTable())), + row(8L)); + assertRows(execute(String.format("select count(*) from %s.%s", KEYSPACE, currentSparseTable())), + row(4L)); + + assertRows(execute(String.format("select count(*) from %s.%s where key = ? AND column1 = ?", KEYSPACE, currentDenseTable()), "key1", "val1"), + row(2L)); + assertRows(execute(String.format("select count(*) from %s.%s where key = ? AND column1 = ?", KEYSPACE, currentSparseTable()), "key1", "val1"), + row(1L)); + assertRows(execute(String.format("select count(*) from %s.%s where key = ?", KEYSPACE, currentSparseTable()), "key1"), + row(2L)); + + assertRows(execute(String.format("select max(value) from %s.%s", KEYSPACE, currentDenseTable())), + row("value5")); + assertRows(execute(String.format("select max(col1) from %s.%s", KEYSPACE, currentSparseTable())), + row(3L)); + + assertRows(execute(String.format("select avg(column2) from %s.%s", KEYSPACE, currentDenseTable())), + row(3)); + assertRows(execute(String.format("select avg(col1) from %s.%s", KEYSPACE, currentSparseTable())), + row(3L)); + } + + private void populateDenseTable() throws Throwable + { + Cassandra.Client client = getClient(); + + Mutation mutation = new Mutation(); + ColumnOrSuperColumn csoc = new ColumnOrSuperColumn(); + csoc.setSuper_column(getSuperColumnForInsert(ByteBufferUtil.bytes("val1"), + Arrays.asList(getColumnForInsert(ByteBufferUtil.bytes(1), ByteBufferUtil.bytes("value1")), + getColumnForInsert(ByteBufferUtil.bytes(2), ByteBufferUtil.bytes("value2"))))); + mutation.setColumn_or_supercolumn(csoc); + + Mutation mutation2 = new Mutation(); + ColumnOrSuperColumn csoc2 = new ColumnOrSuperColumn(); + csoc2.setSuper_column(getSuperColumnForInsert(ByteBufferUtil.bytes("val2"), + Arrays.asList(getColumnForInsert(ByteBufferUtil.bytes(4), ByteBufferUtil.bytes("value4")), + getColumnForInsert(ByteBufferUtil.bytes(5), ByteBufferUtil.bytes("value5"))))); + mutation2.setColumn_or_supercolumn(csoc2); + + client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key1"), + Collections.singletonMap(currentDenseTable(), Arrays.asList(mutation, mutation2))), + ONE); + + client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key2"), + Collections.singletonMap(currentDenseTable(), Arrays.asList(mutation, mutation2))), + ONE); + } + + private void populateSparseTable() throws Throwable + { + Cassandra.Client client = getClient(); + + Mutation mutation = new Mutation(); + ColumnOrSuperColumn csoc = new ColumnOrSuperColumn(); + csoc.setSuper_column(getSuperColumnForInsert(ByteBufferUtil.bytes("val1"), + Arrays.asList(getColumnForInsert(ByteBufferUtil.bytes("value1"), ByteBufferUtil.bytes(1L)), + getColumnForInsert(ByteBufferUtil.bytes("value2"), ByteBufferUtil.bytes(2L)), + getColumnForInsert(ByteBufferUtil.bytes("col1"), ByteBufferUtil.bytes(3L)), + getColumnForInsert(ByteBufferUtil.bytes("col2"), ByteBufferUtil.bytes(4L))))); + mutation.setColumn_or_supercolumn(csoc); + + Mutation mutation2 = new Mutation(); + ColumnOrSuperColumn csoc2 = new ColumnOrSuperColumn(); + csoc2.setSuper_column(getSuperColumnForInsert(ByteBufferUtil.bytes("val2"), + Arrays.asList(getColumnForInsert(ByteBufferUtil.bytes("value1"), ByteBufferUtil.bytes(1L)), + getColumnForInsert(ByteBufferUtil.bytes("value2"), ByteBufferUtil.bytes(2L)), + getColumnForInsert(ByteBufferUtil.bytes("col1"), ByteBufferUtil.bytes(3L)), + getColumnForInsert(ByteBufferUtil.bytes("col2"), ByteBufferUtil.bytes(4L))))); + mutation2.setColumn_or_supercolumn(csoc2); + + client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key1"), + Collections.singletonMap(currentSparseTable(), Arrays.asList(mutation, mutation2))), + ONE); + + client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key2"), + Collections.singletonMap(currentSparseTable(), Arrays.asList(mutation, mutation2))), + ONE); + } + + private void populateCounterTable() throws Throwable + { + Cassandra.Client client = getClient(); + + ColumnParent cp = new ColumnParent(currentCounterTable()); + cp.setSuper_column(ByteBufferUtil.bytes("ck1")); + client.add(ByteBufferUtil.bytes("key1"), + cp, + new CounterColumn(ByteBufferUtil.bytes("counter1"), 10L), + ONE); + cp = new ColumnParent(currentCounterTable()); + cp.setSuper_column(ByteBufferUtil.bytes("ck1")); + client.add(ByteBufferUtil.bytes("key1"), + cp, + new CounterColumn(ByteBufferUtil.bytes("counter2"), 5L), + ONE); + cp = new ColumnParent(currentCounterTable()); + cp.setSuper_column(ByteBufferUtil.bytes("ck1")); + client.add(ByteBufferUtil.bytes("key2"), + cp, + new CounterColumn(ByteBufferUtil.bytes("counter1"), 10L), + ONE); + cp = new ColumnParent(currentCounterTable()); + cp.setSuper_column(ByteBufferUtil.bytes("ck1")); + client.add(ByteBufferUtil.bytes("key2"), + cp, + new CounterColumn(ByteBufferUtil.bytes("counter2"), 5L), + ONE); + } + + private String currentCounterTable() + { + return currentTable() + "_counter"; + } + + private String currentSparseTable() + { + return currentTable() + "_sparse"; + } + + private String currentDenseTable() + { + return currentTable(); + } + + private Column getColumnForInsert(ByteBuffer columnName, ByteBuffer value) + { + Column column = new Column(); + column.setName(columnName); + column.setValue(value); + column.setTimestamp(System.currentTimeMillis()); + return column; + } + + private SuperColumn getSuperColumnForInsert(ByteBuffer columnName, List<Column> columns) + { + SuperColumn column = new SuperColumn(); + column.setName(columnName); + for (Column c : columns) + column.addToColumns(c); + return column; + } + + public void beforeAndAfterFlush(CheckedFunction runnable) throws Throwable + { + runnable.apply(); + flushAll(); + runnable.apply(); + } + + private void flushAll() + { + for (String cfName : new String[]{ currentTable(), currentSparseTable(), currentCounterTable() }) + Keyspace.open(KEYSPACE).getColumnFamilyStore(cfName); + } + } http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/test/unit/org/apache/cassandra/db/ColumnFamilyStoreCQLHelperTest.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/4734ce7d/test/unit/org/apache/cassandra/schema/LegacySchemaMigratorTest.java ---------------------------------------------------------------------- --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
