Comparisons of Oracle DATE column with java.sql.timestamp via JOOQ - oracle

I am using jooq to build queries for Oracle. Everything works fine except for dates:
public static void main(String[] args) throws SQLException {
java.sql.Timestamp now = new java.sql.Timestamp(new Date().getTime());
Connection con = DriverManager.getConnection(... , ... , ...);
final Factory create = new OracleFactory(con);
Statement s = con.createStatement();
s.execute("create table test_table ( test_column DATE )");
s.execute("insert into test_table values (to_date('20111111', 'yyyymmdd'))");
// -- using to_date
ResultSet rs = s.executeQuery("select count(1) from test_table where test_column<to_date('20121212', 'yyyymmdd')");
rs.next();
System.out.println(""+rs.getInt(1));
rs.close();
// -- using a preparedstatement with java.sql.timestamp
PreparedStatement ps = con.prepareStatement("select count(1) from test_table where test_column<?");
ps.setTimestamp(1,now);
rs = ps.executeQuery();
rs.next();
System.out.println(""+rs.getInt(1));
rs.close();
// -- using jooq with java.sql.timestamp
final org.jooq.Table<org.jooq.Record> table = create.tableByName("TEST_TABLE");
final org.jooq.SelectSelectStep sss = create.select(create.count());
final org.jooq.SelectJoinStep sjs = sss.from(table);
final org.jooq.SelectConditionStep scs = sjs.where(create.fieldByName("TEST_COLUMN").lessThan(now));
System.out.println(scs.toString());
rs = s.executeQuery(scs.toString());
rs.next();
System.out.println(""+rs.getInt(1));
rs.close();
s.close();
}
Gives the following output:
1
1
select count(*) from "TEST_TABLE" where "TEST_COLUMN" < '2012-12-12 19:42:34.957'
Exception in thread "main" java.sql.SQLDataException: ORA-01861: literal does not match format string
I would have thought that JOOQ would check the type of Object in lessThan(Object)
to determine whether it can come up with a reasonable conversion, but apparently it
just does an Object.toString() in this case. I also remember that I never had issues with date queries via JOOQ in MySQL (although this is a while back). What am I doing wrong?

I suspect that this issue is due to the fact that create.fieldByName() doesn't know the type of the column (hence, Object), and coerces that unknown type on the right hand side of the comparison predicate. That should be fixed in jOOQ. I have registered #2007 for this:
https://github.com/jOOQ/jOOQ/issues/2007
In the mean time, try explicitly setting the type on your field:
create.fieldByName(Timestamp.class, "TEST_COLUMN").lessThan(now)

Related

Oracle OJDBC MERGE Statement and Generated Keys

Does Oracle ~>12 support generated keys using a Merge statement? Some sudo code..
MERGE INTO TARGET_TABLE TRG
USING (SELECT CAST(? AS NUMBER) AS ID FROM DUAL) SRC
ON (TRG.ID = SRC.ID)
WHEN MATCHED THEN UPDATE SET....
WHEN NOT MATCHED THEN
INSERT(ID....)
VALUES(MYSEQ.NEXTVAL...)
The prepared statement is set up;
try (PreparedStatement pstmt =
connection.prepareStatement(
loadStatement(sqlName, connection, getClass()), new String[] {ID})) {
...
int inserted = pstmt.executeUpdate();
ResultSet rs = pstmt.getGeneratedKeys();
List<Long> keys = new ArrayList<>(inserted);
while (rs.next) {
rs.getLong(1);
}
return keys;
...
I have in-memory tests where the connection uses the H2 driver running the very same SQL and PreparedStatment and that returns the generated key just fine, but Oracle does not.
Reviewing the docs it would suggest it does not?
Thanks!

Call stored procedure and register out parameter using JDBC Driver

We have written a stored procedure in Snowflake that inserts values in a table and returns a primary key. I'm trying to call this stored procedure using its JDBC driver.
final Connection connection = getJdbcTemplate().getDataSource().getConnection();
final CallableStatement callableStatement = connection.prepareCall("{call REWARD.sp_issue_reward(?, ?, ?)}");
callableStatement.setLong(1, reward.getClientSeq());
callableStatement.setLong(2, reward.getUserUniqueId());
callableStatement.registerOutParameter(3, Types.INTEGER); // throws SQLFeatureNotSupportedException
callableStatement.executeUpdate();
The connection.prepareCall returns an instance of SnowflakeCallableStatementV1.class. Problem is that this class has the following implementation for registering for output parameter:
/*
The Snowflake database does not accept OUT or INOUT parameters, so the registerOutParameter functions and the get
functions (which get values of OUT parameters) will remain not implemented)
*/
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException {
throw new SQLFeatureNotSupportedException();
}
A sample stored procedure definition that is in use:
create or replace procedure sp_issue_reward(CLIENT_SEQ float,
USER_SEQ float)
returns float not null
language javascript
called on null input
volatile
as
$$
var REWARD_ID = 1;
var insertStatement = snowflake.createStatement({
sqlText: "INSERT INTO REWARD.REWARD_CPY ("
+ "reward_seq, "
+ "client_seq, "
+ "user_seq) "
+ "VALUES (?, ?, ?)",
binds: [REWARD_ID, CLIENT_SEQ, USER_SEQ]
})
.execute();
return REWARD_ID;
$$;
How to get an output of a stored procedure using Snowflake JDBC driver?
Results are same with this stored procedure as well:
CREATE or replace PROCEDURE testSp()
RETURNS VARCHAR
LANGUAGE javascript
AS
$$
var rs = "Test"
return rs;
$$;
The problem is here:
callableStatement.executeUpdate();
When you're calling a stored procedure from JDBC, you're not executing an update. You're executing a query even though the SP is doing an update.
The stored procedure will return one row with a single column for the result. You can retrieve it like this:
Statement stmt = c.createStatement();
ResultSet rs = stmt.executeQuery("call TEST_JDBC()");
while (rs.next()) {
System.out.println(rs.getString(1));
}
You can of course get more sophisticated than this using prepared statements, but use executeQuery.

Spring JdbcTemplate: Return value type of count(*) in ResultSet of PreparedStatement

What is the return value type of count(*) in the ResultSet of a Prepared Statement with Spring JdbcTemplate?
String query = "select count(*) as ROW_COUNT from table1";
List<Map<String, Object>> list = executePreparedStatement(query);
Iterator<Map<String, Object>> iter = list.iterator();
if (iter.hasNext()) {
Map<String, Object> lom = iter.next();
return (((Long) lom.get("ROW_COUNT"))).intValue();
}
Does this depend on the JDBC driver / and or the database?
For example in DB2 the return value type was Integer, but in PostgreSQL it is Long.
Why is this different?
Different vendors have different implementations.
Sometimes even a single vendor can have different implementations.
You need to code accordingly.
Db2 for Linux/Unix/Windows, Db2 for i-Series, Db2 for Z/OS, all return a large integer from the COUNT function.
Additionally Db2 for i can return DECIMAL(15,0) from the count function if the table is distributed.
There's also the COUNT_BIG function in Db2 which returns DECIMAL(31,0).

JDBC PreparedStatement, UNION Select and parameter passing

Ok, I know the answer is simple and I'm going to feel pretty dumb but...
Java JDK 1.7, Sybase JDBC driver
Code snipit:
String sql = "select <blah>
from <blah blah>
where date1 = ?
UNION
select <blah>
from <blah blah>
where date2 = ?";
Connection conn = ConnectionManager.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql);
logger.info("parmemeter count: " + stmt.getParameterMetaData().getParameterCount());
stmt.setDate(1, new java.sql.Date(date.getTime()));
stmt.setDate(2, new java.sql.Date(date.getTime()));
ResultSet rs = stmt.executeQuery();
while rs.next()) {
// the rest of the code
}
So why is the parmeter count only 1?
Running the program throws an error complaining: java.sql.SQLException: Invalid parameter index 2.
If I reduce the sql to either piece and reduce the setDate() to only 1 it works just fine.
The SQL with the UNION runs just fine in an interactive sql session (? filled in with a date of course)
I just ran into this problem, and this thread was very helpful. It's not the union clause that's throwing errors; it's the date that you're passing in. If you're using to_date () (unclear from your code snippet), you need to be passing a string in the query (instead of a date). Good luck!

How to use ampersand in JDBC?

In oracle we using select * from table_name where column_name=&value in similar way how to use ampersand in JDBC?
stmt = conn.createStatement();
String sql;
sql="select emp_name from employees"+" where emp_no=?";
ResultSet rs=stmt.executeQuery(sql);
while(rs.next()){
String emp_name=rs.getString("emp_name");
System.out.println(emp_name);
}
i wrote the above code but it is not working(showing error)
Did you read the article I provided the link to?
You use the question mark ? to point out places in your query where you want to specify a parameter, and you have to use PreparedStatement. I can't test it, but it should be something like this:
// some code to obtain the Connection object
PreparedStatement stmt = null;
String yourQuery = " SELECT emp_name FROM employees WHERE emp_no = ? ";
try {
stmt = conn.prepareStatement(yourQuery);
stmt.setLong(1, 252);
ResultSet rs = stmt.executeQuery();
while(rs.next()) {
String emp_name = rs.getString("emp_name");
System.out.println(emp_name);
}
} finally {
// close the stmt etc.
}
I'd suggest using a PreparedStatement - from memory it's something like
Connection conn = getConnection();
PreparedStatement pstmnt = conn.prepareStatement("Select * from employees where emp_no =?");
pstmnt.setLong(1,emp_no);
ResultSet rs = pstmnt.executeQuery();
but the link that #Przemyslaw Kruglej high light above will almost certainly have a good example ( I haven;t read it though ... )

Resources