How is SQL Server's timestamp2 supposed to work in JDBC? - java

I'm having some trouble trying to use timestamp2 instead of Timestamp in SQL Server 2008. Apparently, rs.getTimestamp has very different behavior between timestamp and timestamp2. However, I can't find any documentation stating that there should be a difference, or that I should be using something different. I wonder whether I'm just doing something wrong.
Environment:
Tried on both SQL Express 2008 (10.0) and SQL Server 2008 R2 (10.5).
sqljdbc4.jar version 3.0, size of 537,303 bytes, CRC-32=a0aa1e25, MD5=402130141d5f2cee727f4371e2e8fd8a.
Java 1.6
Here is a unit test demonstrating the problem. The only "magic" is the "Db.getConnection()", which you can replace with appropriate code. The test is the same for both datetime and datetime2, but the datetime2 test fails with a date that is 2 days prior. I treat all times in the DB as GMT/UTC, and I haven't attempted to add timezone information into the database data for datetime2 data.
private void testTimestamp(TimeZone gmtTz, Connection conn, String query,
Calendar expectedCal) throws SQLException
{
PreparedStatement stmt = conn.prepareStatement(query);
ResultSet rs = stmt.executeQuery();
while (rs.next())
{
// Note the expectedCal has a GMT timezone.
Date actualTs = rs.getTimestamp("dt", expectedCal);
// Just print out the time difference
long diff = actualTs.getTime() - expectedCal.getTimeInMillis();
System.out.println("Diff=" + diff);
// Do the test to make sure they are the same
// In practice, this succeeds for datetime and fails for datetime2
Assert.assertEquals(expectedCal.getTimeInMillis(), actualTs.getTime());
}
}
#Test
public void testDateTime() throws SQLException
{
Connection conn = Db.getConnection();
TimeZone gmtTz = TimeZone.getTimeZone("GMT");
String query;
Calendar expectedCal = Calendar.getInstance(gmtTz);
expectedCal.clear();
expectedCal.set(2011, 10, 02, 11, 17);
query = "select CAST('2011-11-02 11:17:00' as datetime) as dt";
testTimestamp(gmtTz, conn, query, expectedCal);
query = "select CAST('2011-11-02 11:17:00.0000000' as datetime2) as dt";
testTimestamp(gmtTz, conn, query, expectedCal); // results in an error
}
Is my only option switching back to timestamp?
EDIT: For future Googlers, using sqljdbc4.jar version 3.0, the test fails on Linux, but passes on Windows.
I have not yet tried sqljdbc4.jar version 4.0 that comes with SQL Server 2012.

If you are using Sun JRE 1.7 with the Microsoft JDBC 3.0 driver see this blog post http://blogs.msdn.com/b/jdbcteam/archive/2012/01/20/hotfix-available-for-date-issue-when-using-jre-1-7.aspx.
If you feel you have discovered a bug in our driver you can report it via Microsoft Connect.
https://connect.microsoft.com/SQLServer

I remember not hearing good things about the official SQL Server driver and JTDS being preferred (though I can't seem to be finding that link). I would personally go with JTDS (with rigorous testing of course) or move back to the version which doesn't cause an issue. I haven't worked with SQL Server but from the looks of, it seems that datetime2 is the preferred data type so I'd rather not revert back. Option (d) isn't really a good option IMO. :)

Related

ou was not a ResultSet - MS SQL Driver issue with 6.x version and Hibernate

I'm using Hibernate 5.0.10, Java 7 and Microsoft JDBC Driver 4.1 for SQL Server version 4.1.8112.100.
After changing to Microsoft SQL Server JDBC driver 6.4, I'm getting this error:
Current CallableStatement ou was not a ResultSet, but getResultList was called
It fails on the last line on getResultSet
public List<DocListResultExt> getDocuments(DocList doc) {
StoredProcedureQuery query = entityManagerFactory
.createEntityManager()
.createNamedStoredProcedureQuery("getDocList");
query.setParameter(....);
List<Sp_get_doc_list> spList = (List<Sp_get_doc_list>)query.getResultList();
Any idea why it suddenly seems not compatible with the current code?
Thanks #Mark Rotteveel seem adding SET NOCOUNT ONresolved the issue. Kind of doesn't explain why the driver would handle this differently, but that's ok.

Query with NOW() in criteria behaves differently in psql vs. JDBC

I am executing following query in psql via console and getting output :
select details
from history_transactions
,history_operations
where history_operations.transaction_id = history_transactions.id
and type = 3
and created_at >= NOW() - INTERVAL '5 minutes'
However when I call this code from my java program, it is not returning any output. The ResultSet is null. PFB my code:
Connection conn = getConnection();
java.sql.Statement stmt = null;
String sql ="select details from history_transactions , history_operations where history_operations.transaction_id=history_transactions.id and type =3 and created_at >= NOW() - INTERVAL '5 minutes'";
try{
stmt = conn.createStatement();
rs = stmt.executeQuery(sql);
while(rs.next()) {
System.out.println("Inside resultset");
}
}
catch(Exception e)
{
e.printStackTrace();
}
Any idea where I am going wrong?
I am not getting any exception as well.
Note: If I change the interval from 5 minute to 6 hours or more it is working and giving me output. If I change the interval < 5 hours then the resultset is null. However If I login to psql server and execute the query as it is in the code. I am getting output.
I am using java version "1.8.0_151" and PostgreSQL JDBC 4.2 Driver, 42.2.1 - as per https://jdbc.postgresql.org/download.html - it is the suitable driver.
The PostgreSQL NOW() function returns a timestamp with time zone value. In order to use that value against a column of type timestamp (without time zone) PostgreSQL needs to implicitly CAST that value to match the column type. However, testing shows that if the client and the server are set to different time zones the result of that CAST can be different when connected via psql vs. when connected via JDBC. For example:
Server time zone: UTC
Client time zone: America/Denver, a.k.a. "MST/MDT", currently UTC-7
When connected via psql,
SELECT CAST(CAST(NOW() AS timestamp) AS varchar)
returns the UTC value
2018-02-05 22:40:25.012933
but when connected via JDBC the same query returns the MST value
2018-02-05 15:40:57.288587
To return the UTC value under JDBC we can execute
set time zone 'UTC'
before running our SELECT query.

Query time column from postgresql using jdbc

I'm using PostgreSQL 8.4, and the server is linux, and the linux's time zone is'EDT' not 'UTC'. The configuration of PostgreSQL make the DataBase's time zone to 'UTC'. The code is running on JBoss9.
I have one sql, select to_char(ts_entry.submitted_date, 'MM/DD/YYYY HH24:MM') as submitted_date_format from ts_entry where ....
If we run the sql in PostgreSQL, we will get the value, "07/10/2017 02:07"
But when I try to get the value from resultSet in java,
Statement st = connection.createStatement();
ResultSet rs = st.executeQuery(sql);
String value = rs.getString("submitted_date_format");
The value will be "07/09/2017 22:07".
The origin value in DB is "2017-07-10 02:02:25.268+00".
How can I handle the effect caused by linux server's timezone in code level?
BTW, I know an alternative solution, change the start up scripts of jboss, to make the jboss to start up using timezone 'UTC'. Can this issue be handled in code level?
The Database server machine's time zone has no direct impact on the behaviour, except that it is used to initialize timezone in postgresql.conf, which is the initial setting for the client time zone unless overridden by the database session.
PostgreSQL stores timestamp with time zone in UTC internally and converts it to the client's local time zone upon delivery.
So you should set the database session time zone the way you need with
SET TIME ZONE '<time zone name>';
That will convert dates to that time zone when you select then from PostgreSQL.

MySQL query request from WorkBench client takes much less time than JDBC .executeQuery

I am using this code:
double timeBefore = System.currentTimeMillis();
ResultSet rs = st.executeQuery(sql);
double timeAfter = System.currentTimeMillis();
System.out.println(timeAfter - timeBefore);
The return is 9904.0
While when I do the exact same query from WorkBench MySQL client:
SELECT DISTINCT completeAddress FROM DB_M3_Medium.AvailableAddressesV2 where postNr = 2300 ORDER BY completeAddress ASC;
it takes 0.285s
How is that possible?
PS: I tried it with different payload sizes and it's always approx. 10s with Java JDBC
EDIT:
I tried PreparedStatement with the same query as above and it took the same time, approx. 1s less.
I have also tried pinging with following code:
String query = "/* ping */ SELECT 1";
double timeBefore = System.currentTimeMillis();
PreparedStatement preparedStatement = DBConnect.getInstance().con.prepareStatement(query);
ResultSet rs = preparedStatement.executeQuery(query);
double timeAfter = System.currentTimeMillis();
System.out.println(timeAfter - timeBefore);
And the response was: 1306.0 which is not perfect, but better.
But I am still not getting what is wrong with it.
EDIT2:
I have figured out that the time that it takes is related to the amount of data in the DB (not the payload that I am retrieving). It appears to me like indexing didn't work. But why would I then have the issue only when I go with JDBC but not with WorkBench.
while you code in java, you are creating connection,then passing the query. That query is compiled(as you are using Statement) in the sql server and then you will get the result. This whole process needs some time.But when you execute direclty in workbench you are neither creating connection nor compiling,you are simply running the sql.Hence the time taken is less
As #SpringLearner suggested in JDBC every time you execute a query and made a new connection and cost some time. You can use a Data Source to avoid this overhead and better performance.
One thing to bear in mind is that the JDBC driver is pure Java, so you are probably running into some early JIT compilation that would not apply with the MySQL workbench. After the JDBC driver code has been through the JIT, you will probably see comparable performance. The real test for you would be put that code few more times after that and see what happens.
You can also use a PreparedStatement and see if that helps since that should be the API most comparable to what the MySQL workbench is using to avoid unnecessary recompilation of the query.

INSERT failed because the following SET options have incorrect settings: 'ARITHABORT'

I have read the topics in Stackoverflow about this problem, but I really haven't a solution yet.
My problem is sending a String or Clob as an XML parameter in a Stored Procedure in SQL Server 2008. I'm using jTDS to connect it. I've read that I have to set the "ARITHABORT" to ON, but I really don't know where I can do it.
Maybe in my own session in JAVA or in DB too... Please help!! (And sorry for my very very bad english)
Ok! Here is the method that is giving me the error:
private static final String PR_SV_MUDA_STATUS_EVENTO_CONCLUIDO = "{CALL PR_SV_MUDA_STATUS_EVENTO_CONCLUIDO(?, ?, ?, ?)}";
public String modificaStatus(Connection connection, Integer eventoRobo, String path) throws SQLException {
Connection conn = null;
conn = GenericHibernateDAO.criaConexao();
CallableStatement cs2 = conn.prepareCall(PR_SV_MUDA_STATUS_EVENTO_CONCLUIDO);
cs2.setInt(1, eventoRobo);
cs2.setString(2, null);
cs2.setString(3, null);
cs2.setString(4, path);
cs2.execute();
conn.close();
return null;
}
I believe this is the query
SET ARITHABORT ON;
This needs to be run before your stored procedure. Either you can run it soon after getting the connection.
Once the processing is done, you may want to run the query below.
SET ARITHABORT OFF;
These queries can be run using additional statements in your java program.
I ran into this problem today and got it solved. I created a filtered index on a column in sql server 2008 r2, but would get this error when inserting. Saw this question wasn't completely answered since it might be tedious to always turn arithabort on in every insert. I found a blog that showed it was the database compatibility level that was the issue. Changed the compatibility level from 80 (2000) to 100 (2008) and the issue was solved. not sure if changing the compatibility level to 90 would solve this or not, but worth a try.
SQL Server compatibility levels and command to change here. http://msdn.microsoft.com/en-us/library/bb510680.aspx
If this doesn't work or you can't change the compatibility mode there is another workaround by adding a trigger in the blog I was talking about here http://chrismay.org/2013/05/23/interesting-problem-with-sql-server-arithabort-filtered-indexes-calculated-columns-and-compatibility-mode-of-80/
Note that this change was done on a test database, and all applications should be tested before making a change like this in production. Make sure this is ok with your DBA before changing too.

Categories

Resources