Skip to content

feat(postgresql): Add java.sql.Types.ARRAY support to PostgresqlDataT… - #932

Merged
jeffjensen merged 1 commit into
mainfrom
646-postgresql-array-type
Aug 11, 2026
Merged

feat(postgresql): Add java.sql.Types.ARRAY support to PostgresqlDataT…#932
jeffjensen merged 1 commit into
mainfrom
646-postgresql-array-type

Conversation

@jeffjensen

@jeffjensen jeffjensen commented Aug 11, 2026

Copy link
Copy Markdown
Member

…ypeFactory

  • Add ArrayType, recognized for every array column (e.g. integer[], text[]), read/written as PostgreSQL's own array literal text representation.
  • On write, split the literal into top-level elements - honoring double-quoted, backslash-escaped elements and the unquoted NULL keyword - and bind via the standard Connection#createArrayOf(String, Object[]), so PostgreSQL itself parses and validates each element against the column's actual base type. Only single-dimension arrays are supported for writing.
  • Document ArrayType in databases/postgresql.adoc and databases.adoc.

Refs: 646

Claude-Session: https://claude.ai/code/session_01XBjSJ2bgVtwqyxGv2nvwP9

Summary by Sourcery

Add PostgreSQL array column support by introducing a dedicated ArrayType and wiring it into the PostgresqlDataTypeFactory for java.sql.Types.ARRAY.

New Features:

  • Support PostgreSQL array columns (java.sql.Types.ARRAY) via a new ArrayType that round-trips values using PostgreSQL array literal text.
  • Recognize array column types in PostgresqlDataTypeFactory and map them to ArrayType based on the reported SQL type name.

Enhancements:

  • Document PostgreSQL array handling and ArrayType usage in the PostgreSQL database documentation.
  • Record the new PostgreSQL array support feature in the project changelog.

Tests:

  • Add unit tests for ArrayType covering type metadata, reading/writing literals, element parsing, and error cases.
  • Add integration tests verifying PostgreSQL array columns (including nulls, empty arrays, and quoted elements) round-trip correctly through a real database.

Summary by CodeRabbit

  • New Features

    • Added support for PostgreSQL array columns, including null values, empty arrays, quoted and escaped elements, and null elements.
    • Supports reading arrays with any dimensionality; writing is supported for single-dimensional arrays.
    • Automatically recognizes PostgreSQL array types and preserves their SQL type information.
  • Documentation

    • Updated PostgreSQL documentation with array support details, usage behavior, and known limitations.

@jeffjensen jeffjensen linked an issue Aug 11, 2026 that may be closed by this pull request
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@sourcery-ai

sourcery-ai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds PostgreSQL array (java.sql.Types.ARRAY) support via a new ArrayType and wires it into PostgresqlDataTypeFactory, with comprehensive unit and integration tests plus documentation and changelog updates.

Sequence diagram for writing PostgreSQL array literals via ArrayType

sequenceDiagram
    actor Client
    participant ArrayType
    participant PreparedStatement
    participant Connection

    Client->>ArrayType: setSqlValue(value, column, statement)
    ArrayType->>PreparedStatement: setNull(column, Types.ARRAY) [value is null]
    ArrayType-->>Client: [return]

    alt value is Array
        ArrayType->>PreparedStatement: setArray(column, value)
    else value is literal_text
        ArrayType->>ArrayType: parseElements(value.toString)
        ArrayType->>PreparedStatement: getConnection()
        PreparedStatement-->>ArrayType: connection
        ArrayType->>Connection: createArrayOf(elementSqlTypeName, elements)
        Connection-->>ArrayType: array
        ArrayType->>PreparedStatement: setArray(column, array)
    end
Loading

File-Level Changes

Change Details Files
Introduce ArrayType to handle PostgreSQL array columns using literal text representation and JDBC Array APIs.
  • Add ArrayType class extending AbstractDataType for Types.ARRAY, storing sqlTypeName and derived elementSqlTypeName.
  • Implement getSqlValue() to read java.sql.Array from ResultSet and return its toString() or null.
  • Implement setSqlValue() to handle nulls, existing Array instances, and string literals by parsing to top-level elements and calling Connection#createArrayOf(...).
  • Implement internal parser for PostgreSQL array literals that supports quoted/escaped elements, NULL keyword mapping to null, rejects malformed or nested arrays, and treats empty arrays specially.
  • Expose getSqlTypeName() accessor and rely on string-based typeCast() with no element-level conversion.
src/main/java/org/dbunit/ext/postgresql/ArrayType.java
Wire ArrayType into PostgresqlDataTypeFactory and verify factory behavior.
  • Update createDataType() to return new ArrayType(sqlTypeName) when sqlType == Types.ARRAY.
  • Add unit test ensuring Types.ARRAY with a PostgreSQL array type name (e.g. _int4) returns an ArrayType preserving sqlTypeName.
src/main/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactory.java
src/test/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactoryTest.java
Add unit tests validating ArrayType behavior and literal parsing semantics.
  • Create ArrayTypeTest with Mockito-based tests covering metadata (sql type, type class, sqlTypeName), null handling, and typeCast behavior.
  • Test getSqlValue() for non-null and null arrays using mocked ResultSet and Array.
  • Test setSqlValue() behavior for null, pre-built Array, simple literals, whitespace trimming, quoted elements, escaped characters, NULL keyword, empty arrays, non-underscore type names, malformed literals, and nested arrays.
src/test/java/org/dbunit/ext/postgresql/ArrayTypeTest.java
Add integration test proving array round-trip behavior against a real PostgreSQL database.
  • Create PostgresqlArrayIT that sets up a test table with integer[] and text[] columns using DatabaseEnvironment.
  • Configure DatabaseConfig to use PostgresqlDataTypeFactory so array columns map to ArrayType.
  • Load a FlatXml dataset with integer and text array literals, including whole-column nulls via ReplacementDataSet, null elements, empty arrays, and quoted elements requiring escaping.
  • Execute CLEAN_INSERT and read back data to assert NUMS and TAGS columns have Types.ARRAY, expected sql type names (_int4, _text), and round-tripped literal values.
src/test/java/org/dbunit/ext/postgresql/PostgresqlArrayIT.java
Document the new ArrayType and record the change in the changelog.
  • Update changes.xml with a new action for issue 646 describing ArrayType behavior, its recognition by PostgresqlDataTypeFactory, literal handling, and single-dimension write limitation.
  • Add documentation entries in databases.adoc and databases/postgresql.adoc describing ArrayType usage and semantics (details inferred from diff header).
src/changes/changes.xml
src/site/asciidoc/databases.adoc
src/site/asciidoc/databases/postgresql.adoc

Assessment against linked issues

Issue Objective Addressed Explanation
#646 Add support in PostgresqlDataTypeFactory for PostgreSQL array columns (java.sql.Types.ARRAY) so that array-typed columns are recognized and mapped to a concrete DataType instead of falling back or failing.
#646 Implement a PostgreSQL-specific ArrayType that can correctly read and write array column values (integer[], text[], etc.) and verify this with tests, so dbUnit can store and compare array data for PostgreSQL.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@jeffjensen, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 31 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 25f64caa-6b91-4cf0-a461-b25a756f1078

📥 Commits

Reviewing files that changed from the base of the PR and between 7a57e5b and f807ca8.

📒 Files selected for processing (3)
  • src/main/java/org/dbunit/ext/postgresql/ArrayType.java
  • src/test/java/org/dbunit/ext/postgresql/ArrayTypeTest.java
  • src/test/java/org/dbunit/ext/postgresql/PostgresqlArrayIT.java
📝 Walkthrough

Walkthrough

This change adds PostgreSQL array support through a new ArrayType, factory integration, documentation, unit tests, and PostgreSQL integration tests. Array writes parse single-dimensional literals and bind values with Connection.createArrayOf.

Changes

PostgreSQL array support

Layer / File(s) Summary
Array adapter and factory integration
src/main/java/org/dbunit/ext/postgresql/ArrayType.java, src/main/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactory.java
ArrayType reads PostgreSQL arrays as text, parses supported literals for writes, handles quoted, escaped, empty, and NULL elements, and rejects nested arrays. The factory maps Types.ARRAY to ArrayType.
Array conversion validation
src/test/java/org/dbunit/ext/postgresql/ArrayTypeTest.java, src/test/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactoryTest.java, src/test/java/org/dbunit/ext/postgresql/PostgresqlArrayIT.java
Unit tests cover parsing and JDBC conversion. Factory tests verify SQL type names. PostgreSQL integration tests cover metadata and array round trips.
Documentation and release notes
src/site/asciidoc/databases.adoc, src/site/asciidoc/databases/postgresql.adoc, src/changes/changes.xml
Documentation describes array recognition, literal handling, createArrayOf binding, read and write dimensionality, comparison behavior, and the changelog entry records the feature.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PostgresqlDataTypeFactory
  participant ArrayType
  participant Connection
  participant PreparedStatement
  PostgresqlDataTypeFactory->>ArrayType: create ArrayType from SQL type name
  ArrayType->>ArrayType: parse array literal
  ArrayType->>Connection: createArrayOf element type and values
  ArrayType->>PreparedStatement: bind JDBC array
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely identifies the main change: adding java.sql.Types.ARRAY support to PostgresqlDataTypeFactory.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 646-postgresql-array-type

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/test/java/org/dbunit/ext/postgresql/PostgresqlArrayIT.java (2)

69-69: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use a direct null check.

!Objects.isNull(_connection) is a negated call. _connection != null states the same condition directly.

♻️ Proposed simplification
-        if (!Objects.isNull(_connection))
+        if (_connection != null)

Remove the java.util.Objects import if it becomes unused.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/org/dbunit/ext/postgresql/PostgresqlArrayIT.java` at line 69,
Update the null check in PostgresqlArrayIT to use the direct condition
_connection != null instead of negating Objects.isNull(_connection), and remove
the java.util.Objects import if it is no longer used.

127-148: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Row order is not guaranteed by the query.

createDataSet() reads the table without an ORDER BY. The assertions index rows 0, 1, and 2 and assume insert order. PostgreSQL can return rows in another order. Sort by ID to make the test deterministic, for example through createQueryTable(testTable, "SELECT * FROM " + testTable + " ORDER BY ID").

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/java/org/dbunit/ext/postgresql/PostgresqlArrayIT.java` around lines
127 - 148, Update the dataset retrieval in the PostgreSQL array integration test
to use an explicitly ordered query via createQueryTable, sorting by ID before
indexing rows. Keep the existing assertions and testTable usage unchanged so row
0, 1, and 2 consistently correspond to their intended records.
src/main/java/org/dbunit/ext/postgresql/ArrayType.java (1)

179-210: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Backslash escapes are ignored outside double quotes.

PostgreSQL accepts backslash escapes in unquoted array elements, for example {a\,b} is one element a,b. The parser handles \ only inside quotes, so it splits such a literal into a\ and b. Reads are unaffected, because PostgreSQL quotes elements that need escaping. Writes of hand-written literals can bind wrong elements.

♻️ Proposed handling for unquoted escapes
             } else if (c == '"')
             {
                 inQuotes = true;
                 quoted = true;
+            } else if (c == '\\' && i + 1 < body.length())
+            {
+                token.append(body.charAt(++i));
+                quoted = true;
             } else if (c == '{')

Setting quoted also prevents the escaped text from being trimmed or read as the NULL keyword.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/java/org/dbunit/ext/postgresql/ArrayType.java` around lines 179 -
210, Update the unquoted-element parsing branch in ArrayType’s array-literal
loop to recognize backslash escapes and append the following character as
literal content, including escaped commas. Mark the element as quoted/escaped
when such an escape is encountered so toElement does not trim it or interpret
the result as the NULL keyword, while preserving the existing quoted parsing
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/test/java/org/dbunit/ext/postgresql/PostgresqlArrayIT.java`:
- Line 1: Add the repository’s standard DbUnit LGPL license header at the
beginning of PostgresqlArrayIT.java, before the package declaration, matching
the header used by the other new files in the PR.

---

Nitpick comments:
In `@src/main/java/org/dbunit/ext/postgresql/ArrayType.java`:
- Around line 179-210: Update the unquoted-element parsing branch in ArrayType’s
array-literal loop to recognize backslash escapes and append the following
character as literal content, including escaped commas. Mark the element as
quoted/escaped when such an escape is encountered so toElement does not trim it
or interpret the result as the NULL keyword, while preserving the existing
quoted parsing behavior.

In `@src/test/java/org/dbunit/ext/postgresql/PostgresqlArrayIT.java`:
- Line 69: Update the null check in PostgresqlArrayIT to use the direct
condition _connection != null instead of negating Objects.isNull(_connection),
and remove the java.util.Objects import if it is no longer used.
- Around line 127-148: Update the dataset retrieval in the PostgreSQL array
integration test to use an explicitly ordered query via createQueryTable,
sorting by ID before indexing rows. Keep the existing assertions and testTable
usage unchanged so row 0, 1, and 2 consistently correspond to their intended
records.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a6beeb2d-7b07-4467-b1b5-3632a9bf2aed

📥 Commits

Reviewing files that changed from the base of the PR and between 63011ea and 7a57e5b.

📒 Files selected for processing (8)
  • src/changes/changes.xml
  • src/main/java/org/dbunit/ext/postgresql/ArrayType.java
  • src/main/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactory.java
  • src/site/asciidoc/databases.adoc
  • src/site/asciidoc/databases/postgresql.adoc
  • src/test/java/org/dbunit/ext/postgresql/ArrayTypeTest.java
  • src/test/java/org/dbunit/ext/postgresql/PostgresqlArrayIT.java
  • src/test/java/org/dbunit/ext/postgresql/PostgresqlDataTypeFactoryTest.java

Comment thread src/test/java/org/dbunit/ext/postgresql/PostgresqlArrayIT.java
@jeffjensen

Copy link
Copy Markdown
Member Author

Addressed CodeRabbit's nitpick findings in fixup commit 59afa882 (not yet squashed):

  • Row order in PostgresqlArrayIT — fixed. The round-tripped table is now read via createQueryTable(testTable, "SELECT * FROM " + testTable + " ORDER BY ID") instead of an unordered SELECT * through createDataSet(), so the row-indexed assertions no longer depend on incidental heap-scan order matching insertion order.
  • Backslash escapes outside quotes in ArrayType — fixed. PostgreSQL's array-literal grammar allows escaping delimiter/brace characters directly in an unquoted element (e.g. {a\,b} is one element a,b, not two), which the parser previously mishandled since it only recognized \ inside double quotes. Added the same escape handling to the unquoted branch, plus two regression tests (testSetSqlValue_withBackslashEscapedDelimiterOutsideQuotes_treatsAsOneElement, testSetSqlValue_withBackslashEscapedBraceOutsideQuotes_treatsAsLiteralCharacter).
  • !Objects.isNull(_connection) in PostgresqlArrayIT — left as-is. 5 of the 6 existing *IT.java files in this package use this exact form, including the direct PostgresqlJsonIT.java precedent this file was modeled after; only one file uses != null. Matching the dominant sibling convention over a purely-stylistic, low-value change.

Full unit suite (2091 tests) and the full postgresql-16 IT suite are green against a live container after these changes.

…ypeFactory

* Add ArrayType, recognized for every array column (e.g. integer[],
  text[]), read/written as PostgreSQL's own array literal text
  representation.
* On write, split the literal into top-level elements - honoring
  double-quoted, backslash-escaped elements and the unquoted NULL
  keyword - and bind via the standard
  Connection#createArrayOf(String, Object[]),
  so PostgreSQL itself parses and validates each element against the
  column's actual base type. Only single-dimension arrays are supported
  for writing.
* Document ArrayType in databases/postgresql.adoc and databases.adoc.

Refs: 646

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XBjSJ2bgVtwqyxGv2nvwP9
@jeffjensen
jeffjensen force-pushed the 646-postgresql-array-type branch from 7a57e5b to f807ca8 Compare August 11, 2026 12:55
@jeffjensen
jeffjensen merged commit f92ff08 into main Aug 11, 2026
29 checks passed
@jeffjensen
jeffjensen deleted the 646-postgresql-array-type branch August 11, 2026 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Postgres Aarray Datatype not recognized

1 participant