Package org.voltdb.regressionsuites

Source Code of org.voltdb.regressionsuites.TestSQLTypesSuite

/* 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.math.BigInteger;
import java.util.concurrent.atomic.AtomicInteger;

import org.voltdb.BackendTarget;
import org.voltdb.VoltTable;
import org.voltdb.VoltTableRow;
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.compiler.VoltProjectBuilder;
import org.voltdb.types.TimestampType;
import org.voltdb.types.VoltDecimalHelper;
import org.voltdb.utils.Encoder;
import org.voltdb.utils.VoltTypeUtil;
import org.voltdb_testprocs.regressionsuites.sqltypesprocs.Delete;
import org.voltdb_testprocs.regressionsuites.sqltypesprocs.Insert;
import org.voltdb_testprocs.regressionsuites.sqltypesprocs.InsertBase;
import org.voltdb_testprocs.regressionsuites.sqltypesprocs.InsertMulti;
import org.voltdb_testprocs.regressionsuites.sqltypesprocs.ParamSetArrays;
import org.voltdb_testprocs.regressionsuites.sqltypesprocs.Select;
import org.voltdb_testprocs.regressionsuites.sqltypesprocs.Update;
import org.voltdb_testprocs.regressionsuites.sqltypesprocs.UpdateDecimal;

import com.google_voltpatches.common.base.Charsets;

public class TestSQLTypesSuite extends RegressionSuite {

    // used to generate unique pkeys
    public static final AtomicInteger pkey = new AtomicInteger(0);

    // constant for 0x00
    private static final byte OO = (byte) 0x00; // font test?

    // 1500 character string
    private static final String ReallyLongString;

    /** Procedures used by this suite */
    static final Class<?>[] PROCEDURES = { Delete.class, Insert.class,
            InsertBase.class, InsertMulti.class, Select.class, Update.class,
            UpdateDecimal.class, ParamSetArrays.class };

    /** Utility to create an array of bytes with value "b" of length "length" */
    public static byte[] byteArray(final int length, final byte b) {
        final byte[] arr = new byte[length];
        for (int i = 0; i < length; ++i) {
            arr[i] = b;
        }
        return arr;
    }

    /** Utility to compare two instances of a VoltType for equality */
    @SuppressWarnings({ "incomplete-switch" })
    private boolean comparisonHelper(final Object lhs, final Object rhs,
            final VoltType vt) {
        switch (vt) {
        case TINYINT:
            final Byte b1 = (Byte) lhs;
            final Byte b2 = (Byte) rhs;
            // System.out.println("\tComparing " + b1 + " == " + b2);
            return b1.byteValue() == b2.byteValue();
        case SMALLINT:
            final Short s1 = (Short) lhs;
            final Short s2 = (Short) rhs;
            // System.out.println("\tComparing " + s1 + " == " + s2);
            return s1.shortValue() == s2.shortValue();
        case INTEGER:
            final Integer i1 = (Integer) lhs;
            final Integer i2 = (Integer) rhs;
            // System.out.println("\tComparing " + i1 + " == " + i2);
            return i1.intValue() == i2.intValue();
        case BIGINT:
            final Long l1 = (Long) lhs;
            final Long l2 = (Long) rhs;
            // System.out.println("\tComparing " + l1 + " == " + l2);
            return l1.longValue() == l2.longValue();
        case FLOAT:
            final Double d1 = (Double) lhs;
            final Double d2 = (Double) rhs;
            // System.out.println("\tComparing " + d1 + " == " + d2);
            // Handle the screwy null double value (isn't quite min double)
            if (((d1 == VoltType.NULL_FLOAT) && (d2 <= d1))
                    || ((d2 == VoltType.NULL_FLOAT) && (d1 <= d2))) {
                return true;
            }
            return (Math.abs(d1 - d2) < 0.0000000001);
        case STRING:
            // System.out.println("\tComparing " + lhs + " == " + rhs);
            if ((lhs == null || lhs == VoltType.NULL_STRING_OR_VARBINARY)
                    && (rhs == null || rhs == VoltType.NULL_STRING_OR_VARBINARY)) {
                return true;
            }
            return ((String) lhs).equals(rhs);
        case VARBINARY:
            boolean lhsnull = (lhs == null || lhs == VoltType.NULL_STRING_OR_VARBINARY);
            boolean rhsnull = (rhs == null || rhs == VoltType.NULL_STRING_OR_VARBINARY);
            if (lhsnull && rhsnull)
                return true;
            if (lhsnull != rhsnull)
                return false;

            // assume neither is null from here

            String lhs2 = null;
            String rhs2 = null;

            if (lhs instanceof byte[])
                lhs2 = Encoder.hexEncode((byte[]) lhs);
            else
                lhs2 = (String) lhs;

            if (rhs instanceof byte[])
                rhs2 = Encoder.hexEncode((byte[]) rhs);
            else
                rhs2 = (String) rhs;

            return lhs2.equalsIgnoreCase(rhs2);
        case TIMESTAMP:
            // System.out.println("\tComparing " + lhs + " == " + rhs);
            if ((lhs == null || lhs == VoltType.NULL_TIMESTAMP)
                    && (rhs == null || rhs == VoltType.NULL_TIMESTAMP)) {
                return true;
            }
            return ((TimestampType) lhs).equals(rhs);
        case DECIMAL:
            // System.out.println("\tComparing " + lhs + " == " + rhs);
            if ((lhs == null || lhs == VoltType.NULL_DECIMAL)
                    && (rhs == null || rhs == VoltType.NULL_DECIMAL)) {
                return true;
            }
            return ((BigDecimal) lhs).equals(rhs);
        }

        return false;
    }

    //
    // UPDATE THE COLUMN LIST WHEN ADDING NEW TYPE
    //

    // Class to hold column test information.
    private static class Column {
        final String m_columnName;
        final VoltType m_type;
        final boolean m_supportsMath;
        final Object m_nullValue;
        final Object m_defaultValue;
        final Object m_minValue;
        final Object m_midValue;
        Object m_maxValue;

        Column(String columnName,
               VoltType type,
               boolean supportsMath,
               Object nullValue,
               Object defaultValue,
               Object minValue,
               Object midValue,
               Object maxValue) {
            m_type = type;
            m_supportsMath = supportsMath;
            m_columnName = columnName;
            m_nullValue = nullValue;
            m_defaultValue = defaultValue;
            m_minValue = minValue;
            m_midValue = midValue;
            m_maxValue = maxValue;
        }
    }

    // Non-PKEY column information, including interesting sets of values for the various types.
    // Tests rely on this ordering of the string varchar widths.
    // APPEND HERE WHEN ADDING NEW TYPE/COLUMN
    private static Column[] m_columns = {
        new Column("A_TINYINT", VoltType.TINYINT, true ,
                   VoltType.NULL_TINYINT,
                   new Byte((byte) (1)),
                   new Byte((byte) (Byte.MIN_VALUE + 1)), // MIN is NULL
                   new Byte((byte) 10),
                   Byte.MAX_VALUE),
        new Column("A_SMALLINT", VoltType.SMALLINT, true,
                   VoltType.NULL_SMALLINT,
                   new Short((short) (2)),
                   new Short((short) (Short.MIN_VALUE + 1)), // MIN is NULL
                   new Short((short) 11),
                   Short.MAX_VALUE),
        new Column("A_INTEGER", VoltType.INTEGER, true ,
                   VoltType.NULL_INTEGER,
                   3,
                   Integer.MIN_VALUE + 1, // MIN is NULL
                   new Integer(12),
                   Integer.MAX_VALUE),
        new Column("A_BIGINT", VoltType.BIGINT, true,
                   VoltType.NULL_BIGINT,
                   4L,
                   Long.MIN_VALUE + 1, // MIN is NULL
                   new Long(13),
                   Long.MAX_VALUE),
        new Column("A_FLOAT", VoltType.FLOAT, true,
                   VoltType.NULL_FLOAT,
                   5.1,
                   Double.MIN_VALUE, // NULL is -1.7E308.
                   new Double(14.5),
                   Double.MAX_VALUE),
        new Column("A_TIMESTAMP", VoltType.TIMESTAMP, false,
                   VoltType.NULL_TIMESTAMP,
                   new TimestampType(600000),
                   new TimestampType(Long.MIN_VALUE + 1),
                   new TimestampType(),
                   new TimestampType(Long.MAX_VALUE)),
        new Column("A_INLINE_S1", VoltType.STRING, false,
                   VoltType.NULL_STRING_OR_VARBINARY,
                   new String("abcd"),
                   new String(byteArray(1, OO)),
                   new String("xyz"),
                   new String("ZZZZ")),
        new Column("A_INLINE_S2", VoltType.STRING, false,
                   VoltType.NULL_STRING_OR_VARBINARY,
                   new String("abcdefghij"),
                   new String(byteArray(1, OO)),
                   new String("xyzab"),
                   new String("ZZZZZZZZZZ" + // 10
                              "ZZZZZZZZZZ" + // 20
                              "ZZZZZZZZZZ" + // 30
                              "ZZZZZZZZZZ" + // 40
                              "ZZZZZZZZZZ" + // 50
                              "ZZZZZZZZZZ" + // 60
                              "ZZZ")), // 63
        new Column("A_POOL_S", VoltType.STRING, false,
                   VoltType.NULL_STRING_OR_VARBINARY,
                   new String("abcdefghijklmnopqrstuvwxyz"),
                   new String(byteArray(1, OO)),
                   new String("xyzabcdefghijklmnopqrstuvw"),
                   ""),
        new Column("A_POOL_MAX_S", VoltType.STRING, false,
                   VoltType.NULL_STRING_OR_VARBINARY,
                   new String("abcdefghijklmnopqrstuvwxyz"),
                   new String(byteArray(1, OO)),
                   new String("xyzabcdefghijklmnopqrstuvw"),
                   ""),
        new Column("A_INLINE_B", VoltType.VARBINARY, false,
                   VoltType.NULL_STRING_OR_VARBINARY,
                   new String("ABCDEFABCDEF0123"),
                   new byte[] { 0 },
                   new byte[] { 'a', 'b', 'c' },
                   new String("ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ").getBytes(Charsets.UTF_8)),
        new Column("A_POOL_B", VoltType.VARBINARY, false,
                   VoltType.NULL_STRING_OR_VARBINARY,
                   new String("ABCDEFABCDEF0123456789"),
                   new byte[] { 0 },
                   new byte[] { 'a', 'b', 'c' },
                   new byte[] {}),
        new Column("A_DECIMAL", VoltType.DECIMAL, true,
                   VoltType.NULL_DECIMAL,
                   new BigDecimal(new BigInteger("6000000000000"))
                       .scaleByPowerOfTen(-1 * VoltDecimalHelper.kDefaultScale),
                   new BigDecimal(new BigInteger(
                       "-99999999999999999999999999999999999999"))
                       .scaleByPowerOfTen(-1 * VoltDecimalHelper.kDefaultScale),
                   new BigDecimal(new BigInteger("5115101010101010345634"))
                       .scaleByPowerOfTen(-1 * VoltDecimalHelper.kDefaultScale),
                   new BigDecimal(new BigInteger(
                       "99999999999999999999999999999999999999"))
                       .scaleByPowerOfTen(-1 * VoltDecimalHelper.kDefaultScale))
    };

    // Generate additional m_maxValue data and ReallyLongString..
    static {
        StringBuilder sb = new StringBuilder(1048576);
        int ii = 0;
        for (; ii < 65536; ii++) {
            sb.append('Z');
        }
        m_columns[8].m_maxValue = sb.toString();
        for (; ii < 1048576; ii++) {
            sb.append('Z');
        }
        m_columns[9].m_maxValue = sb.toString();
        sb = new StringBuilder(102400);
        for (ii = 0; ii < 102400; ii++) {
            sb.append('a');
        }
        ReallyLongString = sb.toString();
    }

    // Populate these members from m_columns for backward compatibility.
    // Changing all the references to use m_columns would be much more painful.
    public static int COLS = m_columns.length;
    public static VoltType[] m_types = new VoltType[m_columns.length];
    public static boolean[] m_supportsMath = new boolean[m_columns.length];
    public static String[] m_columnNames = new String[m_columns.length];
    public static Object[] m_nullValues = new Object[m_columns.length];
    public static Object[] m_defaultValues = new Object[m_columns.length];
    public static Object[] m_minValues = new Object[m_columns.length];
    public static Object[] m_midValues = new Object[m_columns.length];
    public static Object[] m_maxValues = new Object[m_columns.length];
    static {
        for (int i = 0; i < m_columns.length; i++) {
            m_types[i] = m_columns[i].m_type;
            m_supportsMath[i] = m_columns[i].m_supportsMath;
            m_columnNames[i] = m_columns[i].m_columnName;
            m_nullValues[i] = m_columns[i].m_nullValue;
            m_defaultValues[i] = m_columns[i].m_defaultValue;
            m_minValues[i] = m_columns[i].m_minValue;
            m_midValues[i] = m_columns[i].m_midValue;
            m_maxValues[i] = m_columns[i].m_maxValue;
        }
    }

    public void testPassingNullObjectToSingleStmtProcedure() throws Exception {
        final Client client = this.getClient();

        client.callProcedure("PassObjectNull", 0, 0, 0, 0, 0, 0.0, null, null,
                null, null, null, null, null, null);
    }

    public void testPassingDateAndTimeObjectsToStatements() throws Exception {
        final Client client = this.getClient();

        // Capture the same value within the supported millisecond granularity
        // in each of the supported time formats to demonstrate that they are interchangeable.
        long millisecondsSinceEpoch = 1001001001L;
        TimestampType tst = new TimestampType(millisecondsSinceEpoch * 1000);
        java.util.Date utild = new java.util.Date(millisecondsSinceEpoch);
        java.sql.Date sqld = new java.sql.Date(millisecondsSinceEpoch);
        java.sql.Timestamp ts = new java.sql.Timestamp(millisecondsSinceEpoch);

        int lowerBound = pkey.incrementAndGet();
        // system-defined CRUD inputs
        client.callProcedure("ALLOW_NULLS.insert", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, tst,
                null, null, null, null, null, null, null);
        client.callProcedure("ALLOW_NULLS.insert", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, utild,
                null, null, null, null, null, null, null);
        client.callProcedure("ALLOW_NULLS.insert", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, sqld,
                null, null, null, null, null, null, null);
        client.callProcedure("ALLOW_NULLS.insert", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, ts,
                null, null, null, null, null, null, null);

        // user-defined statement inputs
        client.callProcedure("PassObjectNull", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, tst,
                null, null, null, null, null, null, null);
        client.callProcedure("PassObjectNull", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, utild,
                null, null, null, null, null, null, null);
        client.callProcedure("PassObjectNull", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, sqld,
                null, null, null, null, null, null, null);
        client.callProcedure("PassObjectNull", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, ts,
                null, null, null, null, null, null, null);

        // stored procedure inputs into queued statement
        // -- this doesn't exercise passing the java types into the stored procedure
        // -- that's covered by TestSQLFeaturesSuite's testPassAllArgTypes
        client.callProcedure("Insert", "ALLOW_NULLS", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, tst,
                null, null, null, null, null, null, null);
        client.callProcedure("Insert", "ALLOW_NULLS and use sql.Timestamp", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, tst,
                null, null, null, null, null, null, null);
        client.callProcedure("Insert", "ALLOW_NULLS and use sql.Date", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, tst,
                null, null, null, null, null, null, null);
        client.callProcedure("Insert", "ALLOW_NULLS and use util.Date", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, tst,
                null, null, null, null, null, null, null);

        ClientResponse cr;
        VoltTable[] result;
        VoltTable vt;
        cr = client.callProcedure("@AdHoc", "SELECT A_TIMESTAMP from ALLOW_NULLS where PKEY > " + lowerBound + ";");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults();
        assertEquals(12, result[0].getRowCount());
        vt = result[0];
        while (vt.advanceRow()) {
            // Within the millisecond granularity all formats should encapsulate the same value.
            assertEquals(tst, vt.getTimestampAsTimestamp(0));
            assertEquals(ts, vt.getTimestampAsSqlTimestamp(0));
            assertEquals(sqld, vt.getTimestampAsSqlTimestamp(0));
            assertEquals(utild, vt.getTimestampAsSqlTimestamp(0));
        }

        // Demonstrate that TimestampType and java.sql.Timestamp support microseconds while Dates truncate to milliseconds.
        // Capture the same value within the supported millisecond granularity
        // in each of the supported time formats to demonstrate that they are interchangeable.
        long microsecondsSinceEpoch = 1001001001001L;
        TimestampType tst_micro = new TimestampType(microsecondsSinceEpoch);
        java.sql.Timestamp ts_micro = new java.sql.Timestamp(microsecondsSinceEpoch/1000);
        // At this point, the additional 1 microsecond was truncated in the division, and so is still not reflected in ts_micro.
        assertEquals(ts, ts_micro);
        // Extract the 1000000 nanos (doubly-counted milliseconds)
        assertEquals(1000000, ts_micro.getNanos());
        // and explicitly add in the truncated 1000 nanos (1 microsecond)
        ts_micro.setNanos(ts_micro.getNanos()+1000);

        assertNotSame(tst, tst_micro);
        assertNotSame(ts, ts_micro);

        // A new round of inserts, just using the more accurate formats.
        lowerBound = pkey.incrementAndGet();
        // system-defined CRUD inputs
        client.callProcedure("ALLOW_NULLS.insert", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, tst_micro,
                null, null, null, null, null, null, null);
        client.callProcedure("ALLOW_NULLS.insert", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, ts_micro,
                null, null, null, null, null, null, null);

        // user-defined statement inputs
        client.callProcedure("PassObjectNull", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, tst_micro,
                null, null, null, null, null, null, null);
        client.callProcedure("PassObjectNull", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, ts_micro,
                null, null, null, null, null, null, null);

        // stored procedure inputs into queued statement
        client.callProcedure("Insert", "ALLOW_NULLS", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, tst_micro,
                null, null, null, null, null, null, null);
        client.callProcedure("Insert", "ALLOW_NULLS and use sql.Timestamp", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, tst_micro,
                null, null, null, null, null, null, null);

        cr = client.callProcedure("@AdHoc", "SELECT A_TIMESTAMP from ALLOW_NULLS where PKEY > " + lowerBound + ";");
        assertEquals(ClientResponse.SUCCESS, cr.getStatus());
        result = cr.getResults();
        assertEquals(6, result[0].getRowCount());
        vt = result[0];
        while (vt.advanceRow()) {
            // Within the microsecond granularity only the detailed formats preserve the "full" accuracy.
            assertNotSame(tst, vt.getTimestampAsTimestamp(0));
            assertNotSame(ts, vt.getTimestampAsSqlTimestamp(0));
            assertEquals(tst_micro, vt.getTimestampAsTimestamp(0));
            assertEquals(ts_micro, vt.getTimestampAsSqlTimestamp(0));
            assertEquals(sqld, vt.getTimestampAsSqlTimestamp(0));
            assertEquals(utild, vt.getTimestampAsSqlTimestamp(0));
        }

        // Now, go overboard, trying to preserve nano accuracy.
        // XXX: The following tests are a little controversial.
        // Some would prefer a gentler response -- just truncating/rounding to the nearest microsecond.
        // When these voices of reason prevail, this test should be replaced by a test that nano-noise
        // gets filtered out but the result is still correct to microsecond granularity.
        java.sql.Timestamp ts_nano = new java.sql.Timestamp(millisecondsSinceEpoch);
        assertEquals(ts, ts_nano);
        // Extract the 1000000 nanos (doubly-counted milliseconds)
        assertEquals(1000000, ts_nano.getNanos());
        // and explicitly add in 1001 nanos (1 microsecond + 1 nanosecond)
        ts_nano.setNanos(ts_nano.getNanos()+1001);

        // Should be off by 1 nano.
        assertNotSame(ts_micro, ts_nano);

        // A new round of inserts, trying to use the too accurate format.
        lowerBound = pkey.incrementAndGet();

        boolean caught;
        try {
            caught = false;
            // system-defined CRUD inputs
            cr = client.callProcedure("ALLOW_NULLS.insert", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, ts_nano,
                    null, null, null, null, null, null, null);
        } catch (RuntimeException e) {
            caught = true;
        }
        assert(caught);

        try {
            caught = false;
            // user-defined statement inputs
            cr = client.callProcedure("PassObjectNull", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, ts_nano,
                    null, null, null, null, null, null, null);
        } catch (RuntimeException e) {
            caught = true;
        }
        assert(caught);

        // Smuggling nanos into a stored procedure is also already covered by TestSQLFeaturesSuite's testPassAllArgTypes

        // Exceptions above should have pre-empted execution (and not just come after successful writes).
        cr = client.callProcedure("@AdHoc", "SELECT A_TIMESTAMP from ALLOW_NULLS where PKEY > " + lowerBound + ";");
        result = cr.getResults();
        assertEquals(0, result[0].getRowCount());
    }

    public void testPassingDateAndTimeObjectsBeforeEpochToStatements() throws Exception {
        final Client client = this.getClient();

        long microsecondsSinceEpoch = -1001003050L;
        TimestampType tst_micro = new TimestampType(microsecondsSinceEpoch);

        // Add 1 more millis from epoch
        java.sql.Timestamp ts_micro = VoltTypeUtil.getSqlTimestampFromMicrosSinceEpoch(microsecondsSinceEpoch);

        client.callProcedure("Insert", "ALLOW_NULLS", 0, 0, 0, 0, 0,
                             null, tst_micro, null,
                             null, null, null, null, null, null);

        VoltTable vt;
        vt = client.callProcedure("@AdHoc", "Select A_TIMESTAMP from allow_nulls where pkey = 0").getResults()[0];
        assertTrue(vt.advanceRow());
        assertEquals(microsecondsSinceEpoch, vt.getTimestampAsLong(0));
        assertEquals(tst_micro, vt.getTimestampAsTimestamp(0));
        assertEquals(ts_micro, vt.getTimestampAsSqlTimestamp(0));

    }

    // ENG-1276
    public void testPassingFloatToDoubleArg() throws Exception {
        final Client client = this.getClient();

        client.callProcedure("Insert", "ALLOW_NULLS", 0, 0, 0, 0, 0,
                             new Float(0.0), null, null,
                             null, null, null, null, null, null);
    }

    //
    // Insert strings that violate the VARCHAR size limit.
    //
    public void testInsertViolatesStringLength() throws IOException,
            ProcCallException {
        final Client client = this.getClient();
        boolean caught = false;

        // perform this test on the NULLS and NO_NULLS tables
        // by looping twice and setting params[0] differently each time.
        for (int i = 0; i < 2; ++i) {
            final Object params[] = new Object[COLS + 2];
            params[0] = (i == 0) ? "NO_NULLS" : "ALLOW_NULLS";

            // insert a string that violates the varchar size.
            // there are three strings in the schema with sizes
            // that can be violated. test each.
            // loop three times and set a different
            // varchar to the too-big value each time.
            for (int stringcount = 0; stringcount < 3; ++stringcount) {
                int curr_string = 0;
                params[1] = pkey.incrementAndGet();
                for (int k = 0; k < COLS; ++k) {
                    if ((m_types[k] == VoltType.STRING)
                            && (stringcount == curr_string)) {
                        params[k + 2] = ReallyLongString;
                    } else {
                        params[k + 2] = m_midValues[k];
                    }
                    if (m_types[k] == VoltType.STRING)
                        curr_string++;
                }
                try {
                    caught = false;
                    client.callProcedure("Insert", params);
                } catch (final ProcCallException e) {
                    caught = true;
                }

                assertTrue(caught);
            }
        }
    }

    //
    // Test that the max serializable string length is correctly handled.
    // It must be rejected always since it is greater than the max varchar size.
    //
    public void testMaxSerializeStringSize() throws IOException,
            ProcCallException {
        final Client client = getClient();
        boolean caught = false;
        final Object params[] = new Object[COLS + 2];
        params[0] = "NO_NULLS";

        // array to build the Big String.
        final char blob[] = new char[VoltType.MAX_VALUE_LENGTH + 4];
        for (int i = 0; i < blob.length; i++) {
            blob[i] = 'a';
        }

        // try to insert a max length string blob into each of the string fields
        // this string *is* fastserializable.
        for (int stringcount = 0; stringcount < 4; ++stringcount) {
            int curr_string = 0;
            params[1] = pkey.incrementAndGet();
            for (int k = 0; k < COLS; ++k) {
                if ((m_types[k] == VoltType.STRING)
                        && (stringcount == curr_string)) {
                    params[k + 2] = new String(blob);
                } else {
                    params[k + 2] = m_midValues[k];
                }
                if (m_types[k] == VoltType.STRING)
                    curr_string++;
            }
            try {
                caught = false;
                client.callProcedure("Insert", params);
            }
            catch (final ProcCallException e) {
                System.err.println(e.getMessage());
                assertTrue(e.toString().contains("exceeds the size of the VARCHAR"));
                caught = true;
            }
            assertTrue(caught);
        }
    }

    //
    // Test that the max supported varchar can be inserted.
    //
    public void testMaxValidStringSize() throws IOException, ProcCallException {
        final Client client = getClient();
        boolean caught = false;
        final Object params[] = new Object[COLS + 2];
        params[0] = "NO_NULLS";

        // array to build the Big String.
        final char blob[] = new char[VoltType.MAX_VALUE_LENGTH];
        for (int i = 0; i < blob.length; i++) {
            blob[i] = 'a';
        }

        // try to insert a max length string blob into each of the string fields
        // this string *is* fastserializable.
        for (int stringcount = 0; stringcount < 4; ++stringcount) {
            int curr_string = 0;
            params[1] = pkey.incrementAndGet();
            for (int k = 0; k < COLS; ++k) {
                if ((m_types[k] == VoltType.STRING)
                        && (stringcount == curr_string)) {
                    params[k + 2] = new String(blob);
                } else {
                    params[k + 2] = m_midValues[k];
                }
                if (m_types[k] == VoltType.STRING)
                    curr_string++;
            }
            try {
                caught = false;
                client.callProcedure("Insert", params);
            } catch (final ProcCallException e) {
                caught = true;
            }
            // the last (1048576) string should be fine here.
            if (stringcount != 3) {
                assertTrue(caught);
            } else {
                assertFalse(caught);
            }
        }
    }

    //
    // Verify that NULLS are rejected in in NOT NULL columns
    //
    public void testInsertNulls_No_Nulls() throws IOException {
        final Client client = this.getClient();

        // Insert a NULL value for each column. For the first
        // row, insert null in the first column, for the 5th row
        // in the 5 column, etc.

        final Object params[] = new Object[COLS + 2];

        for (int k = 0; k < COLS; ++k) {
            boolean caught = false;

            // build the parameter list as described above
            params[0] = "NO_NULLS";
            params[1] = pkey.incrementAndGet();
            for (int i = 0; i < COLS; i++) {
                params[i + 2] = (i == k) ? m_nullValues[i] : m_midValues[i];
                assert (params[i + 2] != null);
            }

            // Each insert into the NO_NULLS table must fail with a
            // constraint failure. Verify this.

            System.out.println("testNullsRejected: :" + k + " " + m_types[k]);
            try {
                client.callProcedure("Insert", params);
            } catch (final ProcCallException e) {
                if (e.getMessage().contains("CONSTRAINT VIOLATION"))
                    caught = true;
                else {
                    e.printStackTrace();
                    fail();
                }
            } catch (final NoConnectionsException e) {
                e.printStackTrace();
                fail();
            }
            assertTrue(caught);
        }
    }

    //
    // Verify that NULLS are allowed in non-NOT NULL columns
    //
    public void testInsertNulls_Nulls_Allowed() throws IOException {
        final Client client = this.getClient();

        // Insert a NULL value for each column. For the first
        // row, insert null in the first column, for the 5th row
        // in the 5 column, etc.

        final Object params[] = new Object[COLS + 2];

        for (int k = 0; k < COLS; ++k) {

            // build the parameter list as described above
            params[0] = "";
            params[1] = pkey.incrementAndGet();
            for (int i = 0; i < COLS; i++) {
                params[i + 2] = (i == k) ? m_nullValues[i] : m_midValues[i];
                assert (params[i + 2] != null);
            }

            // Each insert in to the ALLOW_NULLS table must succeed.
            // Perform the inserts and execute selects, verifying the
            // content of the select matches the parameters passed to
            // insert

            System.out.println("testNullsAllowed: " + k + " NULL type is "
                    + m_types[k]);

            try {
                params[0] = "ALLOW_NULLS";
                // We'll use the multi-partition insert for this test. Between
                // this and testInsertNull_No_Nulls we should cover both
                // cases in ticket 306
                client.callProcedure("InsertMulti", params);
            } catch (final ProcCallException e) {
                e.printStackTrace();
                fail();
            } catch (final NoConnectionsException e) {
                e.printStackTrace();
                fail();
            }

            // verify that the row was inserted
            try {
                final VoltTable[] result = client.callProcedure("Select",
                        "ALLOW_NULLS", pkey.get()).getResults();
                final VoltTableRow row = result[0].fetchRow(0);
                for (int i = 0; i < COLS; ++i) {
                    final Object obj = row.get(i + 1, m_types[i]);
                    if (i == k) {
                        assertTrue(row.wasNull());
                        System.out.println("Row " + i + " verifed as NULL");
                    } else {
                        assertTrue(comparisonHelper(obj, params[i + 2],
                                m_types[i]));
                    }
                }
            } catch (final Exception ex) {
                ex.printStackTrace();
                fail();
            }
        }
    }

    public void testUpdateToNull() throws IOException, ProcCallException {
        final Client client = this.getClient();

        final Object params[] = new Object[COLS + 2];

        for (int k = 0; k < COLS; ++k) {

            // build the parameter list as described above
            // Fill the row with non-null data and insert
            params[0] = "";
            params[1] = pkey.incrementAndGet();
            for (int i = 0; i < COLS; i++) {
                params[i + 2] = m_midValues[i];
                assert (params[i + 2] != null);
            }
            params[0] = "ALLOW_NULLS";
            client.callProcedure("Insert", params);

            for (int i = 0; i < COLS; i++) {
                params[i + 2] = (i == k) ? m_nullValues[i] : m_midValues[i];
                assert (params[i + 2] != null);
            }

            try {
                client.callProcedure("Update", params);
            } catch (final ProcCallException e) {
                e.printStackTrace();
                fail();
            } catch (final NoConnectionsException e) {
                e.printStackTrace();
                fail();
            }

            // verify that the row was updated
            final VoltTable[] result = client.callProcedure("Select",
                    "ALLOW_NULLS", pkey.get()).getResults();
            final VoltTableRow row = result[0].fetchRow(0);
            for (int i = 0; i < COLS; ++i) {
                final Object obj = row.get(i + 1, m_types[i]);
                if (i == k) {
                    assertTrue(row.wasNull());
                } else {
                    assertTrue(comparisonHelper(obj, params[i + 2], m_types[i]));
                }
            }
        }
    }

    public void testUpdateFromNull() throws NoConnectionsException,
            ProcCallException, IOException {
        final Client client = this.getClient();

        final Object params[] = new Object[COLS + 2];

        for (int k = 0; k < COLS; ++k) {

            // build the parameter list as described above
            // Fill the row with diagonal null data and insert
            params[0] = "";
            params[1] = pkey.incrementAndGet();
            for (int i = 0; i < COLS; i++) {
                params[i + 2] = (i == k) ? m_nullValues[i] : m_midValues[i];
                assert (params[i + 2] != null);
            }
            params[0] = "ALLOW_NULLS";
            client.callProcedure("Insert", params);

            for (int i = 0; i < COLS; i++) {
                params[i + 2] = m_midValues[i];
                assert (params[i + 2] != null);
            }

            try {
                client.callProcedure("Update", params);
            } catch (final ProcCallException e) {
                e.printStackTrace();
                fail();
            } catch (final NoConnectionsException e) {
                e.printStackTrace();
                fail();
            }

            // verify that the row was updated
            final VoltTable[] result = client.callProcedure("Select",
                    "ALLOW_NULLS", pkey.get()).getResults();
            final VoltTableRow row = result[0].fetchRow(0);
            for (int i = 0; i < COLS; ++i) {
                final Object obj = row.get(i + 1, m_types[i]);
                assertTrue(comparisonHelper(obj, params[i + 2], m_types[i]));
            }
        }
    }

    public void testDeleteNulls() throws NoConnectionsException,
            ProcCallException, IOException {
        final Client client = this.getClient();

        // Insert a NULL value for each column. For the first
        // row, insert null in the first column, for the 5th row
        // in the 5 column, etc.

        final Object params[] = new Object[COLS + 2];

        for (int k = 0; k < COLS; ++k) {

            // build the parameter list as described above
            // Fill the row with diagonal null data and insert
            params[0] = "ALLOW_NULLS";
            params[1] = pkey.incrementAndGet();
            for (int i = 0; i < COLS; i++) {
                params[i + 2] = (i == k) ? m_nullValues[i] : m_midValues[i];
                assert (params[i + 2] != null);
            }
            client.callProcedure("Insert", params);
            VoltTable[] result = client.callProcedure("Select", "ALLOW_NULLS",
                    pkey.get()).getResults();
            System.out.println(result[0]);

            try {
                client.callProcedure("Delete", "ALLOW_NULLS", pkey.get());
            } catch (final ProcCallException e) {
                e.printStackTrace();
                fail();
            } catch (final NoConnectionsException e) {
                e.printStackTrace();
                fail();
            }

            // verify that the row was deleted
            result = client.callProcedure("Select", "ALLOW_NULLS", pkey.get())
                    .getResults();
            assertEquals(0, result[0].getRowCount());
        }
    }

    public void testMissingAttributeInsert_With_Defaults()
            throws NoConnectionsException, ProcCallException, IOException {
        Client client = this.getClient();

        Object params[] = new Object[COLS + 2];

        params[0] = "WITH_DEFAULTS";
        params[1] = pkey.incrementAndGet();
        for (int i = 0; i < COLS; i++) {
            params[i + 2] = m_defaultValues[i];
            assert (params[i + 2] != null);
        }

        try {
            client.callProcedure("Insert", params);
        } catch (ProcCallException e) {
            e.printStackTrace();
            fail();
        } catch (NoConnectionsException e) {
            e.printStackTrace();
            fail();
        }

        VoltTable[] result = client.callProcedure("Select", "WITH_DEFAULTS",
                pkey.get()).getResults();
        VoltTableRow row = result[0].fetchRow(0);
        for (int i = 0; i < COLS; ++i) {
            Object obj = row.get(i + 1, m_types[i]);
            assertTrue(comparisonHelper(obj, params[i + 2], m_types[i]));
        }
    }

    public void testMissingAttributeInsert_With_Null_Defaults()
            throws NoConnectionsException, ProcCallException, IOException {
        Client client = this.getClient();

        Object params[] = new Object[COLS + 2];

        params[0] = "WITH_NULL_DEFAULTS";
        params[1] = pkey.incrementAndGet();
        for (int i = 0; i < COLS; i++) {
            params[i + 2] = m_nullValues[i];
            assert (params[i + 2] != null);
        }

        try {
            client.callProcedure("Insert", params);
        } catch (ProcCallException e) {
            e.printStackTrace();
            fail();
        } catch (NoConnectionsException e) {
            e.printStackTrace();
            fail();
        }

        VoltTable[] result = client.callProcedure("Select",
                "WITH_NULL_DEFAULTS", pkey.get()).getResults();
        VoltTableRow row = result[0].fetchRow(0);
        for (int i = 0; i < COLS; ++i) {
            Object obj = row.get(i + 1, m_types[i]);
            assertTrue(comparisonHelper(obj, params[i + 2], m_types[i]));
        }
    }

    //
    // Round trip the maximum value
    //
    public void testInsertMaxValues_No_Nulls() throws NoConnectionsException,
            ProcCallException, IOException {
        final Client client = this.getClient();

        // Insert a MAX value for each column. For the first
        // row, insert MAX in the first column, for the 5th row
        // in the 5 column, etc.

        final Object params[] = new Object[COLS + 2];

        for (int k = 0; k < COLS; ++k) {

            // build the parameter list as described above
            params[0] = "";
            params[1] = pkey.incrementAndGet();
            for (int i = 0; i < COLS; i++) {
                params[i + 2] = (i == k) ? m_maxValues[i] : m_midValues[i];
                assert (params[i + 2] != null);
            }

            // Perform the inserts and execute selects, verifying the
            // content of the select matches the parameters passed to
            // insert

            System.out.println("testInsertMaxValues: " + k + " MAX type is "
                    + m_types[k]);
            params[0] = "NO_NULLS";
            client.callProcedure("Insert", params);
            // verify that the row was updated
            final VoltTable[] result = client.callProcedure("Select",
                    "NO_NULLS", pkey.get()).getResults();
            final VoltTableRow row = result[0].fetchRow(0);
            for (int i = 0; i < COLS; ++i) {
                final Object obj = row.get(i + 1, m_types[i]);
                assertTrue(!row.wasNull());
                assertTrue(comparisonHelper(obj, params[i + 2], m_types[i]));
            }
        }
    }

    //
    // Round trip the minimum value.
    //
    public void testInsertMinValues_No_Nulls() throws NoConnectionsException,
            ProcCallException, IOException {
        final Client client = this.getClient();

        // Insert a MIN value for each column. For the first
        // row, insert null in the first column, for the 5th row
        // in the 5 column, etc.

        final Object params[] = new Object[COLS + 2];

        for (int k = 0; k < COLS; ++k) {

            // build the parameter list as described above
            params[0] = "";
            params[1] = pkey.incrementAndGet();
            for (int i = 0; i < COLS; i++) {
                params[i + 2] = (i == k) ? m_minValues[i] : m_midValues[i];
                assert (params[i + 2] != null);
            }

            // Perform the inserts and execute selects, verifying the
            // content of the select matches the parameters passed to
            // insert

            System.out.println("testInsertMinValues: " + k + " MIN type is "
                    + m_types[k]);
            params[0] = "NO_NULLS";
            client.callProcedure("Insert", params);
            final VoltTable[] result = client.callProcedure("Select",
                    "NO_NULLS", pkey.get()).getResults();
            final VoltTableRow row = result[0].fetchRow(0);
            for (int i = 0; i < COLS; ++i) {
                final Object obj = row.get(i + 1, m_types[i]);
                assertTrue(!row.wasNull());
                assertTrue(comparisonHelper(obj, params[i + 2], m_types[i]));
            }
        }
    }

    //
    // Apply a simple expression to each type that supports math.
    //
    public void testSimpleExpressions() throws NoConnectionsException,
            ProcCallException, IOException {
        final Client client = this.getClient();

        // Build a simple expression to do addition and select one column at
        // a time, using that expression in a trivial projection.

        // insert one row with the mid values
        final Object params[] = new Object[COLS + 2];
        params[0] = "NO_NULLS";
        params[1] = pkey.incrementAndGet();
        for (int i = 0; i < COLS; i++) {
            params[i + 2] = m_midValues[i];
        }
        client.callProcedure("Insert", params);

        // insert one row with the max values
        params[0] = "NO_NULLS";
        params[1] = pkey.incrementAndGet();
        for (int i = 0; i < COLS; i++) {
            params[i + 2] = m_maxValues[i];
        }
        client.callProcedure("Insert", params);

        // select A + 11 from no_nulls where A = mid_value
        for (int i = 0; i < COLS; i++) {
            if (!m_supportsMath[i])
                continue;

            // TODO see trac 236.
            // Would be better here to select where the column under test
            // equals its mid value - but decimals can't do that.
            final String sql = "SELECT (" + m_columnNames[i]
                    + " + 11) from NO_NULLS where " + m_columnNames[3] + " = "
                    + m_midValues[3];
            System.out.println("testsimpleexpression: " + sql);
            final VoltTable[] result = client.callProcedure("@AdHoc", sql)
                    .getResults();
            final VoltTableRow row = result[0].fetchRow(0);
            final Object obj = row.get(0, m_types[i]);

            final double expect = ((Number) m_midValues[i]).doubleValue() + 11;
            final double got = ((Number) obj).doubleValue();
            System.out.println("Expect: " + expect + " got: " + got);
            assertEquals(expect, got);
        }
    }

    public void testJumboRow() throws Exception {
        final Client client = getClient();
        byte firstStringBytes[] = new byte[1048576];
        java.util.Arrays.fill(firstStringBytes, (byte) 'c');
        String firstString = new String(firstStringBytes, "UTF-8");
        byte secondStringBytes[] = new byte[1048564];
        java.util.Arrays.fill(secondStringBytes, (byte) 'a');
        String secondString = new String(secondStringBytes, "UTF-8");

        Object params[] = new Object[] { "JUMBO_ROW", 0, 0, 0, 0, 0, 0.0,
                new TimestampType(0), firstString, secondString, "", "",
                new byte[0], new byte[0], VoltType.NULL_DECIMAL };
        VoltTable results[] = client.callProcedure("Insert", params)
                .getResults();
        params = null;
        firstString = null;
        secondString = null;

        assertEquals(results.length, 1);
        assertEquals(1, results[0].asScalarLong());

        results = client.callProcedure("Select", "JUMBO_ROW", 0).getResults();
        assertEquals(results.length, 1);
        assertTrue(results[0].advanceRow());
        assertTrue(java.util.Arrays.equals(results[0].getStringAsBytes(1),
                firstStringBytes));
        assertTrue(java.util.Arrays.equals(results[0].getStringAsBytes(2),
                secondStringBytes));

        java.util.Arrays.fill(firstStringBytes, (byte) 'q');
        firstString = new String(firstStringBytes, "UTF-8");
        java.util.Arrays.fill(secondStringBytes, (byte) 'r');
        secondString = new String(secondStringBytes, "UTF-8");

        params = new Object[] { "JUMBO_ROW", 0, 0, 0, 0, 0, 0.0,
                new TimestampType(0), firstString, secondString, "", "",
                new byte[0], new byte[0], VoltType.NULL_DECIMAL };

        results = client.callProcedure("Update", params).getResults();
        params = null;
        firstString = null;
        secondString = null;

        assertEquals(results.length, 1);
        assertEquals(1, results[0].asScalarLong());

        results = client.callProcedure("Select", "JUMBO_ROW", 0).getResults();
        assertEquals(results.length, 1);
        assertTrue(results[0].advanceRow());
        assertTrue(java.util.Arrays.equals(results[0].getStringAsBytes(1),
                firstStringBytes));
        assertTrue(java.util.Arrays.equals(results[0].getStringAsBytes(2),
                secondStringBytes));
    }

    public void testUpdateDecimalWithPVE() throws NoConnectionsException,
            ProcCallException, IOException {
        // insert a couple of rows.
        final Client client = this.getClient();
        final Object params[] = new Object[COLS + 2];
        params[0] = "ALLOW_NULLS";
        params[1] = 0;
        for (int i = 0; i < COLS; i++) {
            params[i + 2] = m_midValues[i];
        }
        client.callProcedure("Insert", params);

        // insert one row with the max values
        params[0] = "ALLOW_NULLS";
        params[1] = 1;
        for (int i = 0; i < COLS; i++) {
            params[i + 2] = m_maxValues[i];
        }
        client.callProcedure("Insert", params);

        // update the mid value to the minimum decimal value
        VoltTable[] result = client.callProcedure("UpdateDecimal",
                m_minValues[12], m_midValues[12]).getResults();

        // select that same row again by primary key
        result = client.callProcedure("Select", "ALLOW_NULLS", 0).getResults();

        // and verify the row
        final VoltTableRow row = result[0].fetchRow(0);
        final BigDecimal bd = (row.getDecimalAsBigDecimal(13));
        assertTrue(comparisonHelper(m_minValues[12], bd, m_types[12]));
    }

    private void helper_testInvalidParameterSerializations(Client client,
            Object[] params) throws NoConnectionsException, IOException,
            ProcCallException {
        try {
            client.callProcedure("ParamSetArrays", params);
        } catch (RuntimeException e) {
            assertTrue(e.getCause() instanceof IOException);
        }
    }

    public void testInvalidParameterSerializations()
            throws NoConnectionsException, ProcCallException, IOException {
        final Client client = this.getClient();
        final Object params[] = new Object[8];

        params[0] = new short[1];
        params[1] = new int[1];
        params[2] = new long[1];
        params[3] = new double[1];
        params[4] = new String[1];
        params[5] = new TimestampType[1];
        params[6] = new BigDecimal[1];
        params[7] = new byte[1];

        // make sure the procedure CAN work.
        client.callProcedure("ParamSetArrays", params);

        // now cycle through invalid array lengths
        // these should fail in client serialization to the server
        params[0] = new short[Short.MAX_VALUE + 1];
        helper_testInvalidParameterSerializations(client, params);

        params[0] = new short[1];
        params[1] = new int[Short.MAX_VALUE + 1];
        helper_testInvalidParameterSerializations(client, params);

        params[1] = new int[1];
        params[2] = new long[Short.MAX_VALUE + 1];
        helper_testInvalidParameterSerializations(client, params);

        params[2] = new long[1];
        params[3] = new double[Short.MAX_VALUE + 1];
        helper_testInvalidParameterSerializations(client, params);

        params[3] = new double[1];
        params[4] = new String[Short.MAX_VALUE + 1];
        helper_testInvalidParameterSerializations(client, params);

        params[4] = new String[1];
        params[5] = new TimestampType[Short.MAX_VALUE + 1];
        helper_testInvalidParameterSerializations(client, params);

        params[5] = new TimestampType[1];
        params[6] = new BigDecimal[Short.MAX_VALUE + 1];
        helper_testInvalidParameterSerializations(client, params);

        params[6] = new BigDecimal[1];
        helper_testInvalidParameterSerializations(client, params);
    }

    public void testEng5013() throws NoConnectionsException, ProcCallException, IOException {
        Client client = this.getClient();

        client.callProcedure("InsertDecimal", 1, 3.4f);
        client.callProcedure("InsertDecimal", 2, 3.4d);
        client.callProcedure("InsertDecimal", 3, 1f);
        client.callProcedure("InsertDecimal", 4, 1d);
        client.callProcedure("InsertDecimal", 5, 0.25f);
        client.callProcedure("InsertDecimal", 6, 0.25d);
        client.callProcedure("InsertDecimal", 7, 3.3f);
        client.callProcedure("InsertDecimal", 8, 3.3d);

        try {
            client.callProcedure("InsertDecimal", 9, Double.MAX_VALUE);
            fail();
        } catch (ProcCallException e) {
            // should give out of precision range error
            assertTrue(e.getMessage().contains("has more than 38 digits of precision"));
        } catch (Exception e) {
            fail();
        }
        try {
            client.callProcedure("InsertDecimal", 9, -Double.MAX_VALUE);
            fail();
        } catch (ProcCallException e) {
            // should give out of precision range error
            assertTrue(e.getMessage().contains("has more than 38 digits of precision"));
        } catch (Exception e) {
            fail();
        }
        try {
            client.callProcedure("InsertDecimal", 9, Float.MAX_VALUE);
            fail();
        } catch (ProcCallException e) {
            // should give out of precision range error
            assertTrue(e.getMessage().contains("has more than 38 digits of precision"));
        } catch (Exception e) {
            fail();
        }
        try {
            client.callProcedure("InsertDecimal", 9, -Float.MAX_VALUE);
            fail();
        } catch (ProcCallException e) {
            // should give out of precision range error
            assertTrue(e.getMessage().contains("has more than 38 digits of precision"));
        } catch (Exception e) {
            fail();
        }
        double nand = 0.0d / 0.0d;
        float nanf = 0.0f / 0.0f;
        try {
            client.callProcedure("InsertDecimal", 9, nand);
        } catch (ProcCallException e) {
            // passing a NaN value will cause NumberFormatException, and fail the proceudre call
            assertTrue(e.getMessage().contains("NumberFormatException"));
        } catch (Exception e) {
            fail();
        }
        try {
            client.callProcedure("InsertDecimal", 9, nanf);
            fail();
        } catch (ProcCallException e) {
            // passing a NaN value will cause NumberFormatException, and fail the proceudre call
            assertTrue(e.getMessage().contains("NumberFormatException"));
        } catch (Exception e) {
            fail();
        }

        client.callProcedure("InsertDecimal", 9, Double.MIN_VALUE);
        client.callProcedure("InsertDecimal", 10, Float.MIN_VALUE);

        // will lose some precision by truncated to .12f
        client.callProcedure("InsertDecimal", 11, 123456789.01234567890123456789f);
        VoltTable table;
        table = client.callProcedure("@AdHoc", "SELECT A_DECIMAL FROM WITH_DEFAULTS WHERE PKEY = 11").getResults()[0];
        assertTrue(table.getRowCount() == 1);
        table.advanceRow();
        float f = table.getDecimalAsBigDecimal(0).floatValue();
        assertEquals(123456789.01234567890123456789f, f, 0.000000000001);
        // will lose some precision by truncated to .12f
        client.callProcedure("InsertDecimal", 12, 123456789.01234567890123456789d);
        table = client.callProcedure("@AdHoc", "SELECT A_DECIMAL FROM WITH_DEFAULTS WHERE PKEY = 12").getResults()[0];
        assertTrue(table.getRowCount() == 1);
        table.advanceRow();
        double d = table.getDecimalAsBigDecimal(0).doubleValue();
        assertEquals(123456789.01234567890123456789d, d, 0.000000000001);
    }

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

    static public junit.framework.Test suite() {

        VoltServerConfig config = null;
        final MultiConfigSuiteBuilder builder = new MultiConfigSuiteBuilder(
                TestSQLTypesSuite.class);

        final VoltProjectBuilder project = new VoltProjectBuilder();
        project.addSchema(TestSQLTypesSuite.class
                .getResource("sqltypessuite-ddl.sql"));
        project.addSchema(TestSQLTypesSuite.class
                .getResource("sqltypessuite-nonulls-ddl.sql"));
        project.addPartitionInfo("NO_NULLS", "PKEY");
        project.addPartitionInfo("ALLOW_NULLS", "PKEY");
        project.addPartitionInfo("WITH_DEFAULTS", "PKEY");
        project.addPartitionInfo("WITH_NULL_DEFAULTS", "PKEY");
        project.addPartitionInfo("EXPRESSIONS_WITH_NULLS", "PKEY");
        project.addPartitionInfo("EXPRESSIONS_NO_NULLS", "PKEY");
        project.addPartitionInfo("JUMBO_ROW", "PKEY");
        project.addProcedures(PROCEDURES);
        project.addStmtProcedure(
                "PassObjectNull",
                "insert into ALLOW_NULLS values ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
                "NO_NULLS.PKEY: 0");
        project.addStmtProcedure("InsertDecimal", "INSERT INTO WITH_DEFAULTS (PKEY, A_DECIMAL) VALUES (?, ?);");

        boolean success;

        // JNI
        config = new LocalCluster("sqltypes-onesite.jar", 1, 1, 0, BackendTarget.NATIVE_EE_JNI);
        success = config.compile(project);
        assertTrue(success);
        builder.addServerConfig(config);

        // CLUSTER?
        config = new LocalCluster("sqltypes-cluster.jar", 2, 2, 1, BackendTarget.NATIVE_EE_JNI);
        success = config.compile(project);
        assertTrue(success);
        builder.addServerConfig(config);

        return builder;
    }
}
TOP

Related Classes of org.voltdb.regressionsuites.TestSQLTypesSuite

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.