http://git-wip-us.apache.org/repos/asf/phoenix/blob/ebc7ee42/phoenix-core/src/it/java/org/apache/phoenix/end2end/SortMergeJoinIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/SortMergeJoinIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SortMergeJoinIT.java new file mode 100644 index 0000000..469388b --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/SortMergeJoinIT.java @@ -0,0 +1,2822 @@ +/* + * 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; + +import static org.apache.phoenix.util.TestUtil.JOIN_CUSTOMER_TABLE_FULL_NAME; +import static org.apache.phoenix.util.TestUtil.JOIN_ITEM_TABLE_DISPLAY_NAME; +import static org.apache.phoenix.util.TestUtil.JOIN_ITEM_TABLE_FULL_NAME; +import static org.apache.phoenix.util.TestUtil.JOIN_ORDER_TABLE_DISPLAY_NAME; +import static org.apache.phoenix.util.TestUtil.JOIN_ORDER_TABLE_FULL_NAME; +import static org.apache.phoenix.util.TestUtil.JOIN_SCHEMA; +import static org.apache.phoenix.util.TestUtil.JOIN_SUPPLIER_TABLE_DISPLAY_NAME; +import static org.apache.phoenix.util.TestUtil.JOIN_SUPPLIER_TABLE_FULL_NAME; +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.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.sql.Connection; +import java.sql.Date; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import org.apache.phoenix.exception.SQLExceptionCode; +import org.apache.phoenix.query.QueryServices; +import org.apache.phoenix.schema.TableAlreadyExistsException; +import org.apache.phoenix.util.MetaDataUtil; +import org.apache.phoenix.util.PropertiesUtil; +import org.apache.phoenix.util.QueryUtil; +import org.apache.phoenix.util.ReadOnlyProps; +import org.junit.Before; +import org.junit.BeforeClass; +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 com.google.common.collect.Lists; +import com.google.common.collect.Maps; +@Category(HBaseManagedTimeTest.class) +@RunWith(Parameterized.class) +public class SortMergeJoinIT extends BaseHBaseManagedTimeIT { + + private SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private String[] indexDDL; + private String[] plans; + + public SortMergeJoinIT(String[] indexDDL, String[] plans) { + this.indexDDL = indexDDL; + this.plans = plans; + } + + @BeforeClass + @Shadower(classBeingShadowed = BaseHBaseManagedTimeIT.class) + public static void doSetup() throws Exception { + Map<String,String> props = Maps.newHashMapWithExpectedSize(3); + // Forces server cache to be used + props.put(QueryServices.INDEX_MUTATE_BATCH_SIZE_THRESHOLD_ATTRIB, Integer.toString(2)); + // Must update config before starting server + setUpTestDriver(new ReadOnlyProps(props.entrySet().iterator())); + } + + @Before + public void initTable() throws Exception { + initTableValues(); + if (indexDDL != null && indexDDL.length > 0) { + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + for (String ddl : indexDDL) { + try { + conn.createStatement().execute(ddl); + } catch (TableAlreadyExistsException e) { + } + } + conn.close(); + } + } + + @Parameters + public static Collection<Object> data() { + List<Object> testCases = Lists.newArrayList(); + testCases.add(new String[][] { + {}, { + "SORT-MERGE-JOIN (LEFT) TABLES\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SUPPLIER_TABLE_DISPLAY_NAME + "\n" + + "AND\n" + + " SORT-MERGE-JOIN (INNER) TABLES\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ITEM_TABLE_DISPLAY_NAME + "\n" + + " SERVER SORTED BY [I.item_id]\n" + + " CLIENT MERGE SORT\n" + + " AND (SKIP MERGE)\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + + " SERVER FILTER BY QUANTITY < 5000\n" + + " SERVER SORTED BY [O.item_id]\n" + + " CLIENT MERGE SORT\n" + + " CLIENT SORTED BY [I.supplier_id]", + }}); + testCases.add(new String[][] { + { + "CREATE INDEX \"idx_customer\" ON " + JOIN_CUSTOMER_TABLE_FULL_NAME + " (name)", + "CREATE INDEX \"idx_item\" ON " + JOIN_ITEM_TABLE_FULL_NAME + " (name) INCLUDE (price, discount1, discount2, \"supplier_id\", description)", + "CREATE INDEX \"idx_supplier\" ON " + JOIN_SUPPLIER_TABLE_FULL_NAME + " (name)" + }, { + "SORT-MERGE-JOIN (LEFT) TABLES\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_supplier\n" + + " SERVER SORTED BY [S.:supplier_id]\n" + + " CLIENT MERGE SORT\n" + + "AND\n" + + " SORT-MERGE-JOIN (INNER) TABLES\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_SCHEMA + ".idx_item\n" + + " SERVER SORTED BY [I.:item_id]\n" + + " CLIENT MERGE SORT\n" + + " AND (SKIP MERGE)\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + + " SERVER FILTER BY QUANTITY < 5000\n" + + " SERVER SORTED BY [O.item_id]\n" + + " CLIENT MERGE SORT\n" + + " CLIENT SORTED BY [I.0:supplier_id]" + }}); + testCases.add(new String[][] { + { + "CREATE LOCAL INDEX \"idx_customer\" ON " + JOIN_CUSTOMER_TABLE_FULL_NAME + " (name)", + "CREATE LOCAL INDEX \"idx_item\" ON " + JOIN_ITEM_TABLE_FULL_NAME + " (name) INCLUDE (price, discount1, discount2, \"supplier_id\", description)", + "CREATE LOCAL INDEX \"idx_supplier\" ON " + JOIN_SUPPLIER_TABLE_FULL_NAME + " (name)" + }, { + "SORT-MERGE-JOIN (LEFT) TABLES\n" + + " CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX + JOIN_SUPPLIER_TABLE_DISPLAY_NAME + " [-32768]\n" + + " SERVER SORTED BY [S.:supplier_id]\n" + + " CLIENT MERGE SORT\n" + + "AND\n" + + " SORT-MERGE-JOIN (INNER) TABLES\n" + + " CLIENT PARALLEL 1-WAY RANGE SCAN OVER " + MetaDataUtil.LOCAL_INDEX_TABLE_PREFIX + JOIN_ITEM_TABLE_DISPLAY_NAME + " [-32768]\n" + + " SERVER SORTED BY [I.:item_id]\n" + + " CLIENT MERGE SORT\n" + + " AND (SKIP MERGE)\n" + + " CLIENT PARALLEL 1-WAY FULL SCAN OVER " + JOIN_ORDER_TABLE_DISPLAY_NAME + "\n" + + " SERVER FILTER BY QUANTITY < 5000\n" + + " SERVER SORTED BY [O.item_id]\n" + + " CLIENT MERGE SORT\n" + + " CLIENT SORTED BY [I.0:supplier_id]" + }}); + return testCases; + } + + + protected void initTableValues() throws Exception { + ensureTableCreated(getUrl(), JOIN_CUSTOMER_TABLE_FULL_NAME); + ensureTableCreated(getUrl(), JOIN_ITEM_TABLE_FULL_NAME); + ensureTableCreated(getUrl(), JOIN_SUPPLIER_TABLE_FULL_NAME); + ensureTableCreated(getUrl(), JOIN_ORDER_TABLE_FULL_NAME); + + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + conn.createStatement().execute("CREATE SEQUENCE my.seq"); + // Insert into customer table + PreparedStatement stmt = conn.prepareStatement( + "upsert into " + JOIN_CUSTOMER_TABLE_FULL_NAME + + " (\"customer_id\", " + + " NAME, " + + " PHONE, " + + " ADDRESS, " + + " LOC_ID, " + + " DATE) " + + "values (?, ?, ?, ?, ?, ?)"); + stmt.setString(1, "0000000001"); + stmt.setString(2, "C1"); + stmt.setString(3, "999-999-1111"); + stmt.setString(4, "101 XXX Street"); + stmt.setString(5, "10001"); + stmt.setDate(6, new Date(format.parse("2013-11-01 10:20:36").getTime())); + stmt.execute(); + + stmt.setString(1, "0000000002"); + stmt.setString(2, "C2"); + stmt.setString(3, "999-999-2222"); + stmt.setString(4, "202 XXX Street"); + stmt.setString(5, null); + stmt.setDate(6, new Date(format.parse("2013-11-25 16:45:07").getTime())); + stmt.execute(); + + stmt.setString(1, "0000000003"); + stmt.setString(2, "C3"); + stmt.setString(3, "999-999-3333"); + stmt.setString(4, "303 XXX Street"); + stmt.setString(5, null); + stmt.setDate(6, new Date(format.parse("2013-11-25 10:06:29").getTime())); + stmt.execute(); + + stmt.setString(1, "0000000004"); + stmt.setString(2, "C4"); + stmt.setString(3, "999-999-4444"); + stmt.setString(4, "404 XXX Street"); + stmt.setString(5, "10004"); + stmt.setDate(6, new Date(format.parse("2013-11-22 14:22:56").getTime())); + stmt.execute(); + + stmt.setString(1, "0000000005"); + stmt.setString(2, "C5"); + stmt.setString(3, "999-999-5555"); + stmt.setString(4, "505 XXX Street"); + stmt.setString(5, "10005"); + stmt.setDate(6, new Date(format.parse("2013-11-27 09:37:50").getTime())); + stmt.execute(); + + stmt.setString(1, "0000000006"); + stmt.setString(2, "C6"); + stmt.setString(3, "999-999-6666"); + stmt.setString(4, "606 XXX Street"); + stmt.setString(5, "10001"); + stmt.setDate(6, new Date(format.parse("2013-11-01 10:20:36").getTime())); + stmt.execute(); + + // Insert into item table + stmt = conn.prepareStatement( + "upsert into " + JOIN_ITEM_TABLE_FULL_NAME + + " (\"item_id\", " + + " NAME, " + + " PRICE, " + + " DISCOUNT1, " + + " DISCOUNT2, " + + " \"supplier_id\", " + + " DESCRIPTION) " + + "values (?, ?, ?, ?, ?, ?, ?)"); + stmt.setString(1, "0000000001"); + stmt.setString(2, "T1"); + stmt.setInt(3, 100); + stmt.setInt(4, 5); + stmt.setInt(5, 10); + stmt.setString(6, "0000000001"); + stmt.setString(7, "Item T1"); + stmt.execute(); + + stmt.setString(1, "0000000002"); + stmt.setString(2, "T2"); + stmt.setInt(3, 200); + stmt.setInt(4, 5); + stmt.setInt(5, 8); + stmt.setString(6, "0000000001"); + stmt.setString(7, "Item T2"); + stmt.execute(); + + stmt.setString(1, "0000000003"); + stmt.setString(2, "T3"); + stmt.setInt(3, 300); + stmt.setInt(4, 8); + stmt.setInt(5, 12); + stmt.setString(6, "0000000002"); + stmt.setString(7, "Item T3"); + stmt.execute(); + + stmt.setString(1, "0000000004"); + stmt.setString(2, "T4"); + stmt.setInt(3, 400); + stmt.setInt(4, 6); + stmt.setInt(5, 10); + stmt.setString(6, "0000000002"); + stmt.setString(7, "Item T4"); + stmt.execute(); + + stmt.setString(1, "0000000005"); + stmt.setString(2, "T5"); + stmt.setInt(3, 500); + stmt.setInt(4, 8); + stmt.setInt(5, 15); + stmt.setString(6, "0000000005"); + stmt.setString(7, "Item T5"); + stmt.execute(); + + stmt.setString(1, "0000000006"); + stmt.setString(2, "T6"); + stmt.setInt(3, 600); + stmt.setInt(4, 8); + stmt.setInt(5, 15); + stmt.setString(6, "0000000006"); + stmt.setString(7, "Item T6"); + stmt.execute(); + + stmt.setString(1, "invalid001"); + stmt.setString(2, "INVALID-1"); + stmt.setInt(3, 0); + stmt.setInt(4, 0); + stmt.setInt(5, 0); + stmt.setString(6, "0000000000"); + stmt.setString(7, "Invalid item for join test"); + stmt.execute(); + + // Insert into supplier table + stmt = conn.prepareStatement( + "upsert into " + JOIN_SUPPLIER_TABLE_FULL_NAME + + " (\"supplier_id\", " + + " NAME, " + + " PHONE, " + + " ADDRESS, " + + " LOC_ID) " + + "values (?, ?, ?, ?, ?)"); + stmt.setString(1, "0000000001"); + stmt.setString(2, "S1"); + stmt.setString(3, "888-888-1111"); + stmt.setString(4, "101 YYY Street"); + stmt.setString(5, "10001"); + stmt.execute(); + + stmt.setString(1, "0000000002"); + stmt.setString(2, "S2"); + stmt.setString(3, "888-888-2222"); + stmt.setString(4, "202 YYY Street"); + stmt.setString(5, "10002"); + stmt.execute(); + + stmt.setString(1, "0000000003"); + stmt.setString(2, "S3"); + stmt.setString(3, "888-888-3333"); + stmt.setString(4, "303 YYY Street"); + stmt.setString(5, null); + stmt.execute(); + + stmt.setString(1, "0000000004"); + stmt.setString(2, "S4"); + stmt.setString(3, "888-888-4444"); + stmt.setString(4, "404 YYY Street"); + stmt.setString(5, null); + stmt.execute(); + + stmt.setString(1, "0000000005"); + stmt.setString(2, "S5"); + stmt.setString(3, "888-888-5555"); + stmt.setString(4, "505 YYY Street"); + stmt.setString(5, "10005"); + stmt.execute(); + + stmt.setString(1, "0000000006"); + stmt.setString(2, "S6"); + stmt.setString(3, "888-888-6666"); + stmt.setString(4, "606 YYY Street"); + stmt.setString(5, "10006"); + stmt.execute(); + + // Insert into order table + stmt = conn.prepareStatement( + "upsert into " + JOIN_ORDER_TABLE_FULL_NAME + + " (\"order_id\", " + + " \"customer_id\", " + + " \"item_id\", " + + " PRICE, " + + " QUANTITY," + + " DATE) " + + "values (?, ?, ?, ?, ?, ?)"); + stmt.setString(1, "000000000000001"); + stmt.setString(2, "0000000004"); + stmt.setString(3, "0000000001"); + stmt.setInt(4, 100); + stmt.setInt(5, 1000); + stmt.setTimestamp(6, new Timestamp(format.parse("2013-11-22 14:22:56").getTime())); + stmt.execute(); + + stmt.setString(1, "000000000000002"); + stmt.setString(2, "0000000003"); + stmt.setString(3, "0000000006"); + stmt.setInt(4, 552); + stmt.setInt(5, 2000); + stmt.setTimestamp(6, new Timestamp(format.parse("2013-11-25 10:06:29").getTime())); + stmt.execute(); + + stmt.setString(1, "000000000000003"); + stmt.setString(2, "0000000002"); + stmt.setString(3, "0000000002"); + stmt.setInt(4, 190); + stmt.setInt(5, 3000); + stmt.setTimestamp(6, new Timestamp(format.parse("2013-11-25 16:45:07").getTime())); + stmt.execute(); + + stmt.setString(1, "000000000000004"); + stmt.setString(2, "0000000004"); + stmt.setString(3, "0000000006"); + stmt.setInt(4, 510); + stmt.setInt(5, 4000); + stmt.setTimestamp(6, new Timestamp(format.parse("2013-11-26 13:26:04").getTime())); + stmt.execute(); + + stmt.setString(1, "000000000000005"); + stmt.setString(2, "0000000005"); + stmt.setString(3, "0000000003"); + stmt.setInt(4, 264); + stmt.setInt(5, 5000); + stmt.setTimestamp(6, new Timestamp(format.parse("2013-11-27 09:37:50").getTime())); + stmt.execute(); + + conn.commit(); + } finally { + conn.close(); + } + } + + @Test + public void testDefaultJoin() throws Exception { + String query = "SELECT /*+ USE_SORT_MERGE_JOIN*/ item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" = supp.\"supplier_id\" ORDER BY \"item_id\""; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000002"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000003"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "0000000002"); + assertEquals(rs.getString(4), "S2"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000004"); + assertEquals(rs.getString(2), "T4"); + assertEquals(rs.getString(3), "0000000002"); + assertEquals(rs.getString(4), "S2"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000005"); + assertEquals(rs.getString(2), "T5"); + assertEquals(rs.getString(3), "0000000005"); + assertEquals(rs.getString(4), "S5"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000006"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "0000000006"); + assertEquals(rs.getString(4), "S6"); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testInnerJoin() throws Exception { + String query = "SELECT /*+ USE_SORT_MERGE_JOIN*/ item.\"item_id\", item.name, supp.\"supplier_id\", supp.name, next value for my.seq FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item INNER JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" = supp.\"supplier_id\" ORDER BY \"item_id\""; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertEquals(1, rs.getInt(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000002"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertEquals(2, rs.getInt(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000003"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "0000000002"); + assertEquals(rs.getString(4), "S2"); + assertEquals(3, rs.getInt(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000004"); + assertEquals(rs.getString(2), "T4"); + assertEquals(rs.getString(3), "0000000002"); + assertEquals(rs.getString(4), "S2"); + assertEquals(4, rs.getInt(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000005"); + assertEquals(rs.getString(2), "T5"); + assertEquals(rs.getString(3), "0000000005"); + assertEquals(rs.getString(4), "S5"); + assertEquals(5, rs.getInt(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000006"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "0000000006"); + assertEquals(rs.getString(4), "S6"); + assertEquals(6, rs.getInt(5)); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testLeftJoin() throws Exception { + String query[] = new String[3]; + query[0] = "SELECT /*+ USE_SORT_MERGE_JOIN*/ item.\"item_id\", item.name, supp.\"supplier_id\", supp.name, next value for my.seq FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item LEFT JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" = supp.\"supplier_id\" ORDER BY \"item_id\""; + query[1] = "SELECT /*+ USE_SORT_MERGE_JOIN*/ " + JOIN_ITEM_TABLE_FULL_NAME + ".\"item_id\", " + JOIN_ITEM_TABLE_FULL_NAME + ".name, " + JOIN_SUPPLIER_TABLE_FULL_NAME + ".\"supplier_id\", " + JOIN_SUPPLIER_TABLE_FULL_NAME + ".name, next value for my.seq FROM " + JOIN_ITEM_TABLE_FULL_NAME + " LEFT JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " ON " + JOIN_ITEM_TABLE_FULL_NAME + ".\"supplier_id\" = " + JOIN_SUPPLIER_TABLE_FULL_NAME + ".\"supplier_id\" ORDER BY \"item_id\""; + query[2] = "SELECT /*+ USE_SORT_MERGE_JOIN*/ item.\"item_id\", " + JOIN_ITEM_TABLE_FULL_NAME + ".name, supp.\"supplier_id\", " + JOIN_SUPPLIER_TABLE_FULL_NAME + ".name, next value for my.seq FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item LEFT JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON " + JOIN_ITEM_TABLE_FULL_NAME + ".\"supplier_id\" = supp.\"supplier_id\" ORDER BY \"item_id\""; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + for (int i = 0; i < query.length; i++) { + PreparedStatement statement = conn.prepareStatement(query[i]); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000002"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000003"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "0000000002"); + assertEquals(rs.getString(4), "S2"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000004"); + assertEquals(rs.getString(2), "T4"); + assertEquals(rs.getString(3), "0000000002"); + assertEquals(rs.getString(4), "S2"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000005"); + assertEquals(rs.getString(2), "T5"); + assertEquals(rs.getString(3), "0000000005"); + assertEquals(rs.getString(4), "S5"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000006"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "0000000006"); + assertEquals(rs.getString(4), "S6"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "invalid001"); + assertEquals(rs.getString(2), "INVALID-1"); + assertNull(rs.getString(3)); + assertNull(rs.getString(4)); + + assertFalse(rs.next()); + rs.close(); + statement.close(); + } + } finally { + conn.close(); + } + } + + @Test + public void testRightJoin() throws Exception { + String query = "SELECT /*+ USE_SORT_MERGE_JOIN*/ item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp RIGHT JOIN " + JOIN_ITEM_TABLE_FULL_NAME + " item ON item.\"supplier_id\" = supp.\"supplier_id\" ORDER BY \"item_id\""; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000002"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000003"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "0000000002"); + assertEquals(rs.getString(4), "S2"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000004"); + assertEquals(rs.getString(2), "T4"); + assertEquals(rs.getString(3), "0000000002"); + assertEquals(rs.getString(4), "S2"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000005"); + assertEquals(rs.getString(2), "T5"); + assertEquals(rs.getString(3), "0000000005"); + assertEquals(rs.getString(4), "S5"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000006"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "0000000006"); + assertEquals(rs.getString(4), "S6"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "invalid001"); + assertEquals(rs.getString(2), "INVALID-1"); + assertNull(rs.getString(3)); + assertNull(rs.getString(4)); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testInnerJoinWithPreFilters() throws Exception { + String query1 = "SELECT /*+ USE_SORT_MERGE_JOIN*/ item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item INNER JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" = supp.\"supplier_id\" AND supp.\"supplier_id\" BETWEEN '0000000001' AND '0000000005' ORDER BY \"item_id\""; + String query2 = "SELECT /*+ USE_SORT_MERGE_JOIN*/ item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item INNER JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" = supp.\"supplier_id\" AND (supp.\"supplier_id\" = '0000000001' OR supp.\"supplier_id\" = '0000000005') ORDER BY \"item_id\""; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query1); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000002"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000003"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "0000000002"); + assertEquals(rs.getString(4), "S2"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000004"); + assertEquals(rs.getString(2), "T4"); + assertEquals(rs.getString(3), "0000000002"); + assertEquals(rs.getString(4), "S2"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000005"); + assertEquals(rs.getString(2), "T5"); + assertEquals(rs.getString(3), "0000000005"); + assertEquals(rs.getString(4), "S5"); + + assertFalse(rs.next()); + + + statement = conn.prepareStatement(query2); + rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000002"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000005"); + assertEquals(rs.getString(2), "T5"); + assertEquals(rs.getString(3), "0000000005"); + assertEquals(rs.getString(4), "S5"); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testLeftJoinWithPreFilters() throws Exception { + String query = "SELECT /*+ USE_SORT_MERGE_JOIN*/ item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item LEFT JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" = supp.\"supplier_id\" AND (supp.\"supplier_id\" = '0000000001' OR supp.\"supplier_id\" = '0000000005') ORDER BY \"item_id\""; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000002"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000003"); + assertEquals(rs.getString(2), "T3"); + assertNull(rs.getString(3)); + assertNull(rs.getString(4)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000004"); + assertEquals(rs.getString(2), "T4"); + assertNull(rs.getString(3)); + assertNull(rs.getString(4)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000005"); + assertEquals(rs.getString(2), "T5"); + assertEquals(rs.getString(3), "0000000005"); + assertEquals(rs.getString(4), "S5"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000006"); + assertEquals(rs.getString(2), "T6"); + assertNull(rs.getString(3)); + assertNull(rs.getString(4)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "invalid001"); + assertEquals(rs.getString(2), "INVALID-1"); + assertNull(rs.getString(3)); + assertNull(rs.getString(4)); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testJoinWithPostFilters() throws Exception { + String query1 = "SELECT /*+ USE_SORT_MERGE_JOIN*/ item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp RIGHT JOIN " + JOIN_ITEM_TABLE_FULL_NAME + " item ON item.\"supplier_id\" = supp.\"supplier_id\" WHERE supp.\"supplier_id\" BETWEEN '0000000001' AND '0000000005' ORDER BY \"item_id\""; + String query2 = "SELECT /*+ USE_SORT_MERGE_JOIN*/ item.\"item_id\", item.name, supp.\"supplier_id\", supp.name FROM " + JOIN_ITEM_TABLE_FULL_NAME + " item LEFT JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON item.\"supplier_id\" = supp.\"supplier_id\" WHERE supp.\"supplier_id\" = '0000000001' OR supp.\"supplier_id\" = '0000000005' ORDER BY \"item_id\""; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query1); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000002"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000003"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "0000000002"); + assertEquals(rs.getString(4), "S2"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000004"); + assertEquals(rs.getString(2), "T4"); + assertEquals(rs.getString(3), "0000000002"); + assertEquals(rs.getString(4), "S2"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000005"); + assertEquals(rs.getString(2), "T5"); + assertEquals(rs.getString(3), "0000000005"); + assertEquals(rs.getString(4), "S5"); + + assertFalse(rs.next()); + + + statement = conn.prepareStatement(query2); + rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000002"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "0000000001"); + assertEquals(rs.getString(4), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000005"); + assertEquals(rs.getString(2), "T5"); + assertEquals(rs.getString(3), "0000000005"); + assertEquals(rs.getString(4), "S5"); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testStarJoin() throws Exception { + String[] query = new String[5]; + query[0] = "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", c.name, i.name iname, quantity, o.date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o JOIN " + + JOIN_CUSTOMER_TABLE_FULL_NAME + " c ON o.\"customer_id\" = c.\"customer_id\" JOIN " + + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" ORDER BY \"order_id\""; + query[1] = "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", c.name, i.name iname, quantity, o.date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o, " + + JOIN_CUSTOMER_TABLE_FULL_NAME + " c, " + + JOIN_ITEM_TABLE_FULL_NAME + " i WHERE o.\"item_id\" = i.\"item_id\" AND o.\"customer_id\" = c.\"customer_id\" ORDER BY \"order_id\""; + query[2] = "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", c.name, i.name iname, quantity, o.date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o JOIN " + + JOIN_CUSTOMER_TABLE_FULL_NAME + " c ON o.\"customer_id\" = c.\"customer_id\" JOIN " + + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" ORDER BY \"order_id\""; + query[3] = "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", c.name, i.name iname, quantity, o.date FROM (" + JOIN_ORDER_TABLE_FULL_NAME + " o, " + + JOIN_CUSTOMER_TABLE_FULL_NAME + " c), " + + JOIN_ITEM_TABLE_FULL_NAME + " i WHERE o.\"item_id\" = i.\"item_id\" AND o.\"customer_id\" = c.\"customer_id\" ORDER BY \"order_id\""; + query[4] = "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", c.name, i.name iname, quantity, o.date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o, (" + + JOIN_CUSTOMER_TABLE_FULL_NAME + " c, " + + JOIN_ITEM_TABLE_FULL_NAME + " i) WHERE o.\"item_id\" = i.\"item_id\" AND o.\"customer_id\" = c.\"customer_id\" ORDER BY \"order_id\""; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + for (int i = 0; i < query.length; i++) { + PreparedStatement statement = conn.prepareStatement(query[i]); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000001"); + assertEquals(rs.getString("\"order_id\""), "000000000000001"); + assertEquals(rs.getString(2), "C4"); + assertEquals(rs.getString("C.name"), "C4"); + assertEquals(rs.getString(3), "T1"); + assertEquals(rs.getString("iName"), "T1"); + assertEquals(rs.getInt(4), 1000); + assertEquals(rs.getInt("Quantity"), 1000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000002"); + assertEquals(rs.getString(2), "C3"); + assertEquals(rs.getString(3), "T6"); + assertEquals(rs.getInt(4), 2000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000003"); + assertEquals(rs.getString(2), "C2"); + assertEquals(rs.getString(3), "T2"); + assertEquals(rs.getInt(4), 3000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000004"); + assertEquals(rs.getString(2), "C4"); + assertEquals(rs.getString(3), "T6"); + assertEquals(rs.getInt(4), 4000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000005"); + assertEquals(rs.getString(2), "C5"); + assertEquals(rs.getString(3), "T3"); + assertEquals(rs.getInt(4), 5000); + assertNotNull(rs.getDate(5)); + + assertFalse(rs.next()); + } + } finally { + conn.close(); + } + } + + @Test + public void testLeftJoinWithAggregation() throws Exception { + String query1 = "SELECT /*+ USE_SORT_MERGE_JOIN*/ i.name, sum(quantity) FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN " + + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" GROUP BY i.name ORDER BY i.name"; + String query2 = "SELECT /*+ USE_SORT_MERGE_JOIN*/ i.\"item_id\" iid, sum(quantity) q FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN " + + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" GROUP BY i.\"item_id\" ORDER BY q DESC"; + String query3 = "SELECT /*+ USE_SORT_MERGE_JOIN*/ i.\"item_id\" iid, sum(quantity) q FROM " + JOIN_ITEM_TABLE_FULL_NAME + " i LEFT JOIN " + + JOIN_ORDER_TABLE_FULL_NAME + " o ON o.\"item_id\" = i.\"item_id\" GROUP BY i.\"item_id\" ORDER BY q DESC NULLS LAST, iid"; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query1); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "T1"); + assertEquals(rs.getInt(2), 1000); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "T2"); + assertEquals(rs.getInt(2), 3000); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "T3"); + assertEquals(rs.getInt(2), 5000); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "T6"); + assertEquals(rs.getInt(2), 6000); + + assertFalse(rs.next()); + + statement = conn.prepareStatement(query2); + rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000006"); + assertEquals(rs.getInt("q"), 6000); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000003"); + assertEquals(rs.getInt("q"), 5000); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000002"); + assertEquals(rs.getInt("q"), 3000); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000001"); + assertEquals(rs.getInt("q"), 1000); + + assertFalse(rs.next()); + + statement = conn.prepareStatement(query3); + rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000006"); + assertEquals(rs.getInt("q"), 6000); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000003"); + assertEquals(rs.getInt("q"), 5000); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000002"); + assertEquals(rs.getInt("q"), 3000); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000001"); + assertEquals(rs.getInt("q"), 1000); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000004"); + assertEquals(rs.getInt("q"), 0); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000005"); + assertEquals(rs.getInt("q"), 0); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "invalid001"); + assertEquals(rs.getInt("q"), 0); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testRightJoinWithAggregation() throws Exception { + String query1 = "SELECT /*+ USE_SORT_MERGE_JOIN*/ i.name, sum(quantity) FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o RIGHT JOIN " + + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" GROUP BY i.name ORDER BY i.name"; + String query2 = "SELECT /*+ USE_SORT_MERGE_JOIN*/ i.\"item_id\" iid, sum(quantity) q FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o RIGHT JOIN " + + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" GROUP BY i.\"item_id\" ORDER BY q DESC NULLS LAST, iid"; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query1); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "INVALID-1"); + assertEquals(rs.getInt(2), 0); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "T1"); + assertEquals(rs.getInt(2), 1000); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "T2"); + assertEquals(rs.getInt(2), 3000); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "T3"); + assertEquals(rs.getInt(2), 5000); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "T4"); + assertEquals(rs.getInt(2), 0); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "T5"); + assertEquals(rs.getInt(2), 0); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "T6"); + assertEquals(rs.getInt(2), 6000); + + assertFalse(rs.next()); + + statement = conn.prepareStatement(query2); + rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000006"); + assertEquals(rs.getInt("q"), 6000); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000003"); + assertEquals(rs.getInt("q"), 5000); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000002"); + assertEquals(rs.getInt("q"), 3000); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000001"); + assertEquals(rs.getInt("q"), 1000); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000004"); + assertEquals(rs.getInt("q"), 0); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "0000000005"); + assertEquals(rs.getInt("q"), 0); + assertTrue (rs.next()); + assertEquals(rs.getString("iid"), "invalid001"); + assertEquals(rs.getInt("q"), 0); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testLeftRightJoin() throws Exception { + String query1 = "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN " + + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" RIGHT JOIN " + + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\" ORDER BY \"order_id\", s.\"supplier_id\" DESC"; + String query2 = "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN " + + "(" + JOIN_ITEM_TABLE_FULL_NAME + " i RIGHT JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\")" + + " ON o.\"item_id\" = i.\"item_id\" ORDER BY \"order_id\", s.\"supplier_id\" DESC"; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query1); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertNull(rs.getString(2)); + assertEquals(rs.getString(3), "S5"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertNull(rs.getString(2)); + assertEquals(rs.getString(3), "S4"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertNull(rs.getString(2)); + assertEquals(rs.getString(3), "S3"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 1000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000002"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 2000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000003"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 3000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000004"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 4000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000005"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "S2"); + assertEquals(rs.getInt(4), 5000); + assertNotNull(rs.getDate(5)); + + assertFalse(rs.next()); + + statement = conn.prepareStatement(query2); + rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 1000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000002"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 2000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000003"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 3000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000004"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 4000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000005"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "S2"); + assertEquals(rs.getInt(4), 5000); + assertNotNull(rs.getDate(5)); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testRightLeftJoin() throws Exception { + String query1 = "SELECT \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ITEM_TABLE_FULL_NAME + " i RIGHT JOIN " + + JOIN_ORDER_TABLE_FULL_NAME + " o ON o.\"item_id\" = i.\"item_id\" LEFT JOIN " + + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\" ORDER BY \"order_id\""; + String query2 = "SELECT \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o RIGHT JOIN " + + "(" + JOIN_ITEM_TABLE_FULL_NAME + " i LEFT JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\")" + + " ON o.\"item_id\" = i.\"item_id\" ORDER BY \"order_id\", s.\"supplier_id\" DESC"; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query1); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 1000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000002"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 2000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000003"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 3000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000004"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 4000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000005"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "S2"); + assertEquals(rs.getInt(4), 5000); + assertNotNull(rs.getDate(5)); + + assertFalse(rs.next()); + + statement = conn.prepareStatement(query2); + rs = statement.executeQuery(); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertEquals(rs.getString(2), "INVALID-1"); + assertNull(rs.getString(3)); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertEquals(rs.getString(2), "T5"); + assertEquals(rs.getString(3), "S5"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertEquals(rs.getString(2), "T4"); + assertEquals(rs.getString(3), "S2"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 1000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000002"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 2000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000003"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 3000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000004"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 4000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000005"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "S2"); + assertEquals(rs.getInt(4), 5000); + assertNotNull(rs.getDate(5)); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testMultiLeftJoin() throws Exception { + String[] queries = { + "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN " + + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" LEFT JOIN " + + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\" ORDER BY \"order_id\"", + "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o LEFT JOIN " + + "(" + JOIN_ITEM_TABLE_FULL_NAME + " i LEFT JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\") " + + "ON o.\"item_id\" = i.\"item_id\" ORDER BY \"order_id\""}; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + for (String query : queries) { + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 1000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000002"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 2000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000003"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 3000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000004"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 4000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000005"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "S2"); + assertEquals(rs.getInt(4), 5000); + assertNotNull(rs.getDate(5)); + + assertFalse(rs.next()); + } + } finally { + conn.close(); + } + } + + @Test + public void testMultiRightJoin() throws Exception { + String query = "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o RIGHT JOIN " + + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" RIGHT JOIN " + + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\" ORDER BY \"order_id\", s.\"supplier_id\" DESC"; + + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertEquals(rs.getString(2), "T5"); + assertEquals(rs.getString(3), "S5"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertNull(rs.getString(2)); + assertEquals(rs.getString(3), "S4"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertNull(rs.getString(2)); + assertEquals(rs.getString(3), "S3"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertEquals(rs.getString(2), "T4"); + assertEquals(rs.getString(3), "S2"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 1000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000002"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 2000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000003"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 3000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000004"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 4000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000005"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "S2"); + assertEquals(rs.getInt(4), 5000); + assertNotNull(rs.getDate(5)); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + // Basically a copy of testMultiRightJoin, but with a very small result scan chunk size + // to test that repeated row keys within a single chunk are handled properly + @Test + public void testMultiRightJoin_SmallChunkSize() throws Exception { + String query = "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", i.name, s.name, quantity, date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o RIGHT JOIN " + + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" RIGHT JOIN " + + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\" ORDER BY \"order_id\", s.\"supplier_id\" DESC"; + + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + props.setProperty(QueryServices.SCAN_RESULT_CHUNK_SIZE, "1"); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertEquals(rs.getString(2), "T5"); + assertEquals(rs.getString(3), "S5"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertNull(rs.getString(2)); + assertEquals(rs.getString(3), "S4"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertNull(rs.getString(2)); + assertEquals(rs.getString(3), "S3"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertNull(rs.getString(1)); + assertEquals(rs.getString(2), "T4"); + assertEquals(rs.getString(3), "S2"); + assertEquals(rs.getInt(4), 0); + assertNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000001"); + assertEquals(rs.getString(2), "T1"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 1000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000002"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 2000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000003"); + assertEquals(rs.getString(2), "T2"); + assertEquals(rs.getString(3), "S1"); + assertEquals(rs.getInt(4), 3000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000004"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getString(3), "S6"); + assertEquals(rs.getInt(4), 4000); + assertNotNull(rs.getDate(5)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000005"); + assertEquals(rs.getString(2), "T3"); + assertEquals(rs.getString(3), "S2"); + assertEquals(rs.getInt(4), 5000); + assertNotNull(rs.getDate(5)); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testJoinWithWildcard() throws Exception { + String query = "SELECT /*+ USE_SORT_MERGE_JOIN*/ * FROM " + JOIN_ITEM_TABLE_FULL_NAME + " LEFT JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " supp ON " + JOIN_ITEM_TABLE_FULL_NAME + ".\"supplier_id\" = supp.\"supplier_id\" ORDER BY \"item_id\""; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".item_id"), "0000000001"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".NAME"), "T1"); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".PRICE"), 100); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT1"), 5); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT2"), 10); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".supplier_id"), "0000000001"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DESCRIPTION"), "Item T1"); + assertEquals(rs.getString("SUPP.supplier_id"), "0000000001"); + assertEquals(rs.getString("supp.name"), "S1"); + assertEquals(rs.getString("supp.phone"), "888-888-1111"); + assertEquals(rs.getString("supp.address"), "101 YYY Street"); + assertEquals(rs.getString("supp.loc_id"), "10001"); + assertTrue (rs.next()); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".item_id"), "0000000002"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".NAME"), "T2"); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".PRICE"), 200); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT1"), 5); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT2"), 8); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".supplier_id"), "0000000001"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DESCRIPTION"), "Item T2"); + assertEquals(rs.getString("SUPP.supplier_id"), "0000000001"); + assertEquals(rs.getString("supp.name"), "S1"); + assertEquals(rs.getString("supp.phone"), "888-888-1111"); + assertEquals(rs.getString("supp.address"), "101 YYY Street"); + assertEquals(rs.getString("supp.loc_id"), "10001"); + assertTrue (rs.next()); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".item_id"), "0000000003"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".NAME"), "T3"); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".PRICE"), 300); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT1"), 8); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT2"), 12); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".supplier_id"), "0000000002"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DESCRIPTION"), "Item T3"); + assertEquals(rs.getString("SUPP.supplier_id"), "0000000002"); + assertEquals(rs.getString("supp.name"), "S2"); + assertEquals(rs.getString("supp.phone"), "888-888-2222"); + assertEquals(rs.getString("supp.address"), "202 YYY Street"); + assertEquals(rs.getString("supp.loc_id"), "10002"); + assertTrue (rs.next()); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".item_id"), "0000000004"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".NAME"), "T4"); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".PRICE"), 400); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT1"), 6); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT2"), 10); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".supplier_id"), "0000000002"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DESCRIPTION"), "Item T4"); + assertEquals(rs.getString("SUPP.supplier_id"), "0000000002"); + assertEquals(rs.getString("supp.name"), "S2"); + assertEquals(rs.getString("supp.phone"), "888-888-2222"); + assertEquals(rs.getString("supp.address"), "202 YYY Street"); + assertEquals(rs.getString("supp.loc_id"), "10002"); + assertTrue (rs.next()); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".item_id"), "0000000005"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".NAME"), "T5"); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".PRICE"), 500); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT1"), 8); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT2"), 15); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".supplier_id"), "0000000005"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DESCRIPTION"), "Item T5"); + assertEquals(rs.getString("SUPP.supplier_id"), "0000000005"); + assertEquals(rs.getString("supp.name"), "S5"); + assertEquals(rs.getString("supp.phone"), "888-888-5555"); + assertEquals(rs.getString("supp.address"), "505 YYY Street"); + assertEquals(rs.getString("supp.loc_id"), "10005"); + assertTrue (rs.next()); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".item_id"), "0000000006"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".NAME"), "T6"); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".PRICE"), 600); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT1"), 8); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT2"), 15); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".supplier_id"), "0000000006"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DESCRIPTION"), "Item T6"); + assertEquals(rs.getString("SUPP.supplier_id"), "0000000006"); + assertEquals(rs.getString("supp.name"), "S6"); + assertEquals(rs.getString("supp.phone"), "888-888-6666"); + assertEquals(rs.getString("supp.address"), "606 YYY Street"); + assertEquals(rs.getString("supp.loc_id"), "10006"); + assertTrue (rs.next()); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".item_id"), "invalid001"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".NAME"), "INVALID-1"); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".PRICE"), 0); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT1"), 0); + assertEquals(rs.getInt(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DISCOUNT2"), 0); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".supplier_id"), "0000000000"); + assertEquals(rs.getString(JOIN_ITEM_TABLE_DISPLAY_NAME + ".DESCRIPTION"), "Invalid item for join test"); + assertNull(rs.getString("SUPP.supplier_id")); + assertNull(rs.getString("supp.name")); + assertNull(rs.getString("supp.phone")); + assertNull(rs.getString("supp.address")); + assertNull(rs.getString("supp.loc_id")); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testJoinWithTableWildcard() throws Exception { + String query = "SELECT /*+ USE_SORT_MERGE_JOIN*/ s.*, "+ JOIN_ITEM_TABLE_FULL_NAME + ".*, \"order_id\" FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o RIGHT JOIN " + + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" RIGHT JOIN " + + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON i.\"supplier_id\" = s.\"supplier_id\" ORDER BY \"order_id\", s.\"supplier_id\" DESC"; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + ResultSetMetaData md = rs.getMetaData(); + assertEquals(md.getColumnCount(), 13); + + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000005"); + assertEquals(rs.getString(2), "S5"); + assertEquals(rs.getString(3), "888-888-5555"); + assertEquals(rs.getString(4), "505 YYY Street"); + assertEquals(rs.getString(5), "10005"); + assertEquals(rs.getString(6), "0000000005"); + assertEquals(rs.getString(7), "T5"); + assertEquals(rs.getInt(8), 500); + assertEquals(rs.getInt(9), 8); + assertEquals(rs.getInt(10), 15); + assertEquals(rs.getString(11), "0000000005"); + assertEquals(rs.getString(12), "Item T5"); + assertNull(rs.getString(13)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000004"); + assertEquals(rs.getString(2), "S4"); + assertEquals(rs.getString(3), "888-888-4444"); + assertEquals(rs.getString(4), "404 YYY Street"); + assertNull(rs.getString(5)); + assertNull(rs.getString(6)); + assertNull(rs.getString(7)); + assertEquals(rs.getInt(8), 0); + assertEquals(rs.getInt(9), 0); + assertEquals(rs.getInt(10), 0); + assertNull(rs.getString(11)); + assertNull(rs.getString(12)); + assertNull(rs.getString(13)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000003"); + assertEquals(rs.getString(2), "S3"); + assertEquals(rs.getString(3), "888-888-3333"); + assertEquals(rs.getString(4), "303 YYY Street"); + assertNull(rs.getString(5)); + assertNull(rs.getString(6)); + assertNull(rs.getString(7)); + assertEquals(rs.getInt(8), 0); + assertEquals(rs.getInt(9), 0); + assertEquals(rs.getInt(10), 0); + assertNull(rs.getString(11)); + assertNull(rs.getString(12)); + assertNull(rs.getString(13)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000002"); + assertEquals(rs.getString(2), "S2"); + assertEquals(rs.getString(3), "888-888-2222"); + assertEquals(rs.getString(4), "202 YYY Street"); + assertEquals(rs.getString(5), "10002"); + assertEquals(rs.getString(6), "0000000004"); + assertEquals(rs.getString(7), "T4"); + assertEquals(rs.getInt(8), 400); + assertEquals(rs.getInt(9), 6); + assertEquals(rs.getInt(10), 10); + assertEquals(rs.getString(11), "0000000002"); + assertEquals(rs.getString(12), "Item T4"); + assertNull(rs.getString(13)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000001"); + assertEquals(rs.getString(2), "S1"); + assertEquals(rs.getString(3), "888-888-1111"); + assertEquals(rs.getString(4), "101 YYY Street"); + assertEquals(rs.getString(5), "10001"); + assertEquals(rs.getString(6), "0000000001"); + assertEquals(rs.getString(7), "T1"); + assertEquals(rs.getInt(8), 100); + assertEquals(rs.getInt(9), 5); + assertEquals(rs.getInt(10), 10); + assertEquals(rs.getString(11), "0000000001"); + assertEquals(rs.getString(12), "Item T1"); + assertEquals(rs.getString(13), "000000000000001"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000006"); + assertEquals(rs.getString(2), "S6"); + assertEquals(rs.getString(3), "888-888-6666"); + assertEquals(rs.getString(4), "606 YYY Street"); + assertEquals(rs.getString(5), "10006"); + assertEquals(rs.getString(6), "0000000006"); + assertEquals(rs.getString(7), "T6"); + assertEquals(rs.getInt(8), 600); + assertEquals(rs.getInt(9), 8); + assertEquals(rs.getInt(10), 15); + assertEquals(rs.getString(11), "0000000006"); + assertEquals(rs.getString(12), "Item T6"); + assertEquals(rs.getString(13), "000000000000002"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000001"); + assertEquals(rs.getString(2), "S1"); + assertEquals(rs.getString(3), "888-888-1111"); + assertEquals(rs.getString(4), "101 YYY Street"); + assertEquals(rs.getString(5), "10001"); + assertEquals(rs.getString(6), "0000000002"); + assertEquals(rs.getString(7), "T2"); + assertEquals(rs.getInt(8), 200); + assertEquals(rs.getInt(9), 5); + assertEquals(rs.getInt(10), 8); + assertEquals(rs.getString(11), "0000000001"); + assertEquals(rs.getString(12), "Item T2"); + assertEquals(rs.getString(13), "000000000000003"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000006"); + assertEquals(rs.getString(2), "S6"); + assertEquals(rs.getString(3), "888-888-6666"); + assertEquals(rs.getString(4), "606 YYY Street"); + assertEquals(rs.getString(5), "10006"); + assertEquals(rs.getString(6), "0000000006"); + assertEquals(rs.getString(7), "T6"); + assertEquals(rs.getInt(8), 600); + assertEquals(rs.getInt(9), 8); + assertEquals(rs.getInt(10), 15); + assertEquals(rs.getString(11), "0000000006"); + assertEquals(rs.getString(12), "Item T6"); + assertEquals(rs.getString(13), "000000000000004"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "0000000002"); + assertEquals(rs.getString(2), "S2"); + assertEquals(rs.getString(3), "888-888-2222"); + assertEquals(rs.getString(4), "202 YYY Street"); + assertEquals(rs.getString(5), "10002"); + assertEquals(rs.getString(6), "0000000003"); + assertEquals(rs.getString(7), "T3"); + assertEquals(rs.getInt(8), 300); + assertEquals(rs.getInt(9), 8); + assertEquals(rs.getInt(10), 12); + assertEquals(rs.getString(11), "0000000002"); + assertEquals(rs.getString(12), "Item T3"); + assertEquals(rs.getString(13), "000000000000005"); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testJoinMultiJoinKeys() throws Exception { + String query = "SELECT /*+ USE_SORT_MERGE_JOIN*/ c.name, s.name FROM " + JOIN_CUSTOMER_TABLE_FULL_NAME + " c LEFT JOIN " + JOIN_SUPPLIER_TABLE_FULL_NAME + " s ON \"customer_id\" = \"supplier_id\" AND c.loc_id = s.loc_id AND substr(s.name, 2, 1) = substr(c.name, 2, 1) ORDER BY \"customer_id\""; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "C1"); + assertEquals(rs.getString(2), "S1"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "C2"); + assertNull(rs.getString(2)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "C3"); + assertEquals(rs.getString(2), "S3"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "C4"); + assertNull(rs.getString(2)); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "C5"); + assertEquals(rs.getString(2), "S5"); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "C6"); + assertNull(rs.getString(2)); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testJoinWithDifferentNumericJoinKeyTypes() throws Exception { + String query = "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", i.name, i.price, discount2, quantity FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o INNER JOIN " + + JOIN_ITEM_TABLE_FULL_NAME + " i ON o.\"item_id\" = i.\"item_id\" AND o.price = (i.price * (100 - discount2)) / 100.0 WHERE quantity < 5000"; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000004"); + assertEquals(rs.getString(2), "T6"); + assertEquals(rs.getInt(3), 600); + assertEquals(rs.getInt(4), 15); + assertEquals(rs.getInt(5), 4000); + + assertFalse(rs.next()); + } finally { + conn.close(); + } + } + + @Test + public void testJoinWithDifferentDateJoinKeyTypes() throws Exception { + String query = "SELECT /*+ USE_SORT_MERGE_JOIN*/ \"order_id\", c.name, o.date FROM " + JOIN_ORDER_TABLE_FULL_NAME + " o INNER JOIN " + + JOIN_CUSTOMER_TABLE_FULL_NAME + " c ON o.\"customer_id\" = c.\"customer_id\" AND o.date = c.date ORDER BY \"order_id\""; + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + Connection conn = DriverManager.getConnection(getUrl(), props); + try { + PreparedStatement statement = conn.prepareStatement(query); + ResultSet rs = statement.executeQuery(); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000001"); + assertEquals(rs.getString(2), "C4"); + assertEquals(rs.getTimestamp(3), new Timestamp(format.parse("2013-11-22 14:22:56").getTime())); + assertTrue (rs.next()); + assertEquals(rs.getString(1), "000000000000002"); + assertEquals(rs.getString(2), "C3"); + assertEquals(rs.getTimestamp(3), new Ti
<TRUNCATED>