in sql/src/main/java/org/apache/druid/sql/calcite/run/SqlResults.java [53:157]
public static Object coerce(
final ObjectMapper jsonMapper,
final Context context,
final Object value,
final SqlTypeName sqlTypeName,
final String fieldName
)
{
final Object coercedValue;
if (SqlTypeName.CHAR_TYPES.contains(sqlTypeName)) {
if (value == null || value instanceof String) {
coercedValue = value;
} else if (value instanceof NlsString) {
coercedValue = ((NlsString) value).getValue();
} else if (value instanceof Number) {
coercedValue = String.valueOf(value);
} else if (value instanceof Boolean) {
coercedValue = String.valueOf(value);
} else {
final Object maybeList = coerceArrayToList(value, false);
// Check if "maybeList" was originally a Collection of some kind, or was able to be coerced to one.
// Then Iterate through the collection, coercing each value. Useful for handling multi-value dimensions.
if (maybeList instanceof Collection) {
final List<String> valueStrings =
((Collection<?>) maybeList)
.stream()
.map(v -> (String) coerce(jsonMapper, context, v, sqlTypeName, fieldName))
.collect(Collectors.toList());
// Must stringify since the caller is expecting CHAR_TYPES.
coercedValue = coerceUsingObjectMapper(jsonMapper, valueStrings, sqlTypeName, fieldName);
} else {
throw cannotCoerce(value, sqlTypeName, fieldName);
}
}
} else if (value == null) {
coercedValue = null;
} else if (sqlTypeName == SqlTypeName.DATE) {
return Calcites.jodaToCalciteDate(coerceDateTime(value, sqlTypeName, fieldName), context.getTimeZone());
} else if (sqlTypeName == SqlTypeName.TIMESTAMP) {
return Calcites.jodaToCalciteTimestamp(coerceDateTime(value, sqlTypeName, fieldName), context.getTimeZone());
} else if (sqlTypeName == SqlTypeName.BOOLEAN) {
if (value instanceof Boolean) {
coercedValue = value;
} else if (value instanceof String) {
coercedValue = Evals.asBoolean(((String) value));
} else if (value instanceof Number) {
coercedValue = Evals.asBoolean(((Number) value).longValue());
} else {
throw cannotCoerce(value, sqlTypeName, fieldName);
}
} else if (sqlTypeName == SqlTypeName.INTEGER) {
if (value instanceof String) {
coercedValue = Ints.tryParse((String) value);
} else if (value instanceof Number) {
coercedValue = ((Number) value).intValue();
} else {
throw cannotCoerce(value, sqlTypeName, fieldName);
}
} else if (sqlTypeName == SqlTypeName.BIGINT) {
try {
coercedValue = DimensionHandlerUtils.convertObjectToLong(value, fieldName);
}
catch (Exception e) {
throw cannotCoerce(value, sqlTypeName, fieldName);
}
} else if (sqlTypeName == SqlTypeName.FLOAT) {
try {
coercedValue = DimensionHandlerUtils.convertObjectToFloat(value, fieldName);
}
catch (Exception e) {
throw cannotCoerce(value, sqlTypeName, fieldName);
}
} else if (SqlTypeName.FRACTIONAL_TYPES.contains(sqlTypeName)) {
try {
coercedValue = DimensionHandlerUtils.convertObjectToDouble(value, fieldName);
}
catch (Exception e) {
throw cannotCoerce(value, sqlTypeName, fieldName);
}
} else if (sqlTypeName == SqlTypeName.OTHER) {
coercedValue = coerceUsingObjectMapper(jsonMapper, value, sqlTypeName, fieldName);
} else if (sqlTypeName == SqlTypeName.ARRAY) {
if (context.isStringifyArrays()) {
if (value instanceof String) {
coercedValue = value;
} else if (value instanceof NlsString) {
coercedValue = ((NlsString) value).getValue();
} else {
coercedValue = coerceUsingObjectMapper(jsonMapper, value, sqlTypeName, fieldName);
}
} else {
// the protobuf jdbc handler prefers lists (it actually can't handle java arrays as sql arrays, only java lists)
// the json handler could handle this just fine, but it handles lists as sql arrays as well so just convert
// here if needed
coercedValue = coerceArrayToList(value, true);
}
} else {
throw cannotCoerce(value, sqlTypeName, fieldName);
}
return coercedValue;
}