Query from PreparedStatement - java

Is there any way to get the Oracle query from PreparedStatement .I know its not possible as such I can't use log4jdbc or p6spy as it is a secured application and using this will create bigger problems..toString won't work as I am using Oracle? I can't change PreparedStatement to Statement either.

If only need for debug time then You can use DebuggableStatement follow this article

I don't think you should be doing it this way, as there is no officially documented API for this.
If you can mess with the code, why cannot you use log4jdbc ?
Oracle JDBC also supports java.util.logging, which you could try to enable.
If you are just interested in the SQL itself, you can turn on session tracing on the Oracle server.
Or maybe you can put your code to where the statement is being prepared (using something like #pinichi is suggesting)?
But just for fun, poking around with the debugger, with my version of Oracle JDBC, I can do
if (stmt instanceof oracle.jdbc.driver.OraclePreparedStatement) {
String x = ((oracle.jdbc.driver.OraclePreparedStatement) stmt)
.getOriginalSql();
System.out.println(x);
}

If you just want to check SQL statement you can also go straight to the database and check v$sql table.
There you can find all sqls and other information about query. More info: http://download.oracle.com/docs/cd/B19306_01/server.102/b14237/dynviews_2113.htm

Related

How to specify Fastload utility for jdbc:odbc?

My connection string looks like this
String cn = "jdbc:odbc:DSN";
it works fine . However, when i try to modify it to
String cn = "jdbc:odbc:DSN, TYPE=FASTLOAD";
it does not establish connection
I also tried
String cn = "jdbc:odbc:DSN, TYPE=FASTLOADCSV";
Teradata's JDBC driver supports the FastLoad protocol, but you're not using it. You try to connect via JDBC-ODBC bridge, change to jdbc:teradata://...
Try
String cn = "jdbc:odbc:DSN; TYPE=FASTLOAD";
If you want to connect with ODBC, then use semicolons. But if you want to use FastLoad, then you need to connect using JDBC, in which case you should use commas and the forward slash like so:
String cn = "jdbc:teradata://servername/TYPE=FASTLOADCSV";
Also, you'll need to disable auto-committing whenever you fastload (at least if you do batch inserting, which you probably should). Fastload requires an empty table; committing causes the table to be non-empty. To prevent that issue, simply set autocommit to False before inserting, and set it back to True (or whatever you want it to be) after all inserts have been executed and committed.
Alternatively, you can pursue a different approach: commit stuff, but use staging tables. With this method you create new, empty tables for each insert batch. In the end you can consolidate those tables into one with the MERGE operation. If you do this process right, you can avoid any rewriting of data on disk. (Source: this other SO question)
More information:
Teradata JDBC tips on improving performance
Sample code from Teradata about JDBC, with boilerplate code on connectivity, CRUD, etc.
More Teradata docs on connectivity with JDBC

Generic query for both oracle and sql server databases?

I am working on a functionality where i need to check whether database is down or not. i have to use single query which works for both oracle and sqlserver dbs. is there any single query which checks whether db is up or not?
similar to select * from dual;
Thanks!
I'd go with a connection.setAutoCommit(true) and not with a select.
I think it would be best to use the Connection's function to check the server is available.
There should be an Exception when it fails to connect and you can check the state to see if it's still open.
To address your specific need, if you decide to continue with a query.
THIS IS NOT BEST PRACTICE
I don't know of a simple way to do what you wish, Oracle and SQL don't share the same naming for system objects. BUT run that command, it won't work on SQL, but the exception won't be of type 'Server is Down' and you can use it in your try/catch.
THIS IS NOT BEST PRACTICE
Hope it makes sense.
Better way is to obtain the connection and then use the database metadata information like the product version or product name to ensure the database is up or not.
Eg:
try{
Con = DriverManager.getConnection(databaseURL,username,password);
databasemetadata = con.getMetaData();
String databaseName = databasemetedata.getDatabaseProductName();
If(databaseName.equals("<desireddabase>"))
{
//database up and running
}
}
catch(Exception e)
{
// error in connection ...
}
The java.sql.Connection has a method
isValid(timeOut)
Returns true if the connection has not been closed and is still valid. The driver shall submit a query on the connection or use some other mechanism that positively verifies the connection is still valid when this method is called.

PreparedStatement and Oracle 10g bug

I have a big but INTERMITTENT problem with a bug in Oracle 10g when we call some SQL within a Java web application. We can't quickly patch or upgrade to 11g - which seems to be the first 'stupid' oracle support response. There is a work around, but I am having trouble doing this within PreparedStatements within my Java code.
The actual error is:
ORA-00600: internal error code, arguments: [kcblasm_1]
The bug is: Oracle Bug 12419392
The work around is running
alter session set "_hash_join_enabled" = FALSE;
before we run our bug-inducing SQL. However, traditionally a PreparedStatement takes in one single piece of SQL:
PreparedStatement stmt = con.prepareSelect("sql statement2");
Is it possible to have one PreparedStatement call that looks like this:
PreparedStatement stmt = con.prepareSelect("sql statement1; sql statement2;");
Or is this possible just by running a series of sequential PreparedStatements one after the other?
Not the best time to be getting this with Xmas looming and reduced support etc. etc., so I really hope someone can help. Thanks.
Edit: #jonearles asked for the code, so here it is, if it's on any use. Probably very specific to our project, but someone might spot the glaring bug-inducing issue:
SELECT DISTINCT qm.validator_id,
qm.QM_ID,
u.EMAIL,
qm.creation_dt,
qm.emailed,
qm.valid,
qm.resolved,
qm.new_obs_id,
o.*,
nests.*,
s.*,
l.*,
latc.TENKM
FROM query_man qm,
obs o,
obs_aux_aon nests,
sub s,
location l,
l_atlas_tetrad_coverage latc,
users u
WHERE qm.OBS_ID = o.OBS_ID
AND o.SUB_ID = s.SUB_ID
AND u.user_id = qm.user_id
AND o.obs_id = nests.obs_id(+)
AND s.LOC_ID = l.LOC_ID
AND latc.ATLAS_REGION = 'NKNE'
AND (LENGTH (l.gridref) = 6
AND (SUBSTR(l.gridref,1,3)
|| SUBSTR(l.gridref,5,1)) = latc.TENKM
OR LENGTH (l.gridref) = 4
AND l.gridref = latc.TENKM)
AND qm.RESOLVED IS NULL
ORDER BY latc.tenkm,
l.tetrad
OK. The answer to my primary question is NO, you can't create a PreparedStatement like so:
PreparedStatement stmt = con.prepareSelect("sql statement1; sql statement2;");
Running individual statements to alter session temporarily for one bit of SQL did work, but agreed seems awful and also unacceptably slowed response. Options seem to be patch or upgrade, or look into the no_use_hash hint (which I think will be slow too). Will look at code.

how to print Statement (CallableStatement) in Java?

How can I print this OracleCallableStatement ?
ocstmt = (OracleCallableStatement) connection.prepareCall("{?= call
package.method(id => ?, name=>?)}");
ocstmt.registerOutParameter(1, OracleTypes.CURSOR);
ocstmt.setInt(2, obj.getId());
ocstmt.setString(3, obj.getName());
ocstmt.execute();
resultSet = ocstmt.getCursor(1);
What I mean is how can I know that what query goes to the database, how can I print the query? because sometimes it gives me error like "Wrong type" that is why I want to look at this query
Are you using log4j?
If so, add loggers for sql like below.
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
If you are using a ORM framework such as ibatis, you could add additional logger like below.
log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
Yes, you can do this. You can either wrap your callable statement in a proxy that can substitute the actual values when you print it (and show the sql), or hunt around for a driver that has a meaningful toString. javaworld article There is also p6spy, and others.
Stored procedures are harder, but still doable.
You can't get the SQL by printing the Statement.
Is the example you posted one of the "sometimes" that triggers the error?
Why do you have to case this to an OracleCallableStatement? What part of the call is not the standard CallableStatement?
In general, use myObject.toString() to see what it prints. You may or may not be able to see the full query though. If you can't get it to go, the first thing that I would look at is the API documentation(javadocs for that Oracle library or driver that you're using)
I'm not sure if I understand the question, but it seems like you want to see this:
String sql = "{?= call package.method(id => ?, name=>?)}";
System.out.println(sql);
ocstmt = (OracleCallableStatement) connection.prepareCall(sql);
...
It's possible to use proxy jdbc driver to log all jdbc database actions.
this driver can prints all statements with values and all results.
My solution is use ProxyDataSourceBuilder(use it in Spring Boot project).
#Bean
public DataSource dataSource() {
SLF4JQueryLoggingListener loggingListener = new SLF4JQueryLoggingListener();
return ProxyDataSourceBuilder
.create(datasource)
.listener(loggingListener)
.build();
}
...
#Autowired
private DataSource dataSource;
Connection connection = dataSource.getConnection();
ocstmt = (OracleCallableStatement) connection.prepareCall("{?= call
package.method(id => ?, name=>?)}");
And just turn on logging in application.yml:
logging:
level:
net.ttddyy.dsproxy.listener.logging: debug
Try
> java -classpath ojdbc8.jar oracle.jdbc.driver.OracleSql false false "<your sql here>"
That will print the SQL that the driver sends to the database, among other things. This is not documented nor supported, but it's been around forever.
I thought it might be useful if you are looking whether executed query has value or not
System.out.println("value : "+CallableStatement.execute());
i.e The "false" returned by "CallableStatement.execute()" means that the JDBC statement didn't read any rows, (so there's no ResultSet to read). This is what you'd expect, as stored procedures don't directly return ResultSets, they only return values for any OUT or INOUT parameters.

Created a Java Web app/MySql app

Started coming up with a java web app for online user interaction. Decided to use a MySql DB for data storage. I have already created the tables with the proper/expected data types. My question is I always thought the next step would be to creat stored procedures like Search/Add/Delete/etc.. that the user could envoke from the page. So in my java code I could just call the procedure ex:
CallableStatement cs;
Try
{
String outParam = cs.getString(1); // OUT parameter
// Call a procedure with one in and out parameter
cs = connection.prepareCall("{call SearchIt(?)}");
cs.registerOutParameter(1, Types.VARCHAR);
cs.setString(1, "a string");
cs.execute();
outParam = cs.getString(1);
}
catch (SQLException e) {
}
but if my application was not in the need for stored procedures because the user actions would be simple enough to execute simple tedious queries. How could I set up my Java and Sql code to handle that. Could I just have the "Select" or "Update" statements in my code to manipulate the data in my MySQL DB. If so how would that syntax look like?
This URL has documentation on using prepared statements which is what you want to use to avoid security flaws (SQL Injection and such).
http://download.oracle.com/javase/tutorial/jdbc/basics/prepared.html
here's an example from that page
PreparedStatement updateSales = connection.prepareStatement(
"UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
updateSales.setInt(1, 75);
updateSales.setString(2, "Colombian");
updateSales.executeUpdate():
Just use Statement, or PreparedStatement.
http://download.oracle.com/javase/1.4.2/docs/api/java/sql/Statement.html
In a similar way to what you did, just call :
Statement stm = Connection.createStatement();
then execute your SQL :
stm.execute("SELECT * FROM MYTABLE");
grab the resultset and check out the results.
Beware though - this is bad bad as far as security goes - as others have mentioned, PreparedStatements are a bit more secure, but still not 100%.
To be honest, although basic JDBC is pretty simple, I really hate all the SQL strings littered around your code. If you want something a bit more elegant have a quick look at hibernate - it hides all the hackiness from you, and is also pretty easy to setup.

Categories