in druid/src/main/java/org/apache/calcite/adapter/druid/DruidConnectionImpl.java [318:456]
private static void parseFieldForName(List<String> fieldNames,
List<ColumnMetaData.Rep> fieldTypes,
int posTimestampField, Row.RowBuilder rowBuilder, JsonParser parser, String fieldName)
throws IOException {
// Move to next token, which is name's value
JsonToken token = parser.nextToken();
boolean isTimestampColumn = fieldName.equals(DEFAULT_RESPONSE_TIMESTAMP_COLUMN);
int i = fieldNames.indexOf(fieldName);
ColumnMetaData.Rep type = null;
if (i < 0) {
if (!isTimestampColumn) {
// Field not present
return;
}
} else {
type = fieldTypes.get(i);
}
if (isTimestampColumn || ColumnMetaData.Rep.JAVA_SQL_TIMESTAMP == type) {
final int fieldPos = posTimestampField != -1 ? posTimestampField : i;
if (token == JsonToken.VALUE_NUMBER_INT) {
rowBuilder.set(posTimestampField, parser.getLongValue());
return;
} else {
// We don't have any way to figure out the format of time upfront since we only have
// org.apache.calcite.avatica.ColumnMetaData.Rep.JAVA_SQL_TIMESTAMP as type to represent
// both timestamp and timestamp with local timezone.
// Logic where type is inferred can be found at DruidQuery.DruidQueryNode.getPrimitive()
// Thus need to guess via try and catch
synchronized (UTC_TIMESTAMP_FORMAT) {
// synchronized block to avoid race condition
try {
// First try to parse as Timestamp with timezone.
rowBuilder
.set(fieldPos, UTC_TIMESTAMP_FORMAT.parse(parser.getText()).getTime());
} catch (ParseException e) {
// swallow the exception and try timestamp format
try {
rowBuilder
.set(fieldPos, TIMESTAMP_FORMAT.parse(parser.getText()).getTime());
} catch (ParseException e2) {
// unknown format should not happen
throw new RuntimeException(e2);
}
}
}
return;
}
}
switch (token) {
case VALUE_NUMBER_INT:
if (type == null) {
type = ColumnMetaData.Rep.LONG;
}
// fall through
case VALUE_NUMBER_FLOAT:
if (type == null) {
// JSON's "float" is 64-bit floating point
type = ColumnMetaData.Rep.DOUBLE;
}
switch (type) {
case BYTE:
rowBuilder.set(i, parser.getByteValue());
break;
case SHORT:
rowBuilder.set(i, parser.getShortValue());
break;
case INTEGER:
rowBuilder.set(i, parser.getIntValue());
break;
case LONG:
rowBuilder.set(i, parser.getLongValue());
break;
case DOUBLE:
rowBuilder.set(i, parser.getDoubleValue());
break;
default:
break;
}
break;
case VALUE_TRUE:
rowBuilder.set(i, true);
break;
case VALUE_FALSE:
rowBuilder.set(i, false);
break;
case VALUE_NULL:
break;
case VALUE_STRING:
default:
final String s = parser.getText();
if (type != null) {
switch (type) {
case LONG:
case PRIMITIVE_LONG:
case SHORT:
case PRIMITIVE_SHORT:
case INTEGER:
case PRIMITIVE_INT:
switch (s) {
case "Infinity":
case "-Infinity":
case "NaN":
throw new RuntimeException("/ by zero");
default:
break;
}
rowBuilder.set(i, Long.valueOf(s));
break;
case FLOAT:
case PRIMITIVE_FLOAT:
case PRIMITIVE_DOUBLE:
case NUMBER:
case DOUBLE:
switch (s) {
case "Infinity":
rowBuilder.set(i, Double.POSITIVE_INFINITY);
return;
case "-Infinity":
rowBuilder.set(i, Double.NEGATIVE_INFINITY);
return;
case "NaN":
rowBuilder.set(i, Double.NaN);
return;
default:
break;
}
rowBuilder.set(i, Double.valueOf(s));
break;
default:
break;
}
} else {
rowBuilder.set(i, s);
}
}
}