Skip to content

Commit

Permalink
Fix reading null values from db
Browse files Browse the repository at this point in the history
  • Loading branch information
andrey-shishkin committed Dec 29, 2023
1 parent a13a5a5 commit 9c90148
Showing 1 changed file with 45 additions and 64 deletions.
109 changes: 45 additions & 64 deletions core/src/main/scala/zio/jdbc/JdbcDecoder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -616,163 +616,141 @@ trait JdbcDecoderLowPriorityImplicits {
meta.getColumnType(columnIndex) match {
case SqlTypes.ARRAY =>
val array = resultSet.getArray(columnIndex)

createDynamicDecoder(schema, array.getResultSet().getMetaData())(array.getResultSet())
valueOrNone(array, createDynamicDecoder(schema, array.getResultSet().getMetaData)(array.getResultSet()))

case SqlTypes.BIGINT =>
val bigInt = resultSet.getBigDecimal(columnIndex).toBigInteger()

DynamicValue.Primitive(bigInt, StandardType.BigIntegerType)
valueOrNone(bigInt, DynamicValue.Primitive(bigInt, StandardType.BigIntegerType))

case SqlTypes.BINARY =>
val chunk = getBinary(resultSet.getBinaryStream(columnIndex))

DynamicValue.Primitive(chunk, StandardType.BinaryType)
valueOrNone(chunk, DynamicValue.Primitive(chunk, StandardType.BinaryType))

case SqlTypes.BIT =>
val bit = resultSet.getInt(columnIndex) == 1

DynamicValue.Primitive(bit, StandardType.BoolType)
val bit = resultSet.getBoolean(columnIndex)
valueOrNone(bit, DynamicValue.Primitive(bit, StandardType.BoolType))

case SqlTypes.BLOB =>
val blob = resultSet.getBlob(columnIndex)

DynamicValue.Primitive(Chunk.fromArray(blob.getBytes(0, blob.length().toInt)), StandardType.BinaryType)
valueOrNone(
blob,
DynamicValue.Primitive(Chunk.fromArray(blob.getBytes(0, blob.length().toInt)), StandardType.BinaryType)
)

case SqlTypes.BOOLEAN =>
val bool = resultSet.getBoolean(columnIndex)

DynamicValue.Primitive(bool, StandardType.BoolType)
valueOrNone(bool, DynamicValue.Primitive(bool, StandardType.BoolType))

case SqlTypes.CHAR =>
val char: Char = resultSet.getString(columnIndex)(0)

DynamicValue.Primitive(char, StandardType.CharType)
val char = resultSet.getString(columnIndex)(0)
valueOrNone(char, DynamicValue.Primitive(char, StandardType.CharType))

case SqlTypes.CLOB =>
val clob = resultSet.getClob(columnIndex)

DynamicValue.Primitive(clob.getSubString(0L, clob.length().toInt), StandardType.StringType)
valueOrNone(
clob,
DynamicValue.Primitive(clob.getSubString(0L, clob.length().toInt), StandardType.StringType)
)

case SqlTypes.DATE =>
val date = resultSet.getDate(columnIndex)

DynamicValue.Primitive(date.toLocalDate(), StandardType.LocalDateType)
valueOrNone(date, DynamicValue.Primitive(date.toLocalDate(), StandardType.LocalDateType))

case SqlTypes.DECIMAL =>
val bigDecimal = resultSet.getBigDecimal(columnIndex)

DynamicValue.Primitive(bigDecimal, StandardType.BigDecimalType)
valueOrNone(bigDecimal, DynamicValue.Primitive(bigDecimal, StandardType.BigDecimalType))

case SqlTypes.DOUBLE =>
val double = resultSet.getDouble(columnIndex)

DynamicValue.Primitive(double, StandardType.DoubleType)
valueOrNone(double, DynamicValue.Primitive(double, StandardType.DoubleType))

case SqlTypes.FLOAT =>
val float = resultSet.getFloat(columnIndex)

DynamicValue.Primitive(float, StandardType.FloatType)
valueOrNone(float, DynamicValue.Primitive(float, StandardType.FloatType))

case SqlTypes.INTEGER =>
val int = resultSet.getInt(columnIndex)

DynamicValue.Primitive(int, StandardType.IntType)
valueOrNone(int, DynamicValue.Primitive(int, StandardType.IntType))

case SqlTypes.LONGNVARCHAR =>
val string = resultSet.getString(columnIndex)

DynamicValue.Primitive(string, StandardType.StringType)
valueOrNone(string, DynamicValue.Primitive(string, StandardType.StringType))

case SqlTypes.LONGVARBINARY =>
val chunk = getBinary(resultSet.getBinaryStream(columnIndex))

DynamicValue.Primitive(chunk, StandardType.BinaryType)
valueOrNone(chunk, DynamicValue.Primitive(chunk, StandardType.BinaryType))

case SqlTypes.LONGVARCHAR =>
val string = resultSet.getString(columnIndex)

DynamicValue.Primitive(string, StandardType.StringType)
valueOrNone(string, DynamicValue.Primitive(string, StandardType.StringType))

case SqlTypes.NCHAR =>
val string = resultSet.getNString(columnIndex)

DynamicValue.Primitive(string, StandardType.StringType)
valueOrNone(string, DynamicValue.Primitive(string, StandardType.StringType))

case SqlTypes.NCLOB =>
val clob = resultSet.getNClob(columnIndex)

DynamicValue.Primitive(clob.getSubString(0L, clob.length().toInt), StandardType.StringType)
valueOrNone(
clob,
DynamicValue.Primitive(clob.getSubString(0L, clob.length().toInt), StandardType.StringType)
)

case SqlTypes.NULL =>
DynamicValue.Primitive((), StandardType.UnitType)

case SqlTypes.NUMERIC =>
val bigDecimal = resultSet.getBigDecimal(columnIndex)

DynamicValue.Primitive(bigDecimal, StandardType.BigDecimalType)
valueOrNone(bigDecimal, DynamicValue.Primitive(bigDecimal, StandardType.BigDecimalType))

case SqlTypes.NVARCHAR =>
val string = resultSet.getString(columnIndex)

DynamicValue.Primitive(string, StandardType.StringType)
valueOrNone(string, DynamicValue.Primitive(string, StandardType.StringType))

case SqlTypes.REAL =>
val bigDecimal = resultSet.getBigDecimal(columnIndex)

DynamicValue.Primitive(bigDecimal, StandardType.BigDecimalType)
valueOrNone(bigDecimal, DynamicValue.Primitive(bigDecimal, StandardType.BigDecimalType))

case SqlTypes.ROWID =>
val long = resultSet.getLong(columnIndex)

DynamicValue.Primitive(long, StandardType.LongType)
valueOrNone(long, DynamicValue.Primitive(long, StandardType.LongType))

case SqlTypes.SMALLINT =>
val short = resultSet.getShort(columnIndex)

DynamicValue.Primitive(short, StandardType.ShortType)
valueOrNone(short, DynamicValue.Primitive(short, StandardType.ShortType))

case SqlTypes.SQLXML =>
val xml = resultSet.getSQLXML(columnIndex)

DynamicValue.Primitive(xml.getString(), StandardType.StringType)
valueOrNone(xml, DynamicValue.Primitive(xml.getString(), StandardType.StringType))

case SqlTypes.TIME =>
val time = resultSet.getTime(columnIndex)

DynamicValue.Primitive(time.toLocalTime(), StandardType.LocalTimeType)
valueOrNone(time, DynamicValue.Primitive(time.toLocalTime(), StandardType.LocalTimeType))

case SqlTypes.TIMESTAMP =>
val timestamp = resultSet.getTimestamp(columnIndex)

DynamicValue.Primitive(timestamp.toInstant(), StandardType.InstantType)
valueOrNone(timestamp, DynamicValue.Primitive(timestamp.toLocalDateTime, StandardType.LocalDateTimeType))

case SqlTypes.TIMESTAMP_WITH_TIMEZONE =>
// TODO: Timezone
val timestamp = resultSet.getTimestamp(columnIndex)

DynamicValue.Primitive(timestamp.toInstant(), StandardType.InstantType)
valueOrNone(timestamp, DynamicValue.Primitive(timestamp.toInstant(), StandardType.InstantType))

case SqlTypes.TIME_WITH_TIMEZONE =>
// TODO: Timezone
val time = resultSet.getTime(columnIndex)

DynamicValue.Primitive(time.toLocalTime(), StandardType.LocalTimeType)
valueOrNone(time, DynamicValue.Primitive(time.toLocalTime(), StandardType.LocalTimeType))

case SqlTypes.TINYINT =>
val short = resultSet.getShort(columnIndex)

DynamicValue.Primitive(short, StandardType.ShortType)
valueOrNone(short, DynamicValue.Primitive(short, StandardType.ShortType))

case SqlTypes.VARBINARY =>
val chunk = getBinary(resultSet.getBinaryStream(columnIndex))

DynamicValue.Primitive(chunk, StandardType.BinaryType)
valueOrNone(chunk, DynamicValue.Primitive(chunk, StandardType.BinaryType))

case SqlTypes.VARCHAR =>
val string = resultSet.getString(columnIndex)

DynamicValue.Primitive(string, StandardType.StringType)
valueOrNone(string, DynamicValue.Primitive(string, StandardType.StringType))

case other =>
throw new SQLException(
Expand All @@ -788,6 +766,9 @@ trait JdbcDecoderLowPriorityImplicits {
DynamicValue.Record(TypeId.Structural, listMap)
}

protected def valueOrNone(value: Any, dyn: DynamicValue): DynamicValue =
if (value != null) dyn else DynamicValue.NoneValue

def fromSchema[A](implicit schema: Schema[A]): JdbcDecoder[A] =
(columnIndex: Int, resultSet: ResultSet) => {
val dynamicDecoder = createDynamicDecoder(schema, resultSet.getMetaData())
Expand Down

0 comments on commit 9c90148

Please sign in to comment.