/*
* 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.statements;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.apache.cassandra.config.CFMetaData;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.*;
import org.apache.cassandra.cql3.CFDefinition.Name;
import org.apache.cassandra.db.ColumnFamilyType;
import org.apache.cassandra.db.marshal.AbstractType;
import org.apache.cassandra.db.marshal.CompositeType;
import org.apache.cassandra.db.marshal.Int32Type;
import org.apache.cassandra.exceptions.ConfigurationException;
import org.apache.cassandra.exceptions.InvalidRequestException;
import org.apache.cassandra.utils.ByteBufferUtil;
import static org.junit.Assert.assertArrayEquals;
import static java.util.Arrays.asList;
import static org.junit.Assert.assertEquals;
public class SelectStatementTest
{
@Test
public void testBuildBoundWithNoRestrictions() throws Exception
{
Restriction[] restrictions = new Restriction[2];
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
}
/**
* Test 'clustering_0 = 1' with only one clustering column
*/
@Test
public void testBuildBoundWithOneEqRestrictionsAndOneClusteringColumn() throws Exception
{
ByteBuffer clustering_0 = ByteBufferUtil.bytes(1);
SingleColumnRestriction.EQ eq = new SingleColumnRestriction.EQ(toTerm(clustering_0), false);
Restriction[] restrictions = new Restriction[] { eq };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), clustering_0);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), clustering_0);
}
/**
* Test 'clustering_1 = 1' with 2 clustering columns
*/
@Test
public void testBuildBoundWithOneEqRestrictionsAndTwoClusteringColumns() throws Exception
{
ByteBuffer clustering_0 = ByteBufferUtil.bytes(1);
SingleColumnRestriction.EQ eq = new SingleColumnRestriction.EQ(toTerm(clustering_0), false);
Restriction[] restrictions = new Restriction[] { eq, null };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), clustering_0);
bounds = executeBuildBound(cfDef,restrictions, Bound.END);
assertEquals(1, bounds.size());
assertEndOfRangeComposite(cfDef, bounds.get(0), clustering_0);
}
/**
* Test 'clustering_0 IN (1, 2, 3)' with only one clustering column
*/
@Test
public void testBuildBoundWithOneInRestrictionsAndOneClusteringColumn() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
ByteBuffer value3 = ByteBufferUtil.bytes(3);
SingleColumnRestriction.IN in = new SingleColumnRestriction.InWithValues(toTerms(value1, value2, value3));
Restriction[] restrictions = new Restriction[] { in };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef,restrictions, Bound.START);
assertEquals(3, bounds.size());
assertComposite(cfDef, bounds.get(0), value1);
assertComposite(cfDef, bounds.get(1), value2);
assertComposite(cfDef, bounds.get(2), value3);
bounds = executeBuildBound(cfDef,restrictions, Bound.END);
assertEquals(3, bounds.size());
assertComposite(cfDef, bounds.get(0), value1);
assertComposite(cfDef, bounds.get(1), value2);
assertComposite(cfDef, bounds.get(2), value3);
}
/**
* Test slice restriction (e.g 'clustering_0 > 1') with only one clustering column
*/
@Test
public void testBuildBoundWithSliceRestrictionsAndOneClusteringColumn() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
SingleColumnRestriction.Slice slice = new SingleColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GT, toTerm(value1));
Restriction[] restrictions = new Restriction[] { slice };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef,restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GT, value1);
bounds = executeBuildBound(cfDef,restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
slice = new SingleColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GTE, toTerm(value1));
restrictions = new Restriction[] { slice };
bounds = executeBuildBound(cfDef,restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GTE, value1);
bounds = executeBuildBound(cfDef,restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
slice = new SingleColumnRestriction.Slice(false);
slice.setBound(Relation.Type.LTE, toTerm(value1));
restrictions = new Restriction[] { slice };
bounds = executeBuildBound(cfDef,restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
bounds = executeBuildBound(cfDef,restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LTE, value1);
slice = new SingleColumnRestriction.Slice(false);
slice.setBound(Relation.Type.LT, toTerm(value1));
restrictions = new Restriction[] { slice };
bounds = executeBuildBound(cfDef,restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
bounds = executeBuildBound(cfDef,restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LT, value1);
slice = new SingleColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GT, toTerm(value1));
slice.setBound(Relation.Type.LT, toTerm(value2));
restrictions = new Restriction[] { slice };
bounds = executeBuildBound(cfDef,restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GT, value1);
bounds = executeBuildBound(cfDef,restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LT, value2);
slice = new SingleColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GTE, toTerm(value1));
slice.setBound(Relation.Type.LTE, toTerm(value2));
restrictions = new Restriction[] { slice };
bounds = executeBuildBound(cfDef,restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GTE, value1);
bounds = executeBuildBound(cfDef,restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LTE, value2);
}
//
/**
* Test 'clustering_0 = 1 AND clustering_1 IN (1, 2, 3)' with two clustering columns
*/
@Test
public void testBuildBoundWithEqAndInRestrictions() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
ByteBuffer value3 = ByteBufferUtil.bytes(3);
SingleColumnRestriction.EQ eq = new SingleColumnRestriction.EQ(toTerm(value1), false);
SingleColumnRestriction.IN in = new SingleColumnRestriction.InWithValues(toTerms(value1, value2, value3));
Restriction[] restrictions = new Restriction[] { eq, in };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef,restrictions, Bound.START);
assertEquals(3, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value1);
assertComposite(cfDef, bounds.get(1), value1, value2);
assertComposite(cfDef, bounds.get(2), value1, value3);
bounds = executeBuildBound(cfDef,restrictions, Bound.END);
assertEquals(3, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value1);
assertComposite(cfDef, bounds.get(1), value1, value2);
assertComposite(cfDef, bounds.get(2), value1, value3);
}
/**
* Test slice restriction (e.g 'clustering_0 > 1') with only one clustering column
*/
@Test
public void testBuildBoundWithEqAndSliceRestrictions() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
ByteBuffer value3 = ByteBufferUtil.bytes(3);
SingleColumnRestriction.EQ eq = new SingleColumnRestriction.EQ(toTerm(value3), false);
SingleColumnRestriction.Slice slice = new SingleColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GT, toTerm(value1));
Restriction[] restrictions = new Restriction[] { eq, slice };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef,restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GT, value3, value1);
bounds = executeBuildBound(cfDef,restrictions, Bound.END);
assertEquals(1, bounds.size());
assertEndOfRangeComposite(cfDef, bounds.get(0), value3);
slice = new SingleColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GTE, toTerm(value1));
restrictions = new Restriction[] { eq, slice };
bounds = executeBuildBound(cfDef,restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GTE, value3, value1);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertEndOfRangeComposite(cfDef, bounds.get(0), value3);
slice = new SingleColumnRestriction.Slice(false);
slice.setBound(Relation.Type.LTE, toTerm(value1));
restrictions = new Restriction[] { eq, slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value3);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LTE, value3, value1);
slice = new SingleColumnRestriction.Slice(false);
slice.setBound(Relation.Type.LT, toTerm(value1));
restrictions = new Restriction[] { eq, slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value3);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LT, value3, value1);
slice = new SingleColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GT, toTerm(value1));
slice.setBound(Relation.Type.LT, toTerm(value2));
restrictions = new Restriction[] { eq, slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GT, value3, value1);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LT, value3, value2);
slice = new SingleColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GTE, toTerm(value1));
slice.setBound(Relation.Type.LTE, toTerm(value2));
restrictions = new Restriction[] { eq, slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GTE, value3, value1);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LTE, value3, value2);
}
/**
* Test '(clustering_0, clustering_1) = (1, 2)' with two clustering column
*/
@Test
public void testBuildBoundWithMultiEqRestrictions() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
MultiColumnRestriction.EQ eq = new MultiColumnRestriction.EQ(toMultiItemTerminal(value1, value2), false);
Restriction[] restrictions = new Restriction[] { eq, eq };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2);
}
/**
* Test '(clustering_0, clustering_1) IN ((1, 2), (2, 3))' with two clustering column
*/
@Test
public void testBuildBoundWithMultiInRestrictions() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
ByteBuffer value3 = ByteBufferUtil.bytes(3);
List<Term> terms = asList(toMultiItemTerminal(value1, value2), toMultiItemTerminal(value2, value3));
MultiColumnRestriction.IN in = new MultiColumnRestriction.InWithValues(terms);
Restriction[] restrictions = new Restriction[] { in, in };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(2, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2);
assertComposite(cfDef, bounds.get(1), value2, value3);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(2, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2);
assertComposite(cfDef, bounds.get(1), value2, value3);
}
/**
* Test multi-column slice restrictions (e.g '(clustering_0) > (1)') with only one clustering column
*/
@Test
public void testBuildBoundWithMultiSliceRestrictionsWithOneClusteringColumn() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
MultiColumnRestriction.Slice slice = new MultiColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GT, toMultiItemTerminal(value1));
Restriction[] restrictions = new Restriction[] { slice };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GT, value1);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
slice = new MultiColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GTE, toMultiItemTerminal(value1));
restrictions = new Restriction[] { slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GTE, value1);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
slice = new MultiColumnRestriction.Slice(false);
slice.setBound(Relation.Type.LTE, toMultiItemTerminal(value1));
restrictions = new Restriction[] { slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LTE, value1);
slice = new MultiColumnRestriction.Slice(false);
slice.setBound(Relation.Type.LT, toMultiItemTerminal(value1));
restrictions = new Restriction[] { slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LT, value1);
slice = new MultiColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GT, toMultiItemTerminal(value1));
slice.setBound(Relation.Type.LT, toMultiItemTerminal(value2));
restrictions = new Restriction[] { slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GT, value1);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LT, value2);
slice = new MultiColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GTE, toMultiItemTerminal(value1));
slice.setBound(Relation.Type.LTE, toMultiItemTerminal(value2));
restrictions = new Restriction[] { slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GTE, value1);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LTE, value2);
}
/**
* Test multi-column slice restrictions (e.g '(clustering_0, clustering_1) > (1, 2)') with two clustering
* columns
*/
@Test
public void testBuildBoundWithMultiSliceRestrictionsWithTwoClusteringColumn() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
// (clustering_0, clustering1) > (1, 2)
MultiColumnRestriction.Slice slice = new MultiColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GT, toMultiItemTerminal(value1, value2));
Restriction[] restrictions = new Restriction[] { slice, slice };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GT, value1, value2);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
// (clustering_0, clustering1) >= (1, 2)
slice = new MultiColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GTE, toMultiItemTerminal(value1, value2));
restrictions = new Restriction[] { slice, slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GTE, value1, value2);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
// (clustering_0, clustering1) <= (1, 2)
slice = new MultiColumnRestriction.Slice(false);
slice.setBound(Relation.Type.LTE, toMultiItemTerminal(value1, value2));
restrictions = new Restriction[] { slice, slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LTE, value1, value2);
// (clustering_0, clustering1) < (1, 2)
slice = new MultiColumnRestriction.Slice(false);
slice.setBound(Relation.Type.LT, toMultiItemTerminal(value1, value2));
restrictions = new Restriction[] { slice, slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0));
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LT, value1, value2);
// (clustering_0, clustering1) > (1, 2) AND (clustering_0) < (2)
slice = new MultiColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GT, toMultiItemTerminal(value1, value2));
slice.setBound(Relation.Type.LT, toMultiItemTerminal(value2));
restrictions = new Restriction[] { slice, slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GT, value1, value2);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LT, value2);
// (clustering_0, clustering1) >= (1, 2) AND (clustering_0, clustering1) <= (2, 1)
slice = new MultiColumnRestriction.Slice(false);
slice.setBound(Relation.Type.GTE, toMultiItemTerminal(value1, value2));
slice.setBound(Relation.Type.LTE, toMultiItemTerminal(value2, value1));
restrictions = new Restriction[] { slice, slice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GTE, value1, value2);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LTE, value2, value1);
}
/**
* Test mixing single and multi equals restrictions (e.g. clustering_0 = 1 AND (clustering_1, clustering_2) = (2, 3))
*/
@Test
public void testBuildBoundWithSingleEqAndMultiEqRestrictions() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
ByteBuffer value3 = ByteBufferUtil.bytes(3);
ByteBuffer value4 = ByteBufferUtil.bytes(4);
// clustering_0 = 1 AND (clustering_1, clustering_2) = (2, 3)
SingleColumnRestriction.EQ singleEq = new SingleColumnRestriction.EQ(toTerm(value1), false);
MultiColumnRestriction.EQ multiEq = new MultiColumnRestriction.EQ(toMultiItemTerminal(value2, value3), false);
Restriction[] restrictions = new Restriction[] { singleEq, multiEq, multiEq };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3);
// clustering_0 = 1 AND clustering_1 = 2 AND (clustering_2, clustering_3) = (3, 4)
singleEq = new SingleColumnRestriction.EQ(toTerm(value1), false);
SingleColumnRestriction.EQ singleEq2 = new SingleColumnRestriction.EQ(toTerm(value2), false);
multiEq = new MultiColumnRestriction.EQ(toMultiItemTerminal(value3, value4), false);
restrictions = new Restriction[] { singleEq, singleEq2, multiEq, multiEq };
cfDef = createCFDefinition(restrictions.length);
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3, value4);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3, value4);
// (clustering_0, clustering_1) = (1, 2) AND clustering_2 = 3
singleEq = new SingleColumnRestriction.EQ(toTerm(value3), false);
multiEq = new MultiColumnRestriction.EQ(toMultiItemTerminal(value1, value2), false);
restrictions = new Restriction[] { multiEq, multiEq, singleEq };
cfDef = createCFDefinition(restrictions.length);
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3);
// clustering_0 = 1 AND (clustering_1, clustering_2) = (2, 3) AND clustering_3 = 4
singleEq = new SingleColumnRestriction.EQ(toTerm(value1), false);
singleEq2 = new SingleColumnRestriction.EQ(toTerm(value4), false);
multiEq = new MultiColumnRestriction.EQ(toMultiItemTerminal(value2, value3), false);
restrictions = new Restriction[] { singleEq, multiEq, multiEq, singleEq2 };
cfDef = createCFDefinition(restrictions.length);
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3, value4);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3, value4);
}
/**
* Test clustering_0 = 1 AND (clustering_1, clustering_2) IN ((2, 3), (4, 5))
*/
@Test
public void testBuildBoundWithSingleEqAndMultiINRestrictions() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
ByteBuffer value3 = ByteBufferUtil.bytes(3);
ByteBuffer value4 = ByteBufferUtil.bytes(4);
ByteBuffer value5 = ByteBufferUtil.bytes(5);
// clustering_0 = 1 AND (clustering_1, clustering_2) IN ((2, 3), (4, 5))
SingleColumnRestriction.EQ singleEq = new SingleColumnRestriction.EQ(toTerm(value1), false);
MultiColumnRestriction.IN multiIn =
new MultiColumnRestriction.InWithValues(asList(toMultiItemTerminal(value2, value3),
toMultiItemTerminal(value4, value5)));
Restriction[] restrictions = new Restriction[] { singleEq, multiIn, multiIn };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(2, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3);
assertComposite(cfDef, bounds.get(1), value1, value4, value5);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(2, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3);
assertComposite(cfDef, bounds.get(1), value1, value4, value5);
// clustering_0 = 1 AND (clustering_1, clustering_2) IN ((2, 3))
singleEq = new SingleColumnRestriction.EQ(toTerm(value1), false);
multiIn = new MultiColumnRestriction.InWithValues(asList(toMultiItemTerminal(value2, value3),
toMultiItemTerminal(value4, value5)));
restrictions = new Restriction[] { singleEq, multiIn, multiIn };
cfDef = createCFDefinition(restrictions.length);
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(2, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3);
assertComposite(cfDef, bounds.get(1), value1, value4, value5);
// clustering_0 = 1 AND clustering_1 = 5 AND (clustering_2, clustering_3) IN ((2, 3), (4, 5))
singleEq = new SingleColumnRestriction.EQ(toTerm(value1), false);
SingleColumnRestriction.EQ singleEq2 = new SingleColumnRestriction.EQ(toTerm(value5), false);
multiIn = new MultiColumnRestriction.InWithValues(asList(toMultiItemTerminal(value2, value3),
toMultiItemTerminal(value4, value5)));
restrictions = new Restriction[] { singleEq, singleEq2, multiIn, multiIn };
cfDef = createCFDefinition(restrictions.length);
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(2, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value5, value2, value3);
assertComposite(cfDef, bounds.get(1), value1, value5, value4, value5);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(2, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value5, value2, value3);
assertComposite(cfDef, bounds.get(1), value1, value5, value4, value5);
}
/**
* Test mixing single equal restrictions with multi-column slice restrictions
* (e.g. clustering_0 = 1 AND (clustering_1, clustering_2) > (2, 3))
*/
@Test
public void testBuildBoundWithSingleEqAndSliceRestrictions() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
ByteBuffer value3 = ByteBufferUtil.bytes(3);
ByteBuffer value4 = ByteBufferUtil.bytes(4);
ByteBuffer value5 = ByteBufferUtil.bytes(5);
// clustering_0 = 1 AND (clustering_1, clustering_2) > (2, 3)
SingleColumnRestriction.EQ singleEq = new SingleColumnRestriction.EQ(toTerm(value1), false);
MultiColumnRestriction.Slice multiSlice = new MultiColumnRestriction.Slice(false);
multiSlice.setBound(Relation.Type.GT, toMultiItemTerminal(value2, value3));
Restriction[] restrictions = new Restriction[] { singleEq, multiSlice, multiSlice };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GT, value1, value2, value3);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertEndOfRangeComposite(cfDef, bounds.get(0), value1);
// clustering_0 = 1 AND (clustering_1, clustering_2) > (2, 3) AND (clustering_1) < (4)
singleEq = new SingleColumnRestriction.EQ(toTerm(value1), false);
multiSlice = new MultiColumnRestriction.Slice(false);
multiSlice.setBound(Relation.Type.GT, toMultiItemTerminal(value2, value3));
multiSlice.setBound(Relation.Type.LT, toMultiItemTerminal(value4));
restrictions = new Restriction[] { singleEq, multiSlice, multiSlice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GT, value1, value2, value3);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LT, value1, value4);
// clustering_0 = 1 AND (clustering_1, clustering_2) => (2, 3) AND (clustering_1, clustering_2) <= (4, 5)
singleEq = new SingleColumnRestriction.EQ(toTerm(value1), false);
multiSlice = new MultiColumnRestriction.Slice(false);
multiSlice.setBound(Relation.Type.GTE, toMultiItemTerminal(value2, value3));
multiSlice.setBound(Relation.Type.LTE, toMultiItemTerminal(value4, value5));
restrictions = new Restriction[] { singleEq, multiSlice, multiSlice };
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GTE, value1, value2, value3);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.LTE, value1, value4, value5);
}
/**
* Test mixing multi equal restrictions with single-column slice restrictions
* (e.g. clustering_0 = 1 AND (clustering_1, clustering_2) > (2, 3))
*/
@Test
public void testBuildBoundWithMultiEqAndSingleSliceRestrictions() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
ByteBuffer value3 = ByteBufferUtil.bytes(3);
// (clustering_0, clustering_1) = (1, 2) AND clustering_2 > 3
MultiColumnRestriction.EQ multiEq = new MultiColumnRestriction.EQ(toMultiItemTerminal(value1, value2), false);
SingleColumnRestriction.Slice singleSlice = new SingleColumnRestriction.Slice(false);
singleSlice.setBound(Relation.Type.GT, toTerm(value3));
Restriction[] restrictions = new Restriction[] { multiEq, multiEq, singleSlice };
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GT, value1, value2, value3);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertEndOfRangeComposite(cfDef, bounds.get(0), value1, value2);
}
@Test
public void testBuildBoundWithSeveralMultiColumnRestrictions() throws Exception
{
ByteBuffer value1 = ByteBufferUtil.bytes(1);
ByteBuffer value2 = ByteBufferUtil.bytes(2);
ByteBuffer value3 = ByteBufferUtil.bytes(3);
ByteBuffer value4 = ByteBufferUtil.bytes(4);
ByteBuffer value5 = ByteBufferUtil.bytes(5);
// (clustering_0, clustering_1) = (1, 2) AND (clustering_2, clustering_3) > (3, 4)
MultiColumnRestriction.EQ multiEq = new MultiColumnRestriction.EQ(toMultiItemTerminal(value1, value2), false);
MultiColumnRestriction.Slice multiSlice = new MultiColumnRestriction.Slice(false);
multiSlice.setBound(Relation.Type.GT, toMultiItemTerminal(value3, value4));
Restriction[] restrictions = new Restriction[] { multiEq, multiEq, multiSlice, multiSlice};
CFDefinition cfDef = createCFDefinition(restrictions.length);
List<ByteBuffer> bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertForRelationComposite(cfDef, bounds.get(0), Relation.Type.GT,value1, value2, value3, value4);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertEndOfRangeComposite(cfDef, bounds.get(0), value1, value2);
// (clustering_0, clustering_1) = (1, 2) AND (clustering_2, clustering_3) IN ((3, 4), (4, 5))
multiEq = new MultiColumnRestriction.EQ(toMultiItemTerminal(value1, value2), false);
MultiColumnRestriction.IN multiIn =
new MultiColumnRestriction.InWithValues(asList(toMultiItemTerminal(value3, value4),
toMultiItemTerminal(value4, value5)));
restrictions = new Restriction[] { multiEq, multiEq, multiIn, multiIn};
cfDef = createCFDefinition(restrictions.length);
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(2, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3, value4);
assertComposite(cfDef, bounds.get(1), value1, value2, value4, value5);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(2, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3, value4);
assertComposite(cfDef, bounds.get(1), value1, value2, value4, value5);
// (clustering_0, clustering_1) = (1, 2) AND (clustering_2, clustering_3) = ((3, 4), (4, 5))
multiEq = new MultiColumnRestriction.EQ(toMultiItemTerminal(value1, value2), false);
MultiColumnRestriction.EQ multiEq2 = new MultiColumnRestriction.EQ(toMultiItemTerminal(value3, value4), false);
restrictions = new Restriction[] { multiEq, multiEq, multiEq2, multiEq2};
cfDef = createCFDefinition(restrictions.length);
bounds = executeBuildBound(cfDef, restrictions, Bound.START);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3, value4);
bounds = executeBuildBound(cfDef, restrictions, Bound.END);
assertEquals(1, bounds.size());
assertComposite(cfDef, bounds.get(0), value1, value2, value3, value4);
}
/**
* Asserts that the specified composite contains the specified elements.
*
* @param cfDef the Column Family Definition
* @param actual the buffer to test
* @param elements the expected elements of the composite
*/
private static void assertComposite(CFDefinition cfDef, ByteBuffer actual, ByteBuffer... elements)
{
ColumnNameBuilder builder = addElements(cfDef.getColumnNameBuilder(), elements);
assertArrayEquals("the composite is not the expected one:", actual.array(), builder.build().array());
}
/**
* Asserts that the specified composite is an end of range composite that contains the specified elements.
*
* @param cfDef the Column Family Definition
* @param actual the buffer to test
* @param elements the expected elements of the composite
*/
private static void assertEndOfRangeComposite(CFDefinition cfDef, ByteBuffer actual, ByteBuffer... elements)
{
ColumnNameBuilder builder = addElements(cfDef.getColumnNameBuilder(), elements);
assertArrayEquals("the composite is not the expected one:", actual.array(), builder.buildAsEndOfRange().array());
}
/**
* Asserts that the specified composite is an end of range composite that contains the specified elements.
*
* @param cfDef the Column Family Definition
* @param actual the buffer to test
* @param elements the expected elements of the composite
*/
private static void assertForRelationComposite(CFDefinition cfDef,
ByteBuffer actual,
Relation.Type relType,
ByteBuffer... elements)
{
ColumnNameBuilder builder = addElements(cfDef.getColumnNameBuilder(), elements);
assertArrayEquals("the composite is not the expected one:", actual.array(), builder.buildForRelation(relType).array());
}
/**
* Adds all the specified elements to the specified builder.
*
* @param builder the builder to add to
* @param elements the elements to add
* @return the builder
*/
private static ColumnNameBuilder addElements(ColumnNameBuilder builder, ByteBuffer... elements)
{
for (int i = 0, m = elements.length; i < m; i++)
builder.add(elements[i]);
return builder;
}
/**
* Calls the <code>SelectStatement.buildBound</code> with the specified restrictions.
*
* @param cfDef the Column Family Definition
* @param restrictions the restrictions
* @return the result from the method call to <code>SelectStatement.buildBound</code>
* @throws InvalidRequestException if buildBound throw an <code>Exception</code>
*/
private static List<ByteBuffer> executeBuildBound(CFDefinition cfDef,
Restriction[] restrictions,
Bound bound) throws InvalidRequestException
{
return SelectStatement.buildBound(bound,
new ArrayList<Name>(cfDef.clusteringColumns()),
restrictions,
false,
cfDef,
cfDef.getColumnNameBuilder(),
Collections.<ByteBuffer>emptyList());
}
/**
* Creates a <code>CFDefinition</code> to be used in the tests.
*
* @param numberOfClusteringColumns the number of clustering columns
* @return a new a <code>CFDefinition</code> instance
* @throws ConfigurationException if the CFDefinition cannot be created
*/
private static CFDefinition createCFDefinition(int numberOfClusteringColumns) throws ConfigurationException
{
List<AbstractType<?>> types = new ArrayList<>();
for (int i = 0, m = numberOfClusteringColumns; i < m; i++)
types.add(Int32Type.instance);
CompositeType cType = CompositeType.getInstance(types);
CFMetaData cfMetaData = new CFMetaData("keyspace", "test", ColumnFamilyType.Standard, cType);
ByteBuffer partitionKey = ByteBufferUtil.bytes("partitionKey");
cfMetaData.addColumnDefinition(ColumnDefinition.partitionKeyDef(partitionKey, Int32Type.instance, 0));
for (int i = 0, m = numberOfClusteringColumns; i < m; i++)
{
ByteBuffer name = ByteBufferUtil.bytes("clustering_" + i);
cfMetaData.addColumnDefinition(ColumnDefinition.clusteringKeyDef(name, types.get(i), i));
}
cfMetaData.rebuild();
return new CFDefinition(cfMetaData);
}
/**
* Converts the specified values into a <code>MultiItemTerminal</code>.
*
* @param values the values to convert.
* @return the term corresponding to the specified values.
*/
private static Term toMultiItemTerminal(ByteBuffer... values)
{
return new Tuples.Value(values);
}
/**
* Converts the specified value into a term.
*
* @param value the value to convert.
* @return the term corresponding to the specified value.
*/
private static Term toTerm(ByteBuffer value)
{
return new Constants.Value(value);
}
/**
* Converts the specified values into a <code>List</code> of terms.
*
* @param values the values to convert.
* @return a <code>List</code> of terms corresponding to the specified values.
*/
private static List<Term> toTerms(ByteBuffer... values)
{
List<Term> terms = new ArrayList<>();
for (ByteBuffer value : values)
terms.add(toTerm(value));
return terms;
}
}