/* This file is part of VoltDB.
* Copyright (C) 2008-2010 VoltDB L.L.C.
*
* 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.VoltProcedure;
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.regressionsuites.sqltypesprocs.*;
import org.voltdb.types.TimestampType;
import org.voltdb.types.VoltDecimalHelper;
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 */
@SuppressWarnings("unchecked")
public static final Class<? extends VoltProcedure> PROCEDURES[] = (Class<? extends VoltProcedure>[])new Class<?>[] {
Delete.class,
Insert.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 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 */
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 (d1.compareTo(d2) == 0);
case STRING:
//System.out.println("\tComparing " + lhs + " == " + rhs);
if ((lhs == null || lhs == VoltType.NULL_STRING) &&
(rhs == null || rhs == VoltType.NULL_STRING))
{
return true;
}
return ((String)lhs).equals(rhs);
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 WHEN ADDING NEW TYPE
//
// Column count in each sqltypessuite-ddl.sql table NOT including PKEY
public static int COLS = 11;
// Interesting sets of values for the various types
// tests rely on this ordering of the string varchar widths
public static VoltType[] m_types = {
VoltType.TINYINT,
VoltType.SMALLINT,
VoltType.INTEGER,
VoltType.BIGINT,
VoltType.FLOAT,
VoltType.TIMESTAMP,
VoltType.STRING, // varchar(4)
VoltType.STRING, // varchar(63)
VoltType.STRING, // varchar(1024)
VoltType.STRING, // varchar(42000)
VoltType.DECIMAL
// UPDATE WHEN ADDING NEW TYPE
};
// used to filter types that don't support arithmetic expressions
public boolean[] m_supportsMath = {
true, // tinyint
true, // smallint
true, // integer
true, // bigint
true, // float
false, // timestamp
false, // string
false, // string
false, // string
false, // string
true // decimal
// UPDATE WHEN ADDING NEW TYPE
};
// the column names from the DDL used to dynamically create
// sql select lists.
public static String[] m_columnNames = {
"A_TINYINT",
"A_SMALLINT",
"A_INTEGER",
"A_BIGINT",
"A_FLOAT",
"A_TIMESTAMP",
"A_INLINE_S1",
"A_INLINE_S2",
"A_POOL_S",
"A_POOL_MAX_S",
"A_DECIMAL"
// UPDATE WHEN ADDING NEW TYPE
};
// sql null representation for each type
public Object[] m_nullValues = {
VoltType.NULL_TINYINT,
VoltType.NULL_SMALLINT,
VoltType.NULL_INTEGER,
VoltType.NULL_BIGINT,
VoltType.NULL_FLOAT,
VoltType.NULL_TIMESTAMP,
VoltType.NULL_STRING, // inlined LT ptr size
VoltType.NULL_STRING, // inlined GT ptr size
VoltType.NULL_STRING, // not inlined (1024)
VoltType.NULL_STRING, // not inlined (max length)
VoltType.NULL_DECIMAL
// UPDATE WHEN ADDING NEW TYPE
};
// maximum value for each type
public static Object[] m_maxValues = {
Byte.MAX_VALUE,
Short.MAX_VALUE,
Integer.MAX_VALUE,
Long.MAX_VALUE,
Double.MAX_VALUE,
new TimestampType(Long.MAX_VALUE),
new String("ZZZZ"),
new String("ZZZZZZZZZZ" +//10
"ZZZZZZZZZZ" +//20
"ZZZZZZZZZZ" + //30
"ZZZZZZZZZZ" + //40
"ZZZZZZZZZZ" + //50
"ZZZZZZZZZZ" + //60
"ZZZ" ), //63
"",
"",
new BigDecimal(new BigInteger("99999999999999999999999999999999999999")).scaleByPowerOfTen(-1 * VoltDecimalHelper.kDefaultScale)
// UPDATE WHEN ADDING NEW TYPE
};
static {
StringBuilder sb = new StringBuilder(1048576);
int ii = 0;
for ( ; ii < 65536; ii++) {
sb.append('Z');
}
m_maxValues[8] = sb.toString();
for ( ; ii < 1048576; ii++) {
sb.append('Z');
}
m_maxValues[9] = sb.toString();
sb = new StringBuilder(102400);
for (ii = 0; ii < 102400; ii++) {
sb.append('a');
}
ReallyLongString = sb.toString();
}
// a non-max, non-min value for each type
public static Object[] m_midValues = {
new Byte((byte) 10),
new Short((short) 11),
new Integer(12),
new Long(13),
new Double(14.5),
new TimestampType(),
new String("xyz"),
new String("xyzab"),
new String("xyzabcdefghijklmnopqrstuvw"),
new String("xyzabcdefghijklmnopqrstuvw"),
new BigDecimal(new BigInteger("5115101010101010345634")).scaleByPowerOfTen(-1 * VoltDecimalHelper.kDefaultScale)
// UPDATE WHEN ADDING NEW TYPE
};
// minimum value for each type
public Object[] m_minValues = {
new Byte((byte)(Byte.MIN_VALUE + 1)), // MIN is NULL
new Short((short)(Short.MIN_VALUE + 1)), // MIN is NULL
Integer.MIN_VALUE + 1, // MIN is NULL
Long.MIN_VALUE + 1, // MIN is NULL
Double.MIN_VALUE, // NULL is -1.7E308.
new TimestampType(Long.MIN_VALUE + 1),
new String(byteArray(1, OO)),
new String(byteArray(1, OO)),
new String(byteArray(1, OO)),
new String(byteArray(1, OO)),
new BigDecimal(new BigInteger("-99999999999999999999999999999999999999")).scaleByPowerOfTen(-1 * VoltDecimalHelper.kDefaultScale)
// UPDATE WHEN ADDING NEW TYPE
};
// default (defined in DDL) value for each type
public static Object[] m_defaultValues = {
new Byte((byte)(1)),
new Short((short)(2)),
3,
4L,
5.1,
new TimestampType(600000),
new String("abcd"),
new String("abcdefghij"),
new String("abcdefghijklmnopqrstuvwxyz"),
new String("abcdefghijklmnopqrstuvwxyz"),
new BigDecimal(new BigInteger("6000000000000")).scaleByPowerOfTen(-1 * VoltDecimalHelper.kDefaultScale)
// UPDATE WHEN ADDING NEW TYPE
};
//
// 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 RuntimeException e) {
assertTrue(e.getCause() instanceof java.io.IOException);
assertTrue(e.toString().contains("String exceeds maximum length of"));
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;
ClientResponse cr = client.callProcedure("Insert", params);
assertNotNull(cr);
}
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 {
ClientResponse cr = client.callProcedure("Insert", params);
assertNotNull(cr);
} 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,
"",
"",
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,
"",
"",
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[10], m_midValues[10]).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(11));
assertTrue(comparisonHelper(m_minValues[10], bd, m_types[10]));
}
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];
params[7] = new byte[VoltType.MAX_VALUE_LENGTH + 1];
helper_testInvalidParameterSerializations(client, params);
}
//
// 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("sqltypessuite");
project.addSchema(TestSQLTypesSuite.class.getResource("sqltypessuite-ddl.sql"));
project.addTablePartitionInfo("NO_NULLS", "PKEY");
project.addTablePartitionInfo("ALLOW_NULLS", "PKEY");
project.addTablePartitionInfo("WITH_DEFAULTS", "PKEY");
project.addTablePartitionInfo("WITH_NULL_DEFAULTS", "PKEY");
project.addTablePartitionInfo("EXPRESSIONS_WITH_NULLS", "PKEY");
project.addTablePartitionInfo("EXPRESSIONS_NO_NULLS", "PKEY");
project.addTablePartitionInfo("JUMBO_ROW", "PKEY");
project.addProcedures(PROCEDURES);
/* // CONFIG #1: Local Site/Partitions running on IPC backend
config = new LocalSingleProcessServer("sqltypes-onesite.jar", 1, BackendTarget.NATIVE_EE_IPC);
config.compile(project);
builder.addServerConfig(config);
// CONFIG #2: HSQL
config = new LocalSingleProcessServer("sqltypes-hsql.jar", 1, BackendTarget.HSQLDB_BACKEND);
config.compile(project);
builder.addServerConfig(config);
*/
// JNI
config = new LocalSingleProcessServer("sqltypes-onesite.jar", 1, BackendTarget.NATIVE_EE_JNI);
config.setConfParameter("site.exec_adhoc_sql", true);
config.compile(project);
builder.addServerConfig(config);
// CLUSTER?
config = new LocalCluster("sqltypes-cluster.jar", 2, 2, 1, BackendTarget.NATIVE_EE_JNI);
config.setConfParameter("site.exec_adhoc_sql", true);
config.compile(project);
builder.addServerConfig(config);
return builder;
}
}