Skip to content

Escape the metadata column of the SQL status store - #2076

Open
rzo1 wants to merge 1 commit into
mainfrom
fix/sql-status-metadata-encoding
Open

Escape the metadata column of the SQL status store#2076
rzo1 wants to merge 1 commit into
mainfrom
fix/sql-status-metadata-encoding

Conversation

@rzo1

@rzo1 rzo1 commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

StatusUpdaterBolt wrote the metadata column by concatenating \t + key + = + value with no escaping, and the read side split on those same characters, so a value containing a tabulation came back as one or more extra keys. The column is now written in an escaped form behind a v1 marker; rows written by earlier versions are still decoded exactly as before, so no migration is needed. Note a downgrade is not clean, and existing rows are not repaired: worth grepping the metadata column of an existing table for tabulations.

Also guards Date.from(Instant.parse(...)) in AbstractStatusUpdaterBolt, which sat outside the try/catch, so an unparsable status.store.as.is.with.nextfetchdate no longer takes the bolt down; it is logged and the URL goes through the normal scheduler. SQLSpout no longer routes through StringTabScheme, whose behaviour is unchanged for the seed-file spouts that rely on it.

For all changes

  • Is there a issue associated with this PR? Is it referenced in the commit message? - no issue

  • Does your PR title start with #XXXX where XXXX is the issue number you are trying to resolve? - no issue

  • Has your PR been rebased against the latest commit within the target branch (typically main)?

  • Is your initial contribution a single, squashed commit?

  • Is the code properly formatted with mvn git-code-format:format-code -Dgcf.globPattern="**/*" -Dskip.format.code=false?

For code changes

  • Have you ensured that the full suite of tests is executed via mvn clean verify? - core and the full external/sql suite against the MySQL container (18 tests, all green), not a full mvn clean verify
  • Have you written or updated unit tests to verify your changes? - round-trip tests for the new encoding and for the date guard
  • If adding new dependencies to the code, are these dependencies licensed in a way that is compatible for inclusion under ASF 2.0? - no new dependencies
  • If applicable, have you updated the LICENSE file, including the main LICENSE file? - n/a
  • If applicable, have you updated the NOTICE file, including the main NOTICE file? - n/a

@rzo1 rzo1 added this to the 4.0.0 milestone Aug 27, 2026
@rzo1
rzo1 force-pushed the fix/sql-status-metadata-encoding branch from cd658ed to 52fa39f Compare August 27, 2026 12:53

@dpol1 dpol1 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM. Checked the legacy path against StringTabScheme on a pile of random rows, identical, so "no migration" holds.

Two one-liners, not blocking. The new catch around Instant.parse in AbstractStatusUpdaterBolt only takes DateTimeParseException, but Date.from throws IllegalArgumentException on overflow, so +1000000000-12-31T23:59:59Z still escapes execute(). And the loop in MetadataColumn.encode NPEs on an empty key: getValues("") returns null while keySet() lists it, a legacy \t=x row gets you there.

@rzo1 rzo1 assigned rzo1 and unassigned jnioche and dpol1 Aug 28, 2026
@rzo1
rzo1 requested a review from jnioche August 28, 2026 07:28
The SQL status store flattened the metadata into one column as tab
separated key=value pairs without escaping, so a value containing a
tabulation came back from SQLSpout as extra keys and any legitimate
value with a tabulation was corrupted. Keys and values are now escaped
when the column is written and unescaped when it is read, which makes
the round trip lossless rather than dropping characters silently.

Columns written by the previous code start with a tabulation, columns
written now start with a format marker, so existing rows keep being
decoded exactly as before. Rows written from now on are not readable by
earlier versions, which see the marker as an extra key. SQLSpout no
longer decodes the column with StringTabScheme, whose format cannot
represent a tabulation in a value.

AbstractStatusUpdaterBolt also parsed status.store.as.is.with.nextfetchdate
outside its try/catch, so a stored value that is not a valid instant threw
out of execute. It is now logged and the URL scheduled normally, including
a value which parses as an instant but does not fit a java.util.Date.
Encoding a metadata no longer fails on a key which holds no readable
value, such as the empty key a column written before the escaping can
produce.
@rzo1
rzo1 force-pushed the fix/sql-status-metadata-encoding branch from 52fa39f to a9365f0 Compare August 28, 2026 07:59
@rzo1

rzo1 commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

Both fixed: the catch is now DateTimeParseException | IllegalArgumentException, since Date.from throws the latter on overflow rather than a parse failure, and encode skips a key whose values come back null. A regression test for each, both failing before the fix.

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.

3 participants