/**
* 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.ExpressionRow;
import com.foundationdb.qp.expression.IndexBound;
import com.foundationdb.qp.expression.IndexKeyRange;
import com.foundationdb.qp.expression.RowBasedUnboundExpressions;
import com.foundationdb.qp.operator.ExpressionGenerator;
import com.foundationdb.qp.operator.IndexScanSelector;
import com.foundationdb.qp.operator.Operator;
import com.foundationdb.qp.row.BindableRow;
import com.foundationdb.qp.row.Row;
import com.foundationdb.qp.rowtype.IndexRowType;
import com.foundationdb.qp.rowtype.RowType;
import com.foundationdb.server.api.dml.SetColumnSelector;
import com.foundationdb.server.types.mcompat.mtypes.MNumeric;
import com.foundationdb.server.types.value.Value;
import com.foundationdb.server.types.texpressions.TPreparedExpression;
import com.foundationdb.server.types.texpressions.TPreparedLiteral;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static com.foundationdb.qp.operator.API.*;
import static com.foundationdb.server.test.ExpressionGenerators.*;
public class GroupLookup_DefaultLookaheadIT extends GroupLookup_DefaultIT
{
protected void moreDB() {
Row[] daves = new Row[]{
row(order, 23L, 2L, "dave"),
row(order, 24L, 2L, "dave"),
row(order, 25L, 2L, "dave")};
writeRows(daves);
}
@Override
protected boolean pipelineMap() {
return true;
}
@Override
protected int lookaheadQuantum() {
return 4;
}
@Test
public void testAncestorLookupSimple()
{
moreDB();
Operator plan =
groupLookup_Default(
filter_Default(
groupScan_Default(coi),
Collections.singleton(orderRowType)),
coi,
orderRowType,
Collections.singleton(customerRowType),
InputPreservationOption.DISCARD_INPUT,
lookaheadQuantum());
Row[] expected = new Row[]{
row(customerRowType, 1L, "northbridge"),
row(customerRowType, 1L, "northbridge"),
row(customerRowType, 2L, "foundation"),
row(customerRowType, 2L, "foundation"),
row(customerRowType, 2L, "foundation"),
row(customerRowType, 2L, "foundation"),
row(customerRowType, 2L, "foundation"),
};
compareRows(expected, cursor(plan, queryContext, queryBindings));
}
@Test
public void testAncestorLookupMap()
{
moreDB();
RowType cidValueRowType = schema.newValuesType(MNumeric.INT.instance(true));
List<ExpressionGenerator> cidExprs = Arrays.asList(boundField(cidValueRowType, 1, 0));
IndexBound cidBound =
new IndexBound(
new RowBasedUnboundExpressions(orderCidIndexRowType, cidExprs, true),
new SetColumnSelector(0));
IndexKeyRange cidRange = IndexKeyRange.bounded(orderCidIndexRowType, cidBound, true, cidBound, true);
Operator plan =
map_NestedLoops(
valuesScan_Default(
bindableExpressions(intRow(cidValueRowType, 3),
intRow(cidValueRowType, 2),
intRow(cidValueRowType, 10)),
cidValueRowType),
groupLookup_Default(
indexScan_Default(orderCidIndexRowType, cidRange, ordering(orderCidIndexRowType), IndexScanSelector.leftJoinAfter(orderCidIndexRowType.index(), orderRowType.table()), lookaheadQuantum()),
coi,
orderCidIndexRowType,
Arrays.asList(customerRowType, orderRowType),
InputPreservationOption.DISCARD_INPUT,
lookaheadQuantum()),
1, pipelineMap(), 1);
Row[] expected = new Row[]{
row(orderRowType, 31L, 3L, "peter"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 21L, 2L, "tom"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 22L, 2L, "jack"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 23L, 2L, "dave"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 24L, 2L, "dave"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 25L, 2L, "dave"),
};
compareRows(expected, cursor(plan, queryContext, queryBindings));
}
@Test
public void testAncestorLookupMap2()
{
moreDB();
RowType cidValueRowType = schema.newValuesType(MNumeric.INT.instance(true));
List<ExpressionGenerator> cidExprs = Arrays.asList(boundField(cidValueRowType, 1, 0));
IndexBound cidBound =
new IndexBound(
new RowBasedUnboundExpressions(orderCidIndexRowType, cidExprs, true),
new SetColumnSelector(0));
IndexKeyRange cidRange = IndexKeyRange.bounded(orderCidIndexRowType, cidBound, true, cidBound, true);
Operator plan =
map_NestedLoops(
valuesScan_Default(
bindableExpressions(intRow(cidValueRowType, -1),
intRow(cidValueRowType, -2)),
cidValueRowType),
map_NestedLoops(
valuesScan_Default(
bindableExpressions(intRow(cidValueRowType, 3),
intRow(cidValueRowType, 2),
intRow(cidValueRowType, 10)),
cidValueRowType),
groupLookup_Default(
indexScan_Default(orderCidIndexRowType, cidRange, ordering(orderCidIndexRowType), IndexScanSelector.leftJoinAfter(orderCidIndexRowType.index(), orderRowType.table()), lookaheadQuantum()),
coi,
orderCidIndexRowType,
Arrays.asList(customerRowType, orderRowType),
InputPreservationOption.DISCARD_INPUT,
lookaheadQuantum()),
1, pipelineMap(), 2),
0, pipelineMap(), 1);
Row[] expected = new Row[]{
row(orderRowType, 31L, 3L, "peter"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 21L, 2L, "tom"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 22L, 2L, "jack"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 23L, 2L, "dave"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 24L, 2L, "dave"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 25L, 2L, "dave"),
row(orderRowType, 31L, 3L, "peter"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 21L, 2L, "tom"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 22L, 2L, "jack"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 23L, 2L, "dave"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 24L, 2L, "dave"),
row(customerRowType, 2L, "foundation"),
row(orderRowType, 25L, 2L, "dave"),
};
compareRows(expected, cursor(plan, queryContext, queryBindings));
}
// For use by this class
private Row intRow(RowType rowType, int x)
{
List<TPreparedExpression> pExpressions = Arrays.<TPreparedExpression>asList(new TPreparedLiteral(MNumeric.INT.instance(false), new Value(MNumeric.INT.instance(false), x)));
return new ExpressionRow(rowType, queryContext, queryBindings, pExpressions);
}
private Collection<? extends BindableRow> bindableExpressions(Row... rows) {
List<BindableRow> result = new ArrayList<>();
for (Row row : rows) {
result.add(BindableRow.of(row));
}
return result;
}
private Ordering ordering(IndexRowType indexRowType) {
Ordering ordering = new Ordering();
for (int i = 0; i < indexRowType.nFields(); i++) {
ordering.append(field(indexRowType, i), true);
}
return ordering;
}
}