Skip to content

fix: parse text-format array literals according to PostgreSQL array grammar - #4964

Merged
olavloite merged 3 commits into
postgresql-dialectfrom
array-literal-parser
Sep 28, 2026
Merged

olavloite merged 3 commits into
postgresql-dialectfrom
array-literal-parser

Conversation

@olavloite

Copy link
Copy Markdown
Collaborator

Previously, text-format array parameters and COPY FROM rows were parsed using SimpleParser.readArrayLiteral(), which tokenized elements as SQL string literals and processed them with Java string unescaping. This caused multiple data corruption and bind failures:

  1. Adjacent quotes inside quoted elements (such as empty string values in JSON: '{"k":""}') were collapsed as SQL quote-escapes, corrupting element data.
  2. Unquoted elements containing SQL comment markers ('--' or '/*') or lexical tokens (such as apostrophes or dollar quotes) were stripped or caused parameter binding to fail with SQLState 22023.
  3. Elements containing backslashes were subjected to Java unicode unescaping, causing non-Java escape sequences (like Windows file paths 'C:\users' or '\uZZZZ') to throw uncaught IllegalArgumentExceptions.

This change introduces ArrayLiteralParser, a dedicated parser implementing PostgreSQL's text-format array grammar (array_in):

  • Preserves adjacent quotes in quoted elements and SQL tokens in unquoted elements.
  • Unescapes literal backslash escapes without Java-specific string or unicode processing.
  • Conforms to PostgreSQL's ASCII whitespace definition (array_isspace), preserving Unicode spaces such as CJK ideographic space (\u3000).
  • Validates 1-dimensional dimension headers and bounds syntax.
  • Adds INTERVAL array parameter binding support in ArrayParser.bind().
  • Replaces SimpleParser.readArrayLiteral with a 1-line delegate to ArrayLiteralParser, removing the obsolete returnRawHexValue overload and helpers.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a dedicated ArrayLiteralParser to parse PostgreSQL text-format array literals, replacing the previous implementation in SimpleParser. It also adds support for UUID and INTERVAL array types in ArrayParser along with comprehensive unit tests. The review feedback identifies three key areas for improvement: correcting the dimension validation logic in ArrayLiteralParser to reject [0] (since the default lower bound is 1), adding corresponding test cases for this validation, and treating INTERVAL as string-equivalent in ArrayParser to ensure interval array elements are correctly quoted in alignment with PostgreSQL.

…rammar

Previously, text-format array parameters and COPY FROM rows were parsed using
SimpleParser.readArrayLiteral(), which tokenized elements as SQL string
literals and processed them with Java string unescaping. This caused multiple
data corruption and bind failures:
1. Adjacent quotes inside quoted elements (such as empty string values in JSON:
   '{"k":""}') were collapsed as SQL quote-escapes, corrupting element data.
2. Unquoted elements containing SQL comment markers ('--' or '/*') or lexical
   tokens (such as apostrophes or dollar quotes) were stripped or caused
   parameter binding to fail with SQLState 22023.
3. Elements containing backslashes were subjected to Java unicode unescaping,
   causing non-Java escape sequences (like Windows file paths 'C:\users' or
   '\uZZZZ') to throw uncaught IllegalArgumentExceptions.

This change introduces ArrayLiteralParser, a dedicated parser implementing
PostgreSQL's text-format array grammar (array_in):
- Preserves adjacent quotes in quoted elements and SQL tokens in unquoted elements.
- Unescapes literal backslash escapes without Java-specific string or unicode processing.
- Conforms to PostgreSQL's ASCII whitespace definition (array_isspace), preserving
  Unicode spaces such as CJK ideographic space (\u3000).
- Validates 1-dimensional dimension headers and bounds syntax.
- Adds INTERVAL array parameter binding support in ArrayParser.bind().
- Replaces SimpleParser.readArrayLiteral with a 1-line delegate to ArrayLiteralParser,
  removing the obsolete returnRawHexValue overload and helpers.
@olavloite

Copy link
Copy Markdown
Collaborator Author

/gemini review

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a dedicated ArrayLiteralParser class to parse PostgreSQL text-format array literals, replacing the previous implementation in SimpleParser. This new parser supports optional dimension decorations, handles quoted and unquoted elements, preserves adjacent quotes, and correctly manages backslash escapes and comments. Additionally, the PR extends array support to include UUID and INTERVAL types, updating ArrayParser and adding comprehensive unit tests in ArrayLiteralParserTest, ArrayParserTest, and SimpleParserTest. There are no review comments, so I have no feedback to provide.

Comment thread src/main/java/com/google/cloud/spanner/pgadapter/parsers/ArrayLiteralParser.java Outdated
@olavloite
olavloite merged commit f8cf906 into postgresql-dialect Sep 28, 2026
51 checks passed
@olavloite
olavloite deleted the array-literal-parser branch September 28, 2026 14:41
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.

2 participants