/* This file is part of VoltDB. * Copyright (C) 2008-2017 VoltDB Inc. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ package org.voltdb.regressionsuites; import java.io.IOException; import java.math.BigDecimal; import org.apache.commons.lang3.StringUtils; import org.voltdb.BackendTarget; import org.voltdb.VoltTable; import org.voltdb.VoltType; import org.voltdb.client.Client; import org.voltdb.client.ClientResponse; import org.voltdb.client.NoConnectionsException; import org.voltdb.client.ProcCallException; import org.voltdb.client.ProcedureCallback; import org.voltdb.compiler.VoltProjectBuilder; import org.voltdb.types.TimestampType; import org.voltdb_testprocs.regressionsuites.fixedsql.Insert; import org.voltdb_testprocs.regressionsuites.fixedsql.TestENG1232; import org.voltdb_testprocs.regressionsuites.fixedsql.TestENG1232_2; import org.voltdb_testprocs.regressionsuites.fixedsql.TestENG2423; /** * Actual regression tests for SQL that I found that was broken and * have fixed. Didn't like any of the other potential homes that already * existed for this for one reason or another. */ public class TestFixedSQLSuite extends RegressionSuite { /** Procedures used by this suite */ static final Class<?>[] PROCEDURES = { Insert.class, TestENG1232.class, TestENG1232_2.class, TestENG2423.InnerProc.class }; static final int VARCHAR_VARBINARY_THRESHOLD = 100; public void testSmallFixedTests() throws IOException, ProcCallException { subTestInsertNullPartitionString(); subTestAndExpressionComparingSameTableColumns(); subTestSeqScanFailedPredicateDoesntCountAgainstLimit(); subTestSelectExpression(); subTestNestLoopJoinPredicates(); subTestnestLoopJoinPredicatesWithExpressions(); subTestNestLoopJoinPredicatesWithAliases(); subTestGreaterThanOnOrderedIndex(); subTestForHSQLDecimalFailures(); subTestNumericExpressionConversion(); subTestInsertWithCast(); } private void subTestTicketEng2250_IsNull() throws IOException, ProcCallException, InterruptedException { System.out.println("STARTING testTicketEng2250_IsNull"); Client client = getClient(); ProcedureCallback callback = new ProcedureCallback() { @Override public void clientCallback(ClientResponse clientResponse) throws Exception { if (clientResponse.getStatus() != ClientResponse.SUCCESS) { throw new RuntimeException("Failed with response: " + clientResponse.getStatusString()); } } }; /* CREATE TABLE P1 ( ID INTEGER DEFAULT '0' NOT NULL, DESC VARCHAR(300), NUM INTEGER, RATIO FLOAT, PRIMARY KEY (ID) ); */ System.out.println("Eng2250: null entries."); for(int id=0; id < 5; id++) { client.callProcedure(callback, "P1.insert", id, null, 10, 1.1); client.drain(); } System.out.println("Eng2250: not null entries."); for (int id=5; id < 8; id++) { client.callProcedure(callback, "P1.insert", id,"description", 10, 1.1); client.drain(); } VoltTable r1 = client.callProcedure("@AdHoc", "select count(*) from P1 where desc is null").getResults()[0]; //* enable for debugging */ System.out.println(r1); assertEquals(5, r1.asScalarLong()); VoltTable r2 = client.callProcedure("@AdHoc", "select count(*) from P1 where not desc is null").getResults()[0]; //* enable for debugging */ System.out.println(r2); assertEquals(3, r2.asScalarLong()); VoltTable r3 = client.callProcedure("@AdHoc", "select count(*) from P1 where NOT (id=2 and desc is null)").getResults()[0]; //* enable for debugging */ System.out.println(r3); assertEquals(7, r3.asScalarLong()); VoltTable r4 = client.callProcedure("@AdHoc", "select count(*) from P1 where NOT (id=6 and desc is null)").getResults()[0]; //* enable for debugging */ System.out.println(r4); assertEquals(8, r4.asScalarLong()); VoltTable r5 = client.callProcedure("@AdHoc", "select count(*) from P1 where id < 6 and NOT desc is null;").getResults()[0]; //* enable for debugging */ System.out.println(r5); assertEquals(1, r5.asScalarLong()); truncateTable(client, "P1"); } private void subTestTicketEng1850_WhereOrderBy() throws Exception { System.out.println("STARTING testTicketENG1850_WhereOrderBy"); ProcedureCallback callback = new ProcedureCallback() { @Override public void clientCallback(ClientResponse clientResponse) throws Exception { if (clientResponse.getStatus() != ClientResponse.SUCCESS) { throw new RuntimeException("Failed with response: " + clientResponse.getStatusString()); } } }; Client client = getClient(); int cid=0; do { for (int aid = 0; aid < 5; aid++) { int pid = cid % 10; client.callProcedure(callback, "ENG1850.insert", cid++, aid, pid, (pid+aid)); } } while (cid < 1000); client.drain(); VoltTable r1 = client.callProcedure("@AdHoc", "select count(*) from ENG1850;").getResults()[0]; assertEquals(1000, r1.asScalarLong()); VoltTable r2 = client.callProcedure("@AdHoc", "select count(*) from ENG1850 where pid =2;").getResults()[0]; assertEquals(100, r2.asScalarLong()); VoltTable r3 = client.callProcedure("@AdHoc", "select * from ENG1850 where pid = 2 limit 1;").getResults()[0]; //* enable for debugging */ System.out.println("r3\n" + r3); assertEquals(1, r3.getRowCount()); // this failed, returning 0 rows. VoltTable r4 = client.callProcedure("@AdHoc", "select * from ENG1850 where pid = 2 order by pid, aid").getResults()[0]; //* enable for debugging */ System.out.println("r4\n:" + r4); assertEquals(100, r4.getRowCount()); // this is the failing condition reported in the defect report (as above but with the limit) VoltTable r5 = client.callProcedure("@AdHoc", "select * from ENG1850 where pid = 2 order by pid, aid limit 1").getResults()[0]; //* enable for debugging */ System.out.println("r5\n" + r5); assertEquals(1, r5.getRowCount()); truncateTable(client, "ENG1850"); } private void subTestTicketEng1850_WhereOrderBy2() throws Exception { System.out.println("STARTING testTIcketEng1850_WhereOrderBy2"); // verify that selecting * where pid = 2 order by pid, aid gets the right number // of tuples when <pid, null> exists in the relation (as this would be the first // key found by moveToKeyOrGreater - verify this key is added to the output if // it really exists Client client = getClient(); // index is (pid, aid) // schema: insert (cid, aid, pid, attr) client.callProcedure("ENG1850.insert", 0, 1, 1, 0); if (!isHSQL()) { // unsure why HSQL throws out-of-range exception here. // there are sql coverage tests for this case. skip it here. client.callProcedure("ENG1850.insert", 1, null, 2, 0); } client.callProcedure("ENG1850.insert", 2, 1, 2, 0); client.callProcedure("ENG1850.insert", 3, 2, 2, 0); client.callProcedure("ENG1850.insert", 4, 3, 3, 0); VoltTable r1 = client.callProcedure("@AdHoc", "select * from ENG1850 where pid = 2 order by pid, aid").getResults()[0]; //* enable for debugging */ System.out.println(r1); assertEquals(isHSQL() ? 2: 3, r1.getRowCount()); VoltTable r2 = client.callProcedure("@AdHoc", "select * from ENG1850 where pid = 2 order by aid, pid").getResults()[0]; //* enable for debugging */ System.out.println(r2); assertEquals(isHSQL() ? 2 : 3, r2.getRowCount()); VoltTable r3 = client.callProcedure("@AdHoc", "select * from ENG1850 where pid > 1 order by pid, aid").getResults()[0]; //* enable for debugging */ System.out.println(r3); assertEquals(isHSQL() ? 3 : 4, r3.getRowCount()); VoltTable r4 = client.callProcedure("@AdHoc", "select * from ENG1850 where pid = 2").getResults()[0]; //* enable for debugging */ System.out.println(r4); assertEquals(isHSQL() ? 2 : 3, r4.getRowCount()); truncateTable(client, "ENG1850"); } private void subTestTicketENG1232() throws Exception { Client client = getClient(); client.callProcedure("@AdHoc", "insert into test_eng1232 VALUES(9);"); VoltTable result[] = client.callProcedure("TestENG1232", 9).getResults(); assertTrue(result[0].advanceRow()); assertEquals(9, result[0].getLong(0)); assertTrue(result[1].advanceRow()); assertEquals(1, result[1].getLong(0)); client.callProcedure("@AdHoc", "insert into test_eng1232 VALUES(9);"); result = client.callProcedure("TestENG1232_2", 9).getResults(); assertTrue(result[0].advanceRow()); assertEquals(1, result[0].getLong(0)); assertFalse(result[1].advanceRow()); truncateTable(client, "test_eng1232"); } private void subTestInsertNullPartitionString() throws IOException, ProcCallException { // This test is for issue ENG-697 Client client = getClient(); boolean caught = false; try { client.callProcedure("InsertNullString", null, 0, 1); } catch (final ProcCallException e) { if (e.getMessage().contains("CONSTRAINT VIOLATION")) caught = true; else { e.printStackTrace(); fail(); } } assertTrue(caught); } private void subTestTicket309() throws IOException, ProcCallException { String[] tables = {"P1", "R1", "P2", "R2"}; Client client = getClient(); for (String table : tables) { client.callProcedure("Insert", table, 1, "desc", 100, 14.5); client.callProcedure("Insert", table, 2, "desc", 100, 14.5); client.callProcedure("Insert", table, 3, "desc", 100, 14.5); client.callProcedure("Insert", table, 6, "desc", 300, 14.5); client.callProcedure("Insert", table, 7, "desc", 300, 14.5); client.callProcedure("Insert", table, 8, "desc", 500, 14.5); String query = String.format("select count(*), %s.NUM from %s group by %s.NUM", table, table, table); VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(3, results[0].getRowCount()); while (results[0].advanceRow()) { if (results[0].getLong(1) == 100) { assertEquals(3, results[0].getLong(0)); } else if (results[0].getLong(1) == 300) { assertEquals(2, results[0].getLong(0)); } else if (results[0].getLong(1) == 500) { assertEquals(1, results[0].getLong(0)); } else { fail(); } } } truncateTables(client, tables); } // // Regression test for broken SQL of the variety: // // select * from TABLE where (TABLE.ID = value) and // (TABLE.col1 compared_to TABLE.col2) // // which would return results any time TABLE.ID = value was true, // regardless of whether the second expression was true. // private void subTestAndExpressionComparingSameTableColumns() throws IOException, ProcCallException { Client client = getClient(); String[] tables = {"P1", "R1"}; for (String table : tables) { client.callProcedure("Insert", table, 5, "desc", 10, 14.5); client.callProcedure("Insert", table, 15, "desc2", 10, 14.5); // These queries should result in no rows, but the defect in // SubPlanAssembler resulted in only the NO_NULLS.PKEY = 5 expression // being used String query = "select * from " + table + " where (" + table + ".ID = 5) and (" + table + ".NUM < " + table +".ID)"; VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(0, results[0].getRowCount()); query = "select * from " + table + " where (" + table + ".ID = 5) and (" + table + ".NUM <= " + table +".ID)"; results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(0, results[0].getRowCount()); query = "select * from " + table + " where (" + table + ".ID = 15) and (" + table + ".NUM > " + table +".ID)"; results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(0, results[0].getRowCount()); query = "select * from " + table + " where (" + table + ".ID = 15) and (" + table + ".NUM >= " + table +".ID)"; results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(0, results[0].getRowCount()); } truncateTables(client, tables); } // // Regression test for broken SQL of the variety: // // select * from replicated_table where (predicate) LIMIT n // // For replicated tables, LIMIT is inlined in seqscan; the tuple count was // being incremented for each input tuple regardless of the predicate // result, which was resulting in the wrong number of rows returned in some // cases. // @throws IOException // @throws ProcCallException // private void subTestSeqScanFailedPredicateDoesntCountAgainstLimit() throws IOException, ProcCallException { Client client = getClient(); String[] tables = {"P1", "R1"}; for (String table : tables) { // our predicate is going to be ID < NUM. // Insert one row where this is false client.callProcedure("Insert", table, 1, "desc", -1, 14.5); // And two where it is true client.callProcedure("Insert", table, 2, "desc", 100, 14.5); client.callProcedure("Insert", table, 3, "desc", 100, 14.5); String query = "select * from " + table + " where " + table + ".ID < " + table +".NUM limit 2"; VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); // we should get 2 rows but this bug would result in only 1 returned assertEquals(2, results[0].getRowCount()); } truncateTables(client, tables); } // // Regression test for broken SQL of the variety: // // select (non-aggregating expression) from table // e.g. select col1 + col2 from table // // PlanAssembler extracts the left side of the expression to discard // aggregation-type expressions from the parsed SQL, but was basically // assuming that anything not a VALUE_TUPLE was an aggregate. // // Note: Adding 5.5 in the third test here also tests a "fix" in // HSQL where we coerce the type of numeric literals from NUMERIC to DOUBLE // private void subTestSelectExpression() throws IOException, ProcCallException { Client client = getClient(); String[] tables = {"P1", "R1"}; for (String table : tables) { client.callProcedure("Insert", table, 1, "desc", 2, 14.5); String query = String.format("select %s.ID + 10 from %s", table, table); VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); results[0].advanceRow(); assertEquals(11, results[0].getLong(0)); query = String.format("select %s.NUM + 20 from %s", table, table); results = client.callProcedure("@AdHoc", query).getResults(); results[0].advanceRow(); assertEquals(22, results[0].getLong(0)); query = String.format("select %s.RATIO + 5.5 from %s", table, table); results = client.callProcedure("@AdHoc", query).getResults(); results[0].advanceRow(); assertEquals(20.0, results[0].getDouble(0)); query = String.format("select %s.ID + %s.NUM from %s", table, table, table); results = client.callProcedure("@AdHoc", query).getResults(); results[0].advanceRow(); assertEquals(3, results[0].getLong(0)); // ENG-5035 query = String.format("select '%s' from %s", table, table); results = client.callProcedure("@AdHoc", query).getResults(); results[0].advanceRow(); assertEquals(table, results[0].getString(0)); query = String.format("select '%s' from %s", "qwertyuiop", table); results = client.callProcedure("@AdHoc", query).getResults(); results[0].advanceRow(); assertEquals("qwertyuiop", results[0].getString(0)); query = String.format("select %s.RATIO, '%s' from %s", table, "qwertyuiop", table); results = client.callProcedure("@AdHoc", query).getResults(); results[0].advanceRow(); assertEquals("qwertyuiop", results[0].getString(1)); } truncateTables(client, tables); } // // Regression test for broken SQL of the variety: // // trac #166 // // When evaluating the nest loop join predicate, insufficient // information was available to tuplevalue expression nodes to // understand which column(s) needed to be evaluated by the TVE's // operators. // private void subTestNestLoopJoinPredicates() throws IOException, ProcCallException { Client client = getClient(); for (int id=0; id < 5; id++) { // insert id, (5-id) in to P1 client.callProcedure("Insert", "P1", id, "desc", (5-id), 2.5); // insert id, (id) in to R1 client.callProcedure("Insert", "R1", id, "desc", (id), 2.5); } // join on the (5-id), (id) columns String query = "select * from P1, R1 where P1.NUM = R1.NUM"; VoltTable vts[] = client.callProcedure("@AdHoc", query).getResults(); nestLoopJoinPredicates_verify(vts); // same thing using inner join syntax query = "select * from P1 INNER JOIN R1 on P1.NUM = R1.NUM"; vts = client.callProcedure("@AdHoc", query).getResults(); nestLoopJoinPredicates_verify(vts); // join on ID and verify NUM. (ID is indexed) query = "select * from P1, R1 where P1.ID = R1.ID"; vts = client.callProcedure("@AdHoc", query).getResults(); nestLoopJoinPredicates_verifyid(vts); // as above with inner join syntax query = "select * from P1 INNER JOIN R1 on P1.ID = R1.ID"; vts = client.callProcedure("@AdHoc", query).getResults(); nestLoopJoinPredicates_verifyid(vts); truncateTables(client, new String[]{"P1", "R1"}); } private void nestLoopJoinPredicates_verifyid(VoltTable[] vts) { assertEquals(1, vts.length); //* enable for debugging */ System.out.println("verifyid: " + vts[0]); assertEquals(5, vts[0].getRowCount()); while(vts[0].advanceRow()) { int p_id = ((Integer)vts[0].get(0, VoltType.INTEGER)).intValue(); int r_id = ((Integer)vts[0].get(4, VoltType.INTEGER)).intValue(); int p_n = ((Integer)vts[0].get(2, VoltType.INTEGER)).intValue(); int r_n = ((Integer)vts[0].get(6, VoltType.INTEGER)).intValue(); assertEquals(p_id, r_id); assertEquals(5 - p_n, r_n); } } private void nestLoopJoinPredicates_verify(VoltTable[] vts) { assertEquals(1, vts.length); //* enable for debugging */ System.out.println(vts[0]); assertEquals(4, vts[0].getRowCount()); // the id of the first should be (5-id) in the second // because of the insertion trickery done above // verifies trac #125 while(vts[0].advanceRow()) { int id1 = ((Integer)vts[0].get(0, VoltType.INTEGER)).intValue(); int id2 = ((Integer)vts[0].get(4, VoltType.INTEGER)).intValue(); assertEquals(id1, (5 - id2)); } } // // Regression test for broken SQL of the variety: // // trac #125. (verification in addition to testNestLoopJoinPredicates). // // Select a complex expression (not just a TupleValueExpression) // to verify that non-root TVEs are correctly offset. // private void subTestnestLoopJoinPredicatesWithExpressions() throws IOException, ProcCallException { Client client = getClient(); for (int id=0; id < 5; id++) { // insert id, (5-id) in to P1 client.callProcedure("Insert", "P1", id, "desc", (5-id), 2.5); // insert id, (id) in to R1 client.callProcedure("Insert", "R1", id, "desc", (id), 2.5); } // join on the (5-id), (id) columns and select a value modified by an expression String query = "select (P1.ID + 20), (R1.ID + 40) from P1, R1 where P1.NUM = R1.NUM"; VoltTable vts[] = client.callProcedure("@AdHoc", query).getResults(); nestLoopJoinPredicatesWithExpressions_verify(vts); // same thing using inner join syntax query = "select (P1.ID + 20), (R1.ID + 40) from P1 INNER JOIN R1 on P1.NUM = R1.NUM"; vts = client.callProcedure("@AdHoc", query).getResults(); nestLoopJoinPredicatesWithExpressions_verify(vts); truncateTables(client, new String[]{"P1", "R1"}); } private void nestLoopJoinPredicatesWithExpressions_verify( VoltTable[] vts) { assertEquals(1, vts.length); //* enable for debugging */ System.out.println(vts[0]); assertEquals(4, vts[0].getRowCount()); // the id of the first should be (5-id) in the second once the addition // done in the select expression is un-done. while(vts[0].advanceRow()) { int p1_id = ((Integer)vts[0].get(0, VoltType.INTEGER)).intValue(); int r1_id = ((Integer)vts[0].get(1, VoltType.INTEGER)).intValue(); assertEquals( (p1_id - 20), (5 - (r1_id - 40)) ); // and verify that the addition actually happened. assertTrue(p1_id >= 20); assertTrue(p1_id <= 24); assertTrue(r1_id >= 40); assertTrue(r1_id <= 44); } } // // Regression test for broken SQL of the variety: // // trac #125. (additional verification). // // Select columns and expressions with aliases. // private void subTestNestLoopJoinPredicatesWithAliases() throws IOException, ProcCallException { Client client = getClient(); for (int id=0; id < 5; id++) { // insert id, (5-id) in to P1 client.callProcedure("Insert", "P1", id, "desc", (5-id), 2.5); // insert id, (id) in to R1 client.callProcedure("Insert", "R1", id, "desc", (id), 2.5); } // join on the (5-id), (id) columns and select a value modified by an expression // use an alias that would select an invalid column. (be a jerk). String query = "select R1.ID AS DESC, (P1.ID + 20) AS THOMAS from P1, R1 where P1.NUM = R1.NUM"; VoltTable vts[] = client.callProcedure("@AdHoc", query).getResults(); nestLoopJoinPredicatesWithAliases_verify(vts); // same thing using inner join syntax query = "select R1.ID AS DESC, (P1.ID + 20) AS THOMAS from P1 INNER JOIN R1 on P1.NUM = R1.NUM"; vts = client.callProcedure("@AdHoc", query).getResults(); nestLoopJoinPredicatesWithAliases_verify(vts); truncateTables(client, new String[]{"P1", "R1"}); } private void nestLoopJoinPredicatesWithAliases_verify(VoltTable[] vts) { assertEquals(1, vts.length); //* enable for debugging */ System.out.println(vts[0]); assertEquals(4, vts[0].getRowCount()); // the id of the first should be (5-id) in the second once the addition // done in the select expression is un-done. while(vts[0].advanceRow()) { int p1_id = ((Integer)vts[0].get(1, VoltType.INTEGER)).intValue(); int r1_id = ((Integer)vts[0].get(0, VoltType.INTEGER)).intValue(); assertEquals( (p1_id - 20), (5 - r1_id) ); // and verify that the addition actually happened. assertTrue(p1_id >= 20); assertTrue(p1_id <= 24); assertTrue(r1_id >= 0); assertTrue(r1_id <= 4); } } // // Regression test for broken SQL of the sort // // select * from TABLE where COL_WITH_ORDERED_INDEX > n // // The bug is that indexscanexecutor and indexes treat > as >= // @throws IOException // @throws ProcCallException // private void subTestGreaterThanOnOrderedIndex() throws IOException, ProcCallException { String[] tables = {"P2", "R2"}; Client client = getClient(); for (String table : tables) { client.callProcedure("Insert", table, 1, "desc", 100, 14.5); client.callProcedure("Insert", table, 2, "desc", 100, 14.5); client.callProcedure("Insert", table, 3, "desc", 100, 14.5); client.callProcedure("Insert", table, 6, "desc", 100, 14.5); client.callProcedure("Insert", table, 7, "desc", 100, 14.5); client.callProcedure("Insert", table, 8, "desc", 100, 14.5); String query = "select * from " + table + " where " + table + ".ID > 1"; VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); // we should get 5 rows but this bug would result in all 6 returned assertEquals(5, results[0].getRowCount()); // make sure that we work if the value we want isn't present query = "select * from " + table + " where " + table + ".ID > 4"; results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(3, results[0].getRowCount()); query = "select * from " + table + " where " + table + ".ID > 8"; results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(0, results[0].getRowCount()); } truncateTables(client, tables); } public void testFixedTickets() throws Exception { subTestTicketEng2250_IsNull(); subTestTicketEng1850_WhereOrderBy(); subTestTicketEng1850_WhereOrderBy2(); subTestTicketENG1232(); subTestTicket309(); subTestTicket196(); subTestTicket201(); subTestTicket216(); subTestTicket194(); subTestTickets227And228(); subTestTicket220(); subTestTicket310(); subTestTicket221(); subTestTicket222(); subTestTicket224(); subTestTicket226(); subTestTicket231(); subTestTicket232(); subTestTicket293(); subTestTicketEng397(); //subTestTicketEng490(); subTestTicketEng993(); subTestTicketEng1316(); subTestTicket2423(); subTestTicket5151_ColumnDefaultNull(); subTestTicket5486_NULLcomparison(); subTestENG4146(); subTestENG5669(); subTestENG5637_VarcharVarbinaryErrorMessage(); subTestENG6870(); subTestENG6926(); subTestENG7041ViewAndExportTable(); subTestENG7349_InnerJoinWithOverflow(); subTestENG7724(); subTestENG7480(); subTestENG8120(); subTestENG9032(); subTestENG9389(); subTestENG9533(); subTestENG9796(); subTestENG11256(); subTestENG12105(); subTestENG12116(); } private void subTestENG12105() throws Exception { Client client = getClient(); validateTableOfLongs(client, "insert into eng_12105 values (0, " + "null, 12, 13, 14, " + "15.0, 16.00, " + "'foo', 'foo_inline_max', 'foo_inline', " + "'2016-01-01 00:00:00.000000', " + "x'deadbeef');", new long[][] {{1}}); validateTableOfLongs(client, "SELECT ALL TINY " + "FROM ENG_12105 T1 " + "INNER JOIN " + "(SELECT DISTINCT VARBIN C2 " + " FROM ENG_12105 " + " GROUP BY C2 , SMALL , C2 LIMIT 2 ) T2 " + "ON TINY IS NULL " + "GROUP BY TINY " + "LIMIT 8372 " + "OFFSET 0;", new long[][] {{-128}}); } private void subTestENG11256() throws Exception { Client client = getClient(); validateDMLTupleCount(client, "INSERT INTO R1 VALUES(1, 'A', 12, 0.6)", 1); validateDMLTupleCount(client, "INSERT INTO R1 VALUES(2, 'A', 12, 0.2)", 1); validateDMLTupleCount(client, "INSERT INTO R1 VALUES(3, 'B', 34, 0.0)", 1); validateDMLTupleCount(client, "INSERT INTO R1 VALUES(4, 'B', 34, 0.7)", 1); validateDMLTupleCount(client, "INSERT INTO R2 VALUES(5, 'C', 56, 0.8)", 1); validateDMLTupleCount(client, "INSERT INTO R2 VALUES(6, 'C', 56, 0.5)", 1); validateDMLTupleCount(client, "INSERT INTO R2 VALUES(7, 'D', 78, 0.9)", 1); validateDMLTupleCount(client, "INSERT INTO R2 VALUES(8, 'D', 78, 0.3)", 1); String[] filterOps = new String[] { " <> ", " IS DISTINCT FROM " }; for (String filterOp : filterOps) { long expected = " <> ".equals(filterOp) ? 4 : 0; String query; String start = "SELECT count(*) FROM R1 PARENT WHERE DESC NOT IN ("; String end = " ON LHS.ID = RHS.ID " + "WHERE LHS.ID " + filterOp + " PARENT.NUM);"; // Zero result rows because values from R1 always have matches in // R1 JOIN R1. query = start + "SELECT LHS.DESC FROM R1 LHS FULL JOIN R1 RHS " + end; validateTableOfLongs(client, query, new long[][] {{0}}); query = start + "SELECT LHS.DESC FROM R1 LHS FULL JOIN R2 RHS " + end; validateTableOfLongs(client, query, new long[][] {{0}}); // An IS DISTINCT FROM bug in the HSQL backend causes it // to always to return 0 rows, // which is only correct for <>. // Remove this condition when ENG-11256 is fixed. if (isHSQL() && expected != 0) { query = start + "SELECT LHS.DESC FROM R2 LHS FULL JOIN R1 RHS " + end; validateTableOfLongs(client, query, new long[][] {{expected}}); } query = start + "SELECT LHS.DESC FROM R2 LHS FULL JOIN R2 RHS " + end; validateTableOfLongs(client, query, new long[][] {{4}}); } truncateTables(client, new String[]{"R1", "R2"}); } private void subTestTicket196() throws IOException, ProcCallException { String[] tables = {"P1", "R1", "P2", "R2"}; Client client = getClient(); for (String table : tables) { client.callProcedure("Insert", table, 1, "desc", 100, 14.5); client.callProcedure("Insert", table, 2, "desc", 100, 14.5); client.callProcedure("Insert", table, 3, "desc", 100, 14.5); client.callProcedure("Insert", table, 6, "desc", 300, 14.5); client.callProcedure("Insert", table, 7, "desc", 300, 14.5); client.callProcedure("Insert", table, 8, "desc", 500, 14.5); String query = String.format("select count(*) from %s", table); VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(1, results[0].getRowCount()); results[0].advanceRow(); assertEquals(6, results[0].getLong(0)); query = String.format("select %s.NUM, count(*) from %s group by %s.NUM", table, table, table); results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(3, results[0].getRowCount()); while (results[0].advanceRow()) { if (results[0].getLong(0) == 100) { assertEquals(3, results[0].getLong(1)); } else if (results[0].getLong(0) == 300) { assertEquals(2, results[0].getLong(1)); } else if (results[0].getLong(0) == 500) { assertEquals(1, results[0].getLong(1)); } else { fail(); } } } // SO, given our current count(*) hack (replace * with the first column // in the input to the aggregator, this is a test that will // FAIL when we go and implement COUNT to do the right thing with null // values. If this test breaks for you, don't blow it off. String query = "insert into COUNT_NULL values (10, 0, 100)"; client.callProcedure("@AdHoc", query); query = "insert into COUNT_NULL values (NULL, 1, 200)"; client.callProcedure("@AdHoc", query); query = "insert into COUNT_NULL values (10, 2, 300)"; client.callProcedure("@AdHoc", query); query = "insert into COUNT_NULL values (NULL, 3, 400)"; client.callProcedure("@AdHoc", query); query = "select count(*) from COUNT_NULL"; VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(1, results[0].getRowCount()); results[0].advanceRow(); assertEquals(4, results[0].getLong(0)); truncateTables(client, tables); truncateTable(client, "COUNT_NULL"); } private void subTestTicket201() throws IOException, ProcCallException { String[] tables = {"P1", "R1", "P2", "R2"}; Client client = getClient(); for (String table : tables) { client.callProcedure("Insert", table, 1, "desc", 100, 14.5); client.callProcedure("Insert", table, 2, "desc", 200, 14.5); client.callProcedure("Insert", table, 3, "desc", 300, 14.5); client.callProcedure("Insert", table, 6, "desc", 400, 14.5); client.callProcedure("Insert", table, 7, "desc", 500, 14.5); client.callProcedure("Insert", table, 8, "desc", 600, 14.5); String query = String.format("select * from %s where (%s.ID + 1) = 2", table, table); VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(1, results[0].getRowCount()); query = String.format("select * from %s where (%s.ID + 1) > 2", table, table); results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(5, results[0].getRowCount()); query = String.format("select * from %s where (%s.ID + 1) >= 2", table, table); results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(6, results[0].getRowCount()); } truncateTables(client, tables); } //public void testTicket205() throws IOException, ProcCallException //{ // String[] tables = {"P1", "R1", "P2", "R2"}; // Client client = getClient(); // for (String table : tables) // { // client.callProcedure("Insert", table, 1, "desc", 100, 14.5); // client.callProcedure("Insert", table, 2, "desc", 200, 14.5); // client.callProcedure("Insert", table, 3, "desc", 300, 14.5); // client.callProcedure("Insert", table, 6, "desc", 400, 14.5); // client.callProcedure("Insert", table, 7, "desc", 500, 14.5); // client.callProcedure("Insert", table, 8, "desc", 600, 14.5); // String query = String.format("select sum(%s.NUM + 1) from %s", // table, table); // VoltTable[] results = client.callProcedure("@AdHoc", query); // assertEquals(1, results[0].getRowCount()); // query = String.format("select sum(%s.NUM + %s.ID) from %s", // table, table); // results = client.callProcedure("@AdHoc", query); // assertEquals(1, results[0].getRowCount()); // } //} private void subTestTicket216() throws IOException, ProcCallException { String[] tables = {"P1", "R1", "P2", "R2"}; Client client = getClient(); for (String table : tables) { client.callProcedure("Insert", table, 1, "desc", 100, 100.0); client.callProcedure("Insert", table, 2, "desc", 200, 200.0); client.callProcedure("Insert", table, 3, "desc", 300, 300.0); client.callProcedure("Insert", table, 6, "desc", 400, 400.0); client.callProcedure("Insert", table, 7, "desc", 500, 500.0); client.callProcedure("Insert", table, 8, "desc", 600, 600.0); String query = String.format("select %s.RATIO / 2.0 from %s order by ID", table, table); VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(6, results[0].getRowCount()); for (double f=50.0; results[0].advanceRow(); f+=50.0) { double num = (results[0].getDouble(0)); assertEquals(f, num); } query = String.format("select * from %s where %s.RATIO >= 400.0", table, table); results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(3, results[0].getRowCount()); } truncateTables(client, tables); } private void subTestTicket194() throws IOException, ProcCallException { String[] tables = {"P1", "R1", "P2", "R2"}; Client client = getClient(); for (String table : tables) { client.callProcedure("Insert", table, 1, "desc", 100, 14.5); client.callProcedure("Insert", table, 2, "desc", 200, 14.5); client.callProcedure("Insert", table, 3, "desc", 300, 14.5); client.callProcedure("Insert", table, 6, "desc", 400, 14.5); client.callProcedure("Insert", table, 7, "desc", 500, 14.5); client.callProcedure("Insert", table, 8, "desc", 600, 14.5); String query = String.format("select * from %s where %s.ID >= 2.1", table, table); VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(4, results[0].getRowCount()); query = String.format("select * from %s where %s.ID >= 4.0", table, table); results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(3, results[0].getRowCount()); } truncateTables(client, tables); } private void subTestTickets227And228() throws IOException, ProcCallException { String[] tables = {"P2", "R2"}; Client client = getClient(); for (String table : tables) { client.callProcedure("Insert", table, 1, "desc", 100, 14.5); client.callProcedure("Insert", table, 2, "desc", 100, 14.5); client.callProcedure("Insert", table, 3, "desc", 100, 14.5); client.callProcedure("Insert", table, 6, "desc", 100, 14.5); client.callProcedure("Insert", table, 7, "desc", 100, 14.5); client.callProcedure("Insert", table, 8, "desc", 100, 14.5); } // test > on the join (ticket 227) String query = "select * from R2, P2 where R2.ID > 1"; VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(30, results[0].getRowCount()); query = "select * from P2, R2 where R2.ID > 1"; results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(30, results[0].getRowCount()); // test >= on the join (ticket 228) query = "select * from R2, P2 where R2.ID >= 3"; results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(24, results[0].getRowCount()); query = "select * from P2, R2 where R2.ID >= 3"; results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(24, results[0].getRowCount()); query = "select * from R2, P2 where R2.ID >= 4"; results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(18, results[0].getRowCount()); query = "select * from P2, R2 where R2.ID >= 4"; results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(18, results[0].getRowCount()); truncateTables(client, tables); } private void subTestTicket220() throws IOException, ProcCallException { String[] tables = {"P1", "R1"}; Client client = getClient(); int id = 0; for (String table : tables) { client.callProcedure("Insert", table, id++, "desc", 100, 14.5); client.callProcedure("Insert", table, id++, "desc", 100, 14.5); client.callProcedure("Insert", table, id++, "desc", 100, 14.5); } String query = "select R1.ID + 5 from R1, P1 order by R1.ID"; VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(9, results[0].getRowCount()); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { results[0].advanceRow(); assertEquals(i + 3 + 5, results[0].getLong(0)); } } truncateTables(client, tables); } // // At first pass, HSQL barfed on decimal in sql-coverage. Debug/test that here. // private void subTestForHSQLDecimalFailures() throws IOException, ProcCallException { Client client = getClient(); String sql = "INSERT INTO R1_DECIMAL VALUES (26, 307473.174514, 289429.605067, 9.71903320295135486617e-01)"; client.callProcedure("@AdHoc", sql); sql = "select R1_DECIMAL.CASH + 2.0 from R1_DECIMAL"; VoltTable[] results = client.callProcedure("@AdHoc", sql).getResults(); assertEquals(1, results.length); truncateTable(client, "R1_DECIMAL"); } private void subTestTicket310() throws IOException, ProcCallException { Client client = getClient(); String sql = "INSERT INTO R1_DECIMAL VALUES (26, 307473.174514, 289429.605067, 9.71903320295135486617e-01)"; client.callProcedure("@AdHoc", sql); boolean caught = false; // HSQL doesn't choke the same way Volt does at the moment. // Fake the test out. if (isHSQL()) { caught = true; } try { sql = "SELECT * FROM R1_DECIMAL WHERE " + "(R1_DECIMAL.CASH <= 999999999999999999999999999999.0622493314185)" + " AND (R1_DECIMAL.ID > R1_DECIMAL.CASH)"; client.callProcedure("@AdHoc", sql); } catch (ProcCallException e) { caught = true; } assertTrue(caught); truncateTable(client, "R1_DECIMAL"); } private void subTestNumericExpressionConversion() throws IOException, ProcCallException { VoltTable[] results; Client client = getClient(); String sql = "INSERT INTO R1_DECIMAL VALUES " + "(26, 307473.174514, 289429.605067, 9.71903320295135486617e-01)"; results = client.callProcedure("@AdHoc", sql).getResults(); assertEquals(1, results.length); assertEquals(1, results[0].asScalarLong()); sql = "UPDATE R1_DECIMAL SET CASH = CASH * 5 WHERE " + "R1_DECIMAL.CASH != 88687.224073"; results = client.callProcedure("@AdHoc", sql).getResults(); assertEquals(1, results.length); assertEquals(1, results[0].asScalarLong()); sql = "UPDATE R1_DECIMAL SET CASH = CASH + 5.5 WHERE " + "R1_DECIMAL.CASH != 88687.224073"; results = client.callProcedure("@AdHoc", sql).getResults(); assertEquals(1, results.length); assertEquals(1, results[0].asScalarLong()); truncateTable(client, "R1_DECIMAL"); } private void subTestTicket221() throws IOException, ProcCallException { String[] tables = {"P1", "R1"}; Client client = getClient(); int id = 0; for (String table : tables) { client.callProcedure("Insert", table, id++, "desc", 100, 14.5); client.callProcedure("Insert", table, id++, "desc", 200, 15.5); client.callProcedure("Insert", table, id++, "desc", 300, 16.5); } String query = "select distinct P1.NUM from R1, P1 order by P1.NUM"; VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(3, results[0].getRowCount()); for (int i = 100; results[0].advanceRow(); i+=100) { assertEquals(i, results[0].getLong(0)); //* enable for debugging */ System.out.println("i: " + results[0].getLong(0)); } truncateTables(client, tables); } private void subTestTicket222() throws IOException, ProcCallException { String[] tables = {"P1", "R1"}; Client client = getClient(); int id = 0; for (String table : tables) { client.callProcedure("Insert", table, id++, "desc", 100, 14.5); client.callProcedure("Insert", table, id++, "desc", 200, 15.5); client.callProcedure("Insert", table, id++, "desc", 300, 16.5); } String query = "select max(P1.ID) from R1, P1"; VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(1, results[0].getRowCount()); results[0].advanceRow(); assertEquals(2, results[0].getLong(0)); //* enable for debugging */ System.out.println("i: " + results[0].getLong(0)); truncateTables(client, tables); } private void subTestTicket224() throws IOException, ProcCallException { String[] tables = {"P1", "R1"}; Client client = getClient(); int id = 0; for (String table : tables) { client.callProcedure("Insert", table, id++, "desc", 100, 14.5); client.callProcedure("Insert", table, id++, "desc", 200, 15.5); client.callProcedure("Insert", table, id++, "desc", 300, 16.5); } String query = "select P1.ID from R1, P1 group by P1.ID order by P1.ID"; VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(3, results[0].getRowCount()); assertEquals(1, results[0].getColumnCount()); //* enable for debugging */ System.out.println(results[0].toFormattedString()); for (int i = 0; results[0].advanceRow(); i++) { assertEquals(i, results[0].getLong(0)); //* enable for debugging */ System.out.println("i: " + results[0].getLong(0)); } truncateTables(client, tables); } private void subTestTicket226() throws IOException, ProcCallException { String[] tables = {"P1", "R1"}; Client client = getClient(); int id = 0; for (String table : tables) { client.callProcedure("Insert", table, id++, "desc", 100, 14.5); client.callProcedure("Insert", table, id++, "desc", 200, 15.5); client.callProcedure("Insert", table, id++, "desc", 300, 16.5); } String query = "select P1.ID from P1, R1 order by P1.ID"; VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(9, results[0].getRowCount()); assertEquals(1, results[0].getColumnCount()); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { results[0].advanceRow(); assertEquals(i, results[0].getLong(0)); //* enable for debugging */ System.out.println("i: " + results[0].getLong(0)); } } truncateTables(client, tables); } private void subTestTicket231() throws IOException, ProcCallException { String[] tables = {"P1", "R1", "P2", "R2"}; Client client = getClient(); for (String table : tables) { client.callProcedure("Insert", table, 1, "desc", 100, 14.5); client.callProcedure("Insert", table, 2, "desc", 100, 14.5); client.callProcedure("Insert", table, 3, "desc", 200, 14.5); client.callProcedure("Insert", table, 6, "desc", 200, 14.5); client.callProcedure("Insert", table, 7, "desc", 300, 14.5); client.callProcedure("Insert", table, 8, "desc", 300, 14.5); // This statement is a test case for one of the ticket 231 // work-arounds String query = String.format("select (%s.NUM + %s.NUM) as NUMSUM from %s where (%s.NUM + %s.NUM) > 400", table, table, table, table, table); VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(2, results[0].getRowCount()); // This failing statement is the current ticket 231 failing behavior. // query = // String.format("select (%s.NUM + %s.NUM) as NUMSUM from %s order by (%s.NUM + %s.NUM)", // table, table, table, table, table); // results = client.callProcedure("@AdHoc", query); // assertEquals(6, results[0].getRowCount()); } truncateTables(client, tables); } private void subTestTicket232() throws IOException, ProcCallException { String[] tables = {"P1", "R1", "P2", "R2"}; Client client = getClient(); for (String table : tables) { client.callProcedure("Insert", table, 1, "desc", 100, 14.5); client.callProcedure("Insert", table, 2, "desc", 100, 14.5); client.callProcedure("Insert", table, 3, "desc", 200, 14.5); client.callProcedure("Insert", table, 6, "desc", 200, 14.5); client.callProcedure("Insert", table, 7, "desc", 300, 14.5); client.callProcedure("Insert", table, 8, "desc", 300, 14.5); String query = String.format("select %s.NUM from %s group by %s.NUM order by %s.NUM", table, table, table, table); VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(3, results[0].getRowCount()); } truncateTables(client, tables); } private void subTestTicket293() throws IOException, ProcCallException { String[] tables = {"P1", "R1", "P2", "R2"}; Client client = getClient(); int id = 0; for (String table : tables) { client.callProcedure("Insert", table, id++, "desc", 100, 14.5); client.callProcedure("Insert", table, id++, "desc", 200, 15.5); client.callProcedure("Insert", table, id++, "desc", 300, 16.5); client.callProcedure("Insert", table, id++, "desc", 300, 17.5); client.callProcedure("Insert", table, id++, "desc", 400, 18.5); String query = String.format("select distinct %s.NUM from %s order by %s.NUM", table, table, table); VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(4, results[0].getRowCount()); } String query = "select distinct P1.NUM from R1, P1 order by P1.NUM"; VoltTable[] results = client.callProcedure("@AdHoc", query).getResults(); results = client.callProcedure("@AdHoc", query).getResults(); assertEquals(4, results[0].getRowCount()); truncateTables(client, tables); } private void subTestTicketEng397() throws IOException, ProcCallException { Client client = getClient(); for (int i=0; i < 20; i++) { client.callProcedure("Insert", "P1", i, "desc", 100 + i, 4.5); } // base case VoltTable[] results = client.callProcedure("Eng397Limit1", new Integer(10)).getResults(); assertEquals(10, results[0].getRowCount()); // negative limit rollsback boolean caught = false; try { results = client.callProcedure("Eng397Limit1", new Integer(-1)).getResults(); } catch (ProcCallException ignored) { caught = true; } catch (Exception ex) { ex.printStackTrace(); } assertTrue(caught); truncateTable(client, "P1"); } // RE-ENABLE ONCE ENG-490 IS FIXED // private void subTestTicketEng490() throws IOException, ProcCallException { // Client client = getClient(); // // VoltTable[] results = client.callProcedure("Eng490Select").getResults(); // assertEquals(1, results.length); // // String query = "SELECT A.ASSET_ID, A.OBJECT_DETAIL_ID, OD.OBJECT_DETAIL_ID " + // "FROM ASSET A, OBJECT_DETAIL OD WHERE A.OBJECT_DETAIL_ID = OD.OBJECT_DETAIL_ID;"; // results = client.callProcedure("@AdHoc", query).getResults(); // assertEquals(1, results.length); // } private void subTestTicketEng993() throws IOException, ProcCallException { Client client = getClient(); // this tests some other mumbo jumbo as well like ENG-999 and ENG-1001 ClientResponse response = client.callProcedure("Eng993Insert", 5, 5.5); assertTrue(response.getStatus() == ClientResponse.SUCCESS); // Verify ENG-999 (Literal string 'NULL' round-trips as literal string // and doesn't transform into a SQL NULL value) response = client.callProcedure("@AdHoc", "select DESC from P1 where ID = 6"); VoltTable result = response.getResults()[0]; assertEquals("NULL", result.fetchRow(0).get(0, VoltType.STRING)); // Additional verification that inserts are not bothered by math that used to // generate unexpectedly formatted temp tuples and garbled persistent tuples. // ENG-5926 response = client.callProcedure("@AdHoc", "select * from P1"); result = response.getResults()[0]; result.advanceRow(); assertEquals(6, result.getLong(0)); assertEquals("NULL", result.getString(1)); result.getLong(2); // Not sure what's up with HSQL failing to find null here. if ( ! isHSQL()) { assertTrue(result.wasNull()); } assertEquals(6.5, result.getDouble(3)); // Further verify that inline varchar columns still properly handle potentially larger values // even after the temp tuple formatting fix for ENG-5926. response = client.callProcedure("Eng5926Insert", 5, "", 5.5); assertTrue(response.getStatus() == ClientResponse.SUCCESS); try { response = client.callProcedure("Eng5926Insert", 7, "HOO", 7.5); fail("Failed to throw ProcCallException for runtime varchar length exceeded."); } catch(ProcCallException pce) { } response = client.callProcedure("@AdHoc", "select * from PWEE ORDER BY ID DESC"); result = response.getResults()[0]; result.advanceRow(); assertEquals(6, result.getLong(0)); assertEquals("WEE", result.getString(1)); result.getLong(2); // Not sure what's up with HSQL failing to find null here. if ( ! isHSQL()) { assertTrue(result.wasNull()); } assertEquals(6.5, result.getDouble(3)); // this is the actual bug try { client.callProcedure("@AdHoc", "insert into P1 (ID,DESC,NUM,RATIO) VALUES('?',?,?,?);"); fail(); } catch (Exception e) { assertTrue(e.getMessage().contains("Incorrect number of parameters passed: expected 3, passed 0")); } // test that missing parameters don't work (ENG-1000) try { client.callProcedure("@AdHoc", "insert into P1 (ID,DESC,NUM,RATIO) VALUES(?,?,?,?);"); fail(); } catch (Exception e) { assertTrue(e.getMessage().contains("Incorrect number of parameters passed: expected 4, passed 0")); } //VoltTable results = client.callProcedure("@AdHoc", "select * from P1;").getResults()[0]; //System.out.println(results.toJSONString()); truncateTables(client, new String[]{"P1", "PWEE"}); } /** * Verify that DML returns correctly named "modified_tuple" column name * @throws IOException * @throws ProcCallException */ private void subTestTicketEng1316() throws IOException, ProcCallException { // Fake HSQL. Only care about Volt column naming code. if (isHSQL()) { assertTrue(true); return; } Client client = getClient(); ClientResponse rsp = null; // Test partitioned tables (multipartition query) rsp = client.callProcedure("Eng1316Insert_P", 100, "varcharvalue", 120, 1.0); assertEquals(1, rsp.getResults()[0].asScalarLong()); assertEquals("modified_tuples", rsp.getResults()[0].getColumnName(0)); rsp = client.callProcedure("Eng1316Insert_P", 101, "varcharvalue2", 121, 1.1); rsp = client.callProcedure("Eng1316Insert_P", 102, "varcharvalue2", 122, 1.2); rsp = client.callProcedure("Eng1316Insert_P", 103, "varcharvalue2", 123, 1.3); rsp = client.callProcedure("Eng1316Insert_P", 104, "varcharvalue2", 124, 1.4); rsp = client.callProcedure("Eng1316Update_P"); // update where id < 124 assertEquals(4, rsp.getResults()[0].asScalarLong()); assertEquals("modified_tuples", rsp.getResults()[0].getColumnName(0)); // Test partitioned tables (single partition query) rsp = client.callProcedure("Eng1316Insert_P1", 200, "varcharvalue", 120, 1.0); assertEquals(1, rsp.getResults()[0].asScalarLong()); assertEquals("modified_tuples", rsp.getResults()[0].getColumnName(0)); rsp = client.callProcedure("Eng1316Insert_P1", 201, "varcharvalue2", 121, 1.1); rsp = client.callProcedure("Eng1316Insert_P1", 202, "varcharvalue2", 122, 1.2); rsp = client.callProcedure("Eng1316Insert_P1", 203, "varcharvalue2", 123, 1.3); rsp = client.callProcedure("Eng1316Insert_P1", 204, "varcharvalue2", 124, 1.4); rsp = client.callProcedure("Eng1316Update_P1", 201); // update where id == ? assertEquals(1, rsp.getResults()[0].asScalarLong()); assertEquals("modified_tuples", rsp.getResults()[0].getColumnName(0)); // Test replicated tables. rsp = client.callProcedure("Eng1316Insert_R", 100, "varcharvalue", 120, 1.0); assertEquals(1, rsp.getResults()[0].asScalarLong()); assertEquals("modified_tuples", rsp.getResults()[0].getColumnName(0)); rsp = client.callProcedure("Eng1316Insert_R", 101, "varcharvalue2", 121, 1.1); rsp = client.callProcedure("Eng1316Insert_R", 102, "varcharvalue2", 122, 1.2); rsp = client.callProcedure("Eng1316Insert_R", 103, "varcharvalue2", 123, 1.3); rsp = client.callProcedure("Eng1316Insert_R", 104, "varcharvalue2", 124, 1.4); rsp = client.callProcedure("Eng1316Update_R"); // update where id < 104 assertEquals(4, rsp.getResults()[0].asScalarLong()); assertEquals("modified_tuples", rsp.getResults()[0].getColumnName(0)); truncateTables(client, new String[]{"P1", "R1"}); } // make sure we can call an inner proc private void subTestTicket2423() throws NoConnectionsException, IOException, ProcCallException, InterruptedException { Client client = getClient(); client.callProcedure("TestENG2423$InnerProc"); releaseClient(client); // get it again to make sure the server is all good client = getClient(); client.callProcedure("TestENG2423$InnerProc"); } // Ticket: ENG-5151 private void subTestTicket5151_ColumnDefaultNull() throws IOException, ProcCallException { System.out.println("STARTING default null test..."); Client client = getClient(); VoltTable result = null; // It used to throw errors from EE when inserting without giving explicit values for default null columns. result = client.callProcedure("@AdHoc", " INSERT INTO DEFAULT_NULL(id) VALUES (1);").getResults()[0]; result = client.callProcedure("@AdHoc", " select id, num1, num2, ratio from DEFAULT_NULL;").getResults()[0]; assertTrue(result.advanceRow()); assertEquals(1, result.getLong(0)); if (!isHSQL()) { result.getLong(1); assertTrue(result.wasNull()); result.getLong(2); assertTrue(result.wasNull()); result.getDouble(3); assertTrue(result.wasNull()); } truncateTable(client, "DEFAULT_NULL"); } // Ticket: ENG-5486 private void subTestTicket5486_NULLcomparison() throws IOException, ProcCallException { System.out.println("STARTING default null test..."); Client client = getClient(); VoltTable result = null; /** CREATE TABLE DEFAULT_NULL ( ID INTEGER NOT NULL, num1 INTEGER DEFAULT NULL, num2 INTEGER , ratio FLOAT DEFAULT NULL, num3 INTEGER DEFAULT NULL, desc VARCHAR(300) DEFAULT NULL, PRIMARY KEY (ID) ); create index idx_num3 on DEFAULT_NULL (num3); */ result = client.callProcedure("@AdHoc", " INSERT INTO DEFAULT_NULL(id) VALUES (1);").getResults()[0]; validateTableOfScalarLongs(result, new long[]{1}); // Test null column comparison result = client.callProcedure("@AdHoc", " select count(*), count(num1) from DEFAULT_NULL where num1 < 3;").getResults()[0]; validateTableOfLongs(result, new long[][]{{0, 0}}); result = client.callProcedure("@AdHoc", " select count(*), count(num1) from DEFAULT_NULL where num1 <= 3;").getResults()[0]; validateTableOfLongs(result, new long[][]{{0, 0}}); result = client.callProcedure("@AdHoc", " select count(*), count(num1) from DEFAULT_NULL where num1 > 3;").getResults()[0]; validateTableOfLongs(result, new long[][]{{0, 0}}); // Test null column comparison with index result = client.callProcedure("@AdHoc", " select count(*), count(num3) from DEFAULT_NULL where num3 > 3;").getResults()[0]; validateTableOfLongs(result, new long[][]{{0, 0}}); result = client.callProcedure("@AdHoc", " select count(*), count(num3) from DEFAULT_NULL where num3 < 3;").getResults()[0]; validateTableOfLongs(result, new long[][]{{0, 0}}); result = client.callProcedure("@AdHoc", " select count(*), count(num3) from DEFAULT_NULL where num3 <= 3;").getResults()[0]; validateTableOfLongs(result, new long[][]{{0, 0}}); result = client.callProcedure("@Explain", "select count(*) from DEFAULT_NULL where num3 < 3;").getResults()[0]; //* enable for debugging */ System.out.println(result); // Reverse scan, count(*) result = client.callProcedure("@AdHoc", " select count(*) from DEFAULT_NULL where num3 < 3;").getResults()[0]; validateTableOfScalarLongs(result, new long[]{0}); truncateTable(client, "DEFAULT_NULL"); } private void subTestENG4146() throws IOException, ProcCallException { System.out.println("STARTING insert no json string..."); if (isHSQL()) { return; } Client client = getClient(); VoltTable result = null; // it used to throw EE exception // when inserting a non-json encoded var char into a column that has a field() index; client.callProcedure("NO_JSON.insert", 1, "jpiekos1", "foo", "no json"); result = client.callProcedure("@AdHoc","select id, var1, var2, var3 from no_json;").getResults()[0]; assertTrue(result.advanceRow()); assertEquals(1, result.getLong(0)); assertEquals("jpiekos1", result.getString(1)); assertEquals("foo", result.getString(2)); assertEquals("no json", result.getString(3)); client.callProcedure("NO_JSON.insert", 2, "jpiekos2", "foo2", "no json2"); result = client.callProcedure("@AdHoc","select id from no_json " + "order by var2, field(var3,'color');").getResults()[0]; validateTableOfLongs(result, new long[][] {{1},{2}}); result = client.callProcedure("@AdHoc","select id from no_json " + "where var2 = 'foo' and field(var3,'color') = 'red';").getResults()[0]; assertEquals(0, result.getRowCount()); truncateTable(client, "NO_JSON"); } // SQL HAVING bug on partitioned materialized table private void subTestENG5669() throws IOException, ProcCallException { System.out.println("STARTING testing HAVING......"); Client client = getClient(); VoltTable vt = null; String sqlArray = "INSERT INTO P3 VALUES (0, -5377, 837, -21764, 18749);" + "INSERT INTO P3 VALUES (1, -5377, 837, -21764, 26060);" + "INSERT INTO P3 VALUES (2, -5377, 837, -10291, 30855);" + "INSERT INTO P3 VALUES (3, -5377, 837, -10291, 10718);" + "INSERT INTO P3 VALUES (4, -5377, 24139, -12116, -26619);" + "INSERT INTO P3 VALUES (5, -5377, 24139, -12116, -28421);" + "INSERT INTO P3 VALUES (6, -5377, 24139, 26580, 21384);" + "INSERT INTO P3 VALUES (7, -5377, 24139, 26580, 16131);" + "INSERT INTO P3 VALUES (8, 24862, -32179, 17651, 15165);" + "INSERT INTO P3 VALUES (9, 24862, -32179, 17651, -27633);" + "INSERT INTO P3 VALUES (10, 24862, -32179, 12941, 12036);" + "INSERT INTO P3 VALUES (11, 24862, -32179, 12941, 18363);" + "INSERT INTO P3 VALUES (12, 24862, -25522, 7979, 3903);" + "INSERT INTO P3 VALUES (13, 24862, -25522, 7979, 19380);" + "INSERT INTO P3 VALUES (14, 24862, -25522, 29263, 2730);" + "INSERT INTO P3 VALUES (15, 24862, -25522, 29263, -19078);" + "INSERT INTO P3 VALUES (32, 1010, 1010, 1010, 1010);" + "INSERT INTO P3 VALUES (34, 1020, 1020, 1020, 1020);" + "INSERT INTO P3 VALUES (36, -1010, 1010, 1010, 1010);" + "INSERT INTO P3 VALUES (38, -1020, 1020, 1020, 1020);" + "INSERT INTO P3 VALUES (40, 3620, 5836, 10467, 31123);" + "INSERT INTO P3 VALUES (41, 3620, 5836, 10467, -28088);" + "INSERT INTO P3 VALUES (42, 3620, 5836, -29791, -8520);" + "INSERT INTO P3 VALUES (43, 3620, 5836, -29791, 24495);" + "INSERT INTO P3 VALUES (44, 3620, 4927, 18147, -27779);" + "INSERT INTO P3 VALUES (45, 3620, 4927, 18147, -30914);" + "INSERT INTO P3 VALUES (46, 3620, 4927, 8494, -30592);" + "INSERT INTO P3 VALUES (47, 3620, 4927, 8494, 20340);" + "INSERT INTO P3 VALUES (48, -670, 26179, -25323, -23185);" + "INSERT INTO P3 VALUES (49, -670, 26179, -25323, 22429);" + "INSERT INTO P3 VALUES (50, -670, 26179, -17828, 24248);" + "INSERT INTO P3 VALUES (51, -670, 26179, -17828, 4962);" + "INSERT INTO P3 VALUES (52, -670, -14477, -14488, 13599);" + "INSERT INTO P3 VALUES (53, -670, -14477, -14488, -14801);" + "INSERT INTO P3 VALUES (54, -670, -14477, 16827, -12008);" + "INSERT INTO P3 VALUES (55, -670, -14477, 16827, 27722);"; // Test Default String []sqls = sqlArray.split(";"); //* enable for debugging */ System.out.println(sqls); for (String sql: sqls) { sql = sql.trim(); vt = client.callProcedure("@AdHoc", sql).getResults()[0]; } vt = client.callProcedure("@AdHoc", "SELECT SUM(V_SUM_RENT), SUM(V_G2) FROM V_P3;").getResults()[0]; validateTableOfLongs(vt, new long[][] { {90814,-6200}}); vt = client.callProcedure("@AdHoc", "SELECT SUM(V_SUM_RENT) FROM V_P3 HAVING SUM(V_G2) < 42").getResults()[0]; validateTableOfLongs(vt, new long[][] { {90814}}); //* enable for debugging */ System.out.println(vt); truncateTable(client, "P3"); } public void testVarchar() throws IOException, ProcCallException { subTestVarcharByBytes(); subTestVarcharByCharacter(); subTestInlineVarcharAggregation(); } private void subTestVarcharByBytes() throws IOException, ProcCallException { System.out.println("STARTING testing varchar by BYTES ......"); Client client = getClient(); VoltTable vt = null; String var; var = "VO"; client.callProcedure("@AdHoc", "Insert into VarcharBYTES (id, var2) VALUES (0,'" + var + "')"); vt = client.callProcedure("@AdHoc", "select var2 from VarcharBYTES where id = 0").getResults()[0]; validateTableColumnOfScalarVarchar(vt, new String[] {var}); if (isHSQL()) return; var = "VOLT"; try { client.callProcedure("@AdHoc", "Insert into VarcharBYTES (id, var2) VALUES (1,'" + var + "')"); fail(); } catch(Exception ex) { assertTrue(ex.getMessage().contains( String.format("The size %d of the value '%s' exceeds the size of the VARCHAR(%d BYTES) column.", var.length(), var, 2))); } var = "贾鑫"; try { // assert here that this two-character string decodes via UTF8 to a bytebuffer longer than 2 bytes. assertEquals(2, var.length()); assertEquals(6, var.getBytes("UTF-8").length); client.callProcedure("@AdHoc", "Insert into VarcharBYTES (id, var2) VALUES (1,'" + var + "')"); fail(); } catch(Exception ex) { assertTrue(ex.getMessage().contains( String.format("The size %d of the value '%s' exceeds the size of the VARCHAR(%d BYTES) column.", 6, var, 2))); } var = "Voltdb is great | Voltdb is great " + "| Voltdb is great | Voltdb is great| Voltdb is great | Voltdb is great" + "| Voltdb is great | Voltdb is great| Voltdb is great | Voltdb is great"; try { client.callProcedure("VARCHARBYTES.insert", 2, null, var); fail(); } catch(Exception ex) { assertTrue(ex.getMessage().contains( String.format("The size %d of the value '%s...' exceeds the size of the VARCHAR(%d BYTES) column.", var.length(), var.substring(0, VARCHAR_VARBINARY_THRESHOLD), 80))); } var = var.substring(0, 70); client.callProcedure("VARCHARBYTES.insert", 2, null, var); vt = client.callProcedure("@AdHoc", "select var80 from VarcharBYTES where id = 2").getResults()[0]; validateTableColumnOfScalarVarchar(vt, new String[] {var}); truncateTable(client, "VarcharBYTES"); } private void subTestVarcharByCharacter() throws IOException, ProcCallException { System.out.println("STARTING testing varchar by character ......"); Client client = getClient(); VoltTable vt = null; String var; var = "VO"; client.callProcedure("@AdHoc", "Insert into VarcharTB (id, var2) VALUES (0,'" + var + "')"); vt = client.callProcedure("@AdHoc", "select var2 from VarcharTB where id = 0").getResults()[0]; validateTableColumnOfScalarVarchar(vt, new String[] {var}); var = "V贾"; client.callProcedure("@AdHoc", "Insert into VarcharTB (id, var2) VALUES (1,'" + var + "')"); vt = client.callProcedure("@AdHoc", "select var2 from VarcharTB where id = 1").getResults()[0]; validateTableColumnOfScalarVarchar(vt, new String[] {var}); // It used to fail to insert if VARCHAR column is calculated by BYTEs. var = "贾鑫"; client.callProcedure("@AdHoc", "Insert into VarcharTB (id, var2) VALUES (2,'" + var + "')"); vt = client.callProcedure("@AdHoc", "select var2 from VarcharTB where id = 2").getResults()[0]; validateTableColumnOfScalarVarchar(vt, new String[] {var}); var = "VoltDB是一个以内存数据库为主要产品的创业公司."; try { client.callProcedure("VARCHARTB.insert", 3, var, null); fail(); } catch(Exception ex) { System.err.println(ex.getMessage()); if (isHSQL()) { assertTrue(ex.getMessage().contains("HSQL Backend DML Error (data exception: string data, right truncation)")); } else { assertTrue(ex.getMessage().contains( String.format("The size %d of the value '%s' exceeds the size of the VARCHAR(%d) column.", var.length(), var, 2))); // var.length is 26; } } // insert into client.callProcedure("VARCHARTB.insert", 3, null, var); vt = client.callProcedure("@AdHoc", "select var80 from VarcharTB where id = 3").getResults()[0]; validateTableColumnOfScalarVarchar(vt, new String[] {var}); // Test threshold var += "它是Postgres和Ingres联合创始人Mike Stonebraker领导开发的下一代开源数据库管理系统。它能在现有的廉价服务器集群上实现每秒数百万次数据处理。" + "VoltDB大幅降低了服务器资源 开销,单节点每秒数据处理远远高于其它数据库管理系统。"; try { client.callProcedure("VARCHARTB.insert", 4, null, var); fail(); } catch(Exception ex) { System.err.println(ex.getMessage()); if (isHSQL()) { assertTrue(ex.getMessage().contains("HSQL Backend DML Error (data exception: string data, right truncation)")); } else { assertTrue(ex.getMessage().contains( String.format("The size %d of the value '%s...' exceeds the size of the VARCHAR(%d) column.", var.length(), var.substring(0, 100), 80))); } } truncateTable(client, "VarcharTB"); } private void subTestENG5637_VarcharVarbinaryErrorMessage() throws IOException, ProcCallException { System.out.println("STARTING testing error message......"); if (isHSQL()) { return; } Client client = getClient(); // Test Varchar // Test AdHoc String var1 = "Voltdb is a great database product"; try { client.callProcedure("@AdHoc", "Insert into VARLENGTH (id, var1) VALUES (2,'" + var1 + "')"); fail(); } catch(Exception ex) { assertTrue(ex.getMessage().contains("Value ("+var1+") is too wide for a constant varchar value of size 10")); } try { client.callProcedure("@AdHoc", "Insert into VARLENGTH (id, var1) VALUES (2,'" + var1 + "' || 'abc')"); fail(); } catch(Exception ex) { //* enable for debugging */ System.out.println(ex.getMessage()); assertTrue(ex.getMessage().contains("Value ("+var1+"abc) is too wide for a constant varchar value of size 10")); } // Test inlined varchar with stored procedure try { client.callProcedure("VARLENGTH.insert", 1, var1, null, null, null); fail(); } catch(Exception ex) { //* enable for debugging */ System.out.println(ex.getMessage()); assertTrue(ex.getMessage().contains( String.format("The size %d of the value '%s' exceeds the size of the VARCHAR(%d) column.", var1.length(), var1, 10))); } // Test non-inlined varchar with stored procedure and threshold String var2 = "Voltdb is great | Voltdb is great " + "| Voltdb is great | Voltdb is great| Voltdb is great | Voltdb is great" + "| Voltdb is great | Voltdb is great| Voltdb is great | Voltdb is great"; try { client.callProcedure("VARLENGTH.insert", 2, null, var2, null, null); fail(); } catch(Exception ex) { //* enable for debugging */ System.out.println(ex.getMessage()); assertTrue(ex.getMessage().contains( String.format("The size %d of the value '%s...' exceeds the size of the VARCHAR(%d) column.", 174, var2.substring(0, VARCHAR_VARBINARY_THRESHOLD), 80))); } // Test non-inlined varchar with stored procedure var2 = "Voltdb is great | Voltdb is great " + "| Voltdb is great | Voltdb is great| Voltdb is great"; try { client.callProcedure("VARLENGTH.insert", 21, null, var2, null, null); fail(); } catch(Exception ex) { //* enable for debugging */ System.out.println(ex.getMessage()); assertTrue(ex.getMessage().contains( String.format("The size %d of the value '%s' exceeds the size of the VARCHAR(%d) column.", 86, var2, 80))); } // Test update client.callProcedure("VARLENGTH.insert", 1, "voltdb", null, null, null); try { client.callProcedure("VARLENGTH.update", 1, var1, null, null, null, 1); fail(); } catch(Exception ex) { //* enable for debugging */ System.out.println(ex.getMessage()); assertTrue(ex.getMessage().contains( String.format("The size %d of the value '%s' exceeds the size of the VARCHAR(%d) column.", var1.length(), var1, 10))); } // Test varbinary // Test AdHoc String bin1 = "1111111111111111111111000000"; try { client.callProcedure("@AdHoc", "Insert into VARLENGTH (id, bin1) VALUES (6,'" + bin1 + "')"); fail(); } catch(Exception ex) { //* enable for debugging */ System.out.println(ex.getMessage()); assertTrue(ex.getMessage().contains("Value ("+bin1+") is too wide for a constant varbinary value of size 10")); } // Test inlined varchar with stored procedure try { client.callProcedure("VARLENGTH.insert", 7, null, null, bin1, null); fail(); } catch(Exception ex) { //* enable for debugging */ System.out.println(ex.getMessage()); assertTrue(ex.getMessage().contains( String.format("The size %d of the value exceeds the size of the VARBINARY(%d) column.", bin1.length()/2, 10))); } // Test non-inlined varchar with stored procedure String bin2 = "111111111111111111111100000011111111111111111111110000001111111111111111111111000000" + "111111111111111111111100000011111111111111111111110000001111111111111111111111000000" + "111111111111111111111100000011111111111111111111110000001111111111111111111111000000"; try { client.callProcedure("VARLENGTH.insert", 2, null, null, null, bin2); fail(); } catch(Exception ex) { //* enable for debugging */ System.out.println(ex.getMessage()); assertTrue(ex.getMessage().contains( String.format("The size %d of the value exceeds the size of the VARBINARY(%d) column.", bin2.length() / 2, 80))); } // Test update client.callProcedure("VARLENGTH.insert", 7, null, null, "1010", null); try { client.callProcedure("VARLENGTH.update", 7, null, null, bin1, null, 7); fail(); } catch(Exception ex) { //* enable for debugging */ System.out.println(ex.getMessage()); assertTrue(ex.getMessage().contains( String.format("The size %d of the value exceeds the size of the VARBINARY(%d) column.", bin1.length()/2, 10))); } truncateTable(client, "VARLENGTH"); } // This is a regression test for ENG-6792 private void subTestInlineVarcharAggregation() throws IOException, ProcCallException { Client client = getClient(); ClientResponse cr; cr = client.callProcedure("VARCHARTB.insert", 1, "zz", "panda"); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); cr = client.callProcedure("VARCHARTB.insert", 6, "a", "panda"); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); cr = client.callProcedure("VARCHARTB.insert", 7, "mm", "panda"); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); cr = client.callProcedure("VARCHARTB.insert", 8, "z", "orangutan"); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); cr = client.callProcedure("VARCHARTB.insert", 9, "aa", "orangutan"); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); cr = client.callProcedure("VARCHARTB.insert", 10, "n", "orangutan"); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); cr = client.callProcedure("@AdHoc", "select max(var2), min(var2) from VarcharTB"); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); VoltTable vt = cr.getResults()[0]; assertTrue(vt.advanceRow()); assertEquals("zz", vt.getString(0)); assertEquals("a", vt.getString(1)); // Hash aggregation may have the same problem, so let's // test it here as well. String sql = "select var80, max(var2) as maxvar2, min(var2) as minvar2 " + "from VarcharTB " + "group by var80 " + "order by maxvar2, minvar2"; cr = client.callProcedure("@AdHoc", sql); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); vt = cr.getResults()[0]; assertTrue(vt.advanceRow()); // row 1: panda, zz, a // row 2: orangutan, z, aa assertEquals("orangutan", vt.getString(0)); assertEquals("z", vt.getString(1)); assertEquals("aa", vt.getString(2)); assertTrue(vt.advanceRow()); assertEquals("panda", vt.getString(0)); assertEquals("zz", vt.getString(1)); assertEquals("a", vt.getString(2)); cr = client.callProcedure("PWEE_WITH_INDEX.insert", 0, "MM", 88); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); cr = client.callProcedure("PWEE_WITH_INDEX.insert", 1, "ZZ", 88); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); cr = client.callProcedure("PWEE_WITH_INDEX.insert", 2, "AA", 88); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); cr = client.callProcedure("PWEE_WITH_INDEX.insert", 3, "NN", 88); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); cr = client.callProcedure("@AdHoc", "select num, max(wee), min(wee) " + "from pwee_with_index group by num order by num"); assertEquals(ClientResponse.SUCCESS, cr.getStatus()); vt = cr.getResults()[0]; assertTrue(vt.advanceRow()); assertEquals("ZZ", vt.getString(1)); assertEquals("AA", vt.getString(2)); truncateTables(client, new String[]{"VARCHARTB", "PWEE_WITH_INDEX"}); } // Bug: parser drops extra predicates over certain numbers e.g. 10. private void subTestENG6870() throws IOException, ProcCallException { System.out.println("test ENG6870..."); Client client = this.getClient(); VoltTable vt; String sql; client.callProcedure("ENG6870.insert", 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, null, 1, 1); client.callProcedure("ENG6870.insert", 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); client.callProcedure("ENG6870.insert", 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); sql = "SELECT COUNT(*) FROM ENG6870 " + "WHERE C14 = 1 AND C1 IS NOT NULL AND C2 IS NOT NULL " + "AND C5 = 3 AND C7 IS NOT NULL AND C8 IS NOT NULL " + "AND C0 IS NOT NULL AND C10 IS NOT NULL " + "AND C11 IS NOT NULL AND C13 IS NOT NULL " + "AND C12 IS NOT NULL;"; vt = client.callProcedure("@AdHoc", sql).getResults()[0]; validateTableOfScalarLongs(vt, new long[]{0}); truncateTable(client, "ENG6870"); } private void subTestInsertWithCast() throws IOException, ProcCallException { Client client = getClient(); client.callProcedure("@AdHoc", "delete from p1"); // in ENG-5929, this would cause a null pointer exception, // because OperatorException.refineValueType was not robust to casts. String stmt = "insert into p1 (id, num) values (1, cast(1 + ? as integer))"; VoltTable vt = client.callProcedure("@AdHoc", stmt, 100).getResults()[0]; validateTableOfScalarLongs(vt, new long[] {1}); // This should even work when assigning the expression to the partitioning column: // Previously this would fail with a mispartitioned tuple error. stmt = "insert into p1 (id, num) values (cast(1 + ? as integer), 1)"; vt = client.callProcedure("@AdHoc", stmt, 100).getResults()[0]; validateTableOfScalarLongs(vt, new long[] {1}); stmt = "select id, num from p1 order by id"; vt = client.callProcedure("@AdHoc", stmt).getResults()[0]; validateTableOfLongs(vt, new long[][] {{1, 101}, {101, 1}}); truncateTable(client, "P1"); } private void subTestENG6926() throws Exception { // Aggregation of a joined table was not ordered // according to ORDER BY clause when the OB column // was not first in the select list. Client client = getClient(); String insStmt = "insert into eng6926_ipuser(ip, countrycode, province) values (?, ?, ?)"; client.callProcedure("@AdHoc", insStmt, "23.101.135.101", "US", "District of Columbia"); client.callProcedure("@AdHoc", insStmt, "23.101.142.5", "US", "District of Columbia"); client.callProcedure("@AdHoc", insStmt, "23.101.143.89", "US", "District of Columbia"); client.callProcedure("@AdHoc", insStmt, "23.101.138.62", "US", "District of Columbia"); client.callProcedure("@AdHoc", insStmt, "69.67.23.26", "US", "Minnesota"); client.callProcedure("@AdHoc", insStmt, "198.179.137.202", "US", "Minnesota"); client.callProcedure("@AdHoc", insStmt, "23.99.35.61", "US", "Washington"); insStmt = "insert into eng6926_hits(ip, week) values (?, ?)"; client.callProcedure("@AdHoc", insStmt, "23.101.135.101", 20140914); client.callProcedure("@AdHoc", insStmt, "23.101.142.5", 20140914); client.callProcedure("@AdHoc", insStmt, "23.101.143.89", 20140914); client.callProcedure("@AdHoc", insStmt, "23.101.138.62", 20140914); client.callProcedure("@AdHoc", insStmt, "69.67.23.26", 20140914); client.callProcedure("@AdHoc", insStmt, "198.179.137.202", 20140914); client.callProcedure("@AdHoc", insStmt, "23.99.35.61", 20140914); String query = "select count(ip.ip), ip.province as state " + "from eng6926_hits as h, eng6926_ipuser as ip " + "where ip.ip=h.ip and ip.countrycode='US' " + "group by ip.province " + "order by count(ip.ip) desc"; VoltTable vt = client.callProcedure("@AdHoc", query).getResults()[0]; long[] col0Expected = new long[] {4, 2, 1}; String[] col1Expected = new String[] {"District of Columbia", "Minnesota", "Washington"}; int i = 0; while (vt.advanceRow()) { assertEquals(col0Expected[i], vt.getLong(0)); assertEquals(col1Expected[i], vt.getString(1)); ++i; } truncateTable(client, "eng6926_ipuser"); } private void subTestENG7041ViewAndExportTable() throws Exception { Client client = getClient(); // Materialized view wasn't being updated, because the // connection with its source table wasn't getting created // when there was a (completely unrelated) export table in the // database. // // When loading the catalog in the EE, we were erroneously // aborting view processing when encountering an export table. client.callProcedure("TRANSACTION.insert", 1, 99, 100.0, "NH", "Manchester", new TimestampType(), 20); validateTableOfLongs(client, "select count(*) from transaction", new long[][] {{1}}); // The buggy behavior would show zero rows in the view. validateTableOfLongs(client, "select count(*) from acct_vendor_totals", new long[][] {{1}}); truncateTable(client, "TRANSACTION"); } private void subTestENG7349_InnerJoinWithOverflow() throws IOException, ProcCallException { // In this bug, ENG-7349, we would fail an erroneous assertion // in the EE that we must have more than one active index key when // joining with a multi-component index. Client client = getClient(); VoltTable vt = client.callProcedure("SM_IDX_TBL.insert", 1, 1, 1000) .getResults()[0]; validateTableOfScalarLongs(vt, new long[] {1}); validateTableOfLongs(client, "select * " + "from sm_idx_tbl as t1 inner join sm_idx_tbl as t2 " + "on t1.ti1 = t2.bi", new long[][] {}); truncateTable(client, "SM_IDX_TBL"); } private void insertForInParamsTests(Client client) throws IOException, ProcCallException { for (int i = 0; i < 10; ++i) { VoltTable vt = client.callProcedure("P1.insert", i, Integer.toString(i), i * 10, i * 100.0) .getResults()[0]; validateTableOfScalarLongs(vt, new long[] {1}); } } public void testInWithString() throws IOException, ProcCallException, InterruptedException { subTestInWithIntParams(); subTestInWithStringParams(); subTestInWithStringParamsAdHoc(); subTestInWithStringParamsAsync(); } // Note: the following tests for IN with parameters should at some point // be moved into their own suite along with existing tests for IN // that now live in TestIndexesSuite. This is ENG-7607. private void subTestInWithIntParams() throws IOException, ProcCallException { // HSQL does not support WHERE f IN ? if (isHSQL()) return; Client client = getClient(); insertForInParamsTests(client); VoltTable vt = client.callProcedure("one_list_param", new int[] {1, 2}) .getResults()[0]; validateTableOfScalarLongs(vt, new long[] {1, 2}); // The following error message characterizes what happens if the // users passes long array to an IN parameter on an INTEGER column. // VoltDB requires that the data types match exactly here. // // This error message isn't that friendly (ENG-7606). verifyProcFails(client, "tryScalarMakeCompatible: " + "Unable to match parameter array:int to provided long", "one_list_param", new long[] {1, 2}); // scalar param where list should be provided fails verifyProcFails(client, "Array / Scalar parameter mismatch", "one_list_param", 1); vt = client.callProcedure("one_scalar_param", 5) .getResults()[0]; validateTableOfScalarLongs(vt, new long[] {5}); // passing a list to a scalar int parameter fails verifyProcFails(client , "Array / Scalar parameter mismatch", "one_scalar_param", new long[] {1, 2}); truncateTable(client, "P1"); } private void subTestInWithStringParams() throws IOException, ProcCallException { if (isHSQL()) return; Client client = getClient(); insertForInParamsTests(client); String[] stringArgs = {"7", "8"}; // For vararg methods like callProcedure, when there is an array of objects // (not an array of native types) passed as the only vararg argument, the // compile-time type affects how the compiler presents the arguments to the // callee: // cast to Object - callProcedure sees just one param (which is an array) // cast to Object[] - (or a subclass of Object[]) callee sees each array // element as its own parameter value // where desc in ? // Cast parameter value as an object and it's treated as a single parameter in the callee. VoltTable vt = client.callProcedure("one_string_list_param", (Object)stringArgs) .getResults()[0]; validateTableOfScalarLongs(vt, new long[] {7, 8}); // where desc in ? // Casting the argument to object array means it's treated // as two arguments in the callee. verifyProcFails(client, "EXPECTS 1 PARAMS, BUT RECEIVED 2", "one_string_list_param", (Object[])stringArgs); // where desc in ? // scalar parameter fails verifyProcFails(client, "Array / Scalar parameter mismatch", "one_string_list_param", "scalar param"); // where desc in (?) // Caller treats this as a single list parameter. verifyProcFails(client, "Array / Scalar parameter mismatch", "one_string_scalar_param", (Object)stringArgs); // where desc in (?) // Cast to an array type makes caller treat this as two arguments. verifyProcFails(client, "EXPECTS 1 PARAMS, BUT RECEIVED 2", "one_string_scalar_param", (Object[])stringArgs); // where desc in (?) // This succeeds as it should vt = client.callProcedure("one_string_scalar_param", "9") .getResults()[0]; validateTableOfScalarLongs(vt, new long[] {9}); truncateTable(client, "P1"); } private void subTestInWithStringParamsAdHoc() throws IOException, ProcCallException { if (isHSQL()) return; Client client = getClient(); insertForInParamsTests(client); String[] stringArgs = {"7", "8"}; String adHocQueryWithListParam = "select id from P1 where desc in ?"; String adHocQueryWithScalarParam = "select id from P1 where desc in (?)"; VoltTable vt; verifyProcFails(client, "Array / Scalar parameter mismatch", "@AdHoc", adHocQueryWithListParam, stringArgs); // where desc in ? // scalar parameter fails verifyProcFails(client, "rhs of IN expression is of a non-list type varchar", "@AdHoc", adHocQueryWithListParam, "scalar param"); // where desc in (?) // Caller treats this as a single list parameter. verifyProcFails(client, "Array / Scalar parameter mismatch", "@AdHoc", adHocQueryWithScalarParam, stringArgs); // where desc in (?) // This succeeds as it should vt = client.callProcedure("@AdHoc", adHocQueryWithScalarParam, "9") .getResults()[0]; validateTableOfScalarLongs(vt, new long[] {9}); truncateTable(client, "P1"); } static private final class SimpleCallback implements ProcedureCallback { private ClientResponse m_clientResponse = null; @Override public void clientCallback(ClientResponse clientResponse) throws Exception { m_clientResponse = clientResponse; } public ClientResponse getClientResponse() { return m_clientResponse; } } private void subTestInWithStringParamsAsync() throws IOException, ProcCallException, InterruptedException { if (isHSQL()) return; // There is nothing particularly special about asynchronous procedure calls // with IN and parameters. I wrote these test cases to try and // reproduce ENG-7354, which was closed as "not a bug." // // There doesn't seem to be a lot of tests for async call error recovery, // so these tests are preserved here (hopefully they can find a better // home someday). Client client = getClient(); insertForInParamsTests(client); String[] stringArgs = {"7", "8"}; // Try with the async version of callProcedure. boolean b; SimpleCallback callback = new SimpleCallback(); b = client.callProcedure(callback, "one_string_scalar_param", (Object)stringArgs); // This is queued, but execution fails as it should. assertTrue(b); client.drain(); assertEquals(ClientResponse.GRACEFUL_FAILURE, callback.getClientResponse().getStatus()); assertTrue(callback.getClientResponse().getStatusString().contains( "Array / Scalar parameter mismatch")); b = client.callProcedure(callback, "one_string_scalar_param", (Object[])stringArgs); // This is queued, but execution fails as it should. assertTrue(b); client.drain(); assertEquals(ClientResponse.GRACEFUL_FAILURE, callback.getClientResponse().getStatus()); assertTrue(callback.getClientResponse().getStatusString().contains( "EXPECTS 1 PARAMS, BUT RECEIVED 2")); // This should succeed b = client.callProcedure(callback, "one_string_list_param", (Object)stringArgs); assertTrue(b); client.drain(); assertEquals(ClientResponse.SUCCESS, callback.getClientResponse().getStatus()); VoltTable vt = callback.getClientResponse().getResults()[0]; validateTableOfScalarLongs(vt, new long[] {7, 8}); // Try some ad hoc queries as well. String adHocQueryWithListParam = "select id from P1 where desc in ?"; String adHocQueryWithScalarParam = "select id from P1 where desc in (?)"; // Here's what happens with too many parameters b = client.callProcedure(callback, "one_string_scalar_param", "dog", "cat"); // This is queued, but execution fails as it should. assertTrue(b); client.drain(); assertEquals(ClientResponse.GRACEFUL_FAILURE, callback.getClientResponse().getStatus()); assertTrue(callback.getClientResponse().getStatusString().contains( "EXPECTS 1 PARAMS, BUT RECEIVED 2")); b = client.callProcedure(callback, "@AdHoc", adHocQueryWithScalarParam, stringArgs); assertTrue(b); client.drain(); assertEquals(ClientResponse.GRACEFUL_FAILURE, callback.getClientResponse().getStatus()); assertTrue(callback.getClientResponse().getStatusString().contains( "Array / Scalar parameter mismatch")); // This should succeed, but doesn't (ENG-7604 again) b = client.callProcedure(callback, "@AdHoc", adHocQueryWithListParam, stringArgs); assertTrue(b); client.drain(); assertEquals(ClientResponse.GRACEFUL_FAILURE, callback.getClientResponse().getStatus()); assertTrue(callback.getClientResponse().getStatusString().contains( "Array / Scalar parameter mismatch")); truncateTable(client, "P1"); } private void subTestENG7724() throws IOException, ProcCallException { Client client = getClient(); VoltTable vt = client.callProcedure("voltdbSelectProductChanges", 1, 1).getResults()[0]; assertEquals(13, vt.getColumnCount()); } private void runQueryGetDecimal(Client client, String sql, double value) throws IOException, ProcCallException { VoltTable vt = client.callProcedure("@AdHoc", sql).getResults()[0]; assertTrue(vt.advanceRow()); assertEquals(value, vt.getDecimalAsBigDecimal(0).doubleValue(), 0.0001); } private void runQueryGetDouble(Client client, String sql, double value) throws IOException, ProcCallException { VoltTable vt = client.callProcedure("@AdHoc", sql).getResults()[0]; assertTrue(vt.advanceRow()); assertEquals(value, vt.getDouble(0), 0.0001); } private void subTestENG7480() throws IOException, ProcCallException { Client client = getClient(); String sql; sql = "insert into R1 Values(1, 'MA', 2, 2.2);"; client.callProcedure("@AdHoc", sql); // query constants interpreted as DECIMAL // // operation between float and decimal // sql = "SELECT 0.1 + (1-0.1) + ratio FROM R1"; runQueryGetDouble(client, sql, 3.2); sql = "SELECT 0.1 + (1-0.1) - ratio FROM R1"; runQueryGetDouble(client, sql, -1.2); sql = "SELECT 0.1 + (1-0.1) / ratio FROM R1"; runQueryGetDouble(client, sql, 0.509090909091); sql = "SELECT 0.1 + (1-0.1) * ratio FROM R1"; runQueryGetDouble(client, sql, 2.08); // reverse order sql = "SELECT 0.1 + ratio + (1-0.1) FROM R1"; runQueryGetDouble(client, sql, 3.2); sql = "SELECT 0.1 + ratio - (1-0.1) FROM R1"; runQueryGetDouble(client, sql, 1.4); sql = "SELECT 0.1 + ratio / (1-0.1) FROM R1"; runQueryGetDouble(client, sql, 2.544444444444); sql = "SELECT 0.1 + ratio * (1-0.1) FROM R1"; runQueryGetDouble(client, sql, 2.08); // // operation between decimal and integer // sql = "SELECT 0.1 + (1-0.1) + NUM FROM R1"; runQueryGetDecimal(client, sql, 3.0); sql = "SELECT 0.1 + (1-0.1) - NUM FROM R1"; runQueryGetDecimal(client, sql, -1.0); sql = "SELECT 0.1 + (1-0.1) / NUM FROM R1"; runQueryGetDecimal(client, sql, 0.55); sql = "SELECT 0.1 + (1-0.1) * NUM FROM R1"; runQueryGetDecimal(client, sql, 1.9); // reverse order sql = "SELECT 0.1 + NUM + (1-0.1) FROM R1"; runQueryGetDecimal(client, sql, 3.0); sql = "SELECT 0.1 + NUM - (1-0.1) FROM R1"; runQueryGetDecimal(client, sql, 1.2); sql = "SELECT 0.1 + NUM / (1-0.1) FROM R1"; runQueryGetDecimal(client, sql, 2.322222222222); sql = "SELECT 0.1 + NUM * (1-0.1) FROM R1"; runQueryGetDecimal(client, sql, 1.9); // // test Out of range decimal and float // // test overflow and any underflow decimal are rounded sql = "SELECT NUM + 111111111111111111111111111111111111111.1111 FROM R1"; if (isHSQL()) { verifyStmtFails(client, sql, "HSQL-BACKEND ERROR"); verifyStmtFails(client, sql, "to the left of the decimal point is 39 and the max is 26"); } else { verifyStmtFails(client, sql, "Maximum precision exceeded. " + "Maximum of 26 digits to the left of the decimal point"); } sql = "SELECT NUM + 111111.1111111111111111111111111111111111111 FROM R1"; runQueryGetDecimal(client, sql, 111113.1111111111111111111111111111111111111); sql = "SELECT NUM + " + StringUtils.repeat("1", 256) + ".1111E1 FROM R1"; runQueryGetDouble(client, sql, Double.parseDouble(StringUtils.repeat("1", 255) + "3.1111E1")); sql = "SELECT NUM + " + StringUtils.repeat("1", 368) + ".1111E1 FROM R1"; verifyStmtFails(client, sql, "java.lang.NumberFormatException"); // test stored procedure VoltTable vt = null; vt = client.callProcedure("R1_PROC1").getResults()[0]; validateTableColumnOfScalarDecimal(vt, 0, new BigDecimal[]{new BigDecimal(2.1)}); vt = client.callProcedure("R1_PROC2").getResults()[0]; validateTableColumnOfScalarFloat(vt, 0, new double[]{2.1}); truncateTable(client, "R1"); } private void nullIndexSearchKeyChecker(Client client, String sql, String tbleName, String columnName) throws IOException, ProcCallException { VoltTable vt; vt = client.callProcedure("@AdHoc", sql, null).getResults()[0]; validateTableOfScalarLongs(vt, new long[]{}); String sql1; // We replace a select list element with its count. // if tbleName == null, // Replace "SELECT $columnName" with "SELECT COUNT($columnName)" // else // Replace "SELECT $tbleName.$columnName" with "SELECT COUNT($tableName.$columnName)" // // Of course, we can't use $tbleName and $columnName, so we need to // do some hacking with strings. // String pattern = ((tbleName == null) ? "" : (tbleName + ".")) + columnName; String selectListElement = "SELECT " + pattern; String repl = "SELECT COUNT(" + pattern + ")"; sql1 = sql.replace(selectListElement, repl); assertTrue(sql1.contains(repl + " FROM")); vt = client.callProcedure("@AdHoc", sql1, null).getResults()[0]; validateTableOfScalarLongs(vt, new long[]{0}); String sql2 = sql.replace(selectListElement, "SELECT COUNT(*)"); assertTrue(sql2.contains("SELECT COUNT(*) FROM")); vt = client.callProcedure("@AdHoc", sql2, null).getResults()[0]; validateTableOfScalarLongs(vt, new long[]{0}); } private void subTestENG8120() throws IOException, ProcCallException { // hsqldb does not handle null if (isHSQL()) { return; } Client client = getClient(); VoltTable vt; String sql; String[] tables = {"R1", "R3", "R4"}; for (String tb : tables) { sql = "insert into " + tb + " (id, num) Values(?, ?);"; client.callProcedure("@AdHoc", sql, 1, null); client.callProcedure("@AdHoc", sql, 2, null); client.callProcedure("@AdHoc", sql, 3, 3); client.callProcedure("@AdHoc", sql, 4, 4); sql = "select count(*) from " + tb; vt = client.callProcedure("@AdHoc", sql).getResults()[0]; validateTableOfScalarLongs(vt, new long[]{4}); // activate # of searchkey is 1 sql = "SELECT ID FROM " + tb + " B WHERE B.ID > ?;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); sql = "SELECT ID FROM " + tb + " B WHERE B.ID >= ?;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); sql = "SELECT ID FROM " + tb + " B WHERE B.ID = ?;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); sql = "SELECT ID FROM " + tb + " B WHERE B.ID < ?;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); sql = "SELECT ID FROM " + tb + " B WHERE B.ID <= ?;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); // activate # of searchkey is 2 sql = "SELECT ID FROM " + tb + " B WHERE B.ID = 3 and num > ?;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); sql = "SELECT ID FROM " + tb + " B WHERE B.ID = 3 and num >= ?;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); sql = "SELECT ID FROM " + tb + " B WHERE B.ID = 3 and num = ?;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); sql = "SELECT ID FROM " + tb + " B WHERE B.ID = 3 and num < ?;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); sql = "SELECT ID FROM " + tb + " B WHERE B.ID = 3 and num <= ?;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); // post predicate sql = "SELECT ID FROM " + tb + " B WHERE B.ID > ? and num > 1;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); sql = "SELECT ID FROM " + tb + " B WHERE B.ID = ? and num > 1;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); sql = "SELECT ID FROM " + tb + " B WHERE B.ID < ? and num > 1;"; nullIndexSearchKeyChecker(client, sql, null, "ID"); // nest loop index join sql = "SELECT A.ID FROM R4 A, " + tb + " B WHERE B.ID = A.ID and B.num > ?;"; if (tb != "R4") { vt = client.callProcedure("@Explain", sql, null).getResults()[0]; assertTrue(vt.toString().contains("inline INDEX SCAN of \"" + tb)); assertTrue(vt.toString().contains("SEQUENTIAL SCAN of \"R4")); } nullIndexSearchKeyChecker(client, sql, "A", "ID"); sql = "SELECT A.ID FROM R4 A, " + tb + " B WHERE B.ID = A.ID and B.num >= ?;"; nullIndexSearchKeyChecker(client, sql, "A", "ID"); sql = "SELECT A.ID FROM R4 A, " + tb + " B WHERE B.ID = A.ID and B.num = ?;"; nullIndexSearchKeyChecker(client, sql, "A", "ID"); sql = "SELECT A.ID FROM R4 A, " + tb + " B WHERE B.ID = A.ID and B.num < ?;"; nullIndexSearchKeyChecker(client, sql, "A", "ID"); sql = "SELECT A.ID FROM R4 A, " + tb + " B WHERE B.ID = A.ID and B.num <= ?;"; nullIndexSearchKeyChecker(client, sql, "A", "ID"); } truncateTables(client, tables); } private void subTestENG9032() throws IOException, ProcCallException { System.out.println("test subTestENG9032..."); Client client = getClient(); String sql; sql = "INSERT INTO t1 VALUES (NULL, 1);"; client.callProcedure("@AdHoc", sql); sql = "INSERT INTO t1 VALUES (10, 2);"; client.callProcedure("@AdHoc", sql); sql = "INSERT INTO t1 VALUES (20, 3);"; client.callProcedure("@AdHoc", sql); sql = "SELECT * from t1 where a < 15 order by a;"; validateTableOfLongs(client, sql, new long[][]{{10, 2}}); truncateTable(client, "T1"); } private void subTestENG9389() throws IOException, ProcCallException { System.out.println("test subTestENG9389 outerjoin is null..."); Client client = getClient(); String sql; sql = "INSERT INTO t1 VALUES (1, 2);"; client.callProcedure("@AdHoc", sql); sql = "INSERT INTO t1 VALUES (2, 2);"; client.callProcedure("@AdHoc", sql); sql = "INSERT INTO t1 VALUES (3, 2);"; client.callProcedure("@AdHoc", sql); sql = "INSERT INTO t2 VALUES (2, NULL);"; client.callProcedure("@AdHoc", sql); sql = "INSERT INTO t3 VALUES (2, 2, NULL);"; client.callProcedure("@AdHoc", sql); sql = "INSERT INTO t3 VALUES (3, 3, 10);"; client.callProcedure("@AdHoc", sql); sql = "INSERT INTO t3_no_index VALUES (2, 2, NULL);"; client.callProcedure("@AdHoc", sql); sql = "INSERT INTO t3_no_index VALUES (3, 3, 10);"; client.callProcedure("@AdHoc", sql); // NULL padded row in T3 will trigger the bug ENG-9389 // Test with both indexed and unindexed inner table to exercise both // nested-loop and nested-loop-index joins for (String innerTable : new String[] {"t3", "t3_no_index"}) { sql = "select t1.A " + "from t1 left join " + innerTable + " as t3 " + "on t3.A = t1.A " + "where t3.D is null and t1.B = 2 " + "order by t1.A;"; validateTableOfScalarLongs(client, sql, new long[]{1, 2}); sql = " select t1.A " + "from T1 left join " + innerTable + " as t3 " + "on t3.A = t1.A " + "where t3.D is null and t1.B = 2 " + "and exists(select 1 from t2 where t2.B = t1.B and t2.D is null) " + "order by t1.a;"; validateTableOfScalarLongs(client, sql, new long[]{1, 2}); sql = "select t1.A " + "from t1 inner join t2 on t2.B = t1.B " + "left join " + innerTable + " as t3 " + "on t3.A = t1.A " + "where t2.D is null and t3.D is null and t2.B = 2 " + "order by t1.a;"; validateTableOfScalarLongs(client, sql, new long[]{1, 2}); sql = "select t1.b + t3.d as thesum " + "from t1 " + "left outer join " + innerTable + " as t3 " + "on t1.a = t3.a " + "where t1.b > 1 " + "order by thesum;"; System.out.println(client.callProcedure("@Explain", sql).getResults()[0]); validateTableOfScalarLongs(client, sql, new long[]{Long.MIN_VALUE, Long.MIN_VALUE, 12}); } truncateTables(client, new String[]{"T1", "T2", "T3", "T3_NO_INDEX"}); } private void subTestENG9533() throws IOException, ProcCallException { System.out.println("test subTestENG9533 outerjoin with OR pred..."); Client client = getClient(); String insStmts[] = { "insert into test1_eng_9533 values (0);", "insert into test1_eng_9533 values (1);", "insert into test1_eng_9533 values (2);", "insert into test1_eng_9533 values (3);", "insert into test2_eng_9533 values (1, 'athing', 'one', 5);", "insert into test2_eng_9533 values (2, 'otherthing', 'two', 10);", "insert into test2_eng_9533 values (3, 'yetotherthing', 'three', 3);" }; for (String stmt : insStmts) { validateTableOfScalarLongs(client, stmt, new long[] {1}); } String sqlStmt = "select " + " id, t_int " + "from test1_eng_9533 " + " left join test2_eng_9533 " + " on t_id = id " + "where " + " id <= 1 or t_int > 4 " + "order by id * 2"; // this order by is so that we don't force an index scan on the outer table. validateTableOfLongs(client, sqlStmt, new long[][] { {0, Long.MIN_VALUE}, {1, 5}, {2, 10} }); } private void subTestENG9796() throws IOException, ProcCallException { Client client = getClient(); // In this bug, result tables that had duplicate column names // (not possible for a persistent DB table, but is possible // for the output of a join or a subquery), produced wrong // answers. // id, desc, num, ratio client.callProcedure("p1.Insert", 10, "foo", 20, 40.0); client.callProcedure("r1.Insert", 11, "bar", 20, 99.0); client.callProcedure("r2.Insert", 12, "baz", 20, 111.0); VoltTable vt; vt = client.callProcedure("@AdHoc", "select * from (select id as zzz, num as zzz from p1) as derived") .getResults()[0]; assertContentOfTable(new Object[][] {{10, 20}}, vt); vt = client.callProcedure("@AdHoc", "select * from (select id * 5 as zzz, num * 10 as zzz from p1) as derived") .getResults()[0]; assertContentOfTable(new Object[][] {{50, 200}}, vt); vt = client.callProcedure("@AdHoc", "select S1.* " + "from (R1 join R2 using(num)) as S1," + " (R1 join R2 using(num)) as S2") .getResults()[0]; System.out.println(vt); assertContentOfTable(new Object[][] {{20, 11, "bar", 99.0, 12, "baz", 111.0}}, vt); vt = client.callProcedure("@AdHoc", "select * " + "from (R1 join R2 using(num)) as S1," + " (R1 join R2 using(num)) as S2") .getResults()[0]; System.out.println(vt); assertContentOfTable(new Object[][] {{ 20, 11, "bar", 99.0, 12, "baz", 111.0, 20, 11, "bar", 99.0, 12, "baz", 111.0 }}, vt); truncateTables(client, new String[] {"p1", "r1", "r2"}); } private void subTestENG12116() throws Exception { Client client = getClient(); // This is essentially the case which was failing // in ENG-12116. Note that the select statement's // expressions don't depend on the derived table it // selects from. String SQL = "SELECT SIN(0) FROM ( SELECT DISTINCT * FROM P1 AS O, R1 AS I) AS TTT;"; client.callProcedure("p1.Insert", 10, "foo", 20, 40.0); client.callProcedure("r1.Insert", 11, "bar", 30, 99.0); VoltTable vt; vt = client.callProcedure("@AdHoc", SQL).getResults()[0]; assertApproximateContentOfTable(new Object[][] {{ 0.0 }}, vt, 1.0e-7); SQL = "SELECT * FROM ( SELECT DISTINCT * FROM P1 AS O, R1 AS I WHERE O.ID+1 = I.ID) AS TTT;"; client.callProcedure("p1.Insert", 20, "goo", 21, 41.0); client.callProcedure("r1.Insert", 22, "gar", 31, 99.9); vt = client.callProcedure("@AdHoc", SQL).getResults()[0]; // See if we are actually getting the columns // right in the plan. Before ENG-12116 was fixed we would // sometimes choose the wrong columns in a subquery // with select distinct when the column names were // identical, as is the case here. With this test // we can see that the indexes are correct, since the // values are different. assertContentOfTable(new Object[][] {{ 10, "foo", 20, 40.0, 11, "bar", 30, 99.0 }}, vt); } public void testExistsBugEng12204() throws Exception { Client client = getClient(); client.callProcedure("@AdHoc", "insert into p1 values (0, 'foo', 0, 0.1);"); client.callProcedure("@AdHoc", "insert into r1 values (0, 'foo', 0, 0.1);"); client.callProcedure("@AdHoc", "insert into r1 values (1, 'baz', 1, 1.1);"); VoltTable vt; // Simplified version of query that caused a crash vt = client.callProcedure("@AdHoc", "SELECT * " + "FROM P1 " + "WHERE EXISTS (" + " SELECT SUM(ID) " + " FROM R1 " + " WHERE DESC = 'bar' " + " GROUP BY NUM)").getResults()[0]; assertContentOfTable(new Object[][] {}, vt); // Subquery returns zero rows, so NOT EXISTS returns true vt = client.callProcedure("@AdHoc", "SELECT * " + "FROM P1 " + "WHERE NOT EXISTS (" + " SELECT SUM(ID) " + " FROM R1 " + " WHERE DESC = 'bar' " + " GROUP BY NUM) " + "ORDER BY 1, 2, 3, 4").getResults()[0]; assertContentOfTable(new Object[][] {{0, "foo", 0, 0.1}}, vt); // WHERE predicate in inner query sometimes returns true, sometimes false // (bug occurred when predicate was always false and pass through values were // uninitialized) vt = client.callProcedure("@AdHoc", "SELECT * " + "FROM P1 " + "WHERE EXISTS (" + " SELECT SUM(ID) " + " FROM R1 " + " WHERE DESC = 'baz' " + " GROUP BY NUM) " + "ORDER BY 1, 2, 3, 4").getResults()[0]; assertContentOfTable(new Object[][] {{0, "foo", 0, 0.1}}, vt); // The original query vt = client.callProcedure("@AdHoc", "SELECT * " + "FROM P1 T2 " + "WHERE NOT EXISTS (" + " SELECT SUM(COT(ID)) " + " FROM R1 T2 " + " WHERE DESC <> DESC " + " GROUP BY NUM, NUM) " + "OFFSET 9;").getResults()[0]; assertContentOfTable(new Object[][] {}, vt); } // // JUnit / RegressionSuite boilerplate // public TestFixedSQLSuite(String name) { super(name); } static public junit.framework.Test suite() { VoltServerConfig config = null; MultiConfigSuiteBuilder builder = new MultiConfigSuiteBuilder(TestFixedSQLSuite.class); boolean success; VoltProjectBuilder project = new VoltProjectBuilder(); project.addSchema(Insert.class.getResource("fixed-sql-ddl.sql")); project.addProcedures(PROCEDURES); // Now that this fails to compile with an overflow error, it should be migrated to a // Failures suite. //project.addStmtProcedure("Crap", "insert into COUNT_NULL values (" + Long.MIN_VALUE + ", 1, 200)"); project.addStmtProcedure("Eng397Limit1", "Select P1.NUM from P1 order by P1.NUM limit ?;"); // project.addStmtProcedure("Eng490Select", "SELECT A.ASSET_ID, A.OBJECT_DETAIL_ID, OD.OBJECT_DETAIL_ID FROM ASSET A, OBJECT_DETAIL OD WHERE A.OBJECT_DETAIL_ID = OD.OBJECT_DETAIL_ID;"); project.addStmtProcedure("InsertNullString", "Insert into STRINGPART values (?, ?, ?);", "STRINGPART.NAME: 0"); project.addStmtProcedure("Eng993Insert", "insert into P1 (ID,DESC,NUM,RATIO) VALUES(1+?,'NULL',NULL,1+?);"); project.addStmtProcedure("Eng5926Insert", "insert into PWEE (ID,WEE,NUM,RATIO) VALUES(1+?,?||'WEE',NULL,1+?);"); project.addStmtProcedure("Eng1316Insert_R", "insert into R1 values (?, ?, ?, ?);"); project.addStmtProcedure("Eng1316Update_R", "update R1 set num = num + 1 where id < 104"); project.addStmtProcedure("Eng1316Insert_P", "insert into P1 values (?, ?, ?, ?);"); project.addStmtProcedure("Eng1316Update_P", "update P1 set num = num + 1 where id < 104"); project.addStmtProcedure("Eng1316Insert_P1", "insert into P1 values (?, ?, ?, ?);", "P1.ID: 0"); project.addStmtProcedure("Eng1316Update_P1", "update P1 set num = num + 1 where id = ?", "P1.ID: 0"); //* CONFIG #1: JNI -- keep this enabled by default with / / vs. / * config = new LocalCluster("fixedsql-threesite.jar", 3, 1, 0, BackendTarget.NATIVE_EE_JNI); success = config.compile(project); assertTrue(success); builder.addServerConfig(config); /*/ // CONFIG #1b: IPC -- keep this normally disabled with / * vs. // config = new LocalCluster("fixedsql-onesite.jar", 1, 1, 0, BackendTarget.NATIVE_EE_IPC); success = config.compile(project); assertTrue(success); builder.addServerConfig(config); // end of normally disabled section */ //* CONFIG #2: HSQL config = new LocalCluster("fixedsql-hsql.jar", 1, 1, 0, BackendTarget.HSQLDB_BACKEND); success = config.compile(project); assertTrue(success); builder.addServerConfig(config); // end of HSQDB config */ return builder; } }