Java
SQL
PreparedStatement
Database
Programming

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:

java
1String sql = "SELECT * FROM users WHERE email = ? AND age > ?";
2PreparedStatement ps = connection.prepareStatement(sql);
3ps.setString(1, "[email protected]");
4ps.setInt(2, 30);

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:

java
1String sql = "SELECT * FROM users WHERE email = ? AND age > ?";
2String email = "[email protected]";
3int age = 30;
4
5logger.debug("Executing SQL: {} | params: email={}, age={}", sql, email, age);
6
7PreparedStatement ps = connection.prepareStatement(sql);
8ps.setString(1, email);
9ps.setInt(2, age);

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:

java
String rendered = sql.replaceFirst("\\?", "'" + email + "'");

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:

java
System.out.println(ps);

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 PreparedStatement SQL 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.

Course illustration
Course illustration

All Rights Reserved.