[CONJ-416] IllegalArgumentException with getTimestamp Created: 2017-01-26  Updated: 2019-09-13  Resolved: 2019-09-13

Status: Closed
Project: MariaDB Connector/J
Component/s: Other
Affects Version/s: 1.5.7
Fix Version/s: N/A

Type: Bug Priority: Major
Reporter: Robin K Assignee: Diego Dupin
Resolution: Cannot Reproduce Votes: 0
Labels: None
Environment:

Ubuntu 16.04, Mac OSX



 Description   

We are experiencing an Issue when using the following Setup (on multiple machines):

  • Apache Tomcat-Server (7 or 8)
  • Jersey Web-Application (2.13)
  • Spring-JDBC (4.3.5.RELEASE)
  • MariaDB ConnectorJ 1.5.7
  • MariaDB 10.0.29 or MySQL 5.6.33

When reading timestamps from a result set (MariaSelectResultSet) via MariaSelectResultSet.getTimestamp, we are receiving the following exception:

java.lang.IllegalArgumentException: nanos > 999999999 or < 0
	at java.sql.Timestamp.setNanos(Timestamp.java:389)
	at org.mariadb.jdbc.internal.queryresults.resultset.MariaSelectResultSet.binaryTimestamp(MariaSelectResultSet.java:3533)
	at org.mariadb.jdbc.internal.queryresults.resultset.MariaSelectResultSet.getTimestamp(MariaSelectResultSet.java:1676)
	at org.mariadb.jdbc.internal.queryresults.resultset.MariaSelectResultSet.getTimestamp(MariaSelectResultSet.java:1606)
	at org.mariadb.jdbc.internal.queryresults.resultset.MariaSelectResultSet.getTimestamp(MariaSelectResultSet.java:1579)

However, the exception seems to ONLY appear if we include a WHERE clause in the SQL statement. Reading the (very) same timestamps without WHERE leads to no errors. Also, I cannot see any difference between the timestamps when printing the values with getObject or getString instead of getTimestamp. Receiving the timestamps with getString and parsing them to a java.sql.Timestamps after works without issues. The timestamps are stored with the type timestamp(2).

The same code works with an MySQL driver without any issues (the initial reason for us to use the MariaDB driver was that we wanted to support milliseconds, which could not be inserted into MariaDB with the MySQL driver).



 Comments   
Comment by Diego Dupin [ 2017-01-26 ]

Hi Robin.

I don't see any weird things in code. I'll have to dig how that can occur.
This part of code is used only when using binary protocol format. MySQL driver doesn't use this by default, only when option "useServerPrepStmts=true" is set in connection string.

If you have the possibility, could you :

  • use MySQL driver with option useServerPrepStmts=true (and see of same error occur)
  • send results of hexdump(rs.getBytes(_column_index)) to check hexadecimal results with the following method :

 
    private static final char[] hexArray = "0123456789ABCDEF".toCharArray();
 
    public static String hexdump(byte[] bytes) {
        int dataLength = bytes.length;
        if (dataLength <= 0) return "";
 
        char[] hexChars = new char[ dataLength * 2];
        for ( int j = 0; j < dataLength; j++ ) {
            int byteValue = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[byteValue >>> 4];
            hexChars[j * 2 + 1] = hexArray[byteValue & 0x0F];
        }
        return new String(hexChars);
    }

thanks

Comment by Robin K [ 2017-01-26 ]

Hi Diego,

thanks for your reply.

  • using MySQL driver with the 'useServerPrepStmts=true' option first led to some weird ArrayIndexOutOfBoundsExceptions that magically disappeared after the second restart
  • using your hexDump function seems to give the same results for both the working and failing getTimestamp call

323031362D30352D30392031333A34303A35312E3031 (failing timestamp)
323031362D30352D30392031333A34303A35312E3031 (working timestamp)

Edit:
just some more notes that may be useful:

  • I tested the above on my local machine (MacOS) with MySQL
  • the database connection is handled via a connection pool in the Tomcat container resources and accessed via JNDI
  • the timestamp that leads to the error is received via a GREATEST () statement (including multiple COALESCEs: GREATEST (COALESCE(m_slc.lastchange, 0), ...))
Comment by Diego Dupin [ 2017-01-26 ]

the hexadecimal value "323031362D30352D30392031333A34303A35312E3031" correspond to "2016-05-09 13:40:51.01" string in hexadecimal. (so, driver is using text format). In binary format, same date would have been "E00705090D283310270000".
Have you reproduced an issue with text format too ? or it's just misconfiguration (using useServerPrepStmts=false then) ?

if you reproduced the error with mysql too, there must be an error server side, not driver side.

>the timestamp that leads to the error is received via a GREATEST () statement (including multiple COALESCEs: GREATEST (COALESCE(m_slc.lastchange, 0), ...))

I'll try to reproduced it with those functions

Comment by Robin K [ 2017-01-26 ]

>Have you reproduced an issue with text format too ? or it's just misconfiguration (using useServerPrepStmts=false then) ?

using 'useServerPrepStmts=false' indeed seems to have fixed the issue, thanks!

So is this a misbehavior of the driver or intended and the issue is a wrong configuration on our side? Can you explain how exactly that is the case? My understanding from reading the docs is that the option is used to increase performance: "Queries are prepared on the server side before executing, permitting faster execution next time."

Comment by Diego Dupin [ 2017-01-26 ]

sorry, i wasn't clear.
Driver communicate with server in 2 differents format :

  • Text protocol when using useServerPrepStmts=false (default MySQL driver configuration)
  • Binary protocol when using useServerPrepStmts=true (default MariaDB driver configuration)

When using option useServerPrepStmts=true, first execution of a command, a PREPARE command will be executed. So first command will be slower. but then, PREPARE results stay in cache, and other command will be faster. Other improvement, is that data exchange on network level are smaller :
For your example, a date "2016-05-09 13:40:51.01" in text protocol will be send using string value "2016-05-09 13:40:51.01" (=in hexadecimal 32 30 31 36 2D 30 35 2D 30 39 20 31 33 3A 34 30 3A 35 31 2E 30 31) 22 bytes. In binary format, that will be encoded in less than that (=E0 07 05 09 0D 28 33 10 27 00 00) 11 bytes.

This issue (seen because of stacktrace) concern only binary protocol.
So yes, using useServerPrepStmts=false can solve your problem, but not the issue.
And i wonder if server really send the text protocol value or if it was a configuration error.

Server might have send text protocol result !? Server doesn't have any issue of that kind actually, but the hexadecimal value "323031362D30352D30392031333A34303A35312E3031" would create exactly that kind of problem. (nanosecond value would be > 999999999)

Since you seem to reproduce the problem, can you send a SQL command that create this issue ?

Comment by Robin K [ 2017-01-27 ]

Unfortunately, the SQL-Query is quite large and I was not able to reproduce the error with a minimal example just yet. It includes the timestamp generated with GREATEST(COALESCE(...), ...) and multiple GROUP_CONCATs.

My next guess was that it had something to do with the GROUP_CONCATs, which are indeed using timestamps in text format that are later parsed to a sql.Timestamp object. I could not reproduce this though. Is there a possibility that this is related?

I will try to find out at which point it breaks when I find time.

Comment by Diego Dupin [ 2019-09-13 ]

Closing since not reproduced. Feel free to create another issue link to this one if this occurs.

Generated at Thu Feb 08 03:15:30 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.