use of org.voltdb.types.GeographyValue in project voltdb by VoltDB.
the class TestGeographyValueQueries method testCaseWhenElseENG9983ENG9984.
// This is mostly a planner test, as the planner had problems recognizing that geo types
// were compatible with themselves in CASE expressions and that geography was a valid
// variable-length type.
public void testCaseWhenElseENG9983ENG9984() throws Exception {
final double EPSILON = 1.0e-13;
Client client = getClient();
fillCheesyTable(client);
// ENG-9983 CASE WHEN THEN ELSE on geography type.
VoltTable vt = client.callProcedure("@AdHoc", "select CASE WHEN area(t.poly) < area(alt_t.poly) THEN t.poly ELSE alt_t.poly END" + " from t, t alt_t where t.pk + 1 = alt_t.pk and t.pk >= 100 order by t.pk;").getResults()[0];
assertEquals("Expected (N-1) rows.", 3, vt.getRowCount());
assertTrue(vt.advanceRow());
GeographyValue cheesyRoundTripper1 = vt.getGeographyValue(0);
vt = client.callProcedure("@AdHoc", "select CASE WHEN area(t.poly) < area(alt_t.poly) THEN t.poly ELSE alt_t.poly END" + " from t, t alt_t where t.pk >= 100 and alt_t.pk >= 100 order by t.pk;").getResults()[0];
assertEquals("Expected (N^2) rows.", 16, vt.getRowCount());
assertTrue(vt.advanceRow());
GeographyValue cheesyRoundTripper2 = vt.getGeographyValue(0);
assertApproximatelyEquals("Expected Equivalent Round Trip Polygons", cheesyRoundTripper1, cheesyRoundTripper2, EPSILON);
// ENG-9983 CASE WHEN THEN ELSE on geography point type.
vt = client.callProcedure("@AdHoc", "select CASE WHEN longitude(l.loc_point) <= longitude(alt_l.loc_point) THEN l.loc_point ELSE alt_l.loc_point END" + " from location l, location alt_l where l.pk + 1 = alt_l.pk and l.pk >= 300 order by l.pk;").getResults()[0];
assertEquals("Expected (N-1) rows.", 3, vt.getRowCount());
assertTrue(vt.advanceRow());
GeographyPointValue cheesyRoundTripper3 = vt.getGeographyPointValue(0);
vt = client.callProcedure("@AdHoc", "select CASE WHEN longitude(l.loc_point) <= longitude(alt_l.loc_point) THEN l.loc_point ELSE alt_l.loc_point END" + " from location l, location alt_l where l.pk >= 300 and alt_l.pk >= 300 order by l.pk;").getResults()[0];
assertEquals("Expected (N^2) rows.", 16, vt.getRowCount());
assertTrue(vt.advanceRow());
GeographyPointValue cheesyRoundTripper4 = vt.getGeographyPointValue(0);
assertApproximatelyEquals("Expected Equivalent Round Trip Points", cheesyRoundTripper3, cheesyRoundTripper4, EPSILON);
// ENG-9984 CASE WHEN THEN no ELSE on geography type.
vt = client.callProcedure("@AdHoc", "select CASE WHEN area(t.poly) <= area(alt_t.poly) THEN t.poly END" + " from t, t alt_t where t.pk >= 100 and alt_t.pk >= 100 order by t.pk;").getResults()[0];
assertEquals("Expected (N^2) rows.", 16, vt.getRowCount());
assertTrue(vt.advanceRow());
GeographyValue cheesyRoundTripper5 = vt.getGeographyValue(0);
assertFalse(vt.wasNull());
assertApproximatelyEquals("Expected Equivalent Round Trip Polygons", cheesyRoundTripper1, cheesyRoundTripper5, EPSILON);
}
use of org.voltdb.types.GeographyValue in project voltdb by VoltDB.
the class TestGeographyValueQueries method fillCheesyTable.
private void fillCheesyTable(Client client) throws Exception {
GeographyValue cheesyPolygon = GeographyValue.fromWKT(cheesyWKT);
GeographyValue cheesyShellPolygon = GeographyValue.fromWKT(cheesyShellWKT);
//
// Get the holes from the cheesy polygon, and make them
// into polygons in their own right. This means we need
// to reverse them.
//
List<GeographyValue> cheesyHoles = new ArrayList<>();
List<List<GeographyPointValue>> loops = cheesyPolygon.getRings();
for (int idx = 1; idx < loops.size(); idx += 1) {
List<GeographyPointValue> oneHole = loops.get(idx);
List<GeographyPointValue> rev = new ArrayList<>();
rev.addAll(oneHole);
Collections.reverse(rev);
List<List<GeographyPointValue>> holeLoops = new ArrayList<>();
holeLoops.add(rev);
cheesyHoles.add(new GeographyValue(holeLoops));
}
String cheesyOrigin = "POINT(0.0 0.0)";
String cheesyInHole = "POINT(15 15)";
List<String> exteriorPoints = Arrays.asList("POINT( 60 60)", "POINT( 60 -60)", "POINT(-60 -60)", "POINT(-60 60)");
List<String> centers = Arrays.asList("POINT( 11 11)", "POINT( 11 -11)", "POINT(-11 -11)", "POINT(-11 11)");
client.callProcedure("T.INSERT", 0, "SHELL", cheesyShellPolygon);
client.callProcedure("T.INSERT", 1, "Formaggio", cheesyPolygon);
for (int idx = 0; idx < cheesyHoles.size(); idx += 1) {
GeographyValue hole = cheesyHoles.get(idx);
client.callProcedure("T.INSERT", idx + 100, "hole" + idx + 100, hole);
}
client.callProcedure("LOCATION.INSERT", 0, "ORIGIN", GeographyPointValue.fromWKT(cheesyOrigin));
client.callProcedure("LOCATION.INSERT", 1, "INHOLE", GeographyPointValue.fromWKT(cheesyInHole));
for (int idx = 0; idx < exteriorPoints.size(); idx += 1) {
String exPt = exteriorPoints.get(idx);
client.callProcedure("LOCATION.INSERT", idx + 200, exPt, GeographyPointValue.fromWKT(exPt));
idx += 1;
}
for (int idx = 0; idx < centers.size(); idx += 1) {
String ctrPt = centers.get(idx);
client.callProcedure("LOCATION.INSERT", idx + 300, ctrPt, GeographyPointValue.fromWKT(ctrPt));
}
// Make sure that all the polygons
// are valid.
VoltTable vt = client.callProcedure("@AdHoc", "select t.pk from t where not isValid(t.poly) order by t.pk").getResults()[0];
assertTrue("fillCheesyTable: " + vt.getRowCount() + " invalid polygons.", vt.getRowCount() == 0);
}
use of org.voltdb.types.GeographyValue in project voltdb by VoltDB.
the class TestGeographyValueQueries method testNullValues.
public void testNullValues() throws Exception {
Client client = getClient();
for (String tbl : TABLES) {
validateTableOfScalarLongs(client, "select * from " + tbl, new long[] {});
// Insert a null via default value
validateTableOfScalarLongs(client, "insert into " + tbl + " (pk) values (0);", new long[] { 1 });
VoltTable vt = client.callProcedure("@AdHoc", "select poly from " + tbl).getResults()[0];
assertTrue(vt.toString().contains("NULL"));
assertTrue(vt.advanceRow());
GeographyValue gv = vt.getGeographyValue(0);
assertTrue(vt.wasNull());
assertEquals(null, gv);
assertFalse(vt.advanceRow());
// This produces a null geography since the function argument is null
vt = client.callProcedure("@AdHoc", "select polygonfromtext(null) from " + tbl).getResults()[0];
assertTrue(vt.advanceRow());
gv = vt.getGeographyValue(0);
assertTrue(vt.wasNull());
assertEquals(null, gv);
assertFalse(vt.advanceRow());
// This tests the is null predicate for this type
vt = client.callProcedure("@AdHoc", "select poly from " + tbl + " where poly is null").getResults()[0];
assertTrue(vt.advanceRow());
gv = vt.getGeographyValue(0);
assertTrue(vt.wasNull());
assertEquals(null, gv);
assertFalse(vt.advanceRow());
// Try inserting a SQL literal null, which takes a different code path.
validateTableOfScalarLongs(client, "delete from " + tbl, new long[] { 1 });
validateTableOfScalarLongs(client, "insert into " + tbl + " values (0, 'boo', null);", new long[] { 1 });
vt = client.callProcedure("@AdHoc", "select poly from " + tbl).getResults()[0];
assertTrue(vt.advanceRow());
gv = vt.getGeographyValue(0);
assertTrue(vt.wasNull());
assertEquals(null, gv);
assertFalse(vt.advanceRow());
// Insert a null by passing a null reference.
validateTableOfScalarLongs(client, "delete from " + tbl, new long[] { 1 });
vt = client.callProcedure(tbl + ".Insert", 0, "null geog", null).getResults()[0];
validateTableOfScalarLongs(vt, new long[] { 1 });
vt = client.callProcedure("@AdHoc", "select poly from " + tbl).getResults()[0];
assertTrue(vt.advanceRow());
gv = vt.getGeographyValue(0);
assertTrue(vt.wasNull());
assertEquals(null, gv);
assertFalse(vt.advanceRow());
// Insert a null by passing an instance of the null sigil
validateTableOfScalarLongs(client, "delete from " + tbl, new long[] { 1 });
vt = client.callProcedure(tbl + ".Insert", 0, "null geog", VoltType.NULL_GEOGRAPHY).getResults()[0];
validateTableOfScalarLongs(vt, new long[] { 1 });
vt = client.callProcedure("@AdHoc", "select poly from " + tbl).getResults()[0];
assertTrue(vt.advanceRow());
gv = vt.getGeographyValue(0);
assertTrue(vt.wasNull());
assertEquals(null, gv);
assertFalse(vt.advanceRow());
}
}
use of org.voltdb.types.GeographyValue in project voltdb by VoltDB.
the class TestGeographyValueQueries method testUpdate.
public void testUpdate() throws Exception {
Client client = getClient();
String santaCruzWkt = "POLYGON(" + "(-122.061 36.999, " + "-122.058 36.950, " + "-121.974 36.955, " + "-122.061 36.999))";
String southValleyWkt = "POLYGON(" + "(-122.038 37.367, " + "-121.980 37.232, " + "-121.887 37.339, " + "-122.038 37.367))";
for (String tbl : TABLES) {
fillTable(client, tbl, 0);
VoltTable vt = client.callProcedure("@AdHoc", "update " + tbl + " set poly = ?, name = ? where pk = ?", new GeographyValue(santaCruzWkt), "Santa Cruz Triangle", 0).getResults()[0];
validateTableOfScalarLongs(vt, new long[] { 1 });
vt = client.callProcedure("@AdHoc", "update " + tbl + " set poly = polygonfromtext(?), name = ? where pk = ?", southValleyWkt, "South Valley Triangle", 2).getResults()[0];
validateTableOfScalarLongs(vt, new long[] { 1 });
vt = client.callProcedure("@AdHoc", "select * from " + tbl + " order by pk asc").getResults()[0];
assertApproximateContentOfTable(new Object[][] { { 0, "Santa Cruz Triangle", new GeographyValue(santaCruzWkt) }, { 1, "Bermuda Triangle with a hole", BERMUDA_TRIANGLE_HOLE_POLY }, { 2, "South Valley Triangle", new GeographyValue(southValleyWkt) }, { 3, "Lowell Square", LOWELL_SQUARE_POLY }, { 4, "null poly", null } }, vt, GEOGRAPHY_EPSILON);
}
}
use of org.voltdb.types.GeographyValue in project voltdb by VoltDB.
the class ParameterConverter method tryToMakeCompatible.
/**
* Convert the given value to the type given, if possible.
*
* This function is in the performance path, so some effort has been made to order
* the giant string of branches such that most likely things are first, and that
* if the type is already correct, it should move very quickly through the logic.
* Some clarity has been sacrificed for performance, but perfect clarity is pretty
* elusive with complicated logic like this anyway.
*
* @throws Exception with a message describing why the types are incompatible.
*/
public static Object tryToMakeCompatible(final Class<?> expectedClz, final Object param) throws VoltTypeException {
// after the basics to check for those.
if (param == null) {
return nullValueForType(expectedClz);
}
Class<?> inputClz = param.getClass();
// If we make it through this first block, memoize a number value for some range checks later
Number numberParam = null;
if (inputClz == Long.class) {
if (expectedClz == long.class)
return param;
if ((Long) param == VoltType.NULL_BIGINT)
return nullValueForType(expectedClz);
numberParam = (Number) param;
} else if (inputClz == Integer.class) {
if (expectedClz == int.class)
return param;
if ((Integer) param == VoltType.NULL_INTEGER)
return nullValueForType(expectedClz);
if (expectedClz == long.class)
return ((Integer) param).longValue();
numberParam = (Number) param;
} else if (inputClz == Short.class) {
if (expectedClz == short.class)
return param;
if ((Short) param == VoltType.NULL_SMALLINT)
return nullValueForType(expectedClz);
if (expectedClz == long.class)
return ((Short) param).longValue();
if (expectedClz == int.class)
return ((Short) param).intValue();
numberParam = (Number) param;
} else if (inputClz == Byte.class) {
if (expectedClz == byte.class)
return param;
if ((Byte) param == VoltType.NULL_TINYINT)
return nullValueForType(expectedClz);
if (expectedClz == long.class)
return ((Byte) param).longValue();
if (expectedClz == int.class)
return ((Byte) param).intValue();
if (expectedClz == short.class)
return ((Byte) param).shortValue();
numberParam = (Number) param;
} else if (inputClz == Double.class) {
if (expectedClz == double.class)
return param;
if ((Double) param == VoltType.NULL_FLOAT)
return nullValueForType(expectedClz);
} else if (inputClz == String.class) {
String stringParam = (String) param;
if (stringParam.equals(Constants.CSV_NULL))
return nullValueForType(expectedClz);
else if (expectedClz == String.class)
return param;
else // Hack allows hex-encoded strings to be passed into byte[] params
if (expectedClz == byte[].class) {
// unless the param really looks like an x-quoted literal
if (stringParam.startsWith("X") || stringParam.startsWith("x")) {
String hexDigits = SQLParser.getDigitsFromHexLiteral(stringParam);
if (hexDigits != null) {
stringParam = hexDigits;
}
}
return Encoder.hexDecode(stringParam);
}
// This code handles primitive types. Complex types come later.
if (expectedClz.isPrimitive()) {
return convertStringToPrimitive(stringParam, expectedClz);
}
} else if (inputClz == byte[].class) {
if (expectedClz == byte[].class)
return param;
else // allow byte arrays to be passed into string parameters
if (expectedClz == String.class) {
String value = new String((byte[]) param, Constants.UTF8ENCODING);
if (value.equals(Constants.CSV_NULL))
return nullValueForType(expectedClz);
else
return value;
}
} else // why do we have three sigils for three types??)
if (param == VoltType.NULL_TIMESTAMP || param == VoltType.NULL_STRING_OR_VARBINARY || param == VoltType.NULL_GEOGRAPHY || param == VoltType.NULL_POINT || param == VoltType.NULL_DECIMAL) {
return nullValueForType(expectedClz);
} else // If it cannot be converted (say out of range), just display the error message.
if (inputClz == BigDecimal.class) {
// Only conversion to primitive numeric types are considered
BigDecimal pBigDecimal = (BigDecimal) param;
if (expectedClz == long.class) {
try {
long result = pBigDecimal.longValueExact();
return result;
}// The error will be re-thrown below
catch (ArithmeticException e) {
}
} else if (expectedClz == double.class) {
// This conversion could potentially lose information, should a warning be
// given at a higher level ?
double result = pBigDecimal.doubleValue();
// The converted double could be infinity if out of range
if (result != Double.POSITIVE_INFINITY && result != Double.NEGATIVE_INFINITY) {
return result;
}
} else if (expectedClz == int.class) {
try {
int result = pBigDecimal.intValueExact();
return result;
}// The error will be re-thrown below
catch (ArithmeticException e) {
}
} else if (expectedClz == short.class) {
try {
short result = pBigDecimal.shortValueExact();
return result;
}// The error will be re-thrown below
catch (ArithmeticException e) {
}
} else if (expectedClz == byte.class) {
try {
byte result = pBigDecimal.byteValueExact();
return result;
} catch (ArithmeticException e) {
}
}
throw new VoltTypeException("tryToMakeCompatible: The provided value: (" + param.toString() + ") of type: " + inputClz.getName() + " is out of range for the target parameter type: " + expectedClz.getName());
}
// make sure we get the array/scalar match
if (expectedClz.isArray() != inputClz.isArray()) {
throw new VoltTypeException(String.format("Array / Scalar parameter mismatch (%s to %s)", inputClz.getName(), expectedClz.getName()));
}
// handle arrays in a factored-out method
if (expectedClz.isArray()) {
return tryToMakeCompatibleArray(expectedClz.getComponentType(), inputClz.getComponentType(), param);
}
if ((expectedClz == int.class) && (numberParam != null)) {
long val = numberParam.longValue();
if (val == VoltType.NULL_INTEGER) {
throw new VoltTypeException("tryToMakeCompatible: The provided long value: (" + param.toString() + ") might be interpreted as integer null. " + "Try explicitly using a int parameter.");
}
// if it's in the right range, crop the value and return
if ((val <= Integer.MAX_VALUE) && (val >= Integer.MIN_VALUE))
return numberParam.intValue();
} else if ((expectedClz == short.class) && (numberParam != null)) {
if ((inputClz == Long.class) || (inputClz == Integer.class)) {
long val = numberParam.longValue();
if (val == VoltType.NULL_SMALLINT) {
throw new VoltTypeException("tryToMakeCompatible: The provided int or long value: (" + param.toString() + ") might be interpreted as smallint null. " + "Try explicitly using a short parameter.");
}
// if it's in the right range, crop the value and return
if ((val <= Short.MAX_VALUE) && (val >= Short.MIN_VALUE))
return numberParam.shortValue();
}
} else if ((expectedClz == byte.class) && (numberParam != null)) {
if ((inputClz == Long.class) || (inputClz == Integer.class) || (inputClz == Short.class)) {
long val = numberParam.longValue();
if (val == VoltType.NULL_TINYINT) {
throw new VoltTypeException("tryToMakeCompatible: The provided short, int or long value: (" + param.toString() + ") might be interpreted as tinyint null. " + "Try explicitly using a byte parameter.");
}
// if it's in the right range, crop the value and return
if ((val <= Byte.MAX_VALUE) && (val >= Byte.MIN_VALUE))
return numberParam.byteValue();
}
} else if ((expectedClz == double.class) && (numberParam != null)) {
return numberParam.doubleValue();
} else if (expectedClz == TimestampType.class) {
// null values safe
if (inputClz == Integer.class)
return new TimestampType((Integer) param);
// null values safe
if (inputClz == Long.class)
return new TimestampType((Long) param);
if (inputClz == TimestampType.class)
return param;
if (inputClz == Date.class)
return new TimestampType((Date) param);
// if a string is given for a date, use java's JDBC parsing
if (inputClz == String.class) {
String timestring = ((String) param).trim();
try {
return new TimestampType(Long.parseLong(timestring));
} catch (IllegalArgumentException e) {
// Defer errors to the generic Exception throw below, if it's not the right format
}
try {
return SQLParser.parseDate(timestring);
} catch (IllegalArgumentException e) {
// Defer errors to the generic Exception throw below, if it's not the right format
}
}
} else if (expectedClz == java.sql.Timestamp.class) {
if (param instanceof java.sql.Timestamp)
return param;
if (param instanceof java.util.Date)
return new java.sql.Timestamp(((java.util.Date) param).getTime());
if (param instanceof TimestampType)
return ((TimestampType) param).asJavaTimestamp();
// If a string is given for a date, use java's JDBC parsing.
if (inputClz == String.class) {
String longtime = ((String) param).trim();
try {
return new java.sql.Timestamp(Long.parseLong(longtime));
} catch (IllegalArgumentException e) {
// Defer errors to the generic Exception throw below, if it's not the right format
}
try {
return java.sql.Timestamp.valueOf(longtime);
} catch (IllegalArgumentException e) {
// Defer errors to the generic Exception throw below, if it's not the right format
}
}
} else if (expectedClz == java.sql.Date.class) {
// covers java.sql.Date and java.sql.Timestamp
if (param instanceof java.sql.Date)
return param;
if (param instanceof java.util.Date)
return new java.sql.Date(((java.util.Date) param).getTime());
if (param instanceof TimestampType)
return ((TimestampType) param).asExactJavaSqlDate();
// If a string is given for a date, use java's JDBC parsing.
if (inputClz == String.class) {
try {
return new java.sql.Date(TimestampType.millisFromJDBCformat((String) param));
} catch (IllegalArgumentException e) {
// Defer errors to the generic Exception throw below, if it's not the right format
}
}
} else if (expectedClz == java.util.Date.class) {
// covers java.sql.Date and java.sql.Timestamp
if (param instanceof java.util.Date)
return param;
if (param instanceof TimestampType)
return ((TimestampType) param).asExactJavaDate();
// If a string is given for a date, use the default format parser for the default locale.
if (inputClz == String.class) {
try {
return new java.util.Date(TimestampType.millisFromJDBCformat((String) param));
} catch (IllegalArgumentException e) {
// Defer errors to the generic Exception throw below, if it's not the right format
}
}
} else if (expectedClz == BigDecimal.class) {
if (numberParam != null) {
BigDecimal bd = VoltDecimalHelper.stringToDecimal(param.toString());
return bd;
}
if (inputClz == BigDecimal.class) {
BigDecimal bd = (BigDecimal) param;
bd = VoltDecimalHelper.setDefaultScale(bd);
return bd;
}
if (inputClz == Float.class || inputClz == Double.class) {
try {
return VoltDecimalHelper.deserializeBigDecimalFromString(String.format("%.12f", param));
} catch (IOException ex) {
throw new VoltTypeException(String.format("deserialize Float from string failed. (%s to %s)", inputClz.getName(), expectedClz.getName()));
}
}
try {
return VoltDecimalHelper.deserializeBigDecimalFromString(String.valueOf(param));
} catch (IOException ex) {
throw new VoltTypeException(String.format("deserialize BigDecimal from string failed. (%s to %s)", inputClz.getName(), expectedClz.getName()));
}
} else if (expectedClz == GeographyPointValue.class) {
// Is it a point already? If so, just return it.
if (inputClz == GeographyPointValue.class) {
return param;
}
// If so, return the newly constructed point.
if (inputClz == String.class) {
try {
GeographyPointValue pt = GeographyPointValue.fromWKT((String) param);
return pt;
} catch (IllegalArgumentException e) {
throw new VoltTypeException(String.format("deserialize GeographyPointValue from string failed (string %s)", (String) param));
}
}
} else if (expectedClz == GeographyValue.class) {
if (inputClz == GeographyValue.class) {
return param;
}
if (inputClz == String.class) {
String paramStr = (String) param;
try {
GeographyValue gv = GeographyValue.fromWKT(paramStr);
return gv;
} catch (IllegalArgumentException e) {
throw new VoltTypeException(String.format("deserialize GeographyValue from string failed (string %s)", paramStr));
}
}
} else if (expectedClz == VoltTable.class && inputClz == VoltTable.class) {
return param;
} else if (expectedClz == String.class) {
//For VARCHAR columns if not null or not an array send toString value.
if (!param.getClass().isArray()) {
return String.valueOf(param);
}
} else // they do their own validation
if (expectedClz == ParameterSet.class && inputClz == ParameterSet.class) {
return param;
}
// these are used by system procedures and are ignored here
if (expectedClz.getSimpleName().equals("SystemProcedureExecutionContext")) {
if (expectedClz.isAssignableFrom(inputClz)) {
return param;
}
}
throw new VoltTypeException("tryToMakeCompatible: The provided value: (" + param.toString() + ") of type: " + inputClz.getName() + " is not a match or is out of range for the target parameter type: " + expectedClz.getName());
}
Aggregations