Skip to content

PostgreSQL uuid/inet/citext/enum columns NPE when comparing a null value against a non-null value #930

Description

@jeffjensen

Background

Found while implementing #574 (PostgresqlDataTypeFactory json/jsonb support). That issue's own history has a 2015 maintainer reply flagging the original patch attachment's setSqlValue() NPEing on a null value; tracing exactly why that class of bug is possible surfaced that four already-shipped org.dbunit.ext.postgresql classes have the same gap today, live on main.

Root cause

org.dbunit.dataset.datatype.AbstractDataType#compare(Object, Object) - used by Assertion/DbUnitAssert whenever comparing an expected value against an actual value - calls typeCast(o1)/typeCast(o2) directly whenever the two values aren't .equals(), including the case where exactly one of them is null:

if (areObjectsEqual(o1, o2)) { return 0; }
final Object value1 = typeCast(o1);
final Object value2 = typeCast(o2);

Four PostgreSQL Types.OTHER data types don't null-check before dereferencing in typeCast(Object arg0), returning arg0.toString() unconditionally:

  • UuidType
  • InetType
  • CitextType
  • GenericEnumType

Additionally, none of the four null-check inside the private PGobject-building helper (getUUID()/getInet()/getCitext()/getEnum()) that setSqlValue() calls, so a direct setSqlValue(null, ...) call would also NPE. This is normally masked on the write path because SimplePreparedStatement/PreparedBatchStatement#addValue() intercept a null value and call PreparedStatement#setNull(...) directly before ever reaching DataType#setSqlValue() - but AbstractDataType#compare() has no equivalent guard, so the assertion path is genuinely reachable.

Reproduction

Comparing an expected dataset row containing null for a uuid/inet/citext/enum column against an actual row containing a non-null value (or vice versa) via Assertion.assertEquals/DbUnitAssert throws NullPointerException instead of correctly reporting a value mismatch.

Suggested fix

Null-check in typeCast() (returning null for a null input) and in setSqlValue() (bind SQL NULL before ever entering the PGobject-building path) for all four classes. org.dbunit.ext.postgresql.JsonType, added in #574 (branch 574-postgresql-json-type, not yet merged), already implements both guards correctly and can be used as the reference pattern.

Affected classes

  • org.dbunit.ext.postgresql.UuidType
  • org.dbunit.ext.postgresql.InetType
  • org.dbunit.ext.postgresql.CitextType
  • org.dbunit.ext.postgresql.GenericEnumType

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions