/** * 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.ais.model.*; import com.foundationdb.qp.expression.IndexBound; import com.foundationdb.qp.expression.IndexKeyRange; import com.foundationdb.qp.operator.Cursor; import com.foundationdb.qp.operator.ExpressionGenerator; import com.foundationdb.qp.operator.Operator; import com.foundationdb.qp.row.Row; import com.foundationdb.qp.rowtype.RowType; import com.foundationdb.server.types.texpressions.Comparison; import org.junit.Test; import java.util.Arrays; import static com.foundationdb.server.test.ExpressionGenerators.*; import static com.foundationdb.qp.operator.API.*; import static com.foundationdb.qp.operator.API.JoinType.*; public class OperatorIT extends OperatorITBase { @Override protected void setupPostCreateSchema() { super.setupPostCreateSchema(); use(db); } @Test public void testGroupScan() throws Exception { Operator groupScan = groupScan_Default(coi); Cursor executable = cursor(groupScan, queryContext, queryBindings); Row[] expected = new Row[]{row(customerRowType, 1L, "xyz"), row(orderRowType, 11L, 1L, "ori"), row(itemRowType, 111L, 11L), row(itemRowType, 112L, 11L), row(orderRowType, 12L, 1L, "david"), row(itemRowType, 121L, 12L), row(itemRowType, 122L, 12L), row(customerRowType, 2L, "abc"), row(orderRowType, 21L, 2L, "tom"), row(itemRowType, 211L, 21L), row(itemRowType, 212L, 21L), row(orderRowType, 22L, 2L, "jack"), row(itemRowType, 221L, 22L), row(itemRowType, 222L, 22L) }; compareRows(expected, executable); } @Test public void testSelect() { Operator groupScan = groupScan_Default(coi); ExpressionGenerator cidEq2 = compare(field(customerRowType, 0), Comparison.EQ, literal(2L), castResolver()); Operator select = select_HKeyOrdered(groupScan, customerRowType, cidEq2); Row[] expected = new Row[]{row(customerRowType, 2L, "abc"), row(orderRowType, 21L, 2L, "tom"), row(itemRowType, 211L, 21L), row(itemRowType, 212L, 21L), row(orderRowType, 22L, 2L, "jack"), row(itemRowType, 221L, 22L), row(itemRowType, 222L, 22L)}; compareRows(expected, cursor(select, queryContext, queryBindings)); } @Test public void testFlatten() { Operator groupScan = groupScan_Default(coi); Operator flatten = flatten_HKeyOrdered(groupScan, customerRowType, orderRowType, INNER_JOIN); RowType flattenType = flatten.rowType(); Row[] expected = new Row[]{row(flattenType, 1L, "xyz", 11L, 1L, "ori"), row(itemRowType, 111L, 11L), row(itemRowType, 112L, 11L), row(flattenType, 1L, "xyz", 12L, 1L, "david"), row(itemRowType, 121L, 12L), row(itemRowType, 122L, 12L), row(flattenType, 2L, "abc", 21L, 2L, "tom"), row(itemRowType, 211L, 21L), row(itemRowType, 212L, 21L), row(flattenType, 2L, "abc", 22L, 2L, "jack"), row(itemRowType, 221L, 22L), row(itemRowType, 222L, 22L)}; compareRows(expected, cursor(flatten, queryContext, queryBindings)); } @Test public void testTwoFlattens() { Operator groupScan = groupScan_Default(coi); Operator flattenCO = flatten_HKeyOrdered(groupScan, customerRowType, orderRowType, INNER_JOIN); Operator flattenCOI = flatten_HKeyOrdered(flattenCO, flattenCO.rowType(), itemRowType, INNER_JOIN); RowType flattenCOIType = flattenCOI.rowType(); Row[] expected = new Row[]{row(flattenCOIType, 1L, "xyz", 11L, 1L, "ori", 111L, 11L), row(flattenCOIType, 1L, "xyz", 11L, 1L, "ori", 112L, 11L), row(flattenCOIType, 1L, "xyz", 12L, 1L, "david", 121L, 12L), row(flattenCOIType, 1L, "xyz", 12L, 1L, "david", 122L, 12L), row(flattenCOIType, 2L, "abc", 21L, 2L, "tom", 211L, 21L), row(flattenCOIType, 2L, "abc", 21L, 2L, "tom", 212L, 21L), row(flattenCOIType, 2L, "abc", 22L, 2L, "jack", 221L, 22L), row(flattenCOIType, 2L, "abc", 22L, 2L, "jack", 222L, 22L)}; compareRows(expected, cursor(flattenCOI, queryContext, queryBindings)); } @Test public void testIndexScan1() { Operator indexScan = indexScan_Default(indexType(customer, "name")); // TODO: Can't compare rows, because we can't yet obtain fields from index rows. So compare hkeys instead String[] expected = new String[]{"{1,(long)2}", "{1,(long)1}"}; compareRenderedHKeys(expected, cursor(indexScan, queryContext, queryBindings)); } @Test public void testIndexScan2() { Operator indexScan = indexScan_Default(indexType(order, "salesman")); // TODO: Can't compare rows, because we can't yet obtain fields from index rows. So compare hkeys instead String[] expected = new String[]{"{1,(long)1,2,(long)12}", "{1,(long)2,2,(long)22}", "{1,(long)1,2,(long)11}", "{1,(long)2,2,(long)21}"}; compareRenderedHKeys(expected, cursor(indexScan, queryContext, queryBindings)); } @Test public void testIndexLookup() { Operator indexScan = indexScan_Default(indexType(order, "salesman")); Operator lookup = branchLookup_Default(indexScan, coi, orderSalesmanIndexRowType, orderRowType, InputPreservationOption.DISCARD_INPUT); Row[] expected = new Row[]{row(orderRowType, 12L, 1L, "david"), row(itemRowType, 121L, 12L), row(itemRowType, 122L, 12L), row(orderRowType, 22L, 2L, "jack"), row(itemRowType, 221L, 22L), row(itemRowType, 222L, 22L), row(orderRowType, 11L, 1L, "ori"), row(itemRowType, 111L, 11L), row(itemRowType, 112L, 11L), row(orderRowType, 21L, 2L, "tom"), row(itemRowType, 211L, 21L), row(itemRowType, 212L, 21L)}; compareRows(expected, cursor(lookup, queryContext, queryBindings)); } @Test public void testIndexLookupWithOneAncestor() { Operator indexScan = indexScan_Default(indexType(order, "salesman")); Operator lookup = branchLookup_Default(indexScan, coi, orderSalesmanIndexRowType, orderRowType, InputPreservationOption.DISCARD_INPUT); Operator ancestorLookup = ancestorLookup_Default(lookup, coi, orderRowType, Arrays.asList(customerRowType), InputPreservationOption.KEEP_INPUT); Row[] expected = new Row[]{row(customerRowType, 1L, "xyz"), row(orderRowType, 12L, 1L, "david"), row(itemRowType, 121L, 12L), row(itemRowType, 122L, 12L), row(customerRowType, 2L, "abc"), row(orderRowType, 22L, 2L, "jack"), row(itemRowType, 221L, 22L), row(itemRowType, 222L, 22L), row(customerRowType, 1L, "xyz"), row(orderRowType, 11L, 1L, "ori"), row(itemRowType, 111L, 11L), row(itemRowType, 112L, 11L), row(customerRowType, 2L, "abc"), row(orderRowType, 21L, 2L, "tom"), row(itemRowType, 211L, 21L), row(itemRowType, 212L, 21L)}; compareRows(expected, cursor(ancestorLookup, queryContext, queryBindings)); } @Test public void testIndexLookupWithTwoAncestors() { Operator indexScan = indexScan_Default(indexType(item, "oid")); Operator lookup = branchLookup_Default(indexScan, coi, itemOidIndexRowType, itemRowType, InputPreservationOption.DISCARD_INPUT); Operator ancestorLookup = ancestorLookup_Default(lookup, coi, itemRowType, Arrays.asList(customerRowType, orderRowType), InputPreservationOption.KEEP_INPUT); Row[] expected = new Row[]{row(customerRowType, 1L, "xyz"), row(orderRowType, 11L, 1L, "ori"), row(itemRowType, 111L, 11L), row(customerRowType, 1L, "xyz"), row(orderRowType, 11L, 1L, "ori"), row(itemRowType, 112L, 11L), row(customerRowType, 1L, "xyz"), row(orderRowType, 12L, 1L, "david"), row(itemRowType, 121L, 12L), row(customerRowType, 1L, "xyz"), row(orderRowType, 12L, 1L, "david"), row(itemRowType, 122L, 12L), row(customerRowType, 2L, "abc"), row(orderRowType, 21L, 2L, "tom"), row(itemRowType, 211L, 21L), row(customerRowType, 2L, "abc"), row(orderRowType, 21L, 2L, "tom"), row(itemRowType, 212L, 21L), row(customerRowType, 2L, "abc"), row(orderRowType, 22L, 2L, "jack"), row(itemRowType, 221L, 22L), row(customerRowType, 2L, "abc"), row(orderRowType, 22L, 2L, "jack"), row(itemRowType, 222L, 22L)}; compareRows(expected, cursor(ancestorLookup, queryContext, queryBindings)); } @Test public void testRestrictedIndexScan() { Index idxOrderSalesman = orderSalesmanIndexRowType.index(); IndexBound lo = indexBound(row(orderSalesmanIndexRowType, "jack"), columnSelector(idxOrderSalesman)); IndexBound hi = indexBound(row(orderSalesmanIndexRowType, "tom"), columnSelector(idxOrderSalesman)); IndexKeyRange range = indexKeyRange(orderSalesmanIndexRowType, lo, true, hi, false); Operator indexScan = indexScan_Default(orderSalesmanIndexRowType, false, range); // TODO: Can't compare rows, because we can't yet obtain fields from index rows. So compare hkeys instead String[] expected = new String[]{"{1,(long)2,2,(long)22}", "{1,(long)1,2,(long)11}"}; compareRenderedHKeys(expected, cursor(indexScan, queryContext, queryBindings)); } @Test public void testRestrictedIndexLookup() { Index idxOrderSalesman = orderSalesmanIndexRowType.index(); IndexBound tom = indexBound(row(orderSalesmanIndexRowType, "tom"), columnSelector(idxOrderSalesman)); IndexKeyRange matchTom = indexKeyRange(orderSalesmanIndexRowType, tom, true, tom, true); Operator indexScan = indexScan_Default(orderSalesmanIndexRowType, false, matchTom); Operator lookup = branchLookup_Default(indexScan, coi, orderSalesmanIndexRowType, orderRowType, InputPreservationOption.DISCARD_INPUT); Row[] expected = new Row[]{row(orderRowType, 21L, 2L, "tom"), row(itemRowType, 211L, 21L), row(itemRowType, 212L, 21L)}; compareRows(expected, cursor(lookup, queryContext, queryBindings)); } @Test public void testAncestorLookupAfterIndexScan() { // Find customers associated with salesman tom Index idxOrderSalesman = orderSalesmanIndexRowType.index(); IndexBound tom = indexBound(row(orderSalesmanIndexRowType, "tom"), columnSelector(idxOrderSalesman)); IndexKeyRange matchTom = indexKeyRange(orderSalesmanIndexRowType, tom, true, tom, true); Operator indexScan = indexScan_Default(orderSalesmanIndexRowType, false, matchTom); Operator ancestorLookup = ancestorLookup_Default(indexScan, coi, orderSalesmanIndexRowType, Arrays.asList(customerRowType), InputPreservationOption.DISCARD_INPUT); Row[] expected = new Row[]{row(customerRowType, 2L, "abc")}; compareRows(expected, cursor(ancestorLookup, queryContext, queryBindings)); } }