Package com.foundationdb.server.test.it.qp

Source Code of com.foundationdb.server.test.it.qp.UniqueIndexScanIT

/**
* 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.server.test.it.qp;

import com.foundationdb.qp.expression.IndexBound;
import com.foundationdb.qp.expression.IndexKeyRange;
import com.foundationdb.qp.operator.Cursor;
import com.foundationdb.qp.operator.Operator;
import com.foundationdb.qp.row.Row;
import com.foundationdb.qp.rowtype.IndexRowType;
import com.foundationdb.qp.rowtype.Schema;
import com.foundationdb.server.api.dml.ColumnSelector;
import com.foundationdb.server.api.dml.SetColumnSelector;
import org.junit.Test;

import static com.foundationdb.qp.operator.API.cursor;
import static com.foundationdb.qp.operator.API.indexScan_Default;

// Like IndexScanIT, but testing unique indexes and the handling of duplicate nulls

public class UniqueIndexScanIT extends OperatorITBase
{
    @Override
    protected void setupCreateSchema()
    {
        item = createTable(
            "schema", "item",
            "id int not null",
            "x int", // copy of id or null
            "y int", // copy of id or null
            "primary key (id)");
        createUniqueIndex("schema", "item", "idx_x", "x");
        createUniqueIndex("schema", "item", "idx_y", "y");
        createUniqueIndex("schema", "item", "idx_xy", "x", "y");
    }

    @Override
    protected void setupPostCreateSchema()
    {
        schema = new Schema(ais());
        itemRowType = schema.tableRowType(table(item));
        xIndexRowType = indexType(item, "x");
        yIndexRowType = indexType(item, "y");
        xyIndexRowType = indexType(item, "x", "y");
        db = new Row[]{
            row(item, 1L, 10L, 10L),
            row(item, 2L, 20L, 20L),
            row(item, 3L, 30L, 30L),
            row(item, 4L, 40L, 40L),
            row(item, 5L, 50L, 50L),
            row(item, 6L, 60L, 60L),
            row(item, 7L, 70L, null),
            row(item, 8L, 80L, null),
            row(item, 9L, null, 90L),
            row(item, 10L, null, 100L),
            row(item, 11L, null, null),
            row(item, 12L, null, null),
        };
        adapter = newStoreAdapter(schema);
        queryContext = queryContext(adapter);
        queryBindings = queryContext.createBindings();
        use(db);
    }

    @Test
    public void testDuplicateNulls()
    {
        {
            Operator indexScan = indexScan_Default(xIndexRowType);
            compareRenderedHKeys(
                hkeys(9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8),
                cursor(indexScan, queryContext, queryBindings));
        }
        {
            Operator indexScan = indexScan_Default(yIndexRowType);
            compareRenderedHKeys(
                hkeys(7, 8, 11, 12, 1, 2, 3, 4, 5, 6, 9, 10),
                cursor(indexScan, queryContext, queryBindings));
        }
        {
            Operator indexScan = indexScan_Default(xyIndexRowType);
            compareRenderedHKeys(
                hkeys(11, 12, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8),
                cursor(indexScan, queryContext, queryBindings));
        }
    }

    @Test
    public void testExactMatchAbsent()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 5, true, 5, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(), cursor);
    }

    @Test
    public void testExactMatchPresent()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 10, true, 10, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(1), cursor);
    }

    @Test
    public void testEmptyRange()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 11, true, 12, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(), cursor);
    }

    @Test
    public void testStartAtNull()
    {
        {
            Operator indexScan = indexScan_Default(xIndexRowType, false, startAtNull(xIndexRowType, true, 60, true));
            Cursor cursor = cursor(indexScan, queryContext, queryBindings);
            compareRenderedHKeys(hkeys(9, 10, 11, 12, 1, 2, 3, 4, 5, 6), cursor);
        }
        {
            Operator indexScan = indexScan_Default(yIndexRowType, false, startAtNull(xIndexRowType, true, 60, true));
            Cursor cursor = cursor(indexScan, queryContext, queryBindings);
            compareRenderedHKeys(hkeys(7, 8, 11, 12, 1, 2, 3, 4, 5, 6), cursor);
        }
    }

    @Test
    public void testStartAfterNull()
    {
        {
            Operator indexScan = indexScan_Default(xIndexRowType, false, startAtNull(xIndexRowType, false, 60, true));
            Cursor cursor = cursor(indexScan, queryContext, queryBindings);
            compareRenderedHKeys(hkeys(1, 2, 3, 4, 5, 6), cursor);
        }
        {
            Operator indexScan = indexScan_Default(yIndexRowType, false, startAtNull(xIndexRowType, false, 60, true));
            Cursor cursor = cursor(indexScan, queryContext, queryBindings);
            compareRenderedHKeys(hkeys(1, 2, 3, 4, 5, 6), cursor);
        }
    }

    // Naming scheme for next tests:
    // testLoABHiCD
    // A: Inclusive/Exclusive for lo bound
    // B: Match/Miss indicates whether the lo bound matches or misses an actual value in the db
    // C: Inclusive/Exclusive for hi bound
    // D: Match/Miss indicates whether the hi bound matches or misses an actual value in the db

    @Test
    public void testLoInclusiveMatchHiInclusiveMatch()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 20, true, 40, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(2, 3, 4), cursor);
    }

    @Test
    public void testLoInclusiveMatchHiInclusiveMiss()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 20, true, 45, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(2, 3, 4), cursor);
    }

    @Test
    public void testLoInclusiveMatchHiExclusiveMatch()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 20, true, 50, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(2, 3, 4), cursor);
    }

    @Test
    public void testLoInclusiveMatchHiExclusiveMiss()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 20, true, 45, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(2, 3, 4), cursor);
    }

    @Test
    public void testLoInclusiveMissHiInclusiveMatch()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 5, true, 50, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(1, 2, 3, 4, 5), cursor);
    }

    @Test
    public void testLoInclusiveMissHiInclusiveMiss()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 5, true, 55, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(1, 2, 3, 4, 5), cursor);
    }

    @Test
    public void testLoInclusiveMissHiExclusiveMatch()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 5, true, 60, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(1, 2, 3, 4, 5), cursor);
    }

    @Test
    public void testLoInclusiveMissHiExclusiveMiss()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 5, true, 55, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(1, 2, 3, 4, 5), cursor);
    }

    @Test
    public void testLoExclusiveMatchHiInclusiveMatch()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 60, false, 70, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(7), cursor);
    }

    @Test
    public void testLoExclusiveMatchHiInclusiveMiss()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 60, false, 75, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(7), cursor);
    }

    @Test
    public void testLoExclusiveMatchHiExclusiveMatch()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 60, false, 80, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(7), cursor);
    }

    @Test
    public void testLoExclusiveMatchHiExclusiveMiss()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 60, false, 75, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(7), cursor);
    }

    @Test
    public void testLoExclusiveMissHiInclusiveMatch()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 45, false, 60, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(5, 6), cursor);
    }

    @Test
    public void testLoExclusiveMissHiInclusiveMiss()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 45, false, 65, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(5, 6), cursor);
    }

    @Test
    public void testLoExclusiveMissHiExclusiveMatch()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 45, false, 70, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(5, 6), cursor);
    }

    @Test
    public void testLoExclusiveMissHiExclusiveMiss()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, false, keyRange(xIndexRowType, 45, false, 65, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(hkeys(5, 6), cursor);
    }

    // Reverse versions of above tests

    @Test
    public void testDuplicateNullsReverse()
    {
        {
            Operator indexScan = indexScan_Default(xIndexRowType, true);
            compareRenderedHKeys(
                reverse(hkeys(9, 10, 11, 12, 1, 2, 3, 4, 5, 6, 7, 8)),
                cursor(indexScan, queryContext, queryBindings));
        }
        {
            Operator indexScan = indexScan_Default(yIndexRowType, true);
            compareRenderedHKeys(
                reverse(hkeys(7, 8, 11, 12, 1, 2, 3, 4, 5, 6, 9, 10)),
                cursor(indexScan, queryContext, queryBindings));
        }
        {
            Operator indexScan = indexScan_Default(xyIndexRowType, true);
            compareRenderedHKeys(
                reverse(hkeys(11, 12, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8)),
                cursor(indexScan, queryContext, queryBindings));
        }
    }

    @Test
    public void testExactMatchAbsentReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 5, true, 5, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys()), cursor);
    }

    @Test
    public void testExactMatchPresentReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 10, true, 10, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(1)), cursor);
    }

    @Test
    public void testEmptyRangeReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 11, true, 12, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys()), cursor);
    }

    @Test
    public void testStartAtNullReverse()
    {
        {
            Operator indexScan = indexScan_Default(xIndexRowType, true, startAtNull(xIndexRowType, true, 60, true));
            Cursor cursor = cursor(indexScan, queryContext, queryBindings);
            compareRenderedHKeys(reverse(hkeys(9, 10, 11, 12, 1, 2, 3, 4, 5, 6)), cursor);
        }
        {
            Operator indexScan = indexScan_Default(yIndexRowType, true, startAtNull(yIndexRowType, true, 60, true));
            Cursor cursor = cursor(indexScan, queryContext, queryBindings);
            compareRenderedHKeys(reverse(hkeys(7, 8, 11, 12, 1, 2, 3, 4, 5, 6)), cursor);
        }
    }

    @Test
    public void testStartAfterNullReverse()
    {
        {
            Operator indexScan = indexScan_Default(xIndexRowType, true, startAtNull(xIndexRowType, false, 60, true));
            Cursor cursor = cursor(indexScan, queryContext, queryBindings);
            compareRenderedHKeys(reverse(hkeys(1, 2, 3, 4, 5, 6)), cursor);
        }
        {
            Operator indexScan = indexScan_Default(yIndexRowType, true, startAtNull(yIndexRowType, false, 60, true));
            Cursor cursor = cursor(indexScan, queryContext, queryBindings);
            compareRenderedHKeys(reverse(hkeys(1, 2, 3, 4, 5, 6)), cursor);
        }
    }

    // Naming scheme for next tests:
    // testLoABHiCD
    // A: Inclusive/Exclusive for lo bound
    // B: Match/Miss indicates whether the lo bound matches or misses an actual value in the db
    // C: Inclusive/Exclusive for hi bound
    // D: Match/Miss indicates whether the hi bound matches or misses an actual value in the db

    @Test
    public void testLoInclusiveMatchHiInclusiveMatchReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 20, true, 40, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(2, 3, 4)), cursor);
    }

    @Test
    public void testLoInclusiveMatchHiInclusiveMissReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 20, true, 45, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(2, 3, 4)), cursor);
    }

    @Test
    public void testLoInclusiveMatchHiExclusiveMatchReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 20, true, 50, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(2, 3, 4)), cursor);
    }

    @Test
    public void testLoInclusiveMatchHiExclusiveMissReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 20, true, 45, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(2, 3, 4)), cursor);
    }

    @Test
    public void testLoInclusiveMissHiInclusiveMatchReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 5, true, 50, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(1, 2, 3, 4, 5)), cursor);
    }

    @Test
    public void testLoInclusiveMissHiInclusiveMissReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 5, true, 55, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(1, 2, 3, 4, 5)), cursor);
    }

    @Test
    public void testLoInclusiveMissHiExclusiveMatchReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 5, true, 60, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(1, 2, 3, 4, 5)), cursor);
    }

    @Test
    public void testLoInclusiveMissHiExclusiveMissReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 5, true, 55, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(1, 2, 3, 4, 5)), cursor);
    }

    @Test
    public void testLoExclusiveMatchHiInclusiveMatchReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 60, false, 70, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(7)), cursor);
    }

    @Test
    public void testLoExclusiveMatchHiInclusiveMissReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 60, false, 75, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(7)), cursor);
    }

    @Test
    public void testLoExclusiveMatchHiExclusiveMatchReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 60, false, 80, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(7)), cursor);
    }

    @Test
    public void testLoExclusiveMatchHiExclusiveMissReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 60, false, 75, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(7)), cursor);
    }

    @Test
    public void testLoExclusiveMissHiInclusiveMatchReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 45, false, 60, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(5, 6)), cursor);
    }

    @Test
    public void testLoExclusiveMissHiInclusiveMissReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 45, false, 65, true));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(5, 6)), cursor);
    }

    @Test
    public void testLoExclusiveMissHiExclusiveMatchReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 45, false, 70, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(5, 6)), cursor);
    }

    @Test
    public void testLoExclusiveMissHiExclusiveMissReverse()
    {
        Operator indexScan = indexScan_Default(xIndexRowType, true, keyRange(xIndexRowType, 45, false, 65, false));
        Cursor cursor = cursor(indexScan, queryContext, queryBindings);
        compareRenderedHKeys(reverse(hkeys(5, 6)), cursor);
    }

    // For use by this class

    private IndexKeyRange startAtNull(IndexRowType indexRowType, boolean loInclusive, int hi, boolean hiInclusive)
    {
        return IndexKeyRange.bounded(indexRowType,
                                     new IndexBound(row(indexRowType, new Object[]{null}), COLUMN_0),
                                     loInclusive,
                                     new IndexBound(row(indexRowType, hi), COLUMN_0),
                                     hiInclusive);
    }

    private IndexKeyRange keyRange(IndexRowType indexRowType, int lo, boolean loInclusive, int hi, boolean hiInclusive)
    {
        return IndexKeyRange.bounded(indexRowType,
                                     new IndexBound(row(indexRowType, lo), COLUMN_0),
                                     loInclusive,
                                     new IndexBound(row(indexRowType, hi), COLUMN_0),
                                     hiInclusive);
    }

    private String[] hkeys(int... ids)
    {
        String[] hkeys = new String[ids.length];
        for (int i = 0; i < ids.length; i++) {
            hkeys[i] = hkey(ids[i]);
        }
        return hkeys;
    }

    private String hkey(int id)
    {
        return String.format("{1,(long)%s}", id);
    }

    private String[] reverse(String[] a)
    {
        for (int i = 0; i < a.length / 2; i++) {
            String x = a[i];
            a[i] = a[a.length - 1 - i];
            a[a.length - 1 - i] = x;
        }
        return a;
    }

    private static ColumnSelector COLUMN_0 = new SetColumnSelector(0);

    private IndexRowType xIndexRowType;
    private IndexRowType yIndexRowType;
    private IndexRowType xyIndexRowType;

}
TOP

Related Classes of com.foundationdb.server.test.it.qp.UniqueIndexScanIT

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.