Package org.voltdb.regressionsuites

Source Code of org.voltdb.regressionsuites.TestFunctionsSuite$FunctionTestCase

/* This file is part of VoltDB.
* Copyright (C) 2008-2014 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 java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

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_testprocs.regressionsuites.fixedsql.Insert;

/**
* Tests for SQL that was recently (early 2012) unsupported.
*/

public class TestFunctionsSuite extends RegressionSuite {

    /** Procedures used by this suite */
    static final Class<?>[] PROCEDURES = { Insert.class };

    // Padding used to purposely exercise non-inline strings.
    private static final String paddedToNonInlineLength =
        "will you still free me (will memcheck see me) when Im sixty-four";

    // Test some false alarm cases in HSQLBackend that were interfering with sqlcoverage.
    public void testFoundHSQLBackendOutOfRange() throws IOException, InterruptedException, ProcCallException {
        System.out.println("STARTING testFoundHSQLBackendOutOfRange");
        Client client = getClient();
        ClientResponse cr = null;
        /*
        CREATE TABLE P1 (
                ID INTEGER DEFAULT '0' NOT NULL,
                DESC VARCHAR(300),
                NUM INTEGER,
                RATIO FLOAT,
                PAST TIMESTAMP DEFAULT NULL,
                PRIMARY KEY (ID) );
        */

        client.callProcedure("@AdHoc", "INSERT INTO P1 VALUES (0, 'wEoiXIuJwSIKBujWv', -405636, 1.38145922788945552107e-01, NULL)");
        client.callProcedure("@AdHoc", "INSERT INTO P1 VALUES (2, 'wEoiXIuJwSIKBujWv', -29914, 8.98500019539639316335e-01, NULL)");
        client.callProcedure("@AdHoc", "INSERT INTO P1 VALUES (4, 'WCfDDvZBPoqhanfGN', -1309657, 9.34160160574919795629e-01, NULL)");
        client.callProcedure("@AdHoc", "INSERT INTO P1 VALUES (6, 'WCfDDvZBPoqhanfGN', 1414568, 1.14383710279231887164e-01, NULL)");
        cr = client.callProcedure("@AdHoc", "select (5.25 + NUM) from P1");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("@AdHoc", "SELECT FLOOR(NUM + 5.25) NUMSUM FROM P1 ORDER BY NUMSUM");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        // This test case requires HSQL to be taught to do (truncating) integer division of integers as VoltDB does.
        // While not strictly required by the SQL standard, integer division is at least technically compliant,
        // where HSQL's use of floating point division is not.
        // cr = client.callProcedure("@AdHoc", "SELECT SUM(DISTINCT SQRT(ID / (NUM))) AS Q22 FROM P1");
        // assertEquals(ClientResponse.SUCCESS, cr.getStatus());
    }

    public void testStringExpressionIndex() throws Exception {
        System.out.println("STARTING testStringExpressionIndex");
        Client client = getClient();
        initialLoad(client, "P1");

        ClientResponse cr = null;
        VoltTable result = null;
        /*
        CREATE TABLE P1 (
                ID INTEGER DEFAULT '0' NOT NULL,
                DESC VARCHAR(300),
                NUM INTEGER,
                RATIO FLOAT,
                PAST TIMESTAMP DEFAULT NULL,
                PRIMARY KEY (ID) );
                // Test generalized indexes on a string function and combos.
        CREATE INDEX P1_SUBSTRING_DESC ON P1 ( SUBSTRING(DESC FROM 1 FOR 2) );
        CREATE INDEX P1_SUBSTRING_WITH_COL_DESC ON P1 ( SUBSTRING(DESC FROM 1 FOR 2), DESC );
        CREATE INDEX P1_NUM_EXPR_WITH_STRING_COL ON P1 ( DESC, ABS(ID) );
        CREATE INDEX P1_MIXED_TYPE_EXPRS1 ON P1 ( ABS(ID+2), SUBSTRING(DESC FROM 1 FOR 2) );
        CREATE INDEX P1_MIXED_TYPE_EXPRS2 ON P1 ( SUBSTRING(DESC FROM 1 FOR 2), ABS(ID+2) );
        */

        // Do some rudimentary indexed queries -- the real challenge to string expression indexes is defining and loading/maintaining them.
        // TODO: For that reason, it might make sense to break them out into their own suite to make their specific issues easier to isolate.
        cr = client.callProcedure("@AdHoc", "select ID from P1 where SUBSTRING(DESC FROM 1 for 2) = 'X1' and ABS(ID+2) > 7 order by NUM, ID");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(5, result.getRowCount());

        VoltTable r;
        long resultA;
        long resultB;

        // Filters intended to be close enough to bring two different indexes to the same result as no index at all.
        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where ABS(ID+3) = 7 order by NUM, ID");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultA = r.asScalarLong();

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where SUBSTRING(DESC FROM 1 for 2) >= 'X1' and ABS(ID+2) = 8");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where SUBSTRING(DESC FROM 1 for 2) = 'X1' and ABS(ID+2) > 7 and ABS(ID+2) < 9");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        // Do some updates intended to be non-corrupting and inconsequential to the test query results.
        cr = client.callProcedure("@AdHoc", "delete from P1 where ABS(ID+3) <> 7");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        long killCount = r.asScalarLong();
        assertEquals(7, killCount);

        // Repeat the queries on updated indexes.
        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where SUBSTRING(DESC FROM 1 for 2) >= 'X1' and ABS(ID+2) = 8");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where SUBSTRING(DESC FROM 1 for 2) = 'X1' and ABS(ID+2) > 7 and ABS(ID+2) < 9");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

}

    public void testNumericExpressionIndex() throws Exception {
        System.out.println("STARTING testNumericExpressionIndex");
        Client client = getClient();
        initialLoad(client, "R1");

        ClientResponse cr = null;
        VoltTable result = null;
        /*
        CREATE TABLE P1 (
                ID INTEGER DEFAULT '0' NOT NULL,
                DESC VARCHAR(300),
                NUM INTEGER,
                RATIO FLOAT,
                PAST TIMESTAMP DEFAULT NULL,
                PRIMARY KEY (ID) );
        // Test generalized index on a function of a non-indexed column.
        CREATE INDEX P1_ABS_NUM ON P1 ( ABS(NUM) );
        // Test generalized index on an expression of multiple columns.
        CREATE INDEX P1_ABS_ID_PLUS_NUM ON P1 ( ABS(ID) + NUM );
        // Test generalized index on a string function.
        // CREATE INDEX P1_SUBSTRING_DESC ON P1 ( SUBSTRING(DESC FROM 1 FOR 2) );
        CREATE TABLE R1 (
                ID INTEGER DEFAULT '0' NOT NULL,
                DESC VARCHAR(300),
                NUM INTEGER,
                RATIO FLOAT,
                PAST TIMESTAMP DEFAULT NULL,
                PRIMARY KEY (ID) );
        // Test unique generalized index on a function of an already indexed column.
        CREATE UNIQUE INDEX R1_ABS_ID ON R1 ( ABS(ID) );
        // Test generalized expression index with a constant argument.
        CREATE INDEX R1_ABS_ID_SCALED ON R1 ( ID / 3 );
        */

        cr = client.callProcedure("@AdHoc", "select ID from R1 where ABS(ID) = 9 and DESC > 'XYZ' order by ID");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(0, result.getRowCount());


        cr = client.callProcedure("@AdHoc", "select ID from R1 where ABS(ID) > 9 order by NUM, ID");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(5, result.getRowCount());

        VoltTable r;
        long resultA;
        long resultB;

        cr = client.callProcedure("@AdHoc", "select count(*) from R1 where (ID+ID) / 6 = -3");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultA = r.asScalarLong();

        // Here's some hard-won functionality -- matching expression indexes with only the right constants in them.
        cr = client.callProcedure("@AdHoc", "select count(*) from R1 where ID / 3 = -3");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from R1 where (ID+ID) / 6 = -2");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultA = r.asScalarLong();

        // Expecting to use the cached index plan and still get a correct result.
        cr = client.callProcedure("@AdHoc", "select count(*) from R1 where ID / 3 = -2");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from R1 where (ID+ID) / 4 = -3");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultA = r.asScalarLong();

        // Not expecting to use the index -- that's the whole point.
        cr = client.callProcedure("@AdHoc", "select count(*) from R1 where ID / 2 = -3");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

    }

    public void testAbsWithLimit_ENG3572() throws Exception
    {
        System.out.println("STARTING testAbsWithLimit_ENG3572");
        Client client = getClient();
        /*
        CREATE TABLE P1 (
                ID INTEGER DEFAULT '0' NOT NULL,
                DESC VARCHAR(300),
                NUM INTEGER,
                RATIO FLOAT,
                PAST TIMESTAMP DEFAULT NULL,
                PRIMARY KEY (ID)
                );
        */
        ClientResponse cr = null;
        cr = client.callProcedure("@AdHoc", "select abs(NUM) from P1 where ID = 0 limit 1");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
    }

    private void initialLoad(Client client, String tableName) throws IOException, NoConnectionsException, InterruptedException {
        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 ??? (
                ID INTEGER DEFAULT '0' NOT NULL,
                DESC VARCHAR(300),
                NUM INTEGER,
                RATIO FLOAT,
                PAST TIMESTAMP DEFAULT NULL,
                PRIMARY KEY (ID)
                );
        */
        for(int id=7; id < 15; id++) {
            client.callProcedure(callback, tableName+".insert",
                                 - id, // ID
                                 "X"+String.valueOf(id)+paddedToNonInlineLength, // DESC
                                  10, // NUM
                                  1.1, // RATIO
                                  new Timestamp(100000000L)); // PAST
            client.drain();
        }
    }

    public void testAbs() throws Exception
    {
        System.out.println("STARTING testAbs");
        Client client = getClient();
        initialLoad(client, "P1");

        ClientResponse cr = null;
        VoltTable r = null;

        // The next two queries used to fail due to ENG-3913,
        // abuse of compound indexes for partial GT filters.
        // An old issue only brought to light by the addition of a compound index to this suite.
        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where ABS(ID) > 9");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        assertEquals(5, r.asScalarLong()); // used to get 6, matching like >=

        initialLoad(client, "R1");

        cr = client.callProcedure("WHERE_ABS");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        assertEquals(5, r.asScalarLong()); // used to get 6, matching like >=

        try {
            // test decimal support and non-column expressions
            cr = client.callProcedure("WHERE_ABSFF");
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            r = cr.getResults()[0];
            assertEquals(5, r.asScalarLong());
        } catch (ProcCallException hsqlFailed) {
            // Give HSQLDB a pass on this query.
            String msg = hsqlFailed.getMessage();
            assertTrue(msg.matches(".*ExpectedProcedureException.*HSQLDB.*"));
        }

        // Test type promotions
        cr = client.callProcedure("WHERE_ABSIF");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        assertEquals(5, r.asScalarLong());

        try {
            cr = client.callProcedure("WHERE_ABSFI");
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            r = cr.getResults()[0];
        assertEquals(5, r.asScalarLong());
        } catch (ProcCallException hsqlFailed) {
            // Give HSQLDB a pass on this query.
            String msg = hsqlFailed.getMessage();
            assertTrue(msg.matches(".*ExpectedProcedureException.*HSQLDB.*"));
        }


        // Test application to weakly typed NUMERIC constants
        try {
            cr = client.callProcedure("WHERE_ABSWEAK");
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            r = cr.getResults()[0];
            assertEquals(5, r.asScalarLong());
        } catch (ProcCallException hsqlFailed) {
            // Give HSQLDB a pass on this query.
            String msg = hsqlFailed.getMessage();
            assertTrue(msg.matches(".*ExpectedProcedureException.*HSQLDB.*"));
        }

        cr = client.callProcedure("DISPLAY_ABS");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        assertEquals(5, r.asScalarLong());

        cr = client.callProcedure("ORDER_ABS");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        r.advanceRow();
        long value = r.getLong(0);
        assertEquals(5, value);
/*
        cr = client.callProcedure("GROUP_ABS");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        assertEquals(5, r.asScalarLong());
*/
        cr = client.callProcedure("AGG_OF_ABS");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        assertEquals(5, r.asScalarLong());
/*
        cr = client.callProcedure("ABS_OF_AGG");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        assertEquals(5, r.asScalarLong());
*/

        initialLoad(client, "R1");

        initialLoad(client, "R2");

        // The next 2 queries failed in 3.4 with a runtime type exception about casting from VARCHAR reported in ENG-5004
        cr = client.callProcedure("@AdHoc", "select * from P1, R2 where P1.ID = R2.ID AND ABS(P1.NUM) > 0");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        System.out.println(r);
        assertEquals(8, r.getRowCount());

        cr = client.callProcedure("@AdHoc", "select * from P1, R2 where P1.ID = R2.ID AND ABS(P1.NUM+0) > 0");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        System.out.println(r);
        assertEquals(8, r.getRowCount());

        // These next queries fail in 3.5 with a runtime type exception about unrecognized type related?/similar? to ENG-5004?
        cr = client.callProcedure("@AdHoc", "select count(*) from P1, R2 where P1.ID = R2.ID AND ABS(R2.NUM+0) > 0");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        System.out.println(r);
        assertEquals(8, r.asScalarLong());

        cr = client.callProcedure("@AdHoc", "select count(*) from P1, R2 where P1.ID = R2.ID AND ABS(R2.NUM) > 0");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        System.out.println(r);
        assertEquals(8, r.asScalarLong());
        // */


        // Test null propagation
        cr = client.callProcedure("INSERT_NULL", 99);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("INSERT_NULL", 98);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("INSERT_NULL", 97);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("INSERT_NULL", 96);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("INSERT_NULL", 95);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        long resultA;
        long resultB;

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where NUM > 9");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultA = r.asScalarLong();

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where ABS(NUM) > 9");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where ABS(0-NUM) > 9");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where not NUM > 9");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultA = r.asScalarLong();

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where not ABS(0-NUM) > 9");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where not ABS(NUM) > 9");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where ID = -2 - NUM");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultA = r.asScalarLong();

        // These cases were originally failed attempts to trigger ENG-3191, but they still seem worth trying.
        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where ABS(ID) = 2 + NUM");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where ABS(NUM) = (2 - ID)");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where ID < 0");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultA = r.asScalarLong();

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where ABS(ID) = (0 - ID)");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        // Here's the ENG-3191 case, all better now.
        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where ID = (0 - ABS(ID))");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        // Here's the ENG-3196 case, all better now
        cr = client.callProcedure("@AdHoc", "SELECT ABS(ID) AS ENG3196 FROM R1 ORDER BY (ID) LIMIT 5;");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        System.out.println("DEBUG ENG-3196: " + r);
        long resultCount = r.getRowCount();
        assertEquals(5, resultCount);
        r.advanceRow();
        resultB = r.getLong(0);
        assertEquals(14, resultB);
        r.advanceToRow(4);
        resultB = r.getLong(0);
        assertEquals(10, resultB);

        boolean caught = false;

        caught = false;
        try {
            cr = client.callProcedure("@AdHoc", "select count(*) from P1 where not ABS(DESC) > 9");
            assertTrue(cr.getStatus() != ClientResponse.SUCCESS);
        } catch (ProcCallException e) {
            String msg = e.getMessage();
            assertTrue(msg.indexOf("incompatible data type") != -1);
            caught = true;
        }
        assertTrue(caught);

        caught = false;
        try {
            cr = client.callProcedure("@AdHoc", "select count(*) from P1 where not ABS(DESC) > 'ABC'");
            assertTrue(cr.getStatus() != ClientResponse.SUCCESS);
        } catch (ProcCallException e) {
            String msg = e.getMessage();
            assertTrue(msg.indexOf("incompatible data type") != -1);
            caught = true;
        }
        assertTrue(caught);

        cr = client.callProcedure("@AdHoc", "insert into R1 values (1, null, null, null, null)");

        caught = false;
        try {
            // This should violate the UNIQUE ABS constraint without violating the primary key constraint.
            cr = client.callProcedure("@AdHoc", "insert into R1 values (-1, null, null, null, null)");
        } catch (ProcCallException e) {
            String msg = e.getMessage();
            assertTrue(msg.indexOf("violation of constraint") != -1);
            caught = true;
        }
        // If the insert succeeds on VoltDB, the constraint failed to trigger.
        // If the insert fails on HSQL, the test is invalid -- HSQL should not detect the subtle constraint violation we are trying to trigger.
        assertEquals( ! isHSQL(), caught);
    }

    public void testSubstring() throws Exception
    {
        System.out.println("STARTING testSubstring");
        Client client = getClient();
        initialLoad(client, "P1");

        ClientResponse cr = null;
        VoltTable r = null;

        // test where support
        cr = client.callProcedure("WHERE_SUBSTRING2");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        assertEquals(5, r.asScalarLong());

        cr = client.callProcedure("WHERE_SUBSTRING3");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        assertEquals(5, r.asScalarLong());

        // Test select support
        cr = client.callProcedure("DISPLAY_SUBSTRING");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        r.advanceRow();
        assertEquals("12"+paddedToNonInlineLength, r.getString(0));

        cr = client.callProcedure("DISPLAY_SUBSTRING2");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        r.advanceRow();
        assertEquals("12", r.getString(0));

        // Test ORDER BY by support
        cr = client.callProcedure("ORDER_SUBSTRING");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        r.advanceRow();
        long value = r.getLong(0);
        assertEquals(5, value);

        // Test GROUP BY by support
        cr = client.callProcedure("AGG_OF_SUBSTRING");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        r.advanceRow();
        assertEquals("10"+paddedToNonInlineLength, r.getString(0));

        cr = client.callProcedure("AGG_OF_SUBSTRING2");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        r.advanceRow();
        assertEquals("10", r.getString(0));

        // Test null propagation
        cr = client.callProcedure("INSERT_NULL", 99);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("INSERT_NULL", 98);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("INSERT_NULL", 97);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("INSERT_NULL", 96);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("INSERT_NULL", 95);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        long resultA;
        long resultB;

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where DESC >= 'X11'");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultA = r.asScalarLong();

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where SUBSTRING (DESC FROM 2) >= '11'");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where not DESC >= 'X12'");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultA = r.asScalarLong();

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where not SUBSTRING( DESC FROM 2) >= '12'");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where DESC >= 'X2'");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultA = r.asScalarLong();

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where SUBSTRING(DESC FROM 2 FOR 1) >= '2'");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        cr = client.callProcedure("@AdHoc", "select count(*) from P1 where not SUBSTRING( SUBSTRING (DESC FROM 2) FROM 1 FOR 1) < '2'");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        resultB = r.asScalarLong();
        assertEquals(resultA, resultB);

        boolean caught = false;

        caught = false;
        try {
            cr = client.callProcedure("@AdHoc", "select count(*) from P1 where not SUBSTRING( DESC FROM 2) > 9");
            assertTrue(cr.getStatus() != ClientResponse.SUCCESS);
        } catch (ProcCallException e) {
            String msg = e.getMessage();
            assertTrue(msg.indexOf("incompatible data type") != -1);
            caught = true;
        }
        assertTrue(caught);

        caught = false;
        try {
            cr = client.callProcedure("@AdHoc", "select count(*) from P1 where not SUBSTRING (1 FROM 2) > 9");
            assertTrue(cr.getStatus() != ClientResponse.SUCCESS);
        } catch (ProcCallException e) {
            String msg = e.getMessage();
            assertTrue(msg.indexOf("incompatible data type") != -1);
            caught = true;
        }
        assertTrue(caught);

        caught = false;
        try {
            cr = client.callProcedure("@AdHoc", "select count(*) from P1 where not SUBSTRING (1 FROM DESC) > '9'");
            assertTrue(cr.getStatus() != ClientResponse.SUCCESS);
        } catch (ProcCallException e) {
            String msg = e.getMessage();
            assertTrue(msg.indexOf("incompatible data type") != -1);
            caught = true;
        }
        assertTrue(caught);

        caught = false;
        try {
            cr = client.callProcedure("@AdHoc", "select count(*) from P1 where not SUBSTRING (DESC FROM DESC) > 'ABC'");
            assertTrue(cr.getStatus() != ClientResponse.SUCCESS);
        } catch (ProcCallException e) {
            String msg = e.getMessage();
            assertTrue(msg.indexOf("incompatible data type") != -1);
            caught = true;
        }
        assertTrue(caught);

    }

    public void testCurrentTimestamp() throws Exception
    {
        System.out.println("STARTING testCurrentTimestamp");
        /**
         *      "CREATE TABLE R_TIME ( " +
                "ID INTEGER DEFAULT 0 NOT NULL, " +
                "C1 INTEGER DEFAULT 2 NOT NULL, " +
                "T1 TIMESTAMP DEFAULT NULL, " +
                "T2 TIMESTAMP DEFAULT NOW, " +
                "T3 TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " +
                "PRIMARY KEY (ID) ); " +
         */
        Client client = getClient();
        ClientResponse cr = null;
        VoltTable vt = null;
        Date before = null;
        Date after = null;

        // Test Default value with functions.
        before = new Date();
        cr = client.callProcedure("@AdHoc", "Insert into R_TIME (ID) VALUES(1);");
        after = new Date();
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        vt = client.callProcedure("@AdHoc", "SELECT C1, T1, T2, T3 FROM R_TIME WHERE ID = 1;").getResults()[0];
        assertTrue(vt.advanceRow());

        assertEquals(2, vt.getLong(0));
        // Test NULL

        long t2FirstRow = vt.getTimestampAsLong(2);
        long t3FirstRow = vt.getTimestampAsLong(3);

        assertTrue(after.getTime()*1000 >= t2FirstRow);
        assertTrue(before.getTime()*1000 <= t2FirstRow);
        assertEquals(t2FirstRow, t3FirstRow);

        // execute the same insert again, to assert that we get a newer timestamp
        // even if we are re-using the same plan (ENG-6755)

        // sleep a quarter of a second just to be certain we get a different timestamp
        Thread.sleep(250);

        cr = client.callProcedure("@AdHoc", "Insert into R_TIME (ID) VALUES(2);");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        vt = client.callProcedure("@AdHoc", "SELECT C1, T1, T2, T3 FROM R_TIME WHERE ID = 2;").getResults()[0];
        assertTrue(vt.advanceRow());
        long t2SecondRow = vt.getTimestampAsLong(2);
        assertTrue(t2FirstRow < t2SecondRow);

        before = new Date();
        vt = client.callProcedure("@AdHoc", "SELECT NOW, CURRENT_TIMESTAMP FROM R_TIME;").getResults()[0];
        after = new Date();
        assertTrue(vt.advanceRow());

        assertTrue(after.getTime()*1000 >= vt.getTimestampAsLong(0));
        assertTrue(before.getTime()*1000 <= vt.getTimestampAsLong(0));
        assertEquals(vt.getTimestampAsLong(0), vt.getTimestampAsLong(1));
    }

    public void testTimestampConversions() throws Exception
    {
        Client client = getClient();
        ClientResponse cr = null;
        VoltTable r = null;
        long result;
        int columnIndex = 0;

        // Giving up on hsql testing until timestamp precision behavior can be normalized.
        if ( ! isHSQL()) {
            System.out.println("STARTING test CAST between string and timestamp.");
            /*
            CREATE TABLE R2 (
                    ID INTEGER DEFAULT '0' NOT NULL,
                    DESC VARCHAR(300),
                    NUM INTEGER,
                    RATIO FLOAT,
                    PAST TIMESTAMP DEFAULT NULL,
                    PRIMARY KEY (ID) );
            */
            String strTime;
            // Normal test case 2001-9-9 01:46:40.789000
            cr = client.callProcedure("R2.insert", 1, "2001-09-09 01:46:40.789000", 10, 1.1, new Timestamp(1000000000789L));
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            strTime = "2001-10-30 21:46:40.000789";
            cr = client.callProcedure("R2.insert", 2, strTime, 12, 1.1, strTime);
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            strTime = "1601-01-01 00:00:00.000789";
            cr = client.callProcedure("R2.insert", 3, strTime, 13, 1.1, strTime);
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            strTime = "2013-12-31 23:59:59.999999";
            cr = client.callProcedure("R2.insert", 4, strTime, 14, 1.1, strTime);
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            // test only given date
            strTime = "2014-07-02";
            cr = client.callProcedure("R2.insert", 5, strTime + " 00:00:00.000000", 15, 1.1, strTime);
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            strTime = "2014-07-03";
            cr = client.callProcedure("R2.insert", 6, strTime, 16, 1.1, strTime +" 00:00:00.000000");
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            strTime = "2014-07-04";
            cr = client.callProcedure("R2.insert", 7, strTime, 17, 1.1, strTime);
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());

            // test AdHoc cast
            cr = client.callProcedure("@AdHoc", "select cast('2014-07-04 00:00:00.000000' as timestamp) from R2 where id = 1;");
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            r = cr.getResults()[0];
            r.advanceRow();
            assertEquals(r.getTimestampAsTimestamp(0).toString(), "2014-07-04 00:00:00.000000");
            cr = client.callProcedure("@AdHoc", "select cast('2014-07-05' as timestamp) from R2 where id = 1;");
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            r = cr.getResults()[0];
            r.advanceRow();
            assertEquals(r.getTimestampAsTimestamp(0).toString(), "2014-07-05 00:00:00.000000");

            cr = client.callProcedure("VERIFY_TIMESTAMP_STRING_EQ");
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            r = cr.getResults()[0];
            if (r.getRowCount() != 0) {
                System.out.println("VERIFY_TIMESTAMP_STRING_EQ failed on " + r.getRowCount() + " rows:");
                System.out.println(r.toString());
                fail("VERIFY_TIMESTAMP_STRING_EQ failed on " + r.getRowCount() + " rows");
            }

            cr = client.callProcedure("VERIFY_STRING_TIMESTAMP_EQ");
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            r = cr.getResults()[0];
            // there should be 2 rows wrong, because the cast always return a long format string, but we
            // have two rows containing short format strings
            if (r.getRowCount() != 2) {
                System.out.println("VERIFY_STRING_TIMESTAMP_EQ failed on " + r.getRowCount() +
                        " rows, where only 2 were expected:");
                System.out.println(r.toString());
                fail("VERIFY_TIMESTAMP_STRING_EQ failed on " + r.getRowCount() +
                        " rows, where only 2 were expected:");
            }

            cr = client.callProcedure("DUMP_TIMESTAMP_STRING_PATHS");
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            r = cr.getResults()[0];
            System.out.println(r);
        }

        System.out.println("STARTING test Extract");
        /*
        CREATE TABLE P1 (
                ID INTEGER DEFAULT '0' NOT NULL,
                DESC VARCHAR(300),
                NUM INTEGER,
                RATIO FLOAT,
                PAST TIMESTAMP DEFAULT NULL,
                PRIMARY KEY (ID)
                );
        */
        // Test Null timestamp
//        cr = client.callProcedure("P1.insert", 0, "X0", 10, 1.1, null);
//        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
//        cr = client.callProcedure("EXTRACT_TIMESTAMP", 0);
//        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
//        r = cr.getResults()[0];
//        r.advanceRow();
//        for (int i=0; i< 8; i++) {
//            assertNull(r.getLong(i));
//        }
//        assertNull(r.getLong(8));


        // Normal test case 2001-9-9 01:46:40
        cr = client.callProcedure("P1.insert", 1, "X0", 10, 1.1, new Timestamp(1000000000789L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("EXTRACT_TIMESTAMP", 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        r.advanceRow();
        columnIndex = 0;

        int EXPECTED_YEAR = 2001;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_YEAR, result);

        int EXPECTED_MONTH = 9;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_MONTH, result);

        int EXPECTED_DAY = 9;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DAY, result);

        int EXPECTED_DOW = 1;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DOW, result);

        int EXPECTED_DOM = EXPECTED_DAY;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DOM, result);

        int EXPECTED_DOY = 252;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DOY, result);

        int EXPECTED_QUARTER = 3;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_QUARTER, result);

        int EXPECTED_HOUR = 1;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_HOUR, result);

        int EXPECTED_MINUTE = 46;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_MINUTE, result);

        BigDecimal EXPECTED_SECONDS = new BigDecimal("40.789000000000");
        BigDecimal decimalResult = r.getDecimalAsBigDecimal(columnIndex++);
        assertEquals(EXPECTED_SECONDS, decimalResult);

        // ISO 8601 regards Sunday as the last day of a week
        int EXPECTED_WEEK = 36;
        if (isHSQL()) {
            // hsql get answer 37, because it believes a week starts with Sunday
            EXPECTED_WEEK = 37;
        }
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_WEEK, result);
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_WEEK, result);

        // VoltDB has a special function to handle WEEKDAY, and it is not the same as DAY_OF_WEEK
        int EXPECTED_WEEKDAY = 6;
        if (isHSQL()) {
            // We map WEEKDAY keyword to DAY_OF_WEEK in hsql parser
            EXPECTED_WEEKDAY = EXPECTED_DOW;
        }
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_WEEKDAY, result);

        // test timestamp before epoch, Human time (GMT): Thu, 18 Nov 1948 16:32:02 GMT
        // Leap year!
        // http://disc.gsfc.nasa.gov/julian_calendar.shtml
        cr = client.callProcedure("P1.insert", 2, "X0", 10, 1.1, new Timestamp(-666430077123L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("EXTRACT_TIMESTAMP", 2);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        r.advanceRow();
        columnIndex = 0;

        EXPECTED_YEAR = 1948;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_YEAR, result);

        EXPECTED_MONTH = 11;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_MONTH, result);

        EXPECTED_DAY = 18;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DAY, result);

        EXPECTED_DOW = 5;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DOW, result);

        EXPECTED_DOM = EXPECTED_DAY;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DOM, result);

        EXPECTED_DOY = 323;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DOY, result);

        EXPECTED_QUARTER = 4;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_QUARTER, result);

        EXPECTED_HOUR = 16;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_HOUR, result);

        EXPECTED_MINUTE = 32;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_MINUTE, result);

        EXPECTED_SECONDS = new BigDecimal("2.877000000000");
        decimalResult = r.getDecimalAsBigDecimal(columnIndex++);
        assertEquals(EXPECTED_SECONDS, decimalResult);

        EXPECTED_WEEK = 47;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_WEEK, result);
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_WEEK, result);

        // VoltDB has a special function to handle WEEKDAY, and it is not the same as DAY_OF_WEEK
        EXPECTED_WEEKDAY = 3;
        if (isHSQL()) {
            // We map WEEKDAY keyword to DAY_OF_WEEK in hsql parser
            EXPECTED_WEEKDAY = EXPECTED_DOW;
        }
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_WEEKDAY, result);

        // test timestamp with a very old date, Human time (GMT): Fri, 05 Jul 1658 14:22:27 GMT
        cr = client.callProcedure("P1.insert", 3, "X0", 10, 1.1, new Timestamp(-9829676252456L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("EXTRACT_TIMESTAMP", 3);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        r.advanceRow();
        columnIndex = 0;

        EXPECTED_YEAR = 1658;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_YEAR, result);

        EXPECTED_MONTH = 7;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_MONTH, result);

        EXPECTED_DAY = 5;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DAY, result);

        EXPECTED_DOW = 6;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DOW, result);

        EXPECTED_DOM = EXPECTED_DAY;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DOM, result);

        EXPECTED_DOY = 186;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DOY, result);

        EXPECTED_QUARTER = 3;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_QUARTER, result);

        EXPECTED_HOUR = 14;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_HOUR, result);

        EXPECTED_MINUTE = 22;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_MINUTE, result);

        EXPECTED_SECONDS = new BigDecimal("27.544000000000");
        decimalResult = r.getDecimalAsBigDecimal(columnIndex++);
        assertEquals(EXPECTED_SECONDS, decimalResult);

        EXPECTED_WEEK = 27;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_WEEK, result);
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_WEEK, result);

        // VoltDB has a special function to handle WEEKDAY, and it is not the same as DAY_OF_WEEK
        EXPECTED_WEEKDAY = 4;
        if (isHSQL()) {
            // We map WEEKDAY keyword to DAY_OF_WEEK in hsql parser
            EXPECTED_WEEKDAY = EXPECTED_DOW;
        }
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_WEEKDAY, result);

        // Move in this testcase of quickfix-extract(), Human time (GMT): Mon, 02 Jul 1956 12:53:37 GMT
        cr = client.callProcedure("P1.insert", 4, "X0", 10, 1.1, new Timestamp(-425991982877L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = client.callProcedure("EXTRACT_TIMESTAMP", 4);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        r = cr.getResults()[0];
        r.advanceRow();
        columnIndex = 0;
        //System.out.println("Result: " + r);

        EXPECTED_YEAR = 1956;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_YEAR, result);

        EXPECTED_MONTH = 7;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_MONTH, result);

        EXPECTED_DAY = 2;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DAY, result);

        EXPECTED_DOW = 2;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DOW, result);

        EXPECTED_DOM = EXPECTED_DAY;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DOM, result);

        EXPECTED_DOY = 184;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_DOY, result);

        EXPECTED_QUARTER = 3;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_QUARTER, result);

        EXPECTED_HOUR = 12;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_HOUR, result);

        EXPECTED_MINUTE = 53;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_MINUTE, result);

        EXPECTED_SECONDS = new BigDecimal("37.123000000000");
        decimalResult = r.getDecimalAsBigDecimal(columnIndex++);
        assertEquals(EXPECTED_SECONDS, decimalResult);

        EXPECTED_WEEK = 27;
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_WEEK, result);
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_WEEK, result);

        // VoltDB has a special function to handle WEEKDAY, and it is not the same as DAY_OF_WEEK
        EXPECTED_WEEKDAY = 0;
        if (isHSQL()) {
            // We map WEEKDAY keyword to DAY_OF_WEEK in hsql parser
            EXPECTED_WEEKDAY = EXPECTED_DOW;
        }
        result = r.getLong(columnIndex++);
        assertEquals(EXPECTED_WEEKDAY, result);
    }

    public void testParams() throws NoConnectionsException, IOException, ProcCallException {
        System.out.println("STARTING testParams");
        Client client = getClient();
        ClientResponse cr;
        VoltTable result;

        cr = client.callProcedure("P1.insert", 1, "foo", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        // next one disabled until ENG-3486
        /*cr = client.callProcedure("PARAM_SUBSTRING", "eeoo");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertEquals("eoo", result.fetchRow(0).getString(0));*/

        cr = client.callProcedure("PARAM_ABS", -2);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertEquals(1, result.asScalarLong());
    }

    // NOTE: Avoid trouble by keeping values in order, half-negative, then zero, then half-positive.
    private static final double orderedIds[] = { -125, -25, 0, 25, 125 };
    private static final int ROWCOUNT = orderedIds.length;

    private static final double orderedByStringIds[] = { -125, -25, 0, 125, 25 };
    private static final double orderedByFloatStringIds[] = { -125, -25, 0, 125, 25 };
    private static final double orderedByDecimalStringIds[] = { -25, -125, 0, 25, 125  };

    // NOTE: Be careful about how this array may be indexed by hard-coded column numbers sprinkled through the code
    // -- and especially keep the non-integer columns last.
    // These correspond to the column types of table NUMBER_TYPES, in the order that they are defined and typically selected.
    private static String numTypeNames[] = { "INTEGER", "TINYINT", "SMALLINT", "BIGINT", "FLOAT", "DECIMAL" };
    private static String numFormatNames[] = { "LONG""LONG", "LONG", "LONG", "DOUBLE", "DECIMAL" };
    private static final int COLUMNCOUNT = numTypeNames.length;
    private static final int FLOATCOLINDEX = 4;
    private static final int DECIMALCOLINDEX = 5;

    private static final int VALUECOUNT = ROWCOUNT * COLUMNCOUNT;
    private static final double values[] = new double[VALUECOUNT];
    private static final int NONNEGCOUNT = ((ROWCOUNT + 1) / 2) * COLUMNCOUNT;
    private static final double nonnegs[] = new double[NONNEGCOUNT];
    private static final int POSCOUNT = ((ROWCOUNT - 1) / 2) * COLUMNCOUNT;
    private static final double nonnegnonzeros[] = new double[POSCOUNT];
    static
    {
        assert(numTypeNames[FLOATCOLINDEX].equals("FLOAT"));
        assert(numTypeNames[DECIMALCOLINDEX].equals("DECIMAL"));
        int kk = 0;
        int nn = 0;
        int pp = 0;
        for (int jj = 0; jj < ROWCOUNT; ++jj) {
            for (int ii = 0; ii < COLUMNCOUNT; ++ii) {
                double rawValue = orderedIds[jj] * ((ii < FLOATCOLINDEX) ? 1.0 : 0.01);
                values[kk++] = rawValue;
                if (rawValue >= 0.0) {
                    nonnegs[nn++] = rawValue;
                    if (rawValue > 0.0) {
                        nonnegnonzeros[pp++] = rawValue;
                    }
                }
            }
        }
        assert(NONNEGCOUNT == nn);
        assert(POSCOUNT == pp);
    }

    private static void insertNumbers(Client client, double[] rawData, int nRaws) throws Exception
    {
        client.callProcedure("@AdHoc", "delete from NUMBER_TYPES;");
        // Insert non-negative or all input values with and without whole number and fractional parts.
        for (int kk = 0; kk < nRaws; kk += COLUMNCOUNT) {
            client.callProcedure("NUMBER_TYPES.insert", (int)rawData[kk+0], (int)rawData[kk+1], (int)rawData[kk+2], (int)rawData[kk+3], rawData[kk+FLOATCOLINDEX], String.valueOf(rawData[kk+DECIMALCOLINDEX]));
        }
    }

    private static double normalizeZero(double result) { return (result == -0.0) ? 0.0 : result; }

    private static class FunctionTestCase
    {
        public final String m_case;
        public final double m_result;
        public final double m_filter;

        public FunctionTestCase(String proc, double result)
        {
            m_case = proc;
            m_filter = 0.0;
            // Believe it or not, "negative 0" results were causing problems.
            m_result = normalizeZero(result);
        }
        public FunctionTestCase(String proc, double filter, long result)
        {
            m_case = proc;
            m_filter = normalizeZero(filter);
            m_result = result;
        }
    };

    /**
     * @param expectedFormat
     * @param result
     * @param jj
     * @return
     */
    private double getColumnValue(String expectedFormat, VoltTable result, int jj)
    {
        double value;
        if (expectedFormat == null) {
            if (jj < FLOATCOLINDEX) {
                value = result.getLong(jj);
            }
            else if (jj == FLOATCOLINDEX) {
                value = result.getDouble(jj);
            }
            else {
                value = result.getDecimalAsBigDecimal(jj).doubleValue();
            }
        }
        else if (expectedFormat.equals("LONG")) {
            value = result.getLong(jj);
        }
        else if (expectedFormat.equals("DOUBLE")) {
            value = result.getDouble(jj);
        }
        else {
            value = result.getDecimalAsBigDecimal(jj).doubleValue();
        }
        return value;
    }

    /**
     * @param expectedFormat
     * @param client
     * @param proc
     * @param jj
     * @param filter
     * @return
     * @throws IOException
     * @throws NoConnectionsException
     * @throws ProcCallException
     */
    private static ClientResponse callWithParameter(String expectedFormat, Client client, String proc, int jj, double filter)
            throws IOException, NoConnectionsException, ProcCallException
    {
        ClientResponse cr;
        if (expectedFormat == null) {
            if (jj < FLOATCOLINDEX) {
                cr = client.callProcedure(proc, (int)filter);
            }
            else if (jj == FLOATCOLINDEX) {
                cr = client.callProcedure(proc, filter);
            } else {
                cr = client.callProcedure(proc, BigDecimal.valueOf(filter));
            }
        }
        else if (expectedFormat.equals("LONG")) {
            cr = client.callProcedure(proc, (int)filter);
        }
        else if (expectedFormat.equals("DOUBLE")) {
            cr = client.callProcedure(proc, filter);
        }
        else {
            cr = client.callProcedure(proc, BigDecimal.valueOf(filter));
        }
        return cr;
    }

    private FunctionTestCase[] displayFunctionRun(Client client, String fname, int rowCount, String expectedFormat) throws Exception
    {
        ClientResponse cr;
        VoltTable result;

        FunctionTestCase[] resultSet = new FunctionTestCase[numTypeNames.length * rowCount];
        int ii = 0;

        String proc = "DISPLAY_" + fname;
        cr = client.callProcedure(proc);
        result = cr.getResults()[0];
        assertEquals(rowCount, result.getRowCount());
        while (result.advanceRow()) {
            int jj = 0;
            for (String numTypeName : numTypeNames) {
                double value = getColumnValue(expectedFormat, result, jj);
                resultSet[ii++] = new FunctionTestCase(proc + " " + numTypeName, value);
                ++jj;
            }
        }
        return resultSet;
    }

    private FunctionTestCase[] orderFunctionRun(Client client, String fname, int rowCount) throws Exception
    {
        ClientResponse cr;
        VoltTable result;

        FunctionTestCase[] resultSet = new FunctionTestCase[numTypeNames.length * rowCount];
        int ii = 0;

        for (String numTypeName : numTypeNames) {
            String proc = "ORDER_" + fname + "_" + numTypeName;
            cr = client.callProcedure(proc);
            result = cr.getResults()[0];
            assertEquals(rowCount, result.getRowCount());
            int jj = 0;
            while (result.advanceRow()) {
                try {
                    resultSet[ii] = new FunctionTestCase(proc + " ROW " + jj, result.getLong(0));
                    ii++;
                } catch (IllegalArgumentException iae) {
                    // HSQL has been known to claim that the INTEGERNUM column is being returned as a float -- WTF!
                    resultSet[ii] = new FunctionTestCase(proc + " ROW " + jj, result.getDouble(0));
                    ii++;
                }
                // Extraneous columns beyond the first are provided for debug purposes only
                for (int kk = 1; kk < result.getColumnCount(); ++kk) {
                    if (result.getColumnType(kk) == VoltType.FLOAT) {
                        System.out.println("DEBUG " + proc + " Extra column #" + kk + " = " + result.getDouble(kk));
                    }
                    else if (result.getColumnType(kk) == VoltType.DECIMAL) {
                        System.out.println("DEBUG " + proc + " Extra column #" + kk + " = " + result.getDecimalAsBigDecimal(kk));
                    }
                    else if (result.getColumnType(kk) == VoltType.STRING) {
                        System.out.println("DEBUG " + proc + " Extra column #" + kk + " = " + result.getString(kk));
                    }
                    else {
                        System.out.println("DEBUG " + proc + " Extra column #" + kk + " = " + result.getLong(kk));
                    }
                }
                ++jj;
            }
        }
        return resultSet;
    }

    private FunctionTestCase[] whereFunctionRun(Client client, String fname, Set<Double> filters, String expectedFormat) throws Exception
    {
        ClientResponse cr;
        VoltTable result;

        FunctionTestCase[] resultSet = new FunctionTestCase[numTypeNames.length * filters.size()];
        int kk = 0;
        int jj = 0;
        for (String numTypeName : numTypeNames) {
            for (double filter : filters) {
                String proc = "WHERE_" + fname + "_" + numTypeName;
                cr = callWithParameter(expectedFormat, client, proc, jj, filter);
                result = cr.getResults()[0];
                int rowCount = result.getRowCount();
                assertEquals(rowCount, 1);
                resultSet[kk++] = new FunctionTestCase(proc, filter, result.asScalarLong());
            }
            ++jj;
        }
        return resultSet;
    }

    private static int complaintCount = 1;
    private static void complain(String complaint)
    {
        System.out.println("Complaint #" + complaintCount + ": " + complaint);
        ++complaintCount; // NICE PLACE FOR A BREAKPOINT.
    }

    static String formatForFuzziness = "%14e";
    private void functionTest(String fname, double rawData[], double[] resultValues, Set<Double> filters,
                              boolean monotonic, boolean ascending, String expectedFormat) throws Exception
    {
        System.out.println("STARTING test of " + fname);

        Client client = getClient();
        insertNumbers(client, rawData, resultValues.length);

        FunctionTestCase[] results;

        results = displayFunctionRun(client, fname, resultValues.length / COLUMNCOUNT, expectedFormat);

        assertEquals(results.length, resultValues.length);

        Map<String, Integer> valueBag = new HashMap<String, Integer>();
        int kk = 0;
        for (FunctionTestCase result : results) {
            double expected = resultValues[kk++];
            if (expected != result.m_result) {
                // Compromise: accuracy errors get complaints but not asserts.
                complain("Failed " + result.m_case + " expected " + expected + " got " + result.m_result);
            }
            // Use precision-limited string formatting to forgive accuracy errors between the C++ and java floating point function implementations.
            String asExpected = String.format(formatForFuzziness, expected);
            String asResulted = String.format(formatForFuzziness, result.m_result);
            assertEquals(asExpected, asResulted);
            // count occurrences of expected values in anticipation of the WHERE_ tests.
            Integer count = valueBag.get(asExpected);
            if (count == null) {
                count = 0;
            }
            valueBag.put(asExpected, count + 1);
            //*VERBOSIFY TO DEBUG:*/ System.out.println("UPDATING " + result.m_case + " found count of " + asExpected + " to " + (count+1) );
        }

        if (monotonic) {
            // Validate that sorting on the function value does not alter the ordering of its input values.
            results = orderFunctionRun(client, fname, resultValues.length/COLUMNCOUNT);

            // The total number of ordered INTEGERNUM values returned should be the same as the number of stored values.
            assertEquals(results.length, resultValues.length);
            // If not using ALL values of orderedIds for this run, skip early (negative) values to only match later ones.
            int skippedIds = ROWCOUNT - resultValues.length / COLUMNCOUNT;
            if (ascending) {
                kk = skippedIds;
            } else {
                kk = ROWCOUNT-1;
            }
            for (FunctionTestCase result : results) {
                int idIndex;
                if (ascending) {
                    idIndex = kk++;
                    // skip early id values again at the end of each order by query result.
                    if (kk == ROWCOUNT) {
                        kk = skippedIds;
                    }
                } else {
                    idIndex = kk--;
                    if (kk == skippedIds-1) {
                        kk = ROWCOUNT-1;
                    }
                }
                double expected = orderedIds[idIndex];
                if (expected != result.m_result) {
                    complain("Failed " + result.m_case + " expected " + expected + " got " + result.m_result);
                }
                assertEquals(expected, result.m_result);
            }
        }

        results = whereFunctionRun(client, fname, filters, expectedFormat);

        assertEquals(results.length, COLUMNCOUNT*filters.size());
        // If filters represents all the values in resultValues,
        // the filtered counts should total to resultValues.length.
        int coveringCount = resultValues.length;
        //*VERBOSIFY TO DEBUG:*/ System.out.println("EXPECTING total count" + coveringCount);
        for (FunctionTestCase result : results) {
            if (result.m_result == 0.0) {
                // complain("NONMATCHING filter " + result.m_case + " " + result.m_filter);
                continue;
            }
            Integer count = valueBag.get(String.format(formatForFuzziness, result.m_filter));
            if (count == null) {
                complain("Function " + fname + " got unexpected result " + result.m_filter + ".");
            }
            assertNotNull(count);
            //*VERBOSIFY TO DEBUG:*/ System.out.println("REDUCING " + result.m_case + " unfound " + result.m_filter + " count " + count + " by " + result.m_result );
            if (count < result.m_result) {
                complain(result.m_case + " value " + result.m_filter + " not expected or previously depleted from " + valueBag + ".");
            }
            assertTrue(count >= result.m_result);
            valueBag.put(String.format(formatForFuzziness, result.m_filter), count-(int)result.m_result);
            coveringCount -= (int)result.m_result;
            //*VERBOSIFY TO DEBUG:*/ System.out.println("DROPPING TOTAL TO " + coveringCount);
        }
        for (Entry<String, Integer> entry : valueBag.entrySet()) {
            int count = entry.getValue();
            if (count != 0) {
                complain("Function " + fname + " expected result " + entry.getKey() + " lacks " + count + " matches.");
            }
            assertEquals(0, count);
        }
        assertEquals(0, coveringCount);

        System.out.println("ENDING test of " + fname);
    }

    public void testManyNumericFunctions() throws Exception
    {
        subtestFromVarCharCasts();
        subtestToVarCharCasts();
        subtestNumericCasts();
        subtestCeiling();
        subtestExp();
        subtestFloor();
        subtestPowerx7();
        subtestPowerx07();
        subtestPower7x();
        subtestPower07x();
        subtestSqrt();
    }

    public void subtestCeiling() throws Exception
    {
        String fname = "CEILING";
        final double[] resultValues = new double[values.length];
        final Set<Double> filters = new HashSet<Double>();
        for (int kk = 0; kk < resultValues.length; ++kk) {
            // Believe it or not, "negative 0" results were causing problems.
            resultValues[kk] = normalizeZero(Math.ceil(values[kk]));
            filters.add(resultValues[kk]);
        }
        final boolean monotonic = true;
        final boolean ascending = true;
        final String expectedFormat = null; // column/parameter values are variously typed.
        functionTest(fname, values, resultValues, filters, monotonic, ascending, expectedFormat);
    }

    public void subtestExp() throws Exception
    {
        String fname = "EXP";
        final double[] resultValues = new double[values.length];
        final Set<Double> filters = new HashSet<Double>();
        for (int kk = 0; kk < resultValues.length; ++kk) {
            resultValues[kk] = Math.exp(values[kk]);
            filters.add(resultValues[kk]);
        }
        final boolean monotonic = true;
        final boolean ascending = true;
        final String expectedFormat = "DOUBLE";
        functionTest(fname, values, resultValues, filters, monotonic, ascending, expectedFormat);
    }

    public void subtestFloor() throws Exception
    {
        String fname = "FLOOR";
        final double[] resultValues = new double[values.length];
        final Set<Double> filters = new HashSet<Double>();
        for (int kk = 0; kk < resultValues.length; ++kk) {
            resultValues[kk] = Math.floor(values[kk]);
            filters.add(resultValues[kk]);
        }
        final boolean monotonic = true;
        final boolean ascending = true;
        final String expectedFormat = null;
        functionTest(fname, values, resultValues, filters, monotonic, ascending, expectedFormat);

    }

    public void subtestPowerx7() throws Exception
    {
        final String fname = "POWERX7";
        final double[] resultValues = new double[values.length];
        final Set<Double> filters = new HashSet<Double>();
        for (int kk = 0; kk < resultValues.length; ++kk) {
            resultValues[kk] = Math.pow(values[kk], 7.0);
            filters.add(resultValues[kk]);
        }
        final boolean monotonic = true;
        final boolean ascending = true;
        final String expectedFormat = "DOUBLE";
        functionTest(fname, values, resultValues, filters, monotonic, ascending, expectedFormat);
    }

    public void subtestPowerx07() throws Exception
    {
        final String fname = "POWERX07";
        final double[] resultValues = new double[nonnegnonzeros.length];
        final Set<Double> filters = new HashSet<Double>();
        for (int kk = 0; kk < resultValues.length; ++kk) {
            resultValues[kk] = Math.pow(nonnegnonzeros[kk], 0.7);
            filters.add(resultValues[kk]);
        }
        final boolean monotonic = true;
        final boolean ascending = true;
        final String expectedFormat = "DOUBLE";
        functionTest(fname, nonnegnonzeros, resultValues, filters, monotonic, ascending, expectedFormat);
    }

    public void subtestPower7x() throws Exception
    {
        final String fname = "POWER7X";
        final double[] resultValues = new double[values.length];
        final Set<Double> filters = new HashSet<Double>();
        for (int kk = 0; kk < resultValues.length; ++kk) {
            resultValues[kk] = Math.pow(7.0, values[kk]);
            filters.add(resultValues[kk]);
        }
        final boolean monotonic = true;
        final boolean ascending = true;
        final String expectedFormat = "DOUBLE";
        functionTest(fname, values, resultValues, filters, monotonic, ascending, expectedFormat);
    }

    public void subtestPower07x() throws Exception
    {
        final String fname = "POWER07X";
        final double[] resultValues = new double[values.length];
        final Set<Double> filters = new HashSet<Double>();
        for (int kk = 0; kk < resultValues.length; ++kk) {
            resultValues[kk] = Math.pow(0.7, values[kk]);
            filters.add(resultValues[kk]);
        }
        final boolean monotonic = true;
        final boolean ascending = false;
        final String expectedFormat = "DOUBLE";
        functionTest(fname, values, resultValues, filters, monotonic, ascending, expectedFormat);
    }

    public void subtestSqrt() throws Exception
    {
        final String fname = "SQRT";
        final double[] resultValues = new double[nonnegs.length];
        final Set<Double> filters = new HashSet<Double>();
        for (int kk = 0; kk < resultValues.length; ++kk) {
            resultValues[kk] = Math.sqrt(nonnegs[kk]);
            filters.add(resultValues[kk]);
        }
        final boolean monotonic = true;
        final boolean ascending = true;
        final String expectedFormat = "DOUBLE";
        functionTest(fname, nonnegs, resultValues, filters, monotonic, ascending, expectedFormat);
    }

    private static class FunctionVarCharTestCase
    {
        public final String m_case;
        public final String m_filter;
        public final long m_result;

        public FunctionVarCharTestCase(String proc, String filter)
        {
            m_case = proc;
            m_filter = filter;
            m_result = 0;
        }
        public FunctionVarCharTestCase(String proc, String filter, long l)
        {
            m_case = proc;
            m_filter = filter;
            m_result = l;
        }
    };

    private FunctionVarCharTestCase[] displayVarCharCastRun(Client client, int rowCount) throws Exception
    {
        ClientResponse cr;
        VoltTable result;

        FunctionVarCharTestCase[] resultSet = new FunctionVarCharTestCase[numTypeNames.length * rowCount];
        int ii = 0;

        String proc = "DISPLAY_VARCHAR";
        cr = client.callProcedure(proc);
        result = cr.getResults()[0];
        assertEquals(rowCount, result.getRowCount());
        while (result.advanceRow()) {
            int jj = 0;
            for (String numTypeName : numTypeNames) {
                String tooSimple = result.getString(jj);
                String value = Double.valueOf(tooSimple).toString();
                //*VERBOSIFY TO DEBUG:*/ System.out.println("DEBUG " + proc + " " + numTypeName + " GOT " + tooSimple + " into " + value);
                resultSet[ii++] = new FunctionVarCharTestCase(proc + " " + numTypeName, value);
                ++jj;
            }
        }
        return resultSet;
    }

    private FunctionVarCharTestCase[] whereVarCharCastRun(Client client, Set<String> filters) throws Exception
    {
        ClientResponse cr;
        VoltTable result;

        FunctionVarCharTestCase[] resultSet = new FunctionVarCharTestCase[numTypeNames.length * filters.size()];
        int kk = 0;
        int jj = 0;
        for (String numTypeName : numTypeNames) {
            for (String filter : filters) {
                String proc = "WHERE_VARCHAR_CAST_" + numTypeName;
                String param = filter;
                String[] decimalParts = filter.split("\\.");
                if (jj < FLOATCOLINDEX) {
                    // Truncate an integer decimal before the decimal point to match an integer column.
                    if (decimalParts.length < 2 || decimalParts[1].equals("0")) {
                        param = decimalParts[0];
                    }
                    // Else fall through to pass a fractional decimal as it is
                    // to purposely force a mismatch with an integer column.
                }
                else if (jj > FLOATCOLINDEX) {
                    // Pad the decimal string.
                    if (decimalParts.length < 2 || decimalParts[1].equals("0")) {
                        param = decimalParts[0] + ".000000000000";
                    }
                    else {
                        param = decimalParts[0] + "." + (decimalParts[1] + "000000000000").substring(0,12);
                    }
                }
                // Handle float-to-string cast formatting
                // TODO: this code may not be right for multiples of 10 or decimals of magnitude < .1
                // which we don't happen to be using currently to drive this numeric test framework.
                else {
                    if (decimalParts.length < 2 || decimalParts[1].equals("0")) {
                        if (decimalParts[0].equals("0")) {
                            param = "0E0";
                        }
                        else {
                            int signedDigitWidth = (decimalParts[0].charAt(0) == '-') ? 2 : 1;
                            param = decimalParts[0].substring(0, signedDigitWidth) +
                                    "." + decimalParts[0].substring(signedDigitWidth) +
                                    "E" + (decimalParts[0].length() - signedDigitWidth);
                        }
                    }
                    else {
                        if (decimalParts[0].equals("0")) {
                            param = decimalParts[1].substring(0, 1) +
                                    "." + decimalParts[1].substring(1) + "E-1";
                        }
                        else if (decimalParts[0].equals("-0") ) {
                            param = "-" + decimalParts[1].substring(0, 1) +
                                    "." + decimalParts[1].substring(1) + "E-1";
                        }
                        else {
                            int signedDigitWidth = (decimalParts[0].charAt(0) == '-') ? 2 : 1;
                            param = decimalParts[0].substring(0, signedDigitWidth) +
                                    "." + decimalParts[0].substring(signedDigitWidth) + decimalParts[1] +
                                    "E" + (decimalParts[0].length() - signedDigitWidth);
                        }
                    }
                }
                cr = client.callProcedure(proc, param);
                result = cr.getResults()[0];
                int rowCount = result.getRowCount();
                assertEquals(rowCount, 1);
                long tupleCount = result.asScalarLong();
                //*VERBOSIFY TO DEBUG:*/ System.out.println("DEBUG " + proc + " " + numTypeName + " GOT count " + tupleCount);
                resultSet[kk++] = new FunctionVarCharTestCase(proc, filter, tupleCount);
            }
            ++jj;
        }
        return resultSet;
    }

    public void subtestNumericCasts() throws Exception
    {
        System.out.println("STARTING test of numeric CAST");
        final double[] rawData = values;
        final double[] resultIntValues = new double[values.length];
        final Set<Double> intFilters = new HashSet<Double>();
        final Set<Double> rawFilters = new HashSet<Double>();
        for (int kk = 0; kk < resultIntValues.length; ++kk) {
            resultIntValues[kk] = (int)values[kk];
            intFilters.add(resultIntValues[kk]);
            rawFilters.add(values[kk]);
        }

        Client client = getClient();
        insertNumbers(client, rawData, rawData.length);

        FunctionTestCase[] results;
        double[] resultValues;
        Set<Double> filters;

        for (int jj = 0; jj < numTypeNames.length ; ++jj) {
            if (numFormatNames[jj].equals("DECIMAL") || numFormatNames[jj].equals("DOUBLE")) {
                results = displayFunctionRun(client, numTypeNames[jj], values.length / COLUMNCOUNT, numFormatNames[jj]);
                resultValues = rawData;
                filters = rawFilters;
            }
            else {
                results = displayFunctionRun(client, numTypeNames[jj], values.length / COLUMNCOUNT, numFormatNames[jj]);
                resultValues = resultIntValues;
                filters = intFilters;
            }
            assertEquals(results.length, values.length);

            Map<String, Integer> valueBag = new HashMap<String, Integer>();
            int kk = 0;
            for (FunctionTestCase result : results) {
                double expected = resultValues[kk++];
                if (expected != result.m_result) {
                    // Compromise: accuracy errors get complaints but not asserts.
                    complain("Failed " + result.m_case + " expected " + expected + " got " + result.m_result);
                }
                // Use precision-limited string formatting to forgive accuracy errors between the C++ and java floating point function implementations.
                String asExpected = String.format(formatForFuzziness, expected);
                String asResulted = String.format(formatForFuzziness, result.m_result);
                assertEquals(asExpected, asResulted);
                // count occurrences of expected values in anticipation of the WHERE_ tests.
                Integer count = valueBag.get(asExpected);
                if (count == null) {
                    count = 0;
                }
                valueBag.put(asExpected, count + 1);
                //*VERBOSIFY TO DEBUG:*/ System.out.println("UPDATING " + result.m_case + " found count of " + asExpected + " to " + (count+1) );
            }

            // Validate that sorting on the function value does not alter the ordering of its input values.
            results = orderFunctionRun(client, numTypeNames[jj+ "_CAST", resultValues.length/COLUMNCOUNT);

            // The total number of ordered INTEGERNUM values returned should be the same as the number of stored values.
            assertEquals(results.length, resultValues.length);
            kk = 0;
            for (FunctionTestCase result : results) {
                int idIndex = kk++;
                if (kk == ROWCOUNT) {
                    kk = 0;
                }
                double expected = orderedIds[idIndex];
                if (expected != result.m_result) {
                    complain("Failed " + result.m_case + " expected " + expected + " got " + result.m_result);
                }
                assertEquals(expected, result.m_result);
            }

            results = whereFunctionRun(client, numTypeNames[jj] + "_CAST", filters, numFormatNames[jj]);

            assertEquals(results.length, COLUMNCOUNT*filters.size());
            // If filters represents all the values in resultValues,
            // the filtered counts should total to resultValues.length.
            int coveringCount = resultValues.length;
            //*VERBOSIFY TO DEBUG:*/ System.out.println("EXPECTING total count" + coveringCount);
            for (FunctionTestCase result : results) {
                if (result.m_result == 0.0) {
                    // complain("NONMATCHING filter " + result.m_case + " " + result.m_filter);
                    continue;
                }
                Integer count = valueBag.get(String.format(formatForFuzziness, result.m_filter));
                if (count == null) {
                    complain("CAST got unexpected result " + result.m_filter + ".");
                }
                assertNotNull(count);
                //*VERBOSIFY TO DEBUG:*/ System.out.println("REDUCING " + result.m_case + " unfound " + result.m_filter + " count " + count + " by " + result.m_result );
                if (count < result.m_result) {
                    complain(result.m_case + " value " + result.m_filter + " not expected or previously depleted from " + valueBag + ".");
                }
                assertTrue(count >= result.m_result);
                valueBag.put(String.format(formatForFuzziness, result.m_filter), count-(int)result.m_result);
                coveringCount -= (int)result.m_result;
                //*VERBOSIFY TO DEBUG:*/ System.out.println("DROPPING TOTAL TO " + coveringCount);
            }
            for (Entry<String, Integer> entry : valueBag.entrySet()) {
                int count = entry.getValue();
                if (count != 0) {
                    complain("CAST expected result " + entry.getKey() + " lacks " + count + " matches.");
                }
                assertEquals(0, count);
            }
            assertEquals(0, coveringCount);
        }


        System.out.println("ENDING test of numeric CAST");
    }

    private static void insertNumbersViaVarChar(Client client, double[] rawData, int nRaws) throws Exception
    {
        client.callProcedure("@AdHoc", "delete from NUMBER_TYPES;");
        // Insert inputs via string values to test casts from VARCHAR
        for (int kk = 0; kk < nRaws; kk += COLUMNCOUNT) {
            client.callProcedure("@AdHoc",
                                 "INSERT INTO NUMBER_TYPES VALUES (" +
                                 "CAST('" + (int)rawData[kk+0] + "' AS " + numTypeNames[0] + "),  " +
                                 "CAST('" + (int)rawData[kk+1] + "' AS " + numTypeNames[1] + "),  " +
                                 "CAST('" + (int)rawData[kk+2] + "' AS " + numTypeNames[2] + "),  " +
                                 "CAST('" + (int)rawData[kk+3] + "' AS " + numTypeNames[3] + "),  " +
                                 "CAST('" + rawData[kk+FLOATCOLINDEX]   + "' AS FLOAT         ),  " +
                                 "CAST('" + rawData[kk+DECIMALCOLINDEX] + "' AS DECIMAL       ) );");
        }
    }

    private void subtestFromVarCharCasts() throws Exception
    {
        System.out.println("STARTING test of FROM VARCHAR CAST");
        Client client = getClient();
        insertNumbersViaVarChar(client, values, values.length);
        System.out.println("VALIDATING result of 'FROM VARCHAR' CAST via results of 'TO VARCHAR' CASTS");
        subtestVarCharCasts(client);
        System.out.println("ENDING test of FROM VARCHAR CAST");
    }

    private void subtestToVarCharCasts() throws Exception
    {
        System.out.println("STARTING test of TO VARCHAR CAST");
        Client client = getClient();
        insertNumbers(client, values, values.length);
        subtestVarCharCasts(client);
        subtestInlineVarCharCast(client);
        System.out.println("ENDING test of TO VARCHAR CAST");
    }

    private void subtestInlineVarCharCast(Client client) throws Exception {
        // This is regression test coverage for ENG-6666.
        String sql = "INSERT INTO INLINED_VC_VB_TABLE (ID, VC1, VC2, VB1, VB2) " +
            "VALUES (22, 'FOO', 'BAR', 'DEADBEEF', 'CDCDCDCD');";
        client.callProcedure("@AdHoc", sql);
        sql = "SELECT CAST(VC1 AS VARCHAR) FROM INLINED_VC_VB_TABLE WHERE ID = 22;";
        VoltTable vt = client.callProcedure("@AdHoc", sql).getResults()[0];
        vt.advanceRow();
        assertEquals("FOO", vt.getString(0));

        sql = "SELECT CAST(VB1 AS VARBINARY) FROM INLINED_VC_VB_TABLE WHERE ID = 22;";
        vt = client.callProcedure("@AdHoc", sql).getResults()[0];
        vt.advanceRow();
        assertTrue(VoltType.varbinaryToPrintableString(vt.getVarbinary(0)).contains("DEADBEEF"));
    }

    private void subtestVarCharCasts(Client client) throws Exception
    {
        final String[] resultValues = new String[values.length];
        final Set<String> filters = new HashSet<String>();
        for (int kk = 0; kk < resultValues.length; ++kk) {
            resultValues[kk] = "" + values[kk];
            filters.add(resultValues[kk]);
        }

        FunctionVarCharTestCase[] results;

        results = displayVarCharCastRun(client, values.length / COLUMNCOUNT);
        assertEquals(results.length, values.length);

        Map<String, Integer> valueBag = new HashMap<String, Integer>();
        int kk = 0;
        for (FunctionVarCharTestCase result : results) {
            String expected = resultValues[kk++];
            if (! expected.equals(result.m_filter)) {
                // Compromise: accuracy errors get complaints but not asserts.
                complain("Failed " + result.m_case + " expected " + expected + " got " + result.m_filter);
            }
            assertEquals(expected, result.m_filter);
            // count occurrences of expected values in anticipation of the WHERE_ tests.
            Integer count = valueBag.get(expected);
            if (count == null) {
                count = 0;
            }
            valueBag.put(expected, count + 1);
            //*VERBOSIFY TO DEBUG:*/ System.out.println("UPDATING " + result.m_case + " found count of " + expected + " to " + (count+1) );
        }

        results = whereVarCharCastRun(client, filters);

        assertEquals(results.length, COLUMNCOUNT*filters.size());
        // If filters represents all the values in resultValues,
        // the filtered counts should total to resultValues.length.
        int coveringCount = resultValues.length;
        //*VERBOSIFY TO DEBUG:*/ System.out.println("EXPECTING total count" + coveringCount);
        for (FunctionVarCharTestCase result : results) {
            Integer count = valueBag.get(result.m_filter);
            if (count == null) {
                complain("CAST got unexpected result " + result.m_filter + ".");
            }
            assertNotNull(count);
            //*VERBOSIFY TO DEBUG:*/ System.out.println("VARCHAR REDUCING " + result.m_case + " unfound " + result.m_filter + " count " + count + " by " + result.m_result );
            if (count < result.m_result) {
                complain(result.m_case + " value " + result.m_filter + " not expected or previously depleted from " + valueBag + ".");
            }
            assertTrue(count >= result.m_result);
            valueBag.put(result.m_filter, count-(int)result.m_result);
            coveringCount -= (int)result.m_result;
            //*VERBOSIFY TO DEBUG:*/ System.out.println("DROPPING TOTAL TO " + coveringCount);
        }
        for (Entry<String, Integer> entry : valueBag.entrySet()) {
            int count = entry.getValue();
            if (count != 0) {
                complain("VARCHAR CAST expected result " + entry.getKey() + " lacks " + count + " matches.");
            }
            assertEquals(0, count); // Ideally FLOAT behaves in some reasonable standard way.
        }
        assertEquals(0, coveringCount); // Ideally FLOAT behaves in some reasonable standard way.
        //assertTrue(0 == coveringCount /*I WISH*/ || 5 == coveringCount /* former near miss */ );


        // Validate how sorting on the string value alters the ordering of its input values.
        FunctionTestCase[] orderedResults = orderFunctionRun(client, "VARCHAR_CAST", values.length/COLUMNCOUNT);

        // The total number of ordered INTEGERNUM values returned should be the same as the number of stored values.
        assertEquals(values.length, orderedResults.length);
        kk = 0;
        int jj = 0;
        for (FunctionTestCase result : orderedResults) {
            int idIndex = kk++;
            if (kk == ROWCOUNT) {
                kk = 0;
            }
            double[] expecteds = (jj/ROWCOUNT < FLOATCOLINDEX) ? orderedByStringIds :
                (jj/ROWCOUNT > FLOATCOLINDEX) ? orderedByDecimalStringIds : orderedByFloatStringIds;
            if (expecteds[idIndex] != result.m_result) {
                complain("Failed " + result.m_case + " expected " + expecteds[idIndex] + " got " + result.m_result);
            }
            assertEquals(expecteds[idIndex], result.m_result);
            ++jj;
        }
    }

    public void testLeftAndRight() throws NoConnectionsException, IOException, ProcCallException {
        System.out.println("STARTING Left and Right");
        Client client = getClient();
        ClientResponse cr;
        VoltTable result;

        cr = client.callProcedure("P1.insert", 1, "贾鑫Vo", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        // test LEFT function
        cr = client.callProcedure("LEFT", 0, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("", result.getString(1));

        cr = client.callProcedure("LEFT", 1, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("贾", result.getString(1));

        cr = client.callProcedure("LEFT", 2, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("贾鑫", result.getString(1));

        cr = client.callProcedure("LEFT", 3, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("贾鑫V", result.getString(1));

        cr = client.callProcedure("LEFT", 4, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("贾鑫Vo", result.getString(1));

        cr = client.callProcedure("LEFT", 5, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("贾鑫Vo", result.getString(1));

        // invalid case
        Exception ex = null;
        try {
            cr = client.callProcedure("LEFT", -1, 1);
        } catch (Exception e) {
            assertTrue(e instanceof ProcCallException);
            ex = e;
        } finally {
            assertNotNull(ex);
        }

        // test RIGHT function
        cr = client.callProcedure("RIGHT", 0, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("", result.getString(1));

        cr = client.callProcedure("RIGHT", 1, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("o", result.getString(1));

        cr = client.callProcedure("RIGHT", 2, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("Vo", result.getString(1));

        cr = client.callProcedure("RIGHT", 3, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("鑫Vo", result.getString(1));

        cr = client.callProcedure("RIGHT", 4, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("贾鑫Vo", result.getString(1));

        cr = client.callProcedure("RIGHT", 5, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("贾鑫Vo", result.getString(1));

        ex = null;
        try {
            cr = client.callProcedure("RIGHT", -1, 1);
        } catch (Exception e) {
            assertTrue(e instanceof ProcCallException);
            ex = e;
        } finally {
            assertNotNull(ex);
        }
    }

    public void testSpace() throws NoConnectionsException, IOException, ProcCallException {
        System.out.println("STARTING test Space");
        Client client = getClient();
        ClientResponse cr;
        VoltTable result;

        cr = client.callProcedure("P1.insert", 1, "foo", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        cr = client.callProcedure("SPACE", 0, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("", result.getString(1));

        cr = client.callProcedure("SPACE", 1, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals(" ", result.getString(1));

        cr = client.callProcedure("SPACE", 5, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("     ", result.getString(1));
    }


    public void testLowerUpper() throws NoConnectionsException, IOException, ProcCallException {
        System.out.println("STARTING test Space");
        Client client = getClient();
        ClientResponse cr;
        VoltTable result;

        cr = client.callProcedure("P1.insert", 1, "VoltDB", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        cr = client.callProcedure("LOWER_UPPER", 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("voltdb", result.getString(1));
        assertEquals("VOLTDB", result.getString(2));


        cr = client.callProcedure("P1.insert", 2, "VoltDB贾鑫", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        cr = client.callProcedure("LOWER_UPPER", 2);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("voltdb贾鑫", result.getString(1));
        assertEquals("VOLTDB贾鑫", result.getString(2));


        cr = client.callProcedure("P1.insert", 3, null, 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        cr = client.callProcedure("LOWER_UPPER", 3);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals(null, result.getString(1));
        assertEquals(null, result.getString(2));

        // Edge case: UTF-8 string can have Upper and Lower cases
        String grussen = "grüßEN";
        cr = client.callProcedure("P1.insert", 4, grussen, 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        cr = client.callProcedure("LOWER_UPPER", 4);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());

        // Turn on this test case when EE supports the locale CASE conversion
//        if (isHSQL()) {
//            assertEquals(grussen, result.getString(1));
//            assertEquals(grussen, result.getString(2));
//        } else {
//            assertEquals("GRÜSSEN", result.getString(1));
//            assertEquals("grüßen", result.getString(2));
//        }
    }

    public void testTrim() throws NoConnectionsException, IOException, ProcCallException {
        System.out.println("STARTING test Trim");
        Client client = getClient();
        ClientResponse cr;
        VoltTable result;

        cr = client.callProcedure("P1.insert", 1, "  VoltDB   ", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        result = client.callProcedure("@AdHoc", "select trim(LEADING null from desc) from P1").getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals(null, result.getString(0));

        cr = client.callProcedure("TRIM_SPACE", 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("VoltDB   ", result.getString(1));
        assertEquals("VoltDB   ", result.getString(2));
        assertEquals("  VoltDB",  result.getString(3));
        assertEquals("  VoltDB",  result.getString(4));
        assertEquals("VoltDB",  result.getString(5));
        assertEquals("VoltDB",  result.getString(6));


        cr = client.callProcedure("TRIM_ANY", " ", " ", " ", 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("VoltDB   ", result.getString(1));
        assertEquals("  VoltDB",  result.getString(2));
        assertEquals("VoltDB",  result.getString(3));

        try {
            cr = client.callProcedure("TRIM_ANY", "", "", "", 1);
            fail();
        } catch (Exception ex) {
            assertTrue(ex.getMessage().contains("data exception"));
            assertTrue(ex.getMessage().contains("trim error"));
        }

        // Test TRIM with other character
        cr = client.callProcedure("P1.insert", 2, "vVoltDBBB", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        cr = client.callProcedure("TRIM_ANY", "v", "B", "B", 2);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("VoltDBBB", result.getString(1));
        assertEquals("vVoltD", result.getString(2));
        assertEquals("vVoltD", result.getString(3));

        // Multiple character trim, Hsql does not support
        if (!isHSQL()) {
            cr = client.callProcedure("TRIM_ANY", "vV", "BB", "Vv", 2);
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            result = cr.getResults()[0];
            assertEquals(1, result.getRowCount());
            assertTrue(result.advanceRow());
            assertEquals("oltDBBB", result.getString(1));
            assertEquals("vVoltDB", result.getString(2));
            assertEquals("vVoltDBBB", result.getString(3));
        }

        // Test null trim character
        cr = client.callProcedure("TRIM_ANY", null, null, null, 2);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals(null, result.getString(1));
        assertEquals(null, result.getString(2));
        assertEquals(null, result.getString(3));


        // Test non-ASCII trim_char
        cr = client.callProcedure("P1.insert", 3, "贾vVoltDBBB", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        cr = client.callProcedure("TRIM_ANY", "贾", "v", "贾", 3);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("vVoltDBBB", result.getString(1));
        assertEquals("贾vVoltDBBB", result.getString(2));
        assertEquals("vVoltDBBB", result.getString(3));

        if (!isHSQL()) {
            // Complete match
            cr = client.callProcedure("TRIM_ANY", "贾vVoltDBBB", "贾vVoltDBBB", "贾vVoltDBBB", 3);
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            result = cr.getResults()[0];
            assertEquals(1, result.getRowCount());
            assertTrue(result.advanceRow());
            assertEquals("", result.getString(1));
            assertEquals("", result.getString(2));
            assertEquals("", result.getString(3));

            cr = client.callProcedure("TRIM_ANY", "贾vVoltDBBB_TEST", "贾vVoltDBBB贾vVoltDBBB", "贾vVoltDBBBT", 3);
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            result = cr.getResults()[0];
            assertEquals(1, result.getRowCount());
            assertTrue(result.advanceRow());
            assertEquals("贾vVoltDBBB", result.getString(1));
            assertEquals("贾vVoltDBBB", result.getString(2));
            assertEquals("贾vVoltDBBB", result.getString(3));
        }

        // Complicated test
        cr = client.callProcedure("P1.insert", 4, "贾贾vVoltDBBB贾贾贾", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        // UTF-8 hex, 贾: 0xe8 0xb4 0xbe, 辴: 0xe8 0xbe 0xb4
        cr = client.callProcedure("TRIM_ANY", "辴", "辴", "辴", 4);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("贾贾vVoltDBBB贾贾贾", result.getString(1));
        assertEquals("贾贾vVoltDBBB贾贾贾", result.getString(2));
        assertEquals("贾贾vVoltDBBB贾贾贾", result.getString(3));

        cr = client.callProcedure("TRIM_ANY", "贾", "贾", "贾", 4);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("vVoltDBBB贾贾贾", result.getString(1));
        assertEquals("贾贾vVoltDBBB", result.getString(2));
        assertEquals("vVoltDBBB", result.getString(3));

        if (!isHSQL()) {
            cr = client.callProcedure("TRIM_ANY", "贾辴", "贾辴", "贾辴", 4);
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            result = cr.getResults()[0];
            assertEquals(1, result.getRowCount());
            assertTrue(result.advanceRow());
            assertEquals("贾贾vVoltDBBB贾贾贾", result.getString(1));
            assertEquals("贾贾vVoltDBBB贾贾贾", result.getString(2));
            assertEquals("贾贾vVoltDBBB贾贾贾", result.getString(3));

            cr = client.callProcedure("TRIM_ANY", "贾贾vV", "贾贾", "B贾贾贾", 4);
            assertEquals(ClientResponse.SUCCESS, cr.getStatus());
            result = cr.getResults()[0];
            assertEquals(1, result.getRowCount());
            assertTrue(result.advanceRow());
            assertEquals("oltDBBB贾贾贾", result.getString(1));
            assertEquals("贾贾vVoltDBBB贾", result.getString(2));
            assertEquals("贾贾vVoltDBB", result.getString(3));
        }

        cr = client.callProcedure("P1.insert", 5, "vVoltADBDB", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

    }

    public void testRepeat() throws NoConnectionsException, IOException, ProcCallException {
        System.out.println("STARTING test Repeat");
        Client client = getClient();
        ClientResponse cr;
        VoltTable result;

        cr = client.callProcedure("P1.insert", 1, "foo", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        cr = client.callProcedure("REPEAT", 0, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("", result.getString(1));

        cr = client.callProcedure("REPEAT", 1, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("foo", result.getString(1));

        cr = client.callProcedure("REPEAT", 3, 1);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        assertEquals(1, result.getRowCount());
        assertTrue(result.advanceRow());
        assertEquals("foofoofoo", result.getString(1));
    }

    public void testReplace() throws NoConnectionsException, IOException, ProcCallException {
        System.out.println("STARTING test Replace");
        Client client = getClient();
        ClientResponse cr;
        VoltTable result;

        cr = client.callProcedure("P1.insert", 1, "foo", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        result = client.callProcedure("REPLACE", "o", "XX", 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("fXXXX", result.getString(1));

        result = client.callProcedure("REPLACE", "o", null, 1).getResults()[0];
        assertTrue(result.advanceRow());
        if (isHSQL()) {
            // NULL means empty string for Hsql
            assertEquals("f", result.getString(1));
        } else {
            assertEquals(null, result.getString(1));
        }

        result = client.callProcedure("REPLACE", null, "XX", 1).getResults()[0];
        assertTrue(result.advanceRow());
        if (isHSQL()) {
            // NULL means not change for the original string for Hsql
            assertEquals("foo", result.getString(1));
        } else {
            assertEquals(null, result.getString(1));
        }

        result = client.callProcedure("REPLACE", "fo", "V", 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("Vo", result.getString(1));

        // UTF-8 String
        cr = client.callProcedure("P1.insert", 2, "贾鑫@VoltDB", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        result = client.callProcedure("REPLACE", "鑫", "XX", 2).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("贾XX@VoltDB", result.getString(1));
    }

    public void testOverlay() throws NoConnectionsException, IOException, ProcCallException {
        System.out.println("STARTING test Overlay");
        Client client = getClient();
        ClientResponse cr;
        VoltTable result;

        cr = client.callProcedure("P1.insert", 1, "Xin@VoltDB", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        result = client.callProcedure("OVERLAY", "Jia", 4, 7, 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("XinJia", result.getString(1));

        result = client.callProcedure("OVERLAY", "Jia_", 4, 1, 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("XinJia_VoltDB", result.getString(1));

        result = client.callProcedure("OVERLAY", "Jia", 4.2, 7, 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("XinJia", result.getString(1));

        result = client.callProcedure("OVERLAY", "Jia", 4.9, 7, 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("XinJia", result.getString(1));

        // Test NULL results
        result = client.callProcedure("OVERLAY", null, 4, 7, 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals(null, result.getString(1));

        result = client.callProcedure("OVERLAY", "Jia", 4, null, 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals(null, result.getString(1));

        result = client.callProcedure("OVERLAY", "Jia", null, 7, 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals(null, result.getString(1));

        result = client.callProcedure("OVERLAY_FULL_LENGTH", "Jia", 4, 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("XinJialtDB", result.getString(1));

        result = client.callProcedure("OVERLAY_FULL_LENGTH", "J", 4, 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("XinJVoltDB", result.getString(1));


        // Test UTF-8 OVERLAY
        cr = client.callProcedure("P1.insert", 2, "贾鑫@VoltDB", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        result = client.callProcedure("OVERLAY", "XinJia", 1, 2, 2).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("XinJia@VoltDB", result.getString(1));

        result = client.callProcedure("OVERLAY", "XinJia", 8, 2, 2).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("贾鑫@VoltXinJia", result.getString(1));

        result = client.callProcedure("OVERLAY", "XinJia", 1, 9, 2).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("XinJia", result.getString(1));

        result = client.callProcedure("OVERLAY", "XinJia", 2, 7, 2).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("贾XinJiaB", result.getString(1));

        result = client.callProcedure("OVERLAY", "XinJia", 2, 8, 2).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("贾XinJia", result.getString(1));

        result = client.callProcedure("OVERLAY_FULL_LENGTH", "_", 3, 2).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("贾鑫_VoltDB", result.getString(1));

        result = client.callProcedure("OVERLAY_FULL_LENGTH", " at ", 2, 2).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("贾 at ltDB", result.getString(1));


        result = client.callProcedure("OVERLAY", "XinJia", 9, 1, 2).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("贾鑫@VoltDXinJia", result.getString(1));

        result = client.callProcedure("OVERLAY", "石宁", 9, 1, 2).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("贾鑫@VoltD石宁", result.getString(1));

        // Hsql has bugs on string(substring) index
        if (!isHSQL()) {
            result = client.callProcedure("OVERLAY", "XinJia", 9, 2, 2).getResults()[0];
            assertTrue(result.advanceRow());
            assertEquals("贾鑫@VoltDXinJia", result.getString(1));

            result = client.callProcedure("OVERLAY", "石宁", 9, 2, 2).getResults()[0];
            assertTrue(result.advanceRow());
            assertEquals("贾鑫@VoltD石宁", result.getString(1));

            result = client.callProcedure("OVERLAY", "XinJia", 10, 2, 2).getResults()[0];
            assertTrue(result.advanceRow());
            assertEquals("贾鑫@VoltDBXinJia", result.getString(1));

            result = client.callProcedure("OVERLAY", "石宁", 10, 2, 2).getResults()[0];
            assertTrue(result.advanceRow());
            assertEquals("贾鑫@VoltDB石宁", result.getString(1));

            // various start argument tests
            // start from 0, not 1, but treat it at least 1
            result = client.callProcedure("OVERLAY", "XinJia", 100, 2, 2).getResults()[0];
            assertTrue(result.advanceRow());
            assertEquals("贾鑫@VoltDBXinJia", result.getString(1));

            // various length argument
            result = client.callProcedure("OVERLAY", "XinJia", 2, 0, 2).getResults()[0];
            assertTrue(result.advanceRow());
            assertEquals("贾XinJia鑫@VoltDB", result.getString(1));

            result = client.callProcedure("OVERLAY", "XinJia", 1, 10, 2).getResults()[0];
            assertTrue(result.advanceRow());
            assertEquals("XinJia", result.getString(1));

            result = client.callProcedure("OVERLAY", "XinJia", 1, 100, 2).getResults()[0];
            assertTrue(result.advanceRow());
            assertEquals("XinJia", result.getString(1));

            result = client.callProcedure("OVERLAY", "XinJia", 2, 100, 2).getResults()[0];
            assertTrue(result.advanceRow());
            assertEquals("贾XinJia", result.getString(1));


            // Negative tests
            try {
                result = client.callProcedure("OVERLAY", "XinJia", -10, 2, 2).getResults()[0];
                fail();
            } catch (Exception ex) {
                assertTrue(ex.getMessage().contains(
                        "data exception -- OVERLAY error, not positive start argument -10"));
            }

            try {
                result = client.callProcedure("OVERLAY", "XinJia", 0, 2, 2).getResults()[0];
                fail();
            } catch (Exception ex) {
                assertTrue(ex.getMessage().contains(
                        "data exception -- OVERLAY error, not positive start argument 0"));
            }

            try {
                result = client.callProcedure("OVERLAY", "XinJia", 1, -1, 2).getResults()[0];
                fail();
            } catch (Exception ex) {
                assertTrue(ex.getMessage().contains(
                        "data exception -- OVERLAY error, negative length argument -1"));
            }
        }
    }

    // Unicode character to UTF8 string character
    public void testChar() throws NoConnectionsException, IOException, ProcCallException {
        System.out.println("STARTING test CHAR");
        Client client = getClient();
        ClientResponse cr;
        VoltTable result;

        // Hsql has wrong answers.
        if (isHSQL()) return;

        cr = client.callProcedure("P1.insert", 1, "Xin@VoltDB", 1, 1.0, new Timestamp(1000000000000L));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        result = client.callProcedure("CHAR", 36158, 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("贾", result.getString(1));

        result = client.callProcedure("CHAR", 37995, 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals("鑫", result.getString(1));

        String voltDB = "VoltDB";

        for (int i = 0; i < voltDB.length(); i++) {
            char ch = voltDB.charAt(i);
            result = client.callProcedure("CHAR", (int)ch, 1).getResults()[0];
            assertTrue(result.advanceRow());
            assertEquals(String.valueOf(ch), result.getString(1));
        }

        result = client.callProcedure("CHAR", null, 1).getResults()[0];
        assertTrue(result.advanceRow());
        assertEquals(null, result.getString(1));
    }

    public void testCaseWhen() throws Exception {
        System.out.println("STARTING test Case When...");
        Client cl = getClient();
        VoltTable vt;
        String sql;

        //                           ID, DESC,   NUM, FLOAT, TIMESTAMP
        cl.callProcedure("R1.insert", 1, "VoltDB", 1, 1.0, new Timestamp(1000000000000L));
        cl.callProcedure("R1.insert", 2, "Memsql"5, 5.0, new Timestamp(1000000000000L));

        sql = "SELECT ID, CASE WHEN num < 3 THEN 0 ELSE 8 END FROM R1 ORDER BY 1;";
        validateTableOfLongs(cl, sql, new long[][] {{1, 0},{2, 8}});

        sql = "SELECT ID, CASE WHEN num < 3 THEN num/2 ELSE num + 10 END FROM R1 ORDER BY 1;";
        validateTableOfLongs(cl, sql, new long[][] {{1, 0},{2, 15}});

        sql = "SELECT ID, CASE WHEN num > 0 AND num < 5 THEN num * 5 " +
                "WHEN num >=5 THEN num * 10  ELSE num END FROM R1 ORDER BY 1;";
        validateTableOfLongs(cl, sql, new long[][] {{1, 5},{2, 50}});


        // (2) Test case when Types.
        sql = "SELECT ID, CASE WHEN num > 0 AND num < 5 THEN NULL " +
                "WHEN num >=5 THEN num * 10  ELSE num END FROM R1 ORDER BY 1;";
        vt = cl.callProcedure("@AdHoc", sql).getResults()[0];
        assertEquals(VoltType.BIGINT, vt.getColumnType(1));
        if (isHSQL()) {
            validateTableOfLongs(vt, new long[][] {{1, 0},{2, 50}});
        } else {
            validateTableOfLongs(vt, new long[][] {{1, Long.MIN_VALUE},{2, 50}});
        }

        sql = "SELECT ID, CASE WHEN num > 0 AND num < 5 THEN NULL " +
                "WHEN num >=5 THEN NULL  ELSE num END FROM R1 ORDER BY 1;";
        vt = cl.callProcedure("@AdHoc", sql).getResults()[0];
        assertEquals(VoltType.INTEGER, vt.getColumnType(1));
        if (isHSQL()) {
            validateTableOfLongs(vt, new long[][] {{1, 0},{2, 0}});
        } else {
            validateTableOfLongs(vt, new long[][] {{1, Long.MIN_VALUE},{2, Long.MIN_VALUE}});
        }

        // Expected failed type cases:
        try {
            sql = "SELECT ID, CASE WHEN num > 0 AND num < 5 THEN NULL " +
                    "WHEN num >=5 THEN NULL ELSE NULL END FROM R1 ORDER BY 1;";
            vt = cl.callProcedure("@AdHoc", sql).getResults()[0];
            fail();
        } catch (Exception ex) {
            assertNotNull(ex);
            assertTrue(ex.getMessage().contains("data type cast needed for parameter or null literal"));
        }

        try {
            // Use String as the casted type
            sql = "SELECT ID, CASE WHEN num > 0 AND num < 5 THEN NULL " +
                    "WHEN num >=5 THEN NULL ELSE 'NULL' END FROM R1 ORDER BY 1;";
            vt = cl.callProcedure("@AdHoc", sql).getResults()[0];
        } catch (Exception ex) {
            fail();
        }

        try {
            sql = "SELECT ID, CASE WHEN num > 0 AND num < 5 THEN NULL " +
                    "WHEN num >=5 THEN 'I am null'  ELSE num END FROM R1 ORDER BY 1;";
            vt = cl.callProcedure("@AdHoc", sql).getResults()[0];
            fail();
        } catch (Exception ex) {
            assertNotNull(ex);
            assertTrue(ex.getMessage().contains("incompatible data types in combination"));
        }

        // Test string types
        sql = "SELECT ID, CASE WHEN desc > 'Volt' THEN 'Good' ELSE 'Bad' END FROM R1 ORDER BY 1;";
        vt = cl.callProcedure("@AdHoc", sql).getResults()[0];
        assertEquals(2, vt.getRowCount());
        vt.advanceRow();
        assertEquals(vt.getLong(0), 1);
        assertTrue(vt.getString(1).equals("Good"));
        vt.advanceRow();
        assertEquals(vt.getLong(0), 2);
        if (isHSQL()) {
            assertTrue(vt.getString(1).contains("Bad"));
        } else {
            assertTrue(vt.getString(1).equals("Bad"));
        }


        // Test string concatenation
        sql = "SELECT ID, desc || ':' ||  CASE WHEN desc > 'Volt' THEN 'Good' ELSE 'Bad' END FROM R1 ORDER BY 1;";
        vt = cl.callProcedure("@AdHoc", sql).getResults()[0];
        assertEquals(2, vt.getRowCount());
        vt.advanceRow();
        assertEquals(vt.getLong(0), 1);
        assertTrue(vt.getString(1).equals("VoltDB:Good"));
        vt.advanceRow();
        assertEquals(vt.getLong(0), 2);
        if (isHSQL()) {
            assertTrue(vt.getString(1).contains("Memsql:Bad"));
        } else {
            assertTrue(vt.getString(1).equals("Memsql:Bad"));
        }

        // Test inlined varchar/varbinary value produced by CASE WHEN.
        // This is regression coverage for ENG-6666.
        sql = "INSERT INTO INLINED_VC_VB_TABLE (ID, VC1, VC2, VB1, VB2) " +
            "VALUES (72, 'FOO', 'BAR', 'DEADBEEF', 'CDCDCDCD');";
        cl.callProcedure("@AdHoc", sql);
        sql = "SELECT CASE WHEN ID > 11 THEN VC1 ELSE VC2 END FROM INLINED_VC_VB_TABLE WHERE ID = 72;";
        vt = cl.callProcedure("@AdHoc", sql).getResults()[0];
        vt.advanceRow();
        assertEquals("FOO", vt.getString(0));

        sql = "SELECT CASE WHEN ID > 11 THEN VB1 ELSE VB2 END FROM INLINED_VC_VB_TABLE WHERE ID = 72;";
        vt = cl.callProcedure("@AdHoc", sql).getResults()[0];
        vt.advanceRow();
        assertTrue(VoltType.varbinaryToPrintableString(vt.getVarbinary(0)).contains("DEADBEEF"));

        cl.callProcedure("R1.insert", 3, "ORACLE"8, 8.0, new Timestamp(1000000000000L));
        // Test nested case when
        sql = "SELECT ID, CASE WHEN num < 5 THEN num * 5 " +
                "WHEN num < 10 THEN CASE WHEN num > 7 THEN num * 10 ELSE num * 8 END " +
                "END FROM R1 ORDER BY 1;";
        validateTableOfLongs(cl, sql, new long[][] {{1, 5},{2, 40}, {3, 80}});


        // Test case when without ELSE clause
        sql = "SELECT ID, CASE WHEN num > 3 AND num < 5 THEN 4 " +
                "WHEN num >=5 THEN num END FROM R1 ORDER BY 1;";
        vt = cl.callProcedure("@AdHoc", sql).getResults()[0];
        assertEquals(VoltType.INTEGER, vt.getColumnType(1));
        if (isHSQL()) {
            validateTableOfLongs(vt, new long[][] {{1, 0},{2,5}, {3, 8}});
        } else {
            validateTableOfLongs(vt, new long[][] {{1, Long.MIN_VALUE},{2,5}, {3, 8}});
        }

        sql = "SELECT ID, CASE WHEN num > 3 AND num < 5 THEN 4 " +
                "WHEN num >=5 THEN num*10 END FROM R1 ORDER BY 1;";
        vt = cl.callProcedure("@AdHoc", sql).getResults()[0];
        assertEquals(VoltType.BIGINT, vt.getColumnType(1));
        if (isHSQL()) {
            validateTableOfLongs(vt, new long[][] {{1, 0},{2,50}, {3, 80}});
        } else {
            validateTableOfLongs(vt, new long[][] {{1, Long.MIN_VALUE},{2,50}, {3, 80}});
        }

        // Test NULL
        cl.callProcedure("R1.insert", 4, "DB2",  null, null, new Timestamp(1000000000000L));
        sql = "SELECT ID, CASE WHEN num < 3 THEN num/2 ELSE num + 10 END FROM R1 ORDER BY 1;";
        vt = cl.callProcedure("@AdHoc", sql).getResults()[0];
        assertEquals(VoltType.INTEGER, vt.getColumnType(1));
        if (isHSQL()) {
            validateTableOfLongs(vt, new long[][] {{1, 0},{2, 15}, {3, 18}, {4, 0}});
        } else {
            validateTableOfLongs(vt, new long[][] {{1, 0},{2, 15}, {3, 18}, {4, Long.MIN_VALUE}});
        }

    }

    public void testCaseWhenLikeDecodeFunction() throws Exception {
        System.out.println("STARTING test Case When like decode function...");
        Client cl = getClient();
        String sql;

        //      ID, DESC,   NUM, FLOAT, TIMESTAMP
        cl.callProcedure("R1.insert", 1, "VoltDB", 1, 1.0, new Timestamp(1000000000000L));
        cl.callProcedure("R1.insert", 2, "MySQL"5, 5.0, new Timestamp(1000000000000L));

        sql = "SELECT ID, CASE num WHEN 3 THEN 3*2 WHEN 1 THEN 0 ELSE 10 END FROM R1 ORDER BY 1;";
        validateTableOfLongs(cl, sql, new long[][] {{1, 0},{2, 10}});

        // No ELSE clause
        sql = "SELECT ID, CASE num WHEN 1 THEN 10 WHEN 2 THEN 1 END FROM R1 ORDER BY 1;";
        if (isHSQL()) {
            validateTableOfLongs(cl, sql, new long[][] {{1, 10},{2, 0}});
        } else {
            validateTableOfLongs(cl, sql, new long[][] {{1, 10},{2, Long.MIN_VALUE}});
        }

        // Test NULL
        cl.callProcedure("R1.insert", 3, "Oracle",  null, null, new Timestamp(1000000000000L));
        sql = "SELECT ID, CASE num WHEN 5 THEN 50 ELSE num + 10 END FROM R1 ORDER BY 1;";
        if (isHSQL()) {
            validateTableOfLongs(cl, sql, new long[][] {{1, 11},{2, 50}, {3, 0}});
        } else {
            validateTableOfLongs(cl, sql, new long[][] {{1, 11},{2, 50}, {3, Long.MIN_VALUE}});
        }
    }

    private static StringBuilder joinStringArray(String[] params, String sep) {
        StringBuilder sb = new StringBuilder();
        for (String s : params) {
            sb.append(s).append(sep);
        }
        sb.delete(sb.length()-sep.length(), sb.length());
        return sb;
    }

    // concat params with a sql query string, and test the return value
    private void doTestCoalesceWithoutConst(Client cl, String[] params,
                                                   String expect, String id) throws Exception {
        String allPara = joinStringArray(params, ",").toString();
        String sql;
        if (expect=="NULL"){
            // sql = "SELECT CASE WHEN (COALESCE(para1, para2, ...) IS NULL)
            //               THEN 0 ELSE 1
            //               END FROM C_NULL WHERE ID=id";
            sql = "SELECT CASE WHEN(COALESCE(" + allPara + ") IS NULL)" +
                  " THEN 0 ELSE 1 END FROM C_NULL WHERE ID=" + id;
        }
        else {
            // sql = "SELECT CASE COALESCE(para1, para2, ...)
            //               WHEN expect
            //               THEN 0 ELSE 1
            //               END FROM C_NULL WHERE ID=id";
            sql = "SELECT CASE COALESCE(" + allPara + ") " +
                   "WHEN " + expect + " THEN 0 ELSE 1 END FROM C_NULL WHERE ID=" + id;
        }
        validateTableOfLongs(cl, sql, new long[][] {{0}});
    }

    private void doTestCoalesceWithConst(Client cl, String[] params,
                                                String cst ,String expect, String id) throws Exception {
        String allPara = joinStringArray(params, ",").toString();
        allPara += ","+cst;
        String sql;
        if (expect=="NULL"){
            // sql = "SELECT CASE WHEN (COALESCE(para1, para2, ..., cst) IS NULL)
            //               THEN 0 ELSE 1
            //               END FROM C_NULL WHERE ID=id";
            sql = "SELECT CASE WHEN(COALESCE(" + allPara + ") IS NULL)" +
                  " THEN 0 ELSE 1 END FROM C_NULL WHERE ID=" + id;
        }
        else {
            // sql = "SELECT CASE COALESCE(para1, para2, ..., cst)
            //               WHEN expect
            //               THEN 0 ELSE 1
            //               END FROM C_NULL WHERE ID=id";
            sql = "SELECT CASE COALESCE(" + allPara + ") " +
                   "WHEN " + expect + " THEN 0 ELSE 1 END FROM C_NULL WHERE ID=" + id;
        }
        validateTableOfLongs(cl, sql, new long[][] {{0}});
    }

    // col1 is not null while col2 is null
    private void doTestCoalescePairOneNull(Client cl, String col1, String col2) throws Exception {
        // coalesce(col1, col2) == coalesce(col2, col1) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col1, col2}, col1, "1");
        doTestCoalesceWithoutConst(cl, new String[]{col2, col1}, col1, "1");
    }

    private void doTestCoalescePairBothNull(Client cl, String col1, String col2) throws Exception{
        // coalesce(col1, col2) == coalesce(col2, col1) == NULL
        doTestCoalesceWithoutConst(cl, new String[]{col1, col2}, "NULL", "0");
        doTestCoalesceWithoutConst(cl, new String[]{col2, col1}, "NULL", "0");
    }

    // Both the columns are not null
    private void doTestCoalescePairNotNull(Client cl, String col1, String col2) throws Exception {
        // coalesce(col1, col2) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col1, col2}, col1, "2");
        // coalesce(col2, col1) == col2
        doTestCoalesceWithoutConst(cl, new String[]{col2, col1}, col2, "2");
    }

    // All the columns are not null
    private void doTestCoalesceTriNotNull(Client cl, String col1,
                                                 String col2, String col3, String cst) throws Exception {
        // coalesce(col1, col2, col3) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col1, col2, col3}, col1, "3");
        // coalesce(col1, col3, col2) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col1, col3, col2}, col1, "3");
        // coalesce(col2, col1, col3) == col2
        doTestCoalesceWithoutConst(cl, new String[]{col2, col1, col3}, col2, "3");
        // coalesce(col2, col3, col1) == col2
        doTestCoalesceWithoutConst(cl, new String[]{col2, col3, col1}, col2, "3");
        // coalesce(col3, col1, col2) == col3
        doTestCoalesceWithoutConst(cl, new String[]{col3, col1, col2}, col3, "3");
        // coalesce(col3, col2, col1) == col3
        doTestCoalesceWithoutConst(cl, new String[]{col3, col2, col1}, col3, "3");
        // coalesce(col1, col2, col3, cst) == col1
        doTestCoalesceWithConst(cl, new String[]{col1, col2, col3}, cst, col1, "3");
        // coalesce(col1, col3, col2, cst) == col1
        doTestCoalesceWithConst(cl, new String[]{col1, col3, col2}, cst, col1, "3");
        // coalesce(col2, col1, col3, cst) == col2
        doTestCoalesceWithConst(cl, new String[]{col2, col1, col3}, cst, col2, "3");
        // coalesce(col2, col3, col1, cst) == col2
        doTestCoalesceWithConst(cl, new String[]{col2, col3, col1}, cst, col2, "3");
        // coalesce(col3, col1, col2, cst) == col3
        doTestCoalesceWithConst(cl, new String[]{col3, col1, col2}, cst, col3, "3");
        // coalesce(col3, col2, col1, cst) == col3
        doTestCoalesceWithConst(cl, new String[]{col3, col2, col1}, cst, col3, "3");
    }

    // col3 is null
    private void doTestCoalesceTriOneNull(Client cl, String col1,
                                                 String col2, String col3, String cst) throws Exception {
        // coalesce(col1, col2, col3) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col1, col2, col3}, col1, "2");
        // coalesce(col1, col3, col2) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col1, col3, col2}, col1, "2");
        // coalesce(col2, col1, col3) == col2
        doTestCoalesceWithoutConst(cl, new String[]{col2, col1, col3}, col2, "2");
        // coalesce(col2, col3, col1) == col2
        doTestCoalesceWithoutConst(cl, new String[]{col2, col3, col1}, col2, "2");
        // coalesce(col3, col1, col2) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col3, col1, col2}, col1, "2");
        // coalesce(col3, col2, col2) == col2
        doTestCoalesceWithoutConst(cl, new String[]{col3, col2, col1}, col2, "2");
        // coalesce(col1, col2, col3, cst) == col1
        doTestCoalesceWithConst(cl, new String[]{col1, col2, col3}, cst, col1, "2");
        // coalesce(col1, col3, col2, cst) == col1
        doTestCoalesceWithConst(cl, new String[]{col1, col3, col2}, cst, col1, "2");
        // coalesce(col2, col1, col3, cst) == col2
        doTestCoalesceWithConst(cl, new String[]{col2, col1, col3}, cst, col2, "2");
        // coalesce(col2, col3, col1, cst) == col2
        doTestCoalesceWithConst(cl, new String[]{col2, col3, col1}, cst, col2, "2");
        // coalesce(col3, col1, col2, cst) == col1
        doTestCoalesceWithConst(cl, new String[]{col3, col1, col2}, cst, col1, "2");
        // coalesce(col3, col1, col2, cst) == col2
        doTestCoalesceWithConst(cl, new String[]{col3, col2, col1}, cst, col2, "2");
    }

    // col2 and col3 are null
    private void doTestCoalesceTriTwoNull(Client cl, String col1,
                                                 String col2, String col3, String cst) throws Exception {
        // coalesce(col1, col2, col3) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col1, col2, col3}, col1, "1");
        // coalesce(col1, col3, col2) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col1, col3, col2}, col1, "1");
        // coalesce(col2, col1, col3) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col2, col1, col3}, col1, "1");
        // coalesce(col2, col3, col1) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col2, col3, col1}, col1, "1");
        // coalesce(col3, col1, col2) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col3, col1, col2}, col1, "1");
        // coalesce(col3, col2, col2) == col1
        doTestCoalesceWithoutConst(cl, new String[]{col3, col2, col1}, col1, "1");
        // coalesce(col1, col2, col3, cst) == col1
        doTestCoalesceWithConst(cl, new String[]{col1, col2, col3}, cst, col1, "1");
        // coalesce(col1, col3, col2, cst) == col1
        doTestCoalesceWithConst(cl, new String[]{col1, col3, col2}, cst, col1, "1");
        // coalesce(col2, col1, col3, cst) == col1
        doTestCoalesceWithConst(cl, new String[]{col2, col1, col3}, cst, col1, "1");
        // coalesce(col2, col3, col1, cst) == col1
        doTestCoalesceWithConst(cl, new String[]{col2, col3, col1}, cst, col1, "1");
        // coalesce(col3, col1, col2, cst) == col1
        doTestCoalesceWithConst(cl, new String[]{col3, col1, col2}, cst, col1, "1");
        // coalesce(col3, col1, col2, cst) == col1
        doTestCoalesceWithConst(cl, new String[]{col3, col2, col1}, cst, col1, "1");
    }

    // all columns are null
    private void doTestCoalesceTriAllNull(Client cl, String col1,
                                                 String col2, String col3, String cst) throws Exception{
        // coalesce(col1, col2, col3) == NULL
        doTestCoalesceWithoutConst(cl, new String[]{col1, col2, col3}, "NULL", "0");
        // coalesce(col1, col3, col2) == NULL
        doTestCoalesceWithoutConst(cl, new String[]{col1, col3, col2}, "NULL", "0");
        // coalesce(col2, col1, col3) == NULL
        doTestCoalesceWithoutConst(cl, new String[]{col2, col1, col3}, "NULL", "0");
        // coalesce(col2, col3, col1) == NULL
        doTestCoalesceWithoutConst(cl, new String[]{col2, col3, col1}, "NULL", "0");
        // coalesce(col3, col1, col2) == NULL
        doTestCoalesceWithoutConst(cl, new String[]{col3, col1, col2}, "NULL", "0");
        // coalesce(col3, col2, col2) == NULL
        doTestCoalesceWithoutConst(cl, new String[]{col3, col2, col1}, "NULL", "0");
        // coalesce(col1, col2, col3, cst) == cst
        doTestCoalesceWithConst(cl, new String[]{col1, col2, col3}, cst, cst, "0");
        // coalesce(col1, col3, col2, cst) == cst
        doTestCoalesceWithConst(cl, new String[]{col1, col3, col2}, cst, cst, "0");
        // coalesce(col2, col1, col3, cst) == cst
        doTestCoalesceWithConst(cl, new String[]{col2, col1, col3}, cst, cst, "0");
        // coalesce(col2, col3, col1, cst) == cst
        doTestCoalesceWithConst(cl, new String[]{col2, col3, col1}, cst, cst, "0");
        // coalesce(col3, col1, col2, cst) == cst
        doTestCoalesceWithConst(cl, new String[]{col3, col1, col2}, cst, cst, "0");
        // coalesce(col3, col1, col2, cst) == cst
        doTestCoalesceWithConst(cl, new String[]{col3, col2, col1}, cst, cst, "0");
    }

    private void doTestTwoColCoalesce(Client cl, String col1, String col2) throws Exception {
        doTestCoalescePairBothNull(cl, col1, col2);
        doTestCoalescePairOneNull(cl, col1, col2);
        doTestCoalescePairNotNull(cl, col1, col2);
    }

    private void doTestThreeColCoalesce(Client cl, String col1,
                                        String col2, String col3, String cst) throws Exception {
        doTestCoalesceTriAllNull(cl, col1, col2, col3, cst);
        doTestCoalesceTriTwoNull(cl, col1, col2, col3, cst);
        doTestCoalesceTriOneNull(cl, col1, col2, col3, cst);
        doTestCoalesceTriNotNull(cl, col1, col2, col3, cst);
    }

    public void testCoalesce() throws Exception {
        System.out.println("STARTING test COALESCE function...");
        Client cl = getClient();

        // one row with three sets of nulls
        cl.callProcedure("@AdHoc", "insert into C_NULL(ID) values (0);");
        // one row with one set of non-null columns and two sets of nulls
        cl.callProcedure("@AdHoc", "insert into C_NULL(ID,S1,I1,F1,D1,V1,T1) values (1,1,1,1,1,'1',100000)");
        // TODO: below is wrong, because the null timestamp will be regarded as an invalid input by hsql
        //cl.callProcedure("C_NULL.insert", 1,1,1,1,1,"1",new Timestamp(1000000000000L), null, null, null, null, null);
        // two sets of non-null columns and one set of null column
        cl.callProcedure("@AdHoc", "insert into C_NULL(ID,S1,I1,F1,D1,V1,T1,I2,F2,D2,V2,T2)"
                                + " values (2,1,1,1,1,'1',100000,2,2,2,'2',200000)");
        // three set non-nulls
        cl.callProcedure("C_NULL.insert", 3,1,1,1,1,"1",new Timestamp(1000000000000L),
                                              2,2,2,"2",new Timestamp(2000000000000L),
                                              3,3,3,"3",new Timestamp(3000000000000L));

        doTestTwoColCoalesce(cl, "I1", "I2");
        doTestTwoColCoalesce(cl, "F1", "F2");
        doTestTwoColCoalesce(cl, "D1", "D2");
        doTestTwoColCoalesce(cl, "V1", "V2");
        doTestTwoColCoalesce(cl, "T1", "T2");

        doTestThreeColCoalesce(cl, "I1", "I2", "I3", "100");
        doTestThreeColCoalesce(cl, "F1", "F2", "F3", "100.0");
        doTestThreeColCoalesce(cl, "D1", "D2", "D3", "100.0");
        doTestThreeColCoalesce(cl, "V1", "V2", "V3", "'hahaha'");
        doTestThreeColCoalesce(cl, "T1", "T2", "T3", "CAST ('2014-07-09 00:00:00.000000' as TIMESTAMP)");

        // test compatiable types
        doTestThreeColCoalesce(cl, "S1", "I2", "I3", "100");
        doTestThreeColCoalesce(cl, "S1", "F2", "D3", "100.0");
        doTestThreeColCoalesce(cl, "I1", "F2", "D3", "100.0");

        // test incompatiable types
        // TODO: Is the exception throwed by coalesce? Or by decode?
        try {
            doTestThreeColCoalesce(cl, "S1", "I2", "V3", "100");
            fail();
        } catch (ProcCallException pcex){
            assertTrue(pcex.getMessage().contains("incompatible data types"));
        }
        try {
            doTestThreeColCoalesce(cl, "S1", "I2", "T3", "100");
            fail();
        } catch (ProcCallException pcex){
            assertTrue(pcex.getMessage().contains("incompatible data types"));
        }
    }

    public void testManyExtractTimeFieldFunction() throws Exception {
        System.out.println("STARTING test functions extracting fields in timestamp ...");
        Client cl = getClient();
        VoltTable result;
        String sql;

        ClientResponse cr = cl.callProcedure("P1.insert", 0, null, null, null,
                Timestamp.valueOf("2014-07-15 01:02:03.456"));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = cl.callProcedure("P1.insert", 1, null, null, null, Timestamp.valueOf("2012-02-29 12:20:30.123"));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        cr = cl.callProcedure("P1.insert", 2, null, null, null, Timestamp.valueOf("2012-12-31 12:59:30"));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());

        sql = "select id, YEAR(past) from p1 order by id;";
        validateTableOfLongs(cl, sql, new long[][]{{0, 2014}, {1, 2012}, {2, 2012}});

        sql = "select id, MONTH(past) from p1 order by id;";
        validateTableOfLongs(cl, sql, new long[][]{{0, 7}, {1, 2}, {2, 12}});

        sql = "select id, DAY(past) from p1 order by id;";
        validateTableOfLongs(cl, sql, new long[][]{{0, 15}, {1, 29}, {2, 31}});

        sql = "select id, HOUR(past) from p1 order by id;";
        validateTableOfLongs(cl, sql, new long[][]{{0, 1}, {1, 12}, {2, 12}});

        sql = "select id, MINUTE(past) from p1 order by id;";
        validateTableOfLongs(cl, sql, new long[][]{{0, 2}, {1, 20}, {2, 59}});

        sql = "select id, cast(SECOND(past) as VARCHAR) from p1 order by id;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        if (isHSQL()) {
            validateTableColumnOfScalarVarchar(result, 1, new String[]{"3.456000", "30.123000", "30.000000"});
        }
        else {
            validateTableColumnOfScalarVarchar(result, 1, new String[]{"3.456000000000", "30.123000000000",
                    "30.000000000000"});
        }

        sql = "select id, QUARTER(past) from p1 order by id;";
        validateTableOfLongs(cl, sql, new long[][]{{0, 3}, {1, 1}, {2, 4}});

        sql = "select DAYOFWEEK(past) from p1 order by id;";
        validateTableOfLongs(cl, sql,new long[][]{{3}, {4}, {2}});

        sql = "select WEEKDAY(past) from p1 order by id;";
        if (isHSQL()) {
            // we modify the hsql parser, and so it maps to extract week_of_day
            validateTableOfLongs(cl, sql,new long[][]{{3}, {4}, {2}});
        }
        else {
            // call our ee function, and so return different value
            validateTableOfLongs(cl, sql,new long[][]{{1}, {2}, {0}});
        }

        sql = "select DAYOFMONTH(past) from p1 order by id;";
        validateTableOfLongs(cl, sql,new long[][]{{15}, {29}, {31}});

        sql = "select DAYOFYEAR(past) from p1 order by id;";
        validateTableOfLongs(cl, sql,new long[][]{{196}, {60}, {366}});

        // WEEK 1 is often the correct answer for the last day of the year.
        // See https://en.wikipedia.org/wiki/ISO_week_year#Last_week
        sql = "select WEEK(past) from p1 order by id;";
        validateTableOfLongs(cl, sql,new long[][]{{29}, {9}, {1}});
    }

    // ENG-3283
    public void testAliasesOfSomeStringFunctions() throws IOException, ProcCallException {
        String sql;
        VoltTable result;
        Client cl = getClient();
        ClientResponse cr = cl.callProcedure("P1.insert", 0, "abc123ABC", null, null,
                Timestamp.valueOf("2014-07-15 01:02:03.456"));
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        // LTRIM and RTRIM has been implemented and tested

        // SUBSTR
        sql = "select SUBSTR(DESC, 1, 2) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"ab"});

        sql = "select SUBSTR(DESC, 4, 3) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"123"});

        sql = "select SUBSTR(DESC, 3) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"c123ABC"});

        // Test spelled out SUBSTRING with comma delimiters vs. old-school FROM and FOR keywords.
        sql = "select SUBSTRING(DESC, 1, 2) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"ab"});

        sql = "select SUBSTRING(DESC, 4, 3) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"123"});

        sql = "select SUBSTRING(DESC, 3) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"c123ABC"});

        // Some weird cases -- the SQL-2003 standard says that even START < 1
        // moves the end point (in this case, to the left) which is based on (LENGTH + START).
        sql = "select SUBSTR(DESC, 0, 2) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"a"}); // not "ab" !

        sql = "select SUBSTR(DESC, -1, 2) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{""}); // not "ab" !

        sql = "select SUBSTR(DESC, -1, 1) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{""}); // not "a" !

        sql = "select SUBSTR(DESC, -3, 1) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{""}); // not an error !

        sql = "select SUBSTRING(DESC, 0, 2) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"a"}); // not "ab" !

        sql = "select SUBSTRING(DESC, -1, 2) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{""}); // not "ab" !

        sql = "select SUBSTRING(DESC, -1, 1) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{""}); // not "a" !

        sql = "select SUBSTRING(DESC, -3, 1) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{""}); // not an error !

        // LCASE and UCASE
        sql = "select LCASE(DESC) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"abc123abc"});

        sql = "select UCASE(DESC) from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"ABC123ABC"});

        // INSERT
        sql = "select INSERT(DESC, 1, 3,'ABC') from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"ABC123ABC"});

        sql = "select INSERT(DESC, 1, 1,'ABC') from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"ABCbc123ABC"});

        sql = "select INSERT(DESC, 1, 4,'ABC') from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"ABC23ABC"});

        sql = "select INSERT(DESC, 1, 0,'ABC') from p1 where id = 0;";
        cr = cl.callProcedure("@AdHoc", sql);
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults()[0];
        validateTableColumnOfScalarVarchar(result, new String[]{"ABCabc123ABC"});
    }

    //
    // JUnit / RegressionSuite boilerplate
    //
    public TestFunctionsSuite(String name) {
        super(name);
    }

    static public junit.framework.Test suite() {

        VoltServerConfig config = null;
        MultiConfigSuiteBuilder builder =
            new MultiConfigSuiteBuilder(TestFunctionsSuite.class);
        boolean success;

        VoltProjectBuilder project = new VoltProjectBuilder();
        final String literalSchema =
                "CREATE TABLE P1 ( " +
                "ID INTEGER DEFAULT 0 NOT NULL, " +
                "DESC VARCHAR(300), " +
                "NUM INTEGER, " +
                "RATIO FLOAT, " +
                "PAST TIMESTAMP DEFAULT NULL, " +
                "PRIMARY KEY (ID) ); " +

                "PARTITION TABLE P1 ON COLUMN ID;" +

                // Test generalized index on a function of a non-indexed column.
                "CREATE INDEX P1_ABS_NUM ON P1 ( ABS(NUM) ); " +

                // Test generalized index on an expression of multiple columns.
                "CREATE INDEX P1_ABS_ID_PLUS_NUM ON P1 ( ABS(ID) + NUM ); " +

                // Test generalized indexes on a string function and various combos.
                "CREATE INDEX P1_SUBSTRING_DESC ON P1 ( SUBSTRING(DESC FROM 1 FOR 2) ); " +
                "CREATE INDEX P1_SUBSTRING_WITH_COL_DESC ON P1 ( SUBSTRING(DESC FROM 1 FOR 2), DESC ); " +
                "CREATE INDEX P1_NUM_EXPR_WITH_STRING_COL ON P1 ( ABS(ID), DESC ); " +
                "CREATE INDEX P1_MIXED_TYPE_EXPRS1 ON P1 ( ABS(ID+2), SUBSTRING(DESC FROM 1 FOR 2) ); " +
                "CREATE INDEX P1_MIXED_TYPE_EXPRS2 ON P1 ( SUBSTRING(DESC FROM 1 FOR 2), ABS(ID+2) ); " +

                "CREATE TABLE R1 ( " +
                "ID INTEGER DEFAULT 0 NOT NULL, " +
                "DESC VARCHAR(300), " +
                "NUM INTEGER, " +
                "RATIO FLOAT, " +
                "PAST TIMESTAMP, " +
                "PRIMARY KEY (ID) ); " +

                // Test unique generalized index on a function of an already indexed column.
                "CREATE UNIQUE INDEX R1_ABS_ID_DESC ON R1 ( ABS(ID), DESC ); " +

                // Test generalized expression index with a constant argument.
                "CREATE INDEX R1_ABS_ID_SCALED ON R1 ( ID / 3 ); " +

                //Test generalized expression index with case when.
                "CREATE INDEX R1_CASEWHEN ON R1 (CASE WHEN num < 3 THEN num/2 ELSE num + 10 END); " +


                "CREATE TABLE R2 ( " +
                "ID INTEGER DEFAULT 0 NOT NULL, " +
                "DESC VARCHAR(300), " +
                "NUM INTEGER, " +
                "RATIO FLOAT, " +
                "PAST TIMESTAMP DEFAULT NULL, " +
                "PRIMARY KEY (ID) ); " +

                //Another table that has all numeric types, for testing numeric column functions.
                "CREATE TABLE NUMBER_TYPES ( " +
                "INTEGERNUM INTEGER DEFAULT 0 NOT NULL, " +
                "TINYNUM TINYINT, " +
                "SMALLNUM SMALLINT, " +
                "BIGNUM BIGINT, " +
                "FLOATNUM FLOAT, " +
                "DECIMALNUM DECIMAL, " +
                "PRIMARY KEY (INTEGERNUM) );" +

                "CREATE TABLE R_TIME ( " +
                "ID INTEGER DEFAULT 0 NOT NULL, " +
                "C1 INTEGER DEFAULT 2 NOT NULL, " +
                "T1 TIMESTAMP DEFAULT NULL, " +
                "T2 TIMESTAMP DEFAULT NOW, " +
                "T3 TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " +
                "T4 TIMESTAMP DEFAULT '2012-12-12 12:12:12.121212', " +
                "PRIMARY KEY (ID) ); " +

                "CREATE TABLE C_NULL ( " +
                "ID INTEGER DEFAULT 0 NOT NULL, " +
                "S1 SMALLINT DEFAULT NULL, " +
                "I1 INTEGER DEFAULT NULL, " +
                "F1 FLOAT DEFAULT NULL, " +
                "D1 DECIMAL DEFAULT NULL, " +
                "V1 VARCHAR(10) DEFAULT NULL, " +
                "T1 TIMESTAMP DEFAULT NULL, " +
                "I2 INTEGER DEFAULT NULL, " +
                "F2 FLOAT DEFAULT NULL, " +
                "D2 DECIMAL DEFAULT NULL, " +
                "V2 VARCHAR(10) DEFAULT NULL, " +
                "T2 TIMESTAMP DEFAULT NULL, " +
                "I3 INTEGER DEFAULT NULL, " +
                "F3 FLOAT DEFAULT NULL, " +
                "D3 DECIMAL DEFAULT NULL, " +
                "V3 VARCHAR(10) DEFAULT NULL, " +
                "T3 TIMESTAMP DEFAULT NULL, " +
                "PRIMARY KEY (ID) ); " +
                "PARTITION TABLE C_NULL ON COLUMN ID;" +

                "CREATE TABLE INLINED_VC_VB_TABLE (" +
                "ID INTEGER DEFAULT 0 NOT NULL," +
                "VC1 VARCHAR(6)," +     // inlined
                "VC2 VARCHAR(16)," +    // not inlined
                "VB1 VARBINARY(6)," +   // inlined
                "VB2 VARBINARY(64));" + // not inlined
                "";
        try {
            project.addLiteralSchema(literalSchema);
        } catch (IOException e) {
            assertFalse(true);
        }

        project.addStmtProcedure("WHERE_ABS", "select count(*) from P1 where ABS(ID) > 9");
        project.addStmtProcedure("WHERE_ABSFF", "select count(*) from P1 where ABS(ID - 0.4) > 9.5");
        project.addStmtProcedure("WHERE_ABSIF", "select count(*) from P1 where ABS(ID) > 9.5");
        project.addStmtProcedure("WHERE_ABSFI", "select count(*) from P1 where ABS(ID + 0.4) > 9");
        project.addStmtProcedure("WHERE_ABSWEAK", "select count(*) from P1 where ABS(ID - 0.4) > ABS(9.5)");

        project.addStmtProcedure("DISPLAY_ABS", "select ABS(ID)-2 from P1 where ID >= -7");
        project.addStmtProcedure("ORDER_ABS", "select ID+12 from P1 order by ABS(ID)");
        // GROUP BY with complex expressions not yet supported
        // project.addStmtProcedure("GROUP_ABS", "select MIN(ID+17) from P1 group by ABS(ID+12) order by ABS(ID+12)");
        project.addStmtProcedure("AGG_OF_ABS", "select MIN(ABS(ID)-2) from P1");
        // RuntimeException seems to stem from parser failure similar to ENG-2901
        // project.addStmtProcedure("ABS_OF_AGG", "select ABS(MIN(ID+9)) from P1");

        project.addStmtProcedure("DISPLAY_CEILING", "select CEILING(INTEGERNUM), CEILING(TINYNUM), CEILING(SMALLNUM), CEILING(BIGNUM), CEILING(FLOATNUM), CEILING(DECIMALNUM) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_CEILING_INTEGER""select INTEGERNUM from NUMBER_TYPES order by CEILING(INTEGERNUM), INTEGERNUM");
        project.addStmtProcedure("ORDER_CEILING_TINYINT""select INTEGERNUM from NUMBER_TYPES order by CEILING(TINYNUM), TINYNUM");
        project.addStmtProcedure("ORDER_CEILING_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by CEILING(SMALLNUM), SMALLNUM");
        project.addStmtProcedure("ORDER_CEILING_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by CEILING(BIGNUM), BIGNUM");
        project.addStmtProcedure("ORDER_CEILING_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by CEILING(FLOATNUM), FLOATNUM");
        project.addStmtProcedure("ORDER_CEILING_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by CEILING(DECIMALNUM), DECIMALNUM");

        project.addStmtProcedure("WHERE_CEILING_INTEGER""select count(*) from NUMBER_TYPES where CEILING(INTEGERNUM) = ?");
        project.addStmtProcedure("WHERE_CEILING_TINYINT""select count(*) from NUMBER_TYPES where CEILING(TINYNUM) = ?");
        project.addStmtProcedure("WHERE_CEILING_SMALLINT", "select count(*) from NUMBER_TYPES where CEILING(SMALLNUM) = ?");
        project.addStmtProcedure("WHERE_CEILING_BIGINT",   "select count(*) from NUMBER_TYPES where CEILING(BIGNUM) = ?");
        project.addStmtProcedure("WHERE_CEILING_FLOAT",    "select count(*) from NUMBER_TYPES where CEILING(FLOATNUM) = ?");
        project.addStmtProcedure("WHERE_CEILING_DECIMAL""select count(*) from NUMBER_TYPES where CEILING(DECIMALNUM) = ?");

        project.addStmtProcedure("DISPLAY_EXP", "select EXP(INTEGERNUM), EXP(TINYNUM), EXP(SMALLNUM), EXP(BIGNUM), EXP(FLOATNUM), EXP(DECIMALNUM) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_EXP_INTEGER""select INTEGERNUM, EXP(INTEGERNUM) from NUMBER_TYPES order by EXP(INTEGERNUM)");
        project.addStmtProcedure("ORDER_EXP_TINYINT""select INTEGERNUM, EXP(TINYNUM) from NUMBER_TYPES order by EXP(TINYNUM)");
        project.addStmtProcedure("ORDER_EXP_SMALLINT", "select INTEGERNUM, EXP(SMALLNUM) from NUMBER_TYPES order by EXP(SMALLNUM)");
        project.addStmtProcedure("ORDER_EXP_BIGINT",   "select INTEGERNUM, EXP(BIGNUM) from NUMBER_TYPES order by EXP(BIGNUM)");
        project.addStmtProcedure("ORDER_EXP_FLOAT",    "select INTEGERNUM, EXP(FLOATNUM) from NUMBER_TYPES order by EXP(FLOATNUM)");
        project.addStmtProcedure("ORDER_EXP_DECIMAL""select INTEGERNUM, EXP(DECIMALNUM) from NUMBER_TYPES order by EXP(DECIMALNUM)");

        project.addStmtProcedure("WHERE_EXP_INTEGER""select count(*) from NUMBER_TYPES where EXP(INTEGERNUM) = ?");
        project.addStmtProcedure("WHERE_EXP_TINYINT""select count(*) from NUMBER_TYPES where EXP(TINYNUM) = ?");
        project.addStmtProcedure("WHERE_EXP_SMALLINT", "select count(*) from NUMBER_TYPES where EXP(SMALLNUM) = ?");
        project.addStmtProcedure("WHERE_EXP_BIGINT",   "select count(*) from NUMBER_TYPES where EXP(BIGNUM) = ?");
        project.addStmtProcedure("WHERE_EXP_FLOAT",    "select count(*) from NUMBER_TYPES where EXP(FLOATNUM) = ?");
        project.addStmtProcedure("WHERE_EXP_DECIMAL""select count(*) from NUMBER_TYPES where EXP(DECIMALNUM) = ?");

        project.addStmtProcedure("DISPLAY_FLOOR", "select FLOOR(INTEGERNUM), FLOOR(TINYNUM), FLOOR(SMALLNUM), FLOOR(BIGNUM), FLOOR(FLOATNUM), FLOOR(DECIMALNUM) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_FLOOR_INTEGER""select INTEGERNUM from NUMBER_TYPES order by FLOOR(INTEGERNUM), INTEGERNUM");
        project.addStmtProcedure("ORDER_FLOOR_TINYINT""select INTEGERNUM from NUMBER_TYPES order by FLOOR(TINYNUM), TINYNUM");
        project.addStmtProcedure("ORDER_FLOOR_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by FLOOR(SMALLNUM), SMALLNUM");
        project.addStmtProcedure("ORDER_FLOOR_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by FLOOR(BIGNUM), BIGNUM");
        project.addStmtProcedure("ORDER_FLOOR_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by FLOOR(FLOATNUM), FLOATNUM");
        project.addStmtProcedure("ORDER_FLOOR_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by FLOOR(DECIMALNUM), DECIMALNUM");

        project.addStmtProcedure("WHERE_FLOOR_INTEGER""select count(*) from NUMBER_TYPES where FLOOR(INTEGERNUM) = ?");
        project.addStmtProcedure("WHERE_FLOOR_TINYINT""select count(*) from NUMBER_TYPES where FLOOR(TINYNUM) = ?");
        project.addStmtProcedure("WHERE_FLOOR_SMALLINT", "select count(*) from NUMBER_TYPES where FLOOR(SMALLNUM) = ?");
        project.addStmtProcedure("WHERE_FLOOR_BIGINT",   "select count(*) from NUMBER_TYPES where FLOOR(BIGNUM) = ?");
        project.addStmtProcedure("WHERE_FLOOR_FLOAT",    "select count(*) from NUMBER_TYPES where FLOOR(FLOATNUM) = ?");
        project.addStmtProcedure("WHERE_FLOOR_DECIMAL""select count(*) from NUMBER_TYPES where FLOOR(DECIMALNUM) = ?");

        project.addStmtProcedure("DISPLAY_POWER7X", "select POWER(7, INTEGERNUM), POWER(7, TINYNUM), POWER(7, SMALLNUM), POWER(7, BIGNUM), POWER(7, FLOATNUM), POWER(7, DECIMALNUM) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_POWER7X_INTEGER""select INTEGERNUM from NUMBER_TYPES order by POWER(7, INTEGERNUM)");
        project.addStmtProcedure("ORDER_POWER7X_TINYINT""select INTEGERNUM from NUMBER_TYPES order by POWER(7, TINYNUM)");
        project.addStmtProcedure("ORDER_POWER7X_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by POWER(7, SMALLNUM)");
        project.addStmtProcedure("ORDER_POWER7X_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by POWER(7, BIGNUM)");
        project.addStmtProcedure("ORDER_POWER7X_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by POWER(7, FLOATNUM)");
        project.addStmtProcedure("ORDER_POWER7X_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by POWER(7, DECIMALNUM)");

        project.addStmtProcedure("WHERE_POWER7X_INTEGER""select count(*) from NUMBER_TYPES where POWER(7, INTEGERNUM) = ?");
        project.addStmtProcedure("WHERE_POWER7X_TINYINT""select count(*) from NUMBER_TYPES where POWER(7, TINYNUM) = ?");
        project.addStmtProcedure("WHERE_POWER7X_SMALLINT", "select count(*) from NUMBER_TYPES where POWER(7, SMALLNUM) = ?");
        project.addStmtProcedure("WHERE_POWER7X_BIGINT",   "select count(*) from NUMBER_TYPES where POWER(7, BIGNUM) = ?");
        project.addStmtProcedure("WHERE_POWER7X_FLOAT",    "select count(*) from NUMBER_TYPES where POWER(7, FLOATNUM) = ?");
        project.addStmtProcedure("WHERE_POWER7X_DECIMAL""select count(*) from NUMBER_TYPES where POWER(7, DECIMALNUM) = ?");

        project.addStmtProcedure("DISPLAY_POWER07X", "select POWER(0.7, INTEGERNUM), POWER(0.7, TINYNUM), POWER(0.7, SMALLNUM), POWER(0.7, BIGNUM), POWER(0.7, FLOATNUM), POWER(0.7, DECIMALNUM) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_POWER07X_INTEGER""select INTEGERNUM from NUMBER_TYPES order by POWER(0.7, INTEGERNUM)");
        project.addStmtProcedure("ORDER_POWER07X_TINYINT""select INTEGERNUM from NUMBER_TYPES order by POWER(0.7, TINYNUM)");
        project.addStmtProcedure("ORDER_POWER07X_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by POWER(0.7, SMALLNUM)");
        project.addStmtProcedure("ORDER_POWER07X_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by POWER(0.7, BIGNUM)");
        project.addStmtProcedure("ORDER_POWER07X_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by POWER(0.7, FLOATNUM)");
        project.addStmtProcedure("ORDER_POWER07X_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by POWER(0.7, DECIMALNUM)");

        project.addStmtProcedure("WHERE_POWER07X_INTEGER""select count(*) from NUMBER_TYPES where ((0.0000001+POWER(0.7, INTEGERNUM)) / (0.0000001+?)) BETWEEN 0.99 and 1.01");
        project.addStmtProcedure("WHERE_POWER07X_TINYINT""select count(*) from NUMBER_TYPES where ((0.0000001+POWER(0.7, TINYNUM)   ) / (0.0000001+?)) BETWEEN 0.99 and 1.01");
        project.addStmtProcedure("WHERE_POWER07X_SMALLINT", "select count(*) from NUMBER_TYPES where ((0.0000001+POWER(0.7, SMALLNUM)  ) / (0.0000001+?)) BETWEEN 0.99 and 1.01");
        project.addStmtProcedure("WHERE_POWER07X_BIGINT",   "select count(*) from NUMBER_TYPES where ((0.0000001+POWER(0.7, BIGNUM)    ) / (0.0000001+?)) BETWEEN 0.99 and 1.01");
        project.addStmtProcedure("WHERE_POWER07X_FLOAT",    "select count(*) from NUMBER_TYPES where ((0.0000001+POWER(0.7, FLOATNUM)  ) / (0.0000001+?)) BETWEEN 0.99 and 1.01");
        project.addStmtProcedure("WHERE_POWER07X_DECIMAL""select count(*) from NUMBER_TYPES where ((0.0000001+POWER(0.7, DECIMALNUM)) / (0.0000001+?)) BETWEEN 0.99 and 1.01");

        project.addStmtProcedure("DISPLAY_POWERX7", "select POWER(INTEGERNUM, 7), POWER(TINYNUM, 7), POWER(SMALLNUM, 7), POWER(BIGNUM, 7), POWER(FLOATNUM, 7), POWER(DECIMALNUM, 7) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_POWERX7_INTEGER""select INTEGERNUM from NUMBER_TYPES order by POWER(INTEGERNUM, 7)");
        project.addStmtProcedure("ORDER_POWERX7_TINYINT""select INTEGERNUM from NUMBER_TYPES order by POWER(TINYNUM,    7)");
        project.addStmtProcedure("ORDER_POWERX7_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by POWER(SMALLNUM,   7)");
        project.addStmtProcedure("ORDER_POWERX7_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by POWER(BIGNUM,     7)");
        project.addStmtProcedure("ORDER_POWERX7_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by POWER(FLOATNUM,   7)");
        project.addStmtProcedure("ORDER_POWERX7_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by POWER(DECIMALNUM, 7)");

        project.addStmtProcedure("WHERE_POWERX7_INTEGER""select count(*) from NUMBER_TYPES where POWER(INTEGERNUM, 7) = ?");
        project.addStmtProcedure("WHERE_POWERX7_TINYINT""select count(*) from NUMBER_TYPES where POWER(TINYNUM,    7) = ?");
        project.addStmtProcedure("WHERE_POWERX7_SMALLINT", "select count(*) from NUMBER_TYPES where POWER(SMALLNUM,   7) = ?");
        project.addStmtProcedure("WHERE_POWERX7_BIGINT",   "select count(*) from NUMBER_TYPES where POWER(BIGNUM,     7) = ?");
        project.addStmtProcedure("WHERE_POWERX7_FLOAT",    "select count(*) from NUMBER_TYPES where POWER(FLOATNUM,   7) = ?");
        project.addStmtProcedure("WHERE_POWERX7_DECIMAL""select count(*) from NUMBER_TYPES where POWER(DECIMALNUM, 7) = ?");

        // These are intended for application to non-negative values.
        // Failure tests on negative values can be done separately, possibly via ad hoc.
        project.addStmtProcedure("DISPLAY_POWERX07", "select POWER(INTEGERNUM, 0.7), POWER(TINYNUM, 0.7), POWER(SMALLNUM, 0.7), POWER(BIGNUM, 0.7), POWER(FLOATNUM, 0.7), POWER(DECIMALNUM, 0.7) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_POWERX07_INTEGER""select INTEGERNUM from NUMBER_TYPES order by POWER(INTEGERNUM, 0.7)");
        project.addStmtProcedure("ORDER_POWERX07_TINYINT""select INTEGERNUM from NUMBER_TYPES order by POWER(TINYNUM,    0.7)");
        project.addStmtProcedure("ORDER_POWERX07_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by POWER(SMALLNUM,   0.7)");
        project.addStmtProcedure("ORDER_POWERX07_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by POWER(BIGNUM,     0.7)");
        project.addStmtProcedure("ORDER_POWERX07_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by POWER(FLOATNUM,   0.7)");
        project.addStmtProcedure("ORDER_POWERX07_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by POWER(DECIMALNUM, 0.7)");

        project.addStmtProcedure("WHERE_POWERX07_INTEGER""select count(*) from NUMBER_TYPES where ((0.0000001+POWER(INTEGERNUM, 0.7)) / (0.0000001+?)) BETWEEN 0.99 and 1.01");
        project.addStmtProcedure("WHERE_POWERX07_TINYINT""select count(*) from NUMBER_TYPES where ((0.0000001+POWER(TINYNUM,    0.7)) / (0.0000001+?)) BETWEEN 0.99 and 1.01");
        project.addStmtProcedure("WHERE_POWERX07_SMALLINT", "select count(*) from NUMBER_TYPES where ((0.0000001+POWER(SMALLNUM,   0.7)) / (0.0000001+?)) BETWEEN 0.99 and 1.01");
        project.addStmtProcedure("WHERE_POWERX07_BIGINT",   "select count(*) from NUMBER_TYPES where ((0.0000001+POWER(BIGNUM,     0.7)) / (0.0000001+?)) BETWEEN 0.99 and 1.01");
        project.addStmtProcedure("WHERE_POWERX07_FLOAT",    "select count(*) from NUMBER_TYPES where ((0.0000001+POWER(FLOATNUM,   0.7)) / (0.0000001+?)) BETWEEN 0.99 and 1.01");
        project.addStmtProcedure("WHERE_POWERX07_DECIMAL""select count(*) from NUMBER_TYPES where ((0.0000001+POWER(DECIMALNUM, 0.7)) / (0.0000001+?)) BETWEEN 0.99 and 1.01");

        // These are intended for application to non-negative values.
        // Failure tests on negative values can be done separately, possibly via ad hoc.
        project.addStmtProcedure("DISPLAY_SQRT", "select SQRT(INTEGERNUM), SQRT(TINYNUM), SQRT(SMALLNUM), SQRT(BIGNUM), SQRT(FLOATNUM), SQRT(DECIMALNUM) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_SQRT_INTEGER""select INTEGERNUM from NUMBER_TYPES order by SQRT(INTEGERNUM)");
        project.addStmtProcedure("ORDER_SQRT_TINYINT""select INTEGERNUM from NUMBER_TYPES order by SQRT(TINYNUM)");
        project.addStmtProcedure("ORDER_SQRT_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by SQRT(SMALLNUM)");
        project.addStmtProcedure("ORDER_SQRT_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by SQRT(BIGNUM)");
        project.addStmtProcedure("ORDER_SQRT_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by SQRT(FLOATNUM)");
        project.addStmtProcedure("ORDER_SQRT_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by SQRT(DECIMALNUM)");

        project.addStmtProcedure("WHERE_SQRT_INTEGER""select count(*) from NUMBER_TYPES where SQRT(INTEGERNUM) = ?");
        project.addStmtProcedure("WHERE_SQRT_TINYINT""select count(*) from NUMBER_TYPES where SQRT(TINYNUM) = ?");
        project.addStmtProcedure("WHERE_SQRT_SMALLINT", "select count(*) from NUMBER_TYPES where SQRT(SMALLNUM) = ?");
        project.addStmtProcedure("WHERE_SQRT_BIGINT",   "select count(*) from NUMBER_TYPES where SQRT(TINYNUM) = ?");
        project.addStmtProcedure("WHERE_SQRT_FLOAT",    "select count(*) from NUMBER_TYPES where SQRT(FLOATNUM) = ?");
        project.addStmtProcedure("WHERE_SQRT_DECIMAL""select count(*) from NUMBER_TYPES where SQRT(DECIMALNUM) = ?");

        project.addStmtProcedure("DISPLAY_INTEGER", "select CAST(INTEGERNUM AS INTEGER), CAST(TINYNUM AS INTEGER), CAST(SMALLNUM AS INTEGER), CAST(BIGNUM AS INTEGER), CAST(FLOATNUM AS INTEGER), CAST(DECIMALNUM AS INTEGER) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_INTEGER_CAST_INTEGER""select INTEGERNUM from NUMBER_TYPES order by CAST(INTEGERNUM AS INTEGER)");
        project.addStmtProcedure("ORDER_INTEGER_CAST_TINYINT""select INTEGERNUM from NUMBER_TYPES order by CAST(TINYNUM    AS INTEGER)");
        project.addStmtProcedure("ORDER_INTEGER_CAST_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by CAST(SMALLNUM   AS INTEGER)");
        project.addStmtProcedure("ORDER_INTEGER_CAST_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by CAST(BIGNUM     AS INTEGER)");
        // Provide a tie-breaker sort column for lossy casts to ensure a deterministic result.
        project.addStmtProcedure("ORDER_INTEGER_CAST_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by CAST(FLOATNUM   AS INTEGER), INTEGERNUM");
        project.addStmtProcedure("ORDER_INTEGER_CAST_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by CAST(DECIMALNUM AS INTEGER), INTEGERNUM");

        project.addStmtProcedure("WHERE_INTEGER_CAST_INTEGER""select count(*) from NUMBER_TYPES where CAST(INTEGERNUM AS INTEGER) = ?");
        project.addStmtProcedure("WHERE_INTEGER_CAST_TINYINT""select count(*) from NUMBER_TYPES where CAST(TINYNUM    AS INTEGER) = ?");
        project.addStmtProcedure("WHERE_INTEGER_CAST_SMALLINT", "select count(*) from NUMBER_TYPES where CAST(SMALLNUM   AS INTEGER) = ?");
        project.addStmtProcedure("WHERE_INTEGER_CAST_BIGINT",   "select count(*) from NUMBER_TYPES where CAST(BIGNUM     AS INTEGER) = ?");
        project.addStmtProcedure("WHERE_INTEGER_CAST_FLOAT",    "select count(*) from NUMBER_TYPES where CAST(FLOATNUM   AS INTEGER) = ?");
        project.addStmtProcedure("WHERE_INTEGER_CAST_DECIMAL""select count(*) from NUMBER_TYPES where CAST(DECIMALNUM AS INTEGER) = ?");

        project.addStmtProcedure("DISPLAY_TINYINT", "select CAST(INTEGERNUM AS TINYINT), CAST(TINYNUM AS TINYINT), CAST(SMALLNUM AS TINYINT), CAST(BIGNUM AS TINYINT), CAST(FLOATNUM AS TINYINT), CAST(DECIMALNUM AS TINYINT) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_TINYINT_CAST_INTEGER""select INTEGERNUM from NUMBER_TYPES order by CAST(INTEGERNUM AS TINYINT)");
        project.addStmtProcedure("ORDER_TINYINT_CAST_TINYINT""select INTEGERNUM from NUMBER_TYPES order by CAST(TINYNUM    AS TINYINT)");
        project.addStmtProcedure("ORDER_TINYINT_CAST_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by CAST(SMALLNUM   AS TINYINT)");
        project.addStmtProcedure("ORDER_TINYINT_CAST_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by CAST(BIGNUM     AS TINYINT)");
        // Provide a tie-breaker sort column for lossy casts to ensure a deterministic result.
        project.addStmtProcedure("ORDER_TINYINT_CAST_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by CAST(FLOATNUM   AS TINYINT), INTEGERNUM");
        project.addStmtProcedure("ORDER_TINYINT_CAST_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by CAST(DECIMALNUM AS TINYINT), INTEGERNUM");

        project.addStmtProcedure("WHERE_TINYINT_CAST_INTEGER""select count(*) from NUMBER_TYPES where CAST(INTEGERNUM AS TINYINT) = ?");
        project.addStmtProcedure("WHERE_TINYINT_CAST_TINYINT""select count(*) from NUMBER_TYPES where CAST(TINYNUM    AS TINYINT) = ?");
        project.addStmtProcedure("WHERE_TINYINT_CAST_SMALLINT", "select count(*) from NUMBER_TYPES where CAST(SMALLNUM   AS TINYINT) = ?");
        project.addStmtProcedure("WHERE_TINYINT_CAST_BIGINT",   "select count(*) from NUMBER_TYPES where CAST(BIGNUM     AS TINYINT) = ?");
        project.addStmtProcedure("WHERE_TINYINT_CAST_FLOAT",    "select count(*) from NUMBER_TYPES where CAST(FLOATNUM   AS TINYINT) = ?");
        project.addStmtProcedure("WHERE_TINYINT_CAST_DECIMAL""select count(*) from NUMBER_TYPES where CAST(DECIMALNUM AS TINYINT) = ?");

        project.addStmtProcedure("DISPLAY_SMALLINT", "select CAST(INTEGERNUM AS SMALLINT), CAST(TINYNUM AS SMALLINT), CAST(SMALLNUM AS SMALLINT), CAST(BIGNUM AS SMALLINT), CAST(FLOATNUM AS SMALLINT), CAST(DECIMALNUM AS SMALLINT) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_SMALLINT_CAST_INTEGER""select INTEGERNUM from NUMBER_TYPES order by CAST(INTEGERNUM AS SMALLINT)");
        project.addStmtProcedure("ORDER_SMALLINT_CAST_TINYINT""select INTEGERNUM from NUMBER_TYPES order by CAST(TINYNUM    AS SMALLINT)");
        project.addStmtProcedure("ORDER_SMALLINT_CAST_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by CAST(SMALLNUM   AS SMALLINT)");
        project.addStmtProcedure("ORDER_SMALLINT_CAST_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by CAST(BIGNUM     AS SMALLINT)");
        // Provide a tie-breaker sort column for lossy casts to ensure a deterministic result.
        project.addStmtProcedure("ORDER_SMALLINT_CAST_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by CAST(FLOATNUM   AS SMALLINT), INTEGERNUM");
        project.addStmtProcedure("ORDER_SMALLINT_CAST_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by CAST(DECIMALNUM AS SMALLINT), INTEGERNUM");

        project.addStmtProcedure("WHERE_SMALLINT_CAST_INTEGER""select count(*) from NUMBER_TYPES where CAST(INTEGERNUM AS SMALLINT) = ?");
        project.addStmtProcedure("WHERE_SMALLINT_CAST_TINYINT""select count(*) from NUMBER_TYPES where CAST(TINYNUM    AS SMALLINT) = ?");
        project.addStmtProcedure("WHERE_SMALLINT_CAST_SMALLINT", "select count(*) from NUMBER_TYPES where CAST(SMALLNUM   AS SMALLINT) = ?");
        project.addStmtProcedure("WHERE_SMALLINT_CAST_BIGINT",   "select count(*) from NUMBER_TYPES where CAST(BIGNUM     AS SMALLINT) = ?");
        project.addStmtProcedure("WHERE_SMALLINT_CAST_FLOAT",    "select count(*) from NUMBER_TYPES where CAST(FLOATNUM   AS SMALLINT) = ?");
        project.addStmtProcedure("WHERE_SMALLINT_CAST_DECIMAL""select count(*) from NUMBER_TYPES where CAST(DECIMALNUM AS SMALLINT) = ?");

        project.addStmtProcedure("DISPLAY_BIGINT", "select CAST(INTEGERNUM AS BIGINT), CAST(TINYNUM AS BIGINT), CAST(SMALLNUM AS BIGINT), CAST(BIGNUM AS BIGINT), CAST(FLOATNUM AS BIGINT), CAST(DECIMALNUM AS BIGINT) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_BIGINT_CAST_INTEGER""select INTEGERNUM from NUMBER_TYPES order by CAST(INTEGERNUM AS BIGINT)");
        project.addStmtProcedure("ORDER_BIGINT_CAST_TINYINT""select INTEGERNUM from NUMBER_TYPES order by CAST(TINYNUM    AS BIGINT)");
        project.addStmtProcedure("ORDER_BIGINT_CAST_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by CAST(SMALLNUM   AS BIGINT)");
        project.addStmtProcedure("ORDER_BIGINT_CAST_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by CAST(BIGNUM     AS BIGINT)");
        // Provide a tie-breaker sort column for lossy casts to ensure a deterministic result.
        project.addStmtProcedure("ORDER_BIGINT_CAST_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by CAST(FLOATNUM   AS BIGINT), INTEGERNUM");
        project.addStmtProcedure("ORDER_BIGINT_CAST_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by CAST(DECIMALNUM AS BIGINT), INTEGERNUM");

        project.addStmtProcedure("WHERE_BIGINT_CAST_INTEGER""select count(*) from NUMBER_TYPES where CAST(INTEGERNUM AS BIGINT) = ?");
        project.addStmtProcedure("WHERE_BIGINT_CAST_TINYINT""select count(*) from NUMBER_TYPES where CAST(TINYNUM    AS BIGINT) = ?");
        project.addStmtProcedure("WHERE_BIGINT_CAST_SMALLINT", "select count(*) from NUMBER_TYPES where CAST(SMALLNUM   AS BIGINT) = ?");
        project.addStmtProcedure("WHERE_BIGINT_CAST_BIGINT",   "select count(*) from NUMBER_TYPES where CAST(BIGNUM     AS BIGINT) = ?");
        project.addStmtProcedure("WHERE_BIGINT_CAST_FLOAT",    "select count(*) from NUMBER_TYPES where CAST(FLOATNUM   AS BIGINT) = ?");
        project.addStmtProcedure("WHERE_BIGINT_CAST_DECIMAL""select count(*) from NUMBER_TYPES where CAST(DECIMALNUM AS BIGINT) = ?");

        project.addStmtProcedure("DISPLAY_FLOAT", "select CAST(INTEGERNUM AS FLOAT), CAST(TINYNUM AS FLOAT), CAST(SMALLNUM AS FLOAT), CAST(BIGNUM AS FLOAT), CAST(FLOATNUM AS FLOAT), CAST(DECIMALNUM AS FLOAT) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_FLOAT_CAST_INTEGER""select INTEGERNUM from NUMBER_TYPES order by CAST(INTEGERNUM AS FLOAT)");
        project.addStmtProcedure("ORDER_FLOAT_CAST_TINYINT""select INTEGERNUM from NUMBER_TYPES order by CAST(TINYNUM    AS FLOAT)");
        project.addStmtProcedure("ORDER_FLOAT_CAST_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by CAST(SMALLNUM   AS FLOAT)");
        project.addStmtProcedure("ORDER_FLOAT_CAST_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by CAST(BIGNUM     AS FLOAT)");
        project.addStmtProcedure("ORDER_FLOAT_CAST_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by CAST(FLOATNUM   AS FLOAT)");
        project.addStmtProcedure("ORDER_FLOAT_CAST_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by CAST(DECIMALNUM AS FLOAT)");

        project.addStmtProcedure("WHERE_FLOAT_CAST_INTEGER""select count(*) from NUMBER_TYPES where CAST(INTEGERNUM AS FLOAT) = ?");
        project.addStmtProcedure("WHERE_FLOAT_CAST_TINYINT""select count(*) from NUMBER_TYPES where CAST(TINYNUM    AS FLOAT) = ?");
        project.addStmtProcedure("WHERE_FLOAT_CAST_SMALLINT", "select count(*) from NUMBER_TYPES where CAST(SMALLNUM   AS FLOAT) = ?");
        project.addStmtProcedure("WHERE_FLOAT_CAST_BIGINT",   "select count(*) from NUMBER_TYPES where CAST(BIGNUM     AS FLOAT) = ?");
        project.addStmtProcedure("WHERE_FLOAT_CAST_FLOAT",    "select count(*) from NUMBER_TYPES where CAST(FLOATNUM   AS FLOAT) = ?");
        project.addStmtProcedure("WHERE_FLOAT_CAST_DECIMAL""select count(*) from NUMBER_TYPES where CAST(DECIMALNUM AS FLOAT) = ?");

        project.addStmtProcedure("DISPLAY_DECIMAL", "select CAST(INTEGERNUM AS DECIMAL), CAST(TINYNUM AS DECIMAL), CAST(SMALLNUM AS DECIMAL), CAST(BIGNUM AS DECIMAL), CAST(FLOATNUM AS DECIMAL), CAST(DECIMALNUM AS DECIMAL) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_DECIMAL_CAST_INTEGER""select INTEGERNUM from NUMBER_TYPES order by CAST(INTEGERNUM AS DECIMAL)");
        project.addStmtProcedure("ORDER_DECIMAL_CAST_TINYINT""select INTEGERNUM from NUMBER_TYPES order by CAST(TINYNUM    AS DECIMAL)");
        project.addStmtProcedure("ORDER_DECIMAL_CAST_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by CAST(SMALLNUM   AS DECIMAL)");
        project.addStmtProcedure("ORDER_DECIMAL_CAST_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by CAST(BIGNUM     AS DECIMAL)");
        project.addStmtProcedure("ORDER_DECIMAL_CAST_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by CAST(FLOATNUM   AS DECIMAL)");
        project.addStmtProcedure("ORDER_DECIMAL_CAST_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by CAST(DECIMALNUM AS DECIMAL)");

        project.addStmtProcedure("WHERE_DECIMAL_CAST_INTEGER""select count(*) from NUMBER_TYPES where CAST(INTEGERNUM AS DECIMAL) = ?");
        project.addStmtProcedure("WHERE_DECIMAL_CAST_TINYINT""select count(*) from NUMBER_TYPES where CAST(TINYNUM    AS DECIMAL) = ?");
        project.addStmtProcedure("WHERE_DECIMAL_CAST_SMALLINT", "select count(*) from NUMBER_TYPES where CAST(SMALLNUM   AS DECIMAL) = ?");
        project.addStmtProcedure("WHERE_DECIMAL_CAST_BIGINT",   "select count(*) from NUMBER_TYPES where CAST(BIGNUM     AS DECIMAL) = ?");
        project.addStmtProcedure("WHERE_DECIMAL_CAST_FLOAT",    "select count(*) from NUMBER_TYPES where CAST(FLOATNUM   AS DECIMAL) = ?");
        project.addStmtProcedure("WHERE_DECIMAL_CAST_DECIMAL""select count(*) from NUMBER_TYPES where CAST(DECIMALNUM AS DECIMAL) = ?");

        project.addStmtProcedure("DISPLAY_SUBSTRING", "select SUBSTRING (DESC FROM 2) from P1 where ID = -12");
        project.addStmtProcedure("DISPLAY_SUBSTRING2", "select SUBSTRING (DESC FROM 2 FOR 2) from P1 where ID = -12");

        project.addStmtProcedure("EXTRACT_TIMESTAMP", "select EXTRACT(YEAR FROM PAST), EXTRACT(MONTH FROM PAST), EXTRACT(DAY FROM PAST), " +
                "EXTRACT(DAY_OF_WEEK FROM PAST), EXTRACT(DAY_OF_MONTH FROM PAST), EXTRACT(DAY_OF_YEAR FROM PAST), EXTRACT(QUARTER FROM PAST), " +
                "EXTRACT(HOUR FROM PAST), EXTRACT(MINUTE FROM PAST), EXTRACT(SECOND FROM PAST), EXTRACT(WEEK_OF_YEAR FROM PAST), " +
                "EXTRACT(WEEK FROM PAST), EXTRACT(WEEKDAY FROM PAST) from P1 where ID = ?");


        project.addStmtProcedure("VERIFY_TIMESTAMP_STRING_EQ",
                "select PAST, CAST(DESC AS TIMESTAMP), DESC, CAST(PAST AS VARCHAR) from R2 " +
                "where PAST <> CAST(DESC AS TIMESTAMP)");

        project.addStmtProcedure("VERIFY_STRING_TIMESTAMP_EQ",
                "select PAST, CAST(DESC AS TIMESTAMP), DESC, CAST(PAST AS VARCHAR) from R2 " +
                "where DESC <> CAST(PAST AS VARCHAR)");

        project.addStmtProcedure("DUMP_TIMESTAMP_STRING_PATHS",
                "select PAST, CAST(DESC AS TIMESTAMP), DESC, CAST(PAST AS VARCHAR) from R2");



        project.addStmtProcedure("DISPLAY_VARCHAR", "select CAST(INTEGERNUM AS VARCHAR), CAST(TINYNUM AS VARCHAR), CAST(SMALLNUM AS VARCHAR), CAST(BIGNUM AS VARCHAR), CAST(FLOATNUM AS VARCHAR), CAST(DECIMALNUM AS VARCHAR) from NUMBER_TYPES order by INTEGERNUM");

        project.addStmtProcedure("ORDER_VARCHAR_CAST_INTEGER""select INTEGERNUM from NUMBER_TYPES order by CAST(INTEGERNUM AS VARCHAR)");
        project.addStmtProcedure("ORDER_VARCHAR_CAST_TINYINT""select INTEGERNUM from NUMBER_TYPES order by CAST(TINYNUM    AS VARCHAR)");
        project.addStmtProcedure("ORDER_VARCHAR_CAST_SMALLINT", "select INTEGERNUM from NUMBER_TYPES order by CAST(SMALLNUM   AS VARCHAR)");
        project.addStmtProcedure("ORDER_VARCHAR_CAST_BIGINT",   "select INTEGERNUM from NUMBER_TYPES order by CAST(BIGNUM     AS VARCHAR)");
        project.addStmtProcedure("ORDER_VARCHAR_CAST_FLOAT",    "select INTEGERNUM from NUMBER_TYPES order by CAST(FLOATNUM   AS VARCHAR)");
        project.addStmtProcedure("ORDER_VARCHAR_CAST_DECIMAL""select INTEGERNUM from NUMBER_TYPES order by CAST(DECIMALNUM AS VARCHAR)");

        project.addStmtProcedure("WHERE_VARCHAR_CAST_INTEGER""select count(*) from NUMBER_TYPES where CAST(INTEGERNUM AS VARCHAR) = ?");
        project.addStmtProcedure("WHERE_VARCHAR_CAST_TINYINT""select count(*) from NUMBER_TYPES where CAST(TINYNUM    AS VARCHAR) = ?");
        project.addStmtProcedure("WHERE_VARCHAR_CAST_SMALLINT", "select count(*) from NUMBER_TYPES where CAST(SMALLNUM   AS VARCHAR) = ?");
        project.addStmtProcedure("WHERE_VARCHAR_CAST_BIGINT",   "select count(*) from NUMBER_TYPES where CAST(BIGNUM     AS VARCHAR) = ?");
        project.addStmtProcedure("WHERE_VARCHAR_CAST_FLOAT",    "select count(*) from NUMBER_TYPES where CAST(FLOATNUM   AS VARCHAR) = ?");
        project.addStmtProcedure("WHERE_VARCHAR_CAST_DECIMAL""select count(*) from NUMBER_TYPES where CAST(DECIMALNUM AS VARCHAR) = ?");

        project.addStmtProcedure("ORDER_SUBSTRING", "select ID+15 from P1 order by SUBSTRING (DESC FROM 2)");

        project.addStmtProcedure("WHERE_SUBSTRING2",
                                 "select count(*) from P1 " +
                                 "where SUBSTRING (DESC FROM 2) > '12"+paddedToNonInlineLength+"'");
        project.addStmtProcedure("WHERE_SUBSTRING3",
                                 "select count(*) from P1 " +
                                 "where not SUBSTRING (DESC FROM 2 FOR 1) > '13'");

        // Test GROUP BY by support
        project.addStmtProcedure("AGG_OF_SUBSTRING", "select MIN(SUBSTRING (DESC FROM 2)) from P1 where ID < -7");
        project.addStmtProcedure("AGG_OF_SUBSTRING2", "select MIN(SUBSTRING (DESC FROM 2 FOR 2)) from P1 where ID < -7");

        // Test parameterizing functions
        // next one disabled until ENG-3486
        //project.addStmtProcedure("PARAM_SUBSTRING", "select SUBSTRING(? FROM 2) from P1");
        project.addStmtProcedure("PARAM_ABS", "select ABS(? + NUM) from P1");

        project.addStmtProcedure("LEFT", "select id, LEFT(DESC,?) from P1 where id = ?");
        project.addStmtProcedure("RIGHT", "select id, RIGHT(DESC,?) from P1 where id = ?");
        project.addStmtProcedure("SPACE", "select id, SPACE(?) from P1 where id = ?");
        project.addStmtProcedure("LOWER_UPPER", "select id, LOWER(DESC), UPPER(DESC) from P1 where id = ?");

        project.addStmtProcedure("TRIM_SPACE", "select id, LTRIM(DESC), TRIM(LEADING ' ' FROM DESC), " +
                "RTRIM(DESC), TRIM(TRAILING ' ' FROM DESC), TRIM(DESC), TRIM(BOTH ' ' FROM DESC) from P1 where id = ?");
        project.addStmtProcedure("TRIM_ANY", "select id, TRIM(LEADING ? FROM DESC), TRIM(TRAILING ? FROM DESC), " +
                "TRIM(BOTH ? FROM DESC) from P1 where id = ?");

        project.addStmtProcedure("REPEAT", "select id, REPEAT(DESC,?) from P1 where id = ?");
        project.addStmtProcedure("REPLACE", "select id, REPLACE(DESC,?, ?) from P1 where id = ?");
        project.addStmtProcedure("OVERLAY", "select id, OVERLAY(DESC PLACING ? FROM ? FOR ?) from P1 where id = ?");
        project.addStmtProcedure("OVERLAY_FULL_LENGTH", "select id, OVERLAY(DESC PLACING ? FROM ?) from P1 where id = ?");

        project.addStmtProcedure("CHAR", "select id, CHAR(?) from P1 where id = ?");

        project.addStmtProcedure("INSERT_NULL", "insert into P1 values (?, null, null, null, null)");
        // project.addStmtProcedure("UPS", "select count(*) from P1 where UPPER(DESC) > 'L'");

        // CONFIG #1: Local Site/Partitions running on JNI backend
        config = new LocalCluster("fixedsql-onesite.jar", 1, 1, 0, BackendTarget.NATIVE_EE_JNI);
        // alternative to enable for debugging */ config = new LocalCluster("IPC-onesite.jar", 1, 1, 0, BackendTarget.NATIVE_EE_IPC);
        success = config.compile(project);
        assertTrue(success);
        builder.addServerConfig(config);

        // CONFIG #2: HSQL
        config = new LocalCluster("fixedsql-hsql.jar", 1, 1, 0, BackendTarget.HSQLDB_BACKEND);
        success = config.compile(project);
        assertTrue(success);
        builder.addServerConfig(config);

        // no clustering tests for functions

        return builder;
    }
}
TOP

Related Classes of org.voltdb.regressionsuites.TestFunctionsSuite$FunctionTestCase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
', 'auto'); ga('send', 'pageview');