SQL vs Java Equality Checks: Trailing Spaces Can Lie

How SQL might lie to you. The short version: SQL equality checks ignore trailing spaces. Java doesn't. Your DB client hides them. If you don't sanitize at system boundaries, dirty data will silently break your pipeline while tests pass. The investigation trail: Steps 1-2 - No errors, data "looked" perfect. A batch service produced zero output with no exceptions, just a log: 0 records processed. The natural assumption was an empty input. But a direct query WHERE CATEGORY = 'Active' returned thousands of rows. Even a DISTINCT query check looked clean. The database said: the data is here and it's fine. Steps 3-4 - The code was fine. The test data wasn't. Since data existed, I suspected the Java code. But the logic was a simple "Active".equals(j.getCategory()). So I seeded the integration tests, copying rows straight from the DB client's UI grid. Every test passed. What I only realized later: that was the contamination point. DB clients silently strip trailing spaces on display, so I had handed the test suite pre-sanitized strings. Step 5 - Inspecting the raw payload. If the DB had data and the code worked, something in between was wrong. Checking the raw JSON payload revealed it: the value wasn't "Active" it was "Active ". Every field had trailing spaces. This was a VARCHAR column, VARCHAR doesn't pad, so the spaces had been physically inserted by an upstream ETL. Step 6 - Why did the DB hide this? Per the ANSI SQL standard, when comparing strings of unequal length with =, the shorter string is space-padded to match. So 'Active ' = 'Active' evaluates to TRUE. The database wasn't lying exactly it was following spec. But the spec is surprising. Step 7 - The full delivery chain: DB stores dirty VARCHAR strings JDBC extracts the exact dirty string Spring JdbcTemplate maps it directly to the DTO Jackson serializes it verbatim No layer sanitizes. But "Active".equals("Active ") returns FALSE. Every record was silently filtered out. Key takeaways: 1️⃣ SQL and Java equals() speak different languages. SQL space-pads for comparison; Java is strictly character-by-character. 2️⃣ Standard SQL diagnostics lie. DISTINCT, =, and GROUP BY are all space-insensitive. Detect dirty data with LENGTH(col) != LENGTH(RTRIM(col)). 3️⃣ DB clients sanitize display output. UI-copied test data will pass against clean strings while prod fails against dirty ones. 4️⃣ Trim at the boundary, not in the logic. Configure Jackson or your RowMapper to trim at deserialization don't scatter .trim() calls across business logic. Over to you: What is the most frustrating "silent bug" you've chased down? Where do you enforce data sanitization the DB, the API boundary, or business logic? #Java #DB2 #SQL #JDBC #Spring #JdbcTemplate #H2 #BDD #Debugging #DataEngineering #BackendEngineering

Also Null and Empty String?

See more comments

To view or add a comment, sign in

Explore content categories