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)

Reply via email to