Bug #93606 | when use Connector/J preparestatement mysql returns the wrong result | ||
---|---|---|---|
Submitted: | 14 Dec 2018 7:53 | Modified: | 10 Jan 2019 6:54 |
Reporter: | huiping wu | Email Updates: | |
Status: | Verified | Impact on me: | |
Category: | MySQL Server: Optimizer | Severity: | S2 (Serious) |
Version: | 5.6.40,5.7.24 | OS: | CentOS (6.9) |
Assigned to: | CPU Architecture: | x86 | |
Tags: | prepared statement |
[14 Dec 2018 7:53]
huiping wu
[14 Dec 2018 8:02]
huiping wu
HI: Already uploaded to java program to sftp:sftp.oracle.com:/support/incoming/mysql-bug-data-93606.tar.gz
[9 Jan 2019 12:15]
MySQL Verification Team
Hello huiping wu, Thank you for the report and test case. Verified as described with provided jar. Could you please confirm exact C/J version used in your environment? Thank you. regards, Umesh
[10 Jan 2019 6:54]
huiping wu
hello Umesh Shastry! The C/J version used in the environment is mysql-connector-java-5.1.47.jar. thanks.
[23 Nov 2021 15:27]
Alexander Soklakov
Hi huiping wu, This is definitely not a Connector/J bug. The case you reproduce with useServerPrepStmts=true and cachePrepStmts=true just reflects the situation when the real (not the emulated one) prepared statement is prepared on the server side, it is executed several times and the date switch happens between the executions. The test could be simplified a bit: @Test public void testBug93606() throws Exception { createTable("testBug93606", "(" // + "`time` varchar(10) DEFAULT NULL" // + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); this.stmt.executeUpdate("insert into testBug93606 set time=DATE_FORMAT(DATE_ADD(NOW(), INTERVAL - 1 DAY),'%Y-%m-%d')"); Properties props = new Properties(); props.setProperty(PropertyKey.sslMode.getKeyName(), SslMode.DISABLED.name()); props.setProperty(PropertyKey.allowPublicKeyRetrieval.getKeyName(), "true"); props.setProperty(PropertyKey.useServerPrepStmts.getKeyName(), "true"); Connection con = getConnectionWithProps(props); this.pstmt = con.prepareStatement("SELECT " // + "IF(time=DATE_FORMAT(DATE_ADD(NOW(), INTERVAL - 1 DAY),'%Y-%m-%d'),1,0) isContinuity1," // + "IF(time=DATE_FORMAT(DATE_ADD(sysdate(), INTERVAL - 1 DAY),'%Y-%m-%d'),1,0) isContinuity2," // + "DATE_FORMAT(DATE_ADD(NOW(), INTERVAL - 1 DAY),'%Y-%m-%d') as yesterday," // + "DATE_ADD(NOW(), INTERVAL - 1 DAY) yesterdatetime," // + "NOW() as now, sysdate() as sysdate FROM testBug93606"); this.pstmt.execute(); this.rs = this.pstmt.getResultSet(); this.rs.next(); System.out.println("isContinuity with now() = " + this.rs.getString(1)); System.out.println("isContinuity with sysdate() = " + this.rs.getString(2)); System.out.println("yesterday = " + this.rs.getString(3)); System.out.println("yesterdatetime = " + this.rs.getString(4)); System.out.println("now = " + this.rs.getString(5)); System.out.println("sysdate = " + this.rs.getString(6)); System.out.println(); Thread.sleep(15000); // switch server date manually during this sleep this.pstmt.execute(); this.rs = this.pstmt.getResultSet(); this.rs.next(); System.out.println("isContinuity with now() = " + this.rs.getString(1)); System.out.println("isContinuity with sysdate() = " + this.rs.getString(2)); System.out.println("yesterday = " + this.rs.getString(3)); System.out.println("yesterdatetime = " + this.rs.getString(4)); System.out.println("now = " + this.rs.getString(5)); System.out.println("sysdate = " + this.rs.getString(6)); con.close(); } And the output is: === Connected to 5.6.46-log isContinuity with now() = 1 isContinuity with sysdate() = 1 yesterday = 2021-11-22 yesterdatetime = 2021-11-22 18:25:07 now = 2021-11-23 18:25:07 sysdate = 2021-11-23 18:25:07 isContinuity with now() = 1 isContinuity with sysdate() = 0 yesterday = 2021-11-23 yesterdatetime = 2021-11-23 18:25:10 now = 2021-11-24 18:25:10 sysdate = 2021-11-24 18:25:10 === For me it looks like a side effect of the behaviour described here https://dev.mysql.com/doc/refman/8.0/en/date-and-time-functions.html#function_now : "NOW() returns a constant time that indicates the time at which the statement began to execute. (Within a stored function or trigger, NOW() returns the time at which the function or triggering statement began to execute.) This differs from the behavior for SYSDATE(), which returns the exact time at which it executes." I.e., it seems that the NOW() value nested into IF() is calculated only once during the PREPARE step or on the first execution. Since it is inconsistent with other NOW() results on the same query then it could be a bug in parser but I can't say for sure. Let's reassign this bug to the server team to know their opinion. BTW, MySQL 8.0 is not affected: === Connected to 8.0.26 isContinuity with now() = 1 isContinuity with sysdate() = 1 yesterday = 2021-11-22 yesterdatetime = 2021-11-22 18:56:36 now = 2021-11-23 18:56:36 sysdate = 2021-11-23 18:56:36 isContinuity with now() = 0 isContinuity with sysdate() = 0 yesterday = 2021-11-23 yesterdatetime = 2021-11-23 18:56:12 now = 2021-11-24 18:56:12 sysdate = 2021-11-24 18:56:12 === Thanks, Alex