I have a general Java method with the following method signature:
private static ResultSet runSQLResultSet(String sql, Object... queryParams)
It opens a connection, builds a PreparedStatement
using the sql statement and the parameters in the queryParams
variable length array, runs it, caches the ResultSet
(in a CachedRowSetImpl
), closes the connection, and returns the cached result set.
I have exception handling in the method that logs errors. I log the sql statement as part of the log since it's very helpful for debugging. My problem is that logging the String variable sql
logs the template statement with ?'s instead of actual values. I want to log the actual statement that was executed (or tried to execute).
So... Is there any way to get the actual SQL statement that will be run by a PreparedStatement
? (Without building it myself. If I can't find a way to access the PreparedStatement's
SQL, I'll probably end up building it myself in my catch
es.)
I've extracted my sql from PreparedStatement using preparedStatement.toString() In my case toString() returns String like this:
Now I've created a method (Java 8), which is using regex to extract both query and values and put them into map:
This method returns map where we have key-value pairs:
Now - if you want values as list you can just simply use:
If your preparedStatement.toString() is different than in my case it's just a matter of "adjusting" regex.
Using PostgreSQL 9.6.x with official Java driver
42.2.4
:Will show the SQL with the ? already replaced, which is what I was looking for. Just added this answer to cover the postgres case.
I would never have thought it could be so simple.
It's nowhere definied in the JDBC API contract, but if you're lucky, the JDBC driver in question may return the complete SQL by just calling
PreparedStatement#toString()
. I.e.At least MySQL 5.x and PostgreSQL 8.x JDBC drivers support it. However, most other JDBC drivers doesn't support it. If you have such one, then your best bet is using Log4jdbc or P6Spy.
Alternatively, you can also write a generic function which takes a
Connection
, a SQL string and the statement values and returns aPreparedStatement
after logging the SQL string and the values. Kickoff example:and use it as
Another alternative is to implement a custom
PreparedStatement
which wraps (decorates) the realPreparedStatement
on construction and overrides all the methods so that it calls the methods of the realPreparedStatement
and collects the values in all thesetXXX()
methods and lazily constructs the "actual" SQL string whenever one of theexecuteXXX()
methods is called (quite a work, but most IDE's provides autogenerators for decorator methods, Eclipse does). Finally just use it instead. That's also basically what P6Spy and consorts already do under the hoods.Very late :) but you can get the original SQL from an OraclePreparedStatementWrapper by
I'm using Oralce 11g and couldn't manage to get the final SQL from the PreparedStatement. After reading @Pascal MARTIN answer I understand why.
I just abandonned the idea of using PreparedStatement and used a simple text formatter which fitted my needs. Here's my example:
You figure out the sqlInParam can be built dynamically in a (for,while) loop I just made it plain simple to get to the point of using the MessageFormat class to serve as a string template formater for the SQL query.
Using prepared statements, there is no "SQL query" :
But there is no re-construction of an actual real SQL query -- neither on the Java side, nor on the database side.
So, there is no way to get the prepared statement's SQL -- as there is no such SQL.
For debugging purpose, the solutions are either to :