DEV Community

Cover image for How I stopped manually rebuilding Java PreparedStatement SQL
olimar50
olimar50

Posted on

How I stopped manually rebuilding Java PreparedStatement SQL

If you work with Java/JDBC long enough, you eventually run into this situation:

You have code like this:

String sql = "SELECT * FROM users WHERE id = ? AND status = ?";

PreparedStatement pst = con.prepareStatement(sql);

pst.setLong(1, userId);
pst.setString(2, status);
Enter fullscreen mode Exit fullscreen mode

And then, from a log or debugger, you know something like:

userId = 42
status = ACTIVE

But what you actually need is the SQL you can paste into your database client:

SELECT * FROM users
WHERE id = 42
AND status = 'ACTIVE';
Enter fullscreen mode Exit fullscreen mode

Doing this once is trivial.

Doing it repeatedly while debugging production issues is annoying.

It gets worse when:

  • the SQL is split across several Java strings;
  • values come from map.get("KEY");
  • there are dates or timestamps;
  • strings contain apostrophes;
  • some parameters are unresolved;
  • the method contains several PreparedStatements.

I kept doing this manually, so I built a small tool called Bind2SQL.

What it does

Bind2SQL takes Java/JDBC code and reconstructs the executable SQL.

For example:

String sql = "SELECT * FROM person "
    + "WHERE person_id = ? "
    + "AND type_id = ? "
    + "AND created_at >= ?";

PreparedStatement pst = con.prepareStatement(sql);

pst.setLong(1, values.get("PERSON_ID"));
pst.setInt(2, values.get("TYPE_ID"));
pst.setDate(3, Date.valueOf("2026-09-02"));
Enter fullscreen mode Exit fullscreen mode

With runtime values:

{PERSON_ID=12648350, TYPE_ID=29}

It produces something like:

SELECT *
FROM person
WHERE person_id = 12648350
AND type_id = 29
AND created_at >= DATE '2026-09-02';
Enter fullscreen mode Exit fullscreen mode

The important part is that unresolved parameters are not silently guessed.

If Bind2SQL cannot resolve something, it leaves it clearly marked so you can review it manually.

Why I made it browser-only

I often use this kind of tool with real application code and runtime values.

That may include:

  • internal SQL;
  • identifiers;
  • production log values;
  • table names;
  • application-specific data.

So I didn't want a server in the middle.

Bind2SQL runs entirely in the browser.

There is:

  • no backend;
  • no account;
  • no upload;
  • no database;
  • no external processing.

The Java code and values you paste stay on your machine.

Current scope

The free version currently focuses on reconstructing one PreparedStatement at a time.

It supports common JDBC setters such as:

setString
setInt
setLong
setShort
setByte
setBoolean
setBigDecimal
setDouble
setFloat
setDate
setTimestamp
setTime
setNull

It can also resolve common expressions such as:

values.get("USER_ID")
Enter fullscreen mode Exit fullscreen mode

from pasted runtime values like:

{USER_ID=42, STATUS=ACTIVE}

Enter fullscreen mode Exit fullscreen mode

It is intentionally a pragmatic parser, not a complete Java compiler.

Very dynamic SQL may still require manual review.

Try it

The free version is available here:

bind2sql

No signup required.

I would like real JDBC examples

What I'm most interested in now is not adding random features.

I want to find real Java/JDBC patterns that break the parser.

If you work with PreparedStatement, I'd be interested in examples involving things like:

  • unusual setter patterns;
  • SQL assembled across multiple variables;
  • maps or DTOs;
  • nullable parameters;
  • timestamps;
  • reused statement variables;
  • legacy JDBC code.

If you find something Bind2SQL doesn't handle correctly, open an issue or leave an example in the comments.

That feedback is much more useful to me right now than adding features based on guesses.

Top comments (0)