in spanner-data-validator-java/src/main/java/com/google/migration/dto/HashResult.java [173:326]
public static HashResult fromJDBCResultSet(ResultSet resultSet,
Integer keyIndex,
String rangeFieldType,
Boolean adjustTimestampPrecision,
Integer timestampThresholdIndex)
throws SQLException {
HashResult retVal = new HashResult();
ResultSetMetaData rsMetaData = resultSet.getMetaData();
int colCount = rsMetaData.getColumnCount();
StringBuilder sbConcatCols = new StringBuilder();
for(int i = 0; i < colCount; i++) {
int colOrdinal = i+1;
int type = rsMetaData.getColumnType(colOrdinal);
// https://docs.oracle.com/javase/8/docs/api/constant-values.html
// look for (java.sql.Types)
switch (type) {
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
String val = resultSet.getString(colOrdinal);
if(val != null && !resultSet.wasNull()) {
sbConcatCols.append(val);
}
break;
case Types.ARRAY:
Array arrayVal = resultSet.getArray(colOrdinal);
if(arrayVal != null && !resultSet.wasNull()) {
String[] vals = (String[])arrayVal.getArray();
for(int j = 0; j < vals.length; j++) {
sbConcatCols.append(vals[j]);
}
}
break;
// TODO: we're assuming OTHER is jsonb (FIX)
case Types.OTHER:
String otherVal = resultSet.getString(colOrdinal);
if(otherVal != null && !resultSet.wasNull()) {
sbConcatCols.append(getNormalizedJsonString(otherVal));
}
break;
case Types.LONGVARBINARY:
case Types.VARBINARY:
byte[] bytes = resultSet.getBytes(colOrdinal);
if(bytes != null && !resultSet.wasNull()) {
sbConcatCols.append(Base64.encodeBase64String(bytes));
}
break;
case Types.BIT:
case Types.BOOLEAN:
Boolean boolVal = resultSet.getBoolean(colOrdinal);
if(boolVal != null && !resultSet.wasNull()) {
// https://stackoverflow.com/questions/39561112/getting-boolean-from-resultset
sbConcatCols.append(boolVal);
}
break;
case Types.INTEGER:
Integer intVal = resultSet.getInt(colOrdinal);
if(intVal != null && !resultSet.wasNull()) {
sbConcatCols.append(intVal);
}
break;
case Types.DOUBLE:
Double doubleVal = resultSet.getDouble(colOrdinal);
if(doubleVal != null && !resultSet.wasNull()) {
sbConcatCols.append(doubleVal);
}
break;
case Types.REAL:
Float floatVal = resultSet.getFloat(colOrdinal);
if(floatVal != null && !resultSet.wasNull()) {
sbConcatCols.append(floatVal);
}
break;
case Types.TINYINT:
Short shortVal = resultSet.getShort(colOrdinal);
if(shortVal != null && !resultSet.wasNull()) {
sbConcatCols.append(shortVal);
}
break;
case Types.BIGINT:
Long longVal = resultSet.getLong(colOrdinal);
if(longVal != null && !resultSet.wasNull()) {
sbConcatCols.append(longVal);
}
break;
case Types.DECIMAL:
//DECIMAL is mapped to Spanner NUMERIC which does not store trailing zeros
//Strip the trailing zeros from the source result before comparing
BigDecimal decimalVal = new BigDecimal(resultSet.getBigDecimal(colOrdinal).stripTrailingZeros().toPlainString());
if(decimalVal != null && !resultSet.wasNull()) {
sbConcatCols.append(decimalVal);
}
break;
case Types.DATE:
Date dateVal = resultSet.getDate(colOrdinal);
if(dateVal != null && !resultSet.wasNull()) {
LocalDate localDate = dateVal.toLocalDate();
sbConcatCols.append(String.format("%d%d%d",
localDate.getYear(),
localDate.getMonth().getValue(),
localDate.getDayOfMonth()));
}
break;
case Types.TIMESTAMP:
case Types.TIME_WITH_TIMEZONE:
// TODO: This uses millisecond precision; consider using microsecond precision
java.sql.Timestamp timestampVal = resultSet.getTimestamp(colOrdinal);
if(timestampVal != null && !resultSet.wasNull()) {
Long rawTimestamp = timestampVal.getTime();
if (adjustTimestampPrecision)
rawTimestamp = rawTimestamp / 1000;
sbConcatCols.append(rawTimestamp);
if(timestampThresholdIndex >= 0) {
if(i == timestampThresholdIndex) {
retVal.timestampThresholdValue = rawTimestamp;
if(adjustTimestampPrecision)
retVal.timestampThresholdValue = retVal.timestampThresholdValue * 1000;
}
}
}
break;
default:
LOG.error(String.format("Unsupported type: %d", type));
throw new RuntimeException(String.format("Unsupported type: %d", type));
} // switch
} // for
switch(rangeFieldType) {
case TableSpec.UUID_FIELD_TYPE:
case TableSpec.STRING_FIELD_TYPE:
retVal.key = resultSet.getString(keyIndex+1);
break;
case TableSpec.TIMESTAMP_FIELD_TYPE:
retVal.key = resultSet.getTimestamp(keyIndex+1).toString();
break;
case TableSpec.INT_FIELD_TYPE:
retVal.key = String.valueOf(resultSet.getInt(keyIndex+1));
break;
case TableSpec.LONG_FIELD_TYPE:
retVal.key = String.valueOf(resultSet.getLong(keyIndex+1));
break;
default:
throw new RuntimeException(String.format("Unexpected range field type %s", rangeFieldType));
}
retVal.rangeFieldType = rangeFieldType;
retVal.origValue = sbConcatCols.toString();
retVal.sha256 = Helpers.sha256(retVal.origValue);
retVal.isSource = true;
return retVal;
}