Federico Mariani created CAMEL-24048:
----------------------------------------
Summary: camel-sql - stale remove() silently completes in
JdbcAggregationRepository; idempotent add() leaks DuplicateKeyException;
TokenMgrError escapes stored template parser
Key: CAMEL-24048
URL: https://issues.apache.org/jira/browse/CAMEL-24048
Project: Camel
Issue Type: Bug
Components: camel-sql
Reporter: Federico Mariani
Attachments: JdbcAggregationRepositoryStaleRemoveTest.java,
JdbcMessageIdRepositoryDuplicateInsertRaceTest.java,
TemplateParserLexicalErrorTest.java
Three correctness defects found during a camel-sql review, each with a
deterministic reproducer test attached (all fail on current main, must pass
after the fix):
*1. JdbcAggregationRepository.remove() ignores the optimistic delete count*
{{remove()}} deletes with {{WHERE id = ? AND version = ?}} but discards the
update count. With a stale version (a concurrent add on another node bumped
it), 0 rows are deleted, yet the stale aggregated exchange is still inserted
into the completed table and {{remove()}} reports success: the live aggregation
survives and completes again later (duplicate downstream delivery) while a
bogus completed entry also exists. A 0-count delete should raise
{{OptimisticLockingException}}, symmetric with {{updateHelper()}}. Same pattern
in {{ClusteredJdbcAggregationRepository.remove()}}.
Reproducer: JdbcAggregationRepositoryStaleRemoveTest.java
*2. AbstractJdbcMessageIdRepository.add() propagates DuplicateKeyException on a
cross-node insert race*
{{add()}} is check-then-act (count, then insert). When a competing node inserts
the same key between the two statements, the primary-key violation escapes
{{add()}} as a raw Spring {{DuplicateKeyException}} and fails the exchange,
instead of being treated as "already processed" (return false, like the plain
count!=0 case). Idempotency itself holds, but the losing exchange goes to
redelivery/DLQ. Care is needed not to mask rollback-only state when {{add()}}
joins a caller's transaction ({{PROPAGATION_REQUIRED}} is a documented feature).
Reproducer: JdbcMessageIdRepositoryDuplicateInsertRaceTest.java (simulates the
race deterministically with a DataSource wrapper)
*3. sql-stored: lexical errors escape as java.lang.Error*
{{TemplateParser.parseTemplate()}} only catches {{ParseException}}, but the
generated JavaCC lexer throws {{TokenMgrError}} - an {{Error}} - for any
character outside the token alphabet (e.g. {{;}}). With
{{useMessageBodyForTemplate=true}} or the {{CamelSqlStoredTemplate}} header the
template comes from message content, so a stray character raises a raw
{{Error}} in the route that {{onException}} handlers never see. Lexical errors
should be wrapped in {{ParseRuntimeException}} like parse errors are.
Reproducer: TemplateParserLexicalErrorTest.java
--
This message was sent by Atlassian Jira
(v8.20.10#820010)