How can I get the SQL of a PreparedStatement?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In standard JDBC, there is no portable API that returns the final SQL string of a PreparedStatement with every parameter rendered into it. That is why the practical answers are usually logging at the driver layer, using a proxy library such as P6Spy, or logging the SQL template and parameters separately in your own code.
Why JDBC Does Not Expose The Final SQL String
A PreparedStatement sends a SQL template plus bound parameter values to the driver and database. JDBC standardizes how you bind parameters, but it does not standardize a "give me the fully interpolated SQL" method.
Example:
From the application's point of view, the SQL template and the parameter values are separate objects. Some drivers may provide helpful toString() output, but that is driver-specific behavior and not something portable code should rely on.
Log The SQL Template And Parameters Yourself
The most dependable application-level approach is to log the SQL and the bound values explicitly:
This is not the same as a database-ready SQL string, but it is often the best debugging output because:
- it is portable across drivers
- it avoids fake string interpolation rules
- it preserves the actual parameter types
That last point matters because quoting and formatting are not always obvious from a rendered string.
Use A JDBC Proxy Or Spy Library
If you want deeper visibility, use a tool that intercepts JDBC calls. A common option is P6Spy.
Once configured, it can log SQL with parameter values as queries execute, which is usually the cleanest answer during debugging or local development.
This approach is better than manually trying to rebuild the SQL text because the proxy sees the actual JDBC interaction instead of guessing how the statement should look after substitution.
For many teams, that is the practical answer to "how do I get the SQL?"
Be Skeptical Of Manual Placeholder Replacement
A naive helper often looks like this:
That is dangerous as a general solution because:
- strings need quoting and escaping
- dates and timestamps need formatting
- binary values are not human-friendly
- the same placeholder character might appear in string literals
Manual rendering may be acceptable for a narrow internal debug utility if you control the data types, but it should not be treated as a faithful reconstruction of what the database received.
Some Drivers Expose Helpful toString() Output
Certain JDBC drivers include bound values in PreparedStatement.toString(). That can be convenient during ad hoc debugging:
However, this is not portable JDBC behavior. Another driver may print only an object id or a template string.
So the right rule is:
- useful for quick local inspection
- not safe to depend on in generic application logic
Common Pitfalls
One common mistake is assuming JDBC has a standard API for "the final SQL string." It does not.
Another issue is manually replacing question marks in ways that break quoting, escaping, or data type formatting.
A third problem is relying on toString() output from one driver and then being surprised when another driver behaves differently.
Finally, teams sometimes log rendered SQL but omit the original parameter values and types, which are often more useful for debugging than a simulated final string.
Summary
- Standard JDBC does not provide a portable API to extract a fully rendered
PreparedStatementSQL string. - The most reliable application-level approach is to log the SQL template and bound parameter values separately.
- Proxy tools such as P6Spy are often the best way to inspect executed SQL with parameters.
- Driver-specific
toString()output can help, but it is not portable. - Be cautious about manual placeholder replacement because it rarely reproduces database behavior exactly.

