blob: 299091f779686ab736c3a612ae2857db8558897c [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.phoenix.end2end.join;
import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.phoenix.util.PropertiesUtil;
import org.apache.phoenix.util.QueryUtil;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.apache.phoenix.end2end.ParallelStatsDisabledTest;
import org.apache.phoenix.thirdparty.com.google.common.collect.Lists;
import org.apache.phoenix.thirdparty.com.google.common.collect.Maps;
@Category(ParallelStatsDisabledTest.class)
@RunWith(Parameterized.class)
public class HashJoinLocalIndexIT extends HashJoinIT {
private static final Map<String,String> virtualNameToRealNameMap = Maps.newHashMap();
private static final String schemaName = "S_" + generateUniqueName();
@Override
protected String getSchemaName() {
// run all tests in a single schema
return schemaName;
}
@Override
protected Map<String,String> getTableNameMap() {
// cache across tests, so that tables and
// indexes are not recreated each time
return virtualNameToRealNameMap;
}
public HashJoinLocalIndexIT(String[] indexDDL, String[] plans) {
super(indexDDL, plans);
}
@Parameters(name="HashJoinLocalIndexIT_{index}") // name is used by failsafe as file name in reports
public static synchronized Collection<Object> data() {
List<Object> testCases = Lists.newArrayList();
testCases.add(new String[][] {
{
"CREATE LOCAL INDEX " + JOIN_CUSTOMER_INDEX + " ON " +
JOIN_CUSTOMER_TABLE_FULL_NAME + " (name)",
"CREATE LOCAL INDEX " + JOIN_ITEM_INDEX + " ON " +
JOIN_ITEM_TABLE_FULL_NAME + " (name) " +
"INCLUDE (price, discount1, discount2, \"supplier_id\", description)",
"CREATE LOCAL INDEX " + JOIN_SUPPLIER_INDEX + " ON " +
JOIN_SUPPLIER_TABLE_FULL_NAME + " (name)"
}, {
/*
* testLeftJoinWithAggregation()
* SELECT i.name, sum(quantity) FROM joinOrderTable o
* LEFT JOIN joinItemTable i ON o.item_id = i.item_id
* GROUP BY i.name ORDER BY i.name
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" SERVER AGGREGATE INTO DISTINCT ROWS BY [\"I.0:NAME\"]\n" +
"CLIENT MERGE SORT\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" CLIENT MERGE SORT",
/*
* testLeftJoinWithAggregation()
* SELECT i.item_id iid, sum(quantity) q FROM joinOrderTable o
* LEFT JOIN joinItemTable i ON o.item_id = i.item_id
* GROUP BY i.item_id ORDER BY q DESC"
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" SERVER AGGREGATE INTO DISTINCT ROWS BY [\"I.:item_id\"]\n" +
"CLIENT MERGE SORT\n" +
"CLIENT SORTED BY [SUM(O.QUANTITY) DESC]\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" CLIENT MERGE SORT",
/*
* testLeftJoinWithAggregation()
* SELECT i.item_id iid, sum(quantity) q FROM joinItemTable i
* LEFT JOIN joinOrderTable o ON o.item_id = i.item_id
* GROUP BY i.item_id ORDER BY q DESC NULLS LAST, iid
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_FULL_NAME + "\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" SERVER AGGREGATE INTO ORDERED DISTINCT ROWS BY [\"I.item_id\"]\n" +
"CLIENT SORTED BY [SUM(O.QUANTITY) DESC NULLS LAST, \"I.item_id\"]\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME,
/*
* testRightJoinWithAggregation()
* SELECT i.name, sum(quantity) FROM joinOrderTable o
* RIGHT JOIN joinItemTable i ON o.item_id = i.item_id
* GROUP BY i.name ORDER BY i.name
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" SERVER AGGREGATE INTO ORDERED DISTINCT ROWS BY [\"I.0:NAME\"]\n" +
"CLIENT MERGE SORT\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME,
/*
* testRightJoinWithAggregation()
* SELECT i.item_id iid, sum(quantity) q FROM joinOrderTable o
* RIGHT JOIN joinItemTable i ON o.item_id = i.item_id
* GROUP BY i.item_id ORDER BY q DESC NULLS LAST, iid
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_FULL_NAME + "\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" SERVER AGGREGATE INTO ORDERED DISTINCT ROWS BY [\"I.item_id\"]\n" +
"CLIENT SORTED BY [SUM(O.QUANTITY) DESC NULLS LAST, \"I.item_id\"]\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME,
/*
* testJoinWithWildcard()
* SELECT * FROM joinItemTable LEFT JOIN joinSupplierTable supp
* ON joinItemTable.supplier_id = supp.supplier_id
* ORDER BY item_id
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_FULL_NAME + "\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SUPPLIER_TABLE_FULL_NAME,
/*
* testJoinPlanWithIndex()
* SELECT item.item_id, item.name, supp.supplier_id, supp.name
* FROM joinItemTable item LEFT JOIN joinSupplierTable supp
* ON substr(item.name, 2, 1) = substr(supp.name, 2, 1)
* AND (supp.name BETWEEN 'S1' AND 'S5')
* WHERE item.name BETWEEN 'T1' AND 'T5'
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1,'T1'] - [1,'T5']\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
"CLIENT MERGE SORT\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_SUPPLIER_INDEX_FULL_NAME +
"(" + JOIN_SUPPLIER_TABLE_FULL_NAME + ") [1,'S1'] - [1,'S5']\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" CLIENT MERGE SORT",
/*
* testJoinPlanWithIndex()
* SELECT item.item_id, item.name, supp.supplier_id, supp.name
* FROM joinItemTable item INNER JOIN joinSupplierTable supp
* ON item.supplier_id = supp.supplier_id
* WHERE (item.name = 'T1' OR item.name = 'T5')
* AND (supp.name = 'S1' OR supp.name = 'S5')
*/
"CLIENT PARALLEL 1-WAY SKIP SCAN ON 2 KEYS OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1,'T1'] - [1,'T5']\n" +
"CLIENT MERGE SORT\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY SKIP SCAN ON 2 KEYS OVER " +
JOIN_SUPPLIER_INDEX_FULL_NAME + "(" +
JOIN_SUPPLIER_TABLE_FULL_NAME + ") [1,'S1'] - [1,'S5']\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" CLIENT MERGE SORT",
/*
* testJoinWithSkipMergeOptimization()
* SELECT s.name FROM joinItemTable i
* JOIN joinOrderTable o ON o.item_id = i.item_id AND quantity < 5000
* JOIN joinSupplierTable s ON i.supplier_id = s.supplier_id
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
"CLIENT MERGE SORT\n" +
" PARALLEL INNER-JOIN TABLE 0 (SKIP MERGE)\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" SERVER FILTER BY QUANTITY < 5000\n" +
" PARALLEL INNER-JOIN TABLE 1\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_SUPPLIER_INDEX_FULL_NAME +
"(" + JOIN_SUPPLIER_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" CLIENT MERGE SORT\n" +
" DYNAMIC SERVER FILTER BY \"I.:item_id\" IN (\"O.item_id\")",
/*
* testSelfJoin()
* SELECT i2.item_id, i1.name FROM joinItemTable i1
* JOIN joinItemTable i2 ON i1.item_id = i2.item_id
* ORDER BY i1.item_id
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_FULL_NAME + "\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER "+ JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" CLIENT MERGE SORT\n" +
" DYNAMIC SERVER FILTER BY \"I1.item_id\" IN (\"I2.:item_id\")",
/*
* testSelfJoin()
* SELECT i1.name, i2.name FROM joinItemTable i1
* JOIN joinItemTable i2 ON i1.item_id = i2.supplier_id
* ORDER BY i1.name, i2.name
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" SERVER SORTED BY [\"I1.0:NAME\", \"I2.0:NAME\"]\n" +
"CLIENT MERGE SORT\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" CLIENT MERGE SORT\n" +
" DYNAMIC SERVER FILTER BY \"I1.:item_id\" IN (\"I2.0:supplier_id\")",
/*
* testStarJoin()
* SELECT order_id, c.name, i.name iname, quantity, o.date
* FROM joinOrderTable o
* JOIN joinCustomerTable c ON o.customer_id = c.customer_id
* JOIN joinItemTable i ON o.item_id = i.item_id
* ORDER BY order_id
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_CUSTOMER_INDEX_FULL_NAME +
"(" + JOIN_CUSTOMER_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" CLIENT MERGE SORT\n" +
" PARALLEL INNER-JOIN TABLE 1\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" CLIENT MERGE SORT",
/*
* testStarJoin()
* SELECT (*NO_STAR_JOIN*) order_id, c.name, i.name iname, quantity, o.date
* FROM joinOrderTable o
* JOIN joinCustomerTable c ON o.customer_id = c.customer_id
* JOIN joinItemTable i ON o.item_id = i.item_id
* ORDER BY order_id
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" SERVER SORTED BY [\"O.order_id\"]\n"+
"CLIENT MERGE SORT\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " +
JOIN_CUSTOMER_INDEX_FULL_NAME + "(" +
JOIN_CUSTOMER_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" CLIENT MERGE SORT\n" +
" DYNAMIC SERVER FILTER BY \"I.:item_id\" IN (\"O.item_id\")",
/*
* testSubJoin()
* SELECT * FROM joinCustomerTable c
* INNER JOIN (joinOrderTable o
* INNER JOIN (joinSupplierTable s
* RIGHT JOIN joinItemTable i ON i.supplier_id = s.supplier_id)
* ON o.item_id = i.item_id)
* ON c.customer_id = o.customer_id
* WHERE c.customer_id <= '0000000005'
* AND order_id != '000000000000003'
* AND i.name != 'T3'
* ORDER BY c.customer_id, i.name
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_CUSTOMER_TABLE_FULL_NAME + " [*] - ['0000000005']\n" +
" SERVER SORTED BY [\"C.customer_id\", \"I.0:NAME\"]\n"+
"CLIENT MERGE SORT\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" SERVER FILTER BY \"order_id\" != '000000000000003'\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " +
JOIN_ITEM_INDEX_FULL_NAME + "(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY \"NAME\" != 'T3'\n" +
" CLIENT MERGE SORT\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SUPPLIER_TABLE_FULL_NAME + "\n" +
" DYNAMIC SERVER FILTER BY \"C.customer_id\" IN (\"O.customer_id\")",
/*
* testJoinWithSubqueryAndAggregation()
* SELECT i.name, sum(quantity) FROM joinOrderTable o
* LEFT JOIN (SELECT name, item_id iid FROM joinItemTable) AS i
* ON o.item_id = i.iid
* GROUP BY i.name ORDER BY i.name
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" SERVER AGGREGATE INTO DISTINCT ROWS BY [I.NAME]\n" +
"CLIENT MERGE SORT\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" CLIENT MERGE SORT",
/*
* testJoinWithSubqueryAndAggregation()
* SELECT o.iid, sum(o.quantity) q
* FROM (SELECT item_id iid, quantity FROM joinOrderTable) AS o
* LEFT JOIN (SELECT item_id FROM joinItemTable) AS i
* ON o.iid = i.item_id
* GROUP BY o.iid ORDER BY q DESC
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" SERVER AGGREGATE INTO DISTINCT ROWS BY [O.IID]\n" +
"CLIENT MERGE SORT\n" +
"CLIENT SORTED BY [SUM(O.QUANTITY) DESC]\n" +
" PARALLEL LEFT-JOIN TABLE 0 (SKIP MERGE)\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" CLIENT MERGE SORT",
/*
* testJoinWithSubqueryAndAggregation()
* SELECT i.iid, o.q
* FROM (SELECT item_id iid FROM joinItemTable) AS i
* LEFT JOIN (SELECT item_id iid, sum(quantity) q FROM joinOrderTable GROUP BY item_id) AS o
* ON o.iid = i.iid
* ORDER BY o.q DESC NULLS LAST, i.iid
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" SERVER SORTED BY [O.Q DESC NULLS LAST, I.IID]\n"+
"CLIENT MERGE SORT\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" SERVER AGGREGATE INTO DISTINCT ROWS BY [\"item_id\"]\n" +
" CLIENT MERGE SORT",
/*
* testJoinWithSubqueryAndAggregation()
* SELECT i.iid, o.q
* FROM (SELECT item_id iid, sum(quantity) q FROM joinOrderTable GROUP BY item_id) AS o
* JOIN (SELECT item_id iid FROM joinItemTable) AS i
* ON o.iid = i.iid
* ORDER BY o.q DESC, i.iid
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" SERVER SORTED BY [O.Q DESC, I.IID]\n"+
"CLIENT MERGE SORT\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" SERVER AGGREGATE INTO DISTINCT ROWS BY [\"item_id\"]\n" +
" CLIENT MERGE SORT",
/*
* testNestedSubqueries()
* SELECT * FROM (SELECT customer_id cid, name, phone, address, loc_id, date FROM joinCustomerTable) AS c
* INNER JOIN (SELECT o.oid ooid, o.cid ocid, o.iid oiid, o.price * o.quantity, o.date odate,
* qi.iiid iiid, qi.iname iname, qi.iprice iprice, qi.idiscount1 idiscount1, qi.idiscount2 idiscount2, qi.isid isid, qi.idescription idescription,
* qi.ssid ssid, qi.sname sname, qi.sphone sphone, qi.saddress saddress, qi.sloc_id sloc_id
* FROM (SELECT item_id iid, customer_id cid, order_id oid, price, quantity, date FROM joinOrderTable) AS o
* INNER JOIN (SELECT i.iid iiid, i.name iname, i.price iprice, i.discount1 idiscount1, i.discount2 idiscount2, i.sid isid, i.description idescription,
* s.sid ssid, s.name sname, s.phone sphone, s.address saddress, s.loc_id sloc_id
* FROM (SELECT supplier_id sid, name, phone, address, loc_id FROM joinSupplierTable) AS s
* RIGHT JOIN (SELECT item_id iid, name, price, discount1, discount2, supplier_id sid, description FROM joinItemTable) AS i
* ON i.sid = s.sid) as qi
* ON o.iid = qi.iiid) as qo
* ON c.cid = qo.ocid
* WHERE c.cid <= '0000000005'
* AND qo.ooid != '000000000000003'
* AND qo.iname != 'T3'
* ORDER BY c.cid, qo.iname
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_CUSTOMER_TABLE_FULL_NAME + " [*] - ['0000000005']\n" +
" SERVER SORTED BY [C.CID, QO.INAME]\n" +
"CLIENT MERGE SORT\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" SERVER FILTER BY \"order_id\" != '000000000000003'\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " +
JOIN_ITEM_INDEX_FULL_NAME + "(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY \"NAME\" != 'T3'\n" +
" CLIENT MERGE SORT\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SUPPLIER_TABLE_FULL_NAME,
/*
* testJoinWithLimit()
* SELECT order_id, i.name, s.name, s.address, quantity
* FROM joinSupplierTable s
* LEFT JOIN joinItemTable i ON i.supplier_id = s.supplier_id
* LEFT JOIN joinOrderTable o ON o.item_id = i.item_id LIMIT 4
*/
"CLIENT SERIAL 1-WAY FULL SCAN OVER " + JOIN_SUPPLIER_TABLE_FULL_NAME + "\n" +
" SERVER 4 ROW LIMIT\n" +
"CLIENT 4 ROW LIMIT\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER "+ JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" CLIENT MERGE SORT\n" +
" PARALLEL LEFT-JOIN TABLE 1(DELAYED EVALUATION)\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER "+ JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" JOIN-SCANNER 4 ROW LIMIT",
/*
* testJoinWithLimit()
* SELECT order_id, i.name, s.name, s.address, quantity
* FROM joinSupplierTable s
* JOIN joinItemTable i ON i.supplier_id = s.supplier_id
* JOIN joinOrderTable o ON o.item_id = i.item_id LIMIT 4
*/
"CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SUPPLIER_TABLE_FULL_NAME + "\n" +
"CLIENT 4 ROW LIMIT\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER "+ JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" CLIENT MERGE SORT\n" +
" PARALLEL INNER-JOIN TABLE 1(DELAYED EVALUATION)\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER "+ JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" DYNAMIC SERVER FILTER BY \"S.supplier_id\" IN (\"I.0:supplier_id\")\n" +
" JOIN-SCANNER 4 ROW LIMIT",
/*
* testJoinWithSetMaxRows()
* statement.setMaxRows(4);
* SELECT order_id, i.name, quantity FROM joinItemTable i
* JOIN joinOrderTable o ON o.item_id = i.item_id;
* SELECT o.order_id, i.name, o.quantity FROM joinItemTable i
* JOIN (SELECT order_id, item_id, quantity FROM joinOrderTable) o
* ON o.item_id = i.item_id;
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
"CLIENT MERGE SORT\n" +
"CLIENT 4 ROW LIMIT\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" DYNAMIC SERVER FILTER BY \"I.:item_id\" IN (\"O.item_id\")\n" +
" JOIN-SCANNER 4 ROW LIMIT",
/*
* testJoinWithOffset()
* SELECT order_id, i.name, s.name, s.address, quantity
* FROM joinSupplierTable s
* LEFT JOIN joinItemTable i ON i.supplier_id = s.supplier_id
* LEFT JOIN joinOrderTable o ON o.item_id = i.item_id LIMIT 1 OFFSET 2
*/
"CLIENT SERIAL 1-WAY FULL SCAN OVER " + JOIN_SUPPLIER_TABLE_FULL_NAME + "\n" +
" SERVER OFFSET 2\n" +
" SERVER 3 ROW LIMIT\n" +
"CLIENT 1 ROW LIMIT\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER "+ JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" CLIENT MERGE SORT\n" +
" PARALLEL LEFT-JOIN TABLE 1(DELAYED EVALUATION)\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER "+ JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" JOIN-SCANNER 3 ROW LIMIT",
/*
* testJoinWithOffset()
* SELECT order_id, i.name, s.name, s.address, quantity
* FROM joinSupplierTable s
* JOIN joinItemTable i ON i.supplier_id = s.supplier_id
* JOIN joinOrderTable o ON o.item_id = i.item_id LIMIT 1 OFFSET 2
*/
"CLIENT SERIAL 1-WAY FULL SCAN OVER " + JOIN_SUPPLIER_TABLE_FULL_NAME + "\n" +
" SERVER OFFSET 2\n" +
"CLIENT 1 ROW LIMIT\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER "+ JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1]\n" +
" CLIENT MERGE SORT\n" +
" PARALLEL INNER-JOIN TABLE 1(DELAYED EVALUATION)\n" +
" CLIENT PARALLEL 1-WAY FULL SCAN OVER "+ JOIN_ORDER_TABLE_FULL_NAME + "\n" +
" DYNAMIC SERVER FILTER BY \"S.supplier_id\" IN (\"I.0:supplier_id\")\n" +
" JOIN-SCANNER 3 ROW LIMIT",
/*
* testJoinWithLocalIndex()
* SELECT phone, i.name
* FROM joinSupplierTable s
* JOIN joinItemTable i ON s.supplier_id = i.supplier_id
* WHERE s.name = 'S1' AND i.name < 'T6'
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_SUPPLIER_INDEX_FULL_NAME +
"(" + JOIN_SUPPLIER_TABLE_FULL_NAME + ") [1,'S1']\n" +
" SERVER MERGE [0.PHONE]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
"CLIENT MERGE SORT\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1,*] - [1,'T6']\n" +
" CLIENT MERGE SORT\n" +
" DYNAMIC SERVER FILTER BY \"S.:supplier_id\" IN (\"I.0:supplier_id\")",
/*
* testJoinWithLocalIndex()
* SELECT phone, max(i.name)
* FROM joinSupplierTable s
* JOIN joinItemTable i ON s."supplier_id" = i."supplier_id"
* WHERE s.name = 'S1' AND i.name < 'T6'
* GROUP BY phone
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_SUPPLIER_INDEX_FULL_NAME +
"(" + JOIN_SUPPLIER_TABLE_FULL_NAME + ") [1,'S1']\n" +
" SERVER MERGE [0.PHONE]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" SERVER AGGREGATE INTO DISTINCT ROWS BY [\"S.PHONE\"]\n" +
"CLIENT MERGE SORT\n" +
" PARALLEL INNER-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1,*] - [1,'T6']\n" +
" CLIENT MERGE SORT\n" +
" DYNAMIC SERVER FILTER BY \"S.:supplier_id\" IN (\"I.0:supplier_id\")",
/*
* testJoinWithLocalIndex()
* SELECT max(phone), max(i.name)
* FROM joinSupplierTable s
* LEFT JOIN joinItemTable i ON s."supplier_id" = i."supplier_id" AND i.name < 'T6'
* WHERE s.name <= 'S3'
*/
"CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_SUPPLIER_INDEX_FULL_NAME +
"(" + JOIN_SUPPLIER_TABLE_FULL_NAME + ") [1,*] - [1,'S3']\n" +
" SERVER MERGE [0.PHONE]\n" +
" SERVER FILTER BY FIRST KEY ONLY\n" +
" SERVER AGGREGATE INTO SINGLE ROW\n" +
" PARALLEL LEFT-JOIN TABLE 0\n" +
" CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + JOIN_ITEM_INDEX_FULL_NAME +
"(" + JOIN_ITEM_TABLE_FULL_NAME + ") [1,*] - [1,'T6']\n" +
" CLIENT MERGE SORT",
}});
return testCases;
}
@Test
public void testJoinWithLocalIndex() throws Exception {
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
Connection conn = DriverManager.getConnection(getUrl(), props);
try {
String query = "select phone, i.name from " + getTableName(conn, JOIN_SUPPLIER_TABLE_FULL_NAME) + " s join " + getTableName(conn, JOIN_ITEM_TABLE_FULL_NAME) + " i on s.\"supplier_id\" = i.\"supplier_id\" where s.name = 'S1' and i.name < 'T6'";
System.out.println("1)\n" + query);
PreparedStatement statement = conn.prepareStatement(query);
ResultSet rs = statement.executeQuery();
assertTrue (rs.next());
assertEquals(rs.getString(1), "888-888-1111");
assertTrue (rs.next());
assertEquals(rs.getString(1), "888-888-1111");
assertFalse(rs.next());
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
assertPlansEqual(plans[24], QueryUtil.getExplainPlan(rs));
query = "select phone, max(i.name) from " + getTableName(conn, JOIN_SUPPLIER_TABLE_FULL_NAME) + " s join " + getTableName(conn, JOIN_ITEM_TABLE_FULL_NAME) + " i on s.\"supplier_id\" = i.\"supplier_id\" where s.name = 'S1' and i.name < 'T6' group by phone";
statement = conn.prepareStatement(query);
rs = statement.executeQuery();
assertTrue (rs.next());
assertEquals(rs.getString(1), "888-888-1111");
assertEquals(rs.getString(2), "T2");
assertFalse(rs.next());
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
assertPlansEqual(plans[25], QueryUtil.getExplainPlan(rs));
query = "select max(phone), max(i.name) from " + getTableName(conn, JOIN_SUPPLIER_TABLE_FULL_NAME) + " s left join " + getTableName(conn, JOIN_ITEM_TABLE_FULL_NAME) + " i on s.\"supplier_id\" = i.\"supplier_id\" and i.name < 'T6' where s.name <= 'S3'";
statement = conn.prepareStatement(query);
rs = statement.executeQuery();
assertTrue (rs.next());
assertEquals(rs.getString(1), "888-888-3333");
assertEquals(rs.getString(2), "T4");
assertFalse(rs.next());
rs = conn.createStatement().executeQuery("EXPLAIN " + query);
assertPlansEqual(plans[26], QueryUtil.getExplainPlan(rs));
} finally {
conn.close();
}
}
}