blob: 4b138770f9713c026005b9eb8e1ca3776317dc42 [file] [log] [blame]
/*
* 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.restrictions;
import java.util.List;
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.cql3.Operator;
import org.apache.cassandra.cql3.Term;
import org.apache.cassandra.cql3.functions.Function;
import org.apache.cassandra.cql3.statements.Bound;
import org.apache.cassandra.index.Index;
public final class TermSlice
{
/**
* The slice boundaries.
*/
private final Term[] bounds;
/**
* Specifies if a slice boundary is inclusive or not.
*/
private final boolean[] boundInclusive;
/**
* Creates a new <code>TermSlice</code> with the specified boundaries.
*
* @param start the lower boundary
* @param includeStart <code>true</code> if the lower boundary is inclusive
* @param end the upper boundary
* @param includeEnd <code>true</code> if the upper boundary is inclusive
*/
private TermSlice(Term start, boolean includeStart, Term end, boolean includeEnd)
{
bounds = new Term[]{start, end};
boundInclusive = new boolean[]{includeStart, includeEnd};
}
/**
* Creates a new <code>TermSlice</code> with the specified boundary.
*
* @param bound the boundary type
* @param include <code>true</code> if the boundary is inclusive
* @param term the value
* @return a new <code>TermSlice</code> instance
*/
public static TermSlice newInstance(Bound bound, boolean include, Term term)
{
return bound.isStart() ? new TermSlice(term, include, null, false)
: new TermSlice(null, false, term, include);
}
/**
* Returns the boundary value.
*
* @param bound the boundary type
* @return the boundary value
*/
public Term bound(Bound bound)
{
return bounds[bound.idx];
}
/**
* Checks if this slice has a boundary for the specified type.
*
* @param b the boundary type
* @return <code>true</code> if this slice has a boundary for the specified type, <code>false</code> otherwise.
*/
public boolean hasBound(Bound b)
{
return bounds[b.idx] != null;
}
/**
* Checks if this slice boundary is inclusive for the specified type.
*
* @param b the boundary type
* @return <code>true</code> if this slice boundary is inclusive for the specified type,
* <code>false</code> otherwise.
*/
public boolean isInclusive(Bound b)
{
return bounds[b.idx] == null || boundInclusive[b.idx];
}
/**
* Merges this slice with the specified one.
*
* @param otherSlice the slice to merge to
* @return the new slice resulting from the merge
*/
public TermSlice merge(TermSlice otherSlice)
{
if (hasBound(Bound.START))
{
assert !otherSlice.hasBound(Bound.START);
return new TermSlice(bound(Bound.START),
isInclusive(Bound.START),
otherSlice.bound(Bound.END),
otherSlice.isInclusive(Bound.END));
}
assert !otherSlice.hasBound(Bound.END);
return new TermSlice(otherSlice.bound(Bound.START),
otherSlice.isInclusive(Bound.START),
bound(Bound.END),
isInclusive(Bound.END));
}
@Override
public String toString()
{
return String.format("(%s %s, %s %s)", boundInclusive[0] ? ">=" : ">",
bounds[0],
boundInclusive[1] ? "<=" : "<",
bounds[1]);
}
/**
* Returns the index operator corresponding to the specified boundary.
*
* @param b the boundary type
* @return the index operator corresponding to the specified boundary
*/
public Operator getIndexOperator(Bound b)
{
if (b.isStart())
return boundInclusive[b.idx] ? Operator.GTE : Operator.GT;
return boundInclusive[b.idx] ? Operator.LTE : Operator.LT;
}
/**
* Check if this <code>TermSlice</code> is supported by the specified index.
*
* @param index the secondary index
* @return <code>true</code> this type of <code>TermSlice</code> is supported by the specified index,
* <code>false</code> otherwise.
*/
public boolean isSupportedBy(ColumnDefinition column, Index index)
{
boolean supported = false;
if (hasBound(Bound.START))
supported |= isInclusive(Bound.START) ? index.supportsExpression(column, Operator.GTE)
: index.supportsExpression(column, Operator.GT);
if (hasBound(Bound.END))
supported |= isInclusive(Bound.END) ? index.supportsExpression(column, Operator.LTE)
: index.supportsExpression(column, Operator.LT);
return supported;
}
public void addFunctionsTo(List<Function> functions)
{
if (hasBound(Bound.START))
bound(Bound.START).addFunctionsTo(functions);
if (hasBound(Bound.END))
bound(Bound.END).addFunctionsTo(functions);
}
}