From ffbb93cd7de0571a6e0313c51aae48effac24956 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 11:54:29 +0000 Subject: [PATCH 1/3] Initial plan From dea8583cb7abd0683e7f6a55b973ee287e6d3a72 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 12:28:43 +0000 Subject: [PATCH 2/3] Fix #560: UnexpectedNullableFound incorrectly mapped to ColumnNotFound in parseColumn Co-authored-by: gaeljw <18280708+gaeljw@users.noreply.github.com> --- core/src/main/scala/anorm/SqlParser.scala | 7 +------ core/src/test/scala/AnormSpec.scala | 9 +++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/core/src/main/scala/anorm/SqlParser.scala b/core/src/main/scala/anorm/SqlParser.scala index 286f5390..6392fc36 100644 --- a/core/src/main/scala/anorm/SqlParser.scala +++ b/core/src/main/scala/anorm/SqlParser.scala @@ -541,12 +541,7 @@ object SqlParser extends FunctionAdapter with DeprecatedSqlParser { name: String, c: Column[T], input: (Any, MetaDataItem) - ): Either[SqlRequestError, T] = c.tupled(input).left.map { - case UnexpectedNullableFound(_) => - ColumnNotFound(name, row) - - case cause => cause - } + ): Either[SqlRequestError, T] = c.tupled(input) } @deprecated("Do not use these combinators", "2.5.4") diff --git a/core/src/test/scala/AnormSpec.scala b/core/src/test/scala/AnormSpec.scala index 5d22ec0b..7f14d3dd 100644 --- a/core/src/test/scala/AnormSpec.scala +++ b/core/src/test/scala/AnormSpec.scala @@ -66,6 +66,15 @@ final class AnormSpec } + "throw UnexpectedNullableFound when non-nullable scalar result is null" in withQueryResult( + rowList1(classOf[Integer] -> "n") :+ null.asInstanceOf[Integer] + ) { implicit c: Connection => + SQL("SELECT * FROM test").as(scalar[Int].single) must throwA[AnormException].like { + case e: AnormException => + e.getMessage must startWith("UnexpectedNullableFound(") + } + } + "throw exception when single result is missing" in withQueryResult(fooBarTable) { implicit c: Connection => SQL("SELECT * FROM test").as(fooBarParser1.single).aka("mapping") must throwA[Exception].like { From 852216278284363846f82a4c911dbfca6899b82f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 28 Feb 2026 12:40:39 +0000 Subject: [PATCH 3/3] Fix RowParser.? to catch UnexpectedNullableFound and add test for null column with ? operator Co-authored-by: gaeljw <18280708+gaeljw@users.noreply.github.com> --- core/src/main/scala/anorm/RowParser.scala | 6 +++--- core/src/test/scala/anorm/SqlResultSpec.scala | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/src/main/scala/anorm/RowParser.scala b/core/src/main/scala/anorm/RowParser.scala index 8c6c0a50..2311b623 100644 --- a/core/src/main/scala/anorm/RowParser.scala +++ b/core/src/main/scala/anorm/RowParser.scala @@ -98,9 +98,9 @@ trait RowParser[+A] extends (Row => SqlResult[A]) { parent => */ def ? : RowParser[Option[A]] = RowParser { parent(_) match { - case Success(a) => Success(Some(a)) - case Error(ColumnNotFound(_, _)) => - Success(None) + case Success(a) => Success(Some(a)) + case Error(ColumnNotFound(_, _)) => Success(None) + case Error(UnexpectedNullableFound(_)) => Success(None) case e @ Error(_) => e } diff --git a/core/src/test/scala/anorm/SqlResultSpec.scala b/core/src/test/scala/anorm/SqlResultSpec.scala index 34318760..e0146aa0 100644 --- a/core/src/test/scala/anorm/SqlResultSpec.scala +++ b/core/src/test/scala/anorm/SqlResultSpec.scala @@ -161,6 +161,12 @@ final class SqlResultSpec extends org.specs2.mutable.Specification with H2Databa SQL"SELECT *".as(SqlParser.str("foo").?.single) must beNone } + + "be None when column is NULL for non-nullable type" in withQueryResult( + rowList1(classOf[Integer] -> "n") :+ null.asInstanceOf[Integer] + ) { implicit c: Connection => + SQL"SELECT *".as(SqlParser.int("n").?.single) must beNone + } } "Collecting" should {