/* This file is part of VoltDB.
* Copyright (C) 2008-2017 VoltDB Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.voltdb.regressionsuites;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Random;
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.GeographyPointValue;
import org.voltdb.types.GeographyValue;
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);
case GEOGRAPHY_POINT: {
if ((lhs == VoltType.NULL_POINT || lhs == null)
&& (rhs == VoltType.NULL_POINT || rhs == null)) {
return true;
}
GeographyPointValue gpvLhs = (GeographyPointValue)lhs;
GeographyPointValue gpvRhs = (GeographyPointValue)rhs;
return gpvLhs.equals(gpvRhs);
}
case GEOGRAPHY: {
if ((lhs == VoltType.NULL_GEOGRAPHY || lhs == null)
&& (rhs == VoltType.NULL_GEOGRAPHY || rhs == null)) {
return true;
}
GeographyValue gvLhs = (GeographyValue)lhs;
GeographyValue gvRhs = (GeographyValue)rhs;
return gvLhs.equals(gvRhs);
}
default:
throw new IllegalArgumentException("Unknown type in comparisonHelper");
}
}
//
// 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,
Math.nextAfter(VoltType.NULL_FLOAT, 0), // 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)),
new Column("A_GEOGRAPHY_POINT",
VoltType.GEOGRAPHY_POINT,
false, // supports math
VoltType.NULL_POINT, // null value
new GeographyPointValue(-122.0, 37.0),
new GeographyPointValue(-180.0, -90.0),
new GeographyPointValue(0.0, 0.0),
new GeographyPointValue(180.0, 90.0)),
new Column("A_GEOGRAPHY",
VoltType.GEOGRAPHY,
false, // supports math
VoltType.NULL_GEOGRAPHY, // null value
GeographyValue.fromWKT("polygon((-122 37, -122 39, -120 39, -122 37))"),
GeographyValue.fromWKT("polygon((-142 37, -142 39, -140 39, -142 37))"),
GeographyValue.fromWKT("polygon((-152 37, -152 39, -150 39, -152 37))"),
GeographyValue.fromWKT("polygon((-162 37, -162 39, -160 39, -162 37))"))
};
// 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, 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, null, null);
client.callProcedure("ALLOW_NULLS.insert", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, utild,
null, null, 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, null, null);
client.callProcedure("ALLOW_NULLS.insert", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, ts,
null, null, 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, null, null);
client.callProcedure("PassObjectNull", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, utild,
null, null, 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, null, null);
client.callProcedure("PassObjectNull", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, ts,
null, null, 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, 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, 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, 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, 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, null, null);
client.callProcedure("ALLOW_NULLS.insert", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, ts_micro,
null, null, 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, null, null);
client.callProcedure("PassObjectNull", pkey.incrementAndGet(), 0, 0, 0, 0, 0.0, ts_micro,
null, null, 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, 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, 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, null, null);
} catch (RuntimeException e) {
assertEquals("Can't serialize TIMESTAMP value with fractional microseconds", e.getMessage());
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, null, null);
} catch (RuntimeException e) {
assertEquals("Can't serialize TIMESTAMP value with fractional microseconds", e.getMessage());
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();
Random rn = new Random();
for (int i = 0; i < 100; ++i) {
long ts = rn.nextLong();
long[] timestampValues = {
ts, // random
ts / 1000 * 1000, // even milliseconds
ts / 1000000 * 1000000, // even seconds
ts / 1000000 * -1000000 // even seconds
};
for (long microsecondsSinceEpoch: timestampValues) {
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, 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));
client.callProcedure("@AdHoc", "truncate table allow_nulls;");
}
}
}
// 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, 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(e.getMessage());
} catch (final NoConnectionsException e) {
e.printStackTrace();
fail(e.getMessage());
}
// 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]);
if (m_types[i] == VoltType.GEOGRAPHY || m_types[i] == VoltType.GEOGRAPHY_POINT) {
// Default values are not supported for these types (yet?)
assertNull(obj);
}
else {
assertTrue("Expected to be equal: (" + obj + ", " + params[i + 2] + ")",
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("Expected to be equal: (" + obj + ", " + params[i + 2] + ")",
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, null, null };
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, null, null };
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("NO_NULLS_GRP", "PKEY");
project.addPartitionInfo("ALLOW_NULLS", "PKEY");
project.addPartitionInfo("ALLOW_NULLS_GRP", "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;
}
}