/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.sql.optimizer.rule.range; import com.foundationdb.server.types.texpressions.Comparison; import com.foundationdb.sql.optimizer.plan.ColumnExpression; import com.foundationdb.sql.optimizer.plan.ConditionExpression; import com.foundationdb.sql.optimizer.plan.ConstantExpression; import org.junit.Test; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.Set; import static com.foundationdb.sql.optimizer.rule.range.TUtils.*; import static org.junit.Assert.assertEquals; public final class ColumnRangesTest { @Test public void colLtValue() { ConstantExpression value = constant("joe"); ConditionExpression compare = compare(firstName, Comparison.LT, value); ColumnRanges expected = columnRanges( firstName, compare, segment(nullExclusive("joe"), exclusive("joe")) ); assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void valueLtCol() { ConstantExpression value = constant("joe"); ConditionExpression compare = compare(value, Comparison.LT, firstName); ColumnRanges expected = columnRanges( firstName, compare, segment(exclusive("joe"), RangeEndpoint.UPPER_WILD) ); assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void colLeValue() { ConstantExpression value = constant("joe"); ConditionExpression compare = compare(firstName, Comparison.LE, value); ColumnRanges expected = columnRanges( firstName, compare, segment(nullExclusive("joe"), inclusive("joe")) ); assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void valueLeCol() { ConstantExpression value = constant("joe"); ConditionExpression compare = compare(value, Comparison.LE, firstName); ColumnRanges expected = columnRanges( firstName, compare, segment(inclusive("joe"), RangeEndpoint.UPPER_WILD) ); assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void colGtValue() { ConstantExpression value = constant("joe"); ConditionExpression compare = compare(firstName, Comparison.GT, value); ColumnRanges expected = columnRanges( firstName, compare, segment(exclusive("joe"), RangeEndpoint.UPPER_WILD) ); assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void valueGtCol() { ConstantExpression value = constant("joe"); ConditionExpression compare = compare(value, Comparison.GT, firstName); ColumnRanges expected = columnRanges( firstName, compare, segment(nullExclusive("joe"), exclusive("joe")) ); assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void colGeValue() { ConstantExpression value = constant("joe"); ConditionExpression compare = compare(firstName, Comparison.GE, value); ColumnRanges expected = columnRanges( firstName, compare, segment(inclusive("joe"), RangeEndpoint.UPPER_WILD) ); assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void valueGeCol() { ConstantExpression value = constant("joe"); ConditionExpression compare = compare(value, Comparison.GE, firstName); ColumnRanges expected = columnRanges( firstName, compare, segment(nullExclusive("joe"), inclusive("joe")) ); assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void colEqValue() { ConstantExpression value = constant("joe"); ConditionExpression compare = compare(firstName, Comparison.EQ, value); ColumnRanges expected = columnRanges( firstName, compare, segment(inclusive("joe"), inclusive("joe")) ); assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void valueEqCol() { ConstantExpression value = constant("joe"); ConditionExpression compare = compare(value, Comparison.EQ, firstName); ColumnRanges expected = columnRanges( firstName, compare, segment(inclusive("joe"), inclusive("joe")) ); assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void colNeValue() { ConstantExpression value = constant("joe"); ConditionExpression compare = compare(firstName, Comparison.NE, value); ColumnRanges expected = columnRanges( firstName, compare, segment(nullExclusive("joe"), exclusive("joe")), segment(exclusive("joe"), RangeEndpoint.UPPER_WILD) ); assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void valueNeCol() { ConstantExpression value = constant("joe"); ConditionExpression compare = compare(value, Comparison.NE, firstName); ColumnRanges expected = columnRanges( firstName, compare, segment(nullExclusive("joe"), exclusive("joe")), segment(exclusive("joe"), RangeEndpoint.UPPER_WILD) ); assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void notColLtValue() { ConstantExpression value = constant("joe"); ConditionExpression compare = not(compare(value, Comparison.LT, firstName)); ColumnRanges expected = null; assertEquals(expected, ColumnRanges.rangeAtNode(compare)); } @Test public void columnIsNull() { ConditionExpression isNull = isNull(firstName); ColumnRanges expected = columnRanges( firstName, isNull, segment(RangeEndpoint.nullInclusive(firstName), RangeEndpoint.nullInclusive(firstName)) ); assertEquals(expected, ColumnRanges.rangeAtNode(isNull)); } @Test public void differentColumns() { ConditionExpression firstNameLtJoe = compare(firstName, Comparison.LT, constant("joe")); ConditionExpression lastNameLtSmith = compare(lastName, Comparison.LT, constant("smith")); ConditionExpression either = or(firstNameLtJoe, lastNameLtSmith); ColumnRanges expected = null; assertEquals(expected, ColumnRanges.rangeAtNode(either)); } // the and/or tests are pretty sparse, since RangeSegmentTest is more exhaustive about // the overlaps and permutations. @Test public void orNoOverlap() { ConditionExpression nameLtAbe = compare(firstName, Comparison.LT, constant("abe")); ConditionExpression nameGeJoe = compare(firstName, Comparison.GE, constant("joe")); ConditionExpression either = or(nameLtAbe, nameGeJoe); ColumnRanges expected = columnRanges( firstName, either, segment(nullExclusive("joe"), exclusive("abe")), segment(inclusive("joe"), RangeEndpoint.UPPER_WILD) ); assertEquals(expected, ColumnRanges.rangeAtNode(either)); } @Test public void orWithOverlap() { ConditionExpression nameLtAbe = compare(firstName, Comparison.LT, constant("joe")); ConditionExpression nameGeJoe = compare(firstName, Comparison.GE, constant("abe")); ConditionExpression either = or(nameLtAbe, nameGeJoe); ColumnRanges expected = columnRanges( firstName, either, segment(nullExclusive("joe"), RangeEndpoint.UPPER_WILD) ); assertEquals(expected, ColumnRanges.rangeAtNode(either)); } @Test public void andNoOverlap() { ConditionExpression nameLtAbe = compare(firstName, Comparison.LT, constant("abe")); ConditionExpression nameGeJoe = compare(firstName, Comparison.GE, constant("joe")); ConditionExpression both = and(nameLtAbe, nameGeJoe); ColumnRanges expected = columnRanges( firstName, both ); assertEquals(expected, ColumnRanges.rangeAtNode(both)); } @Test public void andWithOverlap() { ConditionExpression nameLtAbe = compare(firstName, Comparison.LT, constant("joe")); ConditionExpression nameGeJoe = compare(firstName, Comparison.GE, constant("abe")); ConditionExpression both = and(nameLtAbe, nameGeJoe); ColumnRanges expected = columnRanges( firstName, both, segment(inclusive("abe"), exclusive("joe")) ); assertEquals(expected, ColumnRanges.rangeAtNode(both)); } @Test public void explicitAnd() { ConditionExpression nameLtAbe = compare(firstName, Comparison.LT, constant("joe")); ConditionExpression nameGeJoe = compare(firstName, Comparison.GE, constant("abe")); ColumnRanges nameLtAbeRanges = ColumnRanges.rangeAtNode(nameLtAbe); ColumnRanges nameGeJoeRanges = ColumnRanges.rangeAtNode(nameGeJoe); ColumnRanges expected = columnRanges( firstName, set(nameLtAbe, nameGeJoe), segment(inclusive("abe"), exclusive("joe")) ); assertEquals(expected, ColumnRanges.andRanges(nameLtAbeRanges, nameGeJoeRanges)); assertEquals(expected, ColumnRanges.andRanges(nameGeJoeRanges, nameLtAbeRanges)); } @Test public void sinOfColumn() { ConditionExpression isNull = sin(firstName); ColumnRanges expected = null; assertEquals(expected, ColumnRanges.rangeAtNode(isNull)); } private ColumnRanges columnRanges(ColumnExpression col, ConditionExpression condition, RangeSegment... segments) { return new ColumnRanges( col, Collections.singleton(condition), Arrays.asList(segments) ); } private ColumnRanges columnRanges(ColumnExpression col, Set<ConditionExpression> conditions, RangeSegment... segs) { return new ColumnRanges( col, conditions, Arrays.asList(segs) ); } private Set<ConditionExpression> set(ConditionExpression... args) { Set<ConditionExpression> result = new HashSet<>(); for (ConditionExpression object : args) { result.add(object); } return result; } }