Bug #99604 Add support to row alias on INSERT... ON DUPLICATE KEY UPDATE on batch mode
Submitted: 16 May 2020 19:04 Modified: 17 Nov 2022 18:06
Reporter: Alisson Oliveira Email Updates:
Status: Closed Impact on me:
None 
Category:Connector / J Severity:S3 (Non-critical)
Version:8.0.20 OS:Any
Assigned to: CPU Architecture:Any

[16 May 2020 19:04] Alisson Oliveira
Description:
The new row alias is being considered part of valuesClause on ParseInfo class. 

When executing an Insert with ON DUPLICATE KEY UPDATE in batch mode, the row alias is repeated alongside the values. The execution fails with:

Caused by: java.sql.BatchUpdateException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ',(32970,2,5,0) AS new ,(32970,3,2,0) AS new ,(32970,4,3,0) AS new ,(32970,5,1,0)' at line 1

How to repeat:
1. mysql-connector-java: 8.0.20

2. Table structure:

create table costumes
(
    owner_id  int unsigned  not null,
    id        smallint      not null,
    amount    smallint      default 0 not null,
    ready     tinyint(1)    default 0 not null,
);

2. Execution Code:

var collection = List.of(new int[]{ 32970,2,5,0 }, new int[]{ 32970,3,2,0 }, new int[]{ 32970,4,3,0 });

var sql = "INSERT INTO costumes (owner_id, id, amount, ready) VALUES (?, ?, ?, ?) AS new ON DUPLICATE KEY UPDATE amount = amount + new.amount";
var statement = con.prepareStatement(sql);

for (var obj : collection) {
   statment.setInt(1, obj[0]);
   statment.setInt(2, obj[1]);
   statment.setInt(3, obj[2]);
   statment.setInt(4, obj[3]);
   statement.addBatch();
}

statement.executeBatch();
[13 Jul 2020 11:13] MySQL Verification Team
Hello Alisson Oliveira,

Thank you for the report and test case.
Verified as described.

regards,
Umesh
[13 Jul 2020 11:15] MySQL Verification Team
-table structure
create table costumes
(
    owner_id  int unsigned  not null,
    id        smallint      not null,
    amount    smallint      default 0 not null,
    ready     tinyint(1)    default 0 not null, primary key(id)
);
- 
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;

public class Bug99604 {

        public static void main(String[] args) throws ClassNotFoundException, SQLException {
        
        Connection connection = DriverManager.getConnection("jdbc:mysql://localhost/test?user=root&password=mysql123!&serverTimezone=UTC&rewriteBatchedStatements=true");
        
        Runtime.Version version = Runtime.version();
        System.out.println("JDK version: " + version);
        DatabaseMetaData meta = connection.getMetaData();
        System.out.println("MySQL Server: " + meta.getDatabaseProductVersion());
        System.out.println("Driver Name & Ver: " + meta.getDriverName() + meta.getDriverVersion());

        try{
                var collection = List.of(new int[]{ 32970,2,5,0 }, new int[]{ 32970,3,2,0 }, new int[]{ 32970,4,3,0 });

                var sql = "INSERT INTO costumes (owner_id, id, amount, ready) VALUES (?, ?, ?, ?) AS T ON DUPLICATE KEY UPDATE costumes.amount = costumes.amount + T.amount";
                var statement = connection.prepareStatement(sql);

                for (var obj : collection) {
                   statement.setInt(1, obj[0]);
                   statement.setInt(2, obj[1]);
                   statement.setInt(3, obj[2]);
                   statement.setInt(4, obj[3]);
                   statement.addBatch();
                }
                System.out.println(statement);
                statement.executeBatch();        

        }catch(SQLException e){
			e.printStackTrace();
            }
        }    
}
--
ant -f C:\\Work\\MySQLJava\\Bug99604 -Dnb.internal.action.name=run run
init:
Deleting: C:\Work\MySQLJava\Bug99604\build\built-jar.properties
deps-jar:
Updating property file: C:\Work\MySQLJava\Bug99604\build\built-jar.properties
Compiling 1 source file to C:\Work\MySQLJava\Bug99604\build\classes
compile:
run:
JDK version: 11.0.3+12-LTS
MySQL Server: 8.0.20
Driver Name & Ver: MySQL Connector/Jmysql-connector-java-8.0.20 (Revision: afc0a13cd3c5a0bf57eaa809ee0ee6df1fd5ac9b)
com.mysql.cj.jdbc.ClientPreparedStatement: INSERT INTO costumes (owner_id, id, amount, ready) VALUES (32970, 4, 3, 0) AS T ON DUPLICATE KEY UPDATE costumes.amount = costumes.amount + T.amount
java.sql.BatchUpdateException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ',(32970, 3, 2, 0) AS T ,(32970, 4, 3, 0) AS T  ON DUPLICATE KEY UPDATE costumes.' at line 1
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
	at com.mysql.cj.util.Util.handleNewInstance(Util.java:192)
	at com.mysql.cj.util.Util.getInstance(Util.java:167)
	at com.mysql.cj.util.Util.getInstance(Util.java:174)
	at com.mysql.cj.jdbc.exceptions.SQLError.createBatchUpdateException(SQLError.java:224)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeBatchedInserts(ClientPreparedStatement.java:755)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeBatchInternal(ClientPreparedStatement.java:426)
	at com.mysql.cj.jdbc.StatementImpl.executeBatch(StatementImpl.java:796)
	at Bug99604.main(Bug99604.java:33)
Caused by: java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ',(32970, 3, 2, 0) AS T ,(32970, 4, 3, 0) AS T  ON DUPLICATE KEY UPDATE costumes.' at line 1
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:97)
	at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeInternal(ClientPreparedStatement.java:953)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1092)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeUpdateInternal(ClientPreparedStatement.java:1040)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeLargeUpdate(ClientPreparedStatement.java:1347)
	at com.mysql.cj.jdbc.ClientPreparedStatement.executeBatchedInserts(ClientPreparedStatement.java:716)
	... 3 more
BUILD SUCCESSFUL (total time: 2 seconds)
[19 Jul 2020 5:54] MySQL Verification Team
Bug #100252 marked as duplicate of this one
[17 Nov 2022 18:06] Filipe Silva
Fixed in MySQL Connector/J 8.0.29 after ParseInfo/QueryInfo under fix for Bug#106240.
[21 Dec 2022 18:05] Daniel So
Posted by developer:
 
Added the following entry to the Connector/J 8.0.32 changelog: 

"Insert statements with ON DUPLICATE KEY UPDATE that used value aliases caused a syntax error when the batched statements were being rewritten. It was because the value alias were being added repeatedly after each value group while only one alias was expected. This fix eliminates the undue repetitions."