question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Parameterized ON DUPLICATE KEY UPDATE in insert statement doesn't work on MySQL proxy

See original GitHub issue

Bug Report

Which version of ShardingSphere did you use?

5.0.0-RC1-SNAPSHOT

Which project did you use? ShardingSphere-JDBC or ShardingSphere-Proxy?

ShardingSphere-Proxy

Expected behavior

Sql could be executed correctly, just like MySQL 5.7 server.

Actual behavior

Exception thrown:

Exception in thread "main" java.sql.SQLException: Statement parameter 5 not set.
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:965)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:898)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:887)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:861)
	at com.mysql.jdbc.ServerPreparedStatement.serverExecute(ServerPreparedStatement.java:1174)
	at com.mysql.jdbc.ServerPreparedStatement.executeInternal(ServerPreparedStatement.java:787)
	at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2133)
	at com.mysql.jdbc.PreparedStatement.executeUpdateInternal(PreparedStatement.java:2067)
	at com.mysql.jdbc.PreparedStatement.executeLargeUpdate(PreparedStatement.java:5175)
	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2052)

Reason analyze (If you can)

mysql-connector-java-5.1.48
ServerPreparedStatement.java, serverPrepare(String sql)
                Buffer prepareResultPacket = mysql.sendCommand(MysqlDefs.COM_PREPARE, sql, null, false, characterEncoding, 0);

                if (this.connection.versionMeetsMinimum(4, 1, 1)) {
                    // 4.1.1 and newer use the first byte as an 'ok' or 'error' flag, so move the buffer pointer past it to start reading the statement id.
                    prepareResultPacket.setPosition(1);
                } else {
                    // 4.1.0 doesn't use the first byte as an 'ok' or 'error' flag
                    prepareResultPacket.setPosition(0);
                }

                this.serverStatementId = prepareResultPacket.readLong();
                this.fieldCount = prepareResultPacket.readInt();
                this.parameterCount = prepareResultPacket.readInt();
                this.parameterBindings = new BindValue[this.parameterCount];
this.parameterCount is 5, which is from proxy server side, but it's 4 in fact
org.apache.shardingsphere.proxy.frontend.mysql.command.query.binary.prepare.MySQLComStmtPrepareExecutor.java, execute()
        SQLStatement sqlStatement = schema.getRuntimeContext().getSqlParserEngine().parse(packet.getSql(), true);
        if (!MySQLComStmtPrepareChecker.isStatementAllowed(sqlStatement)) {
            result.add(new MySQLErrPacket(++currentSequenceId, MySQLServerErrorCode.ER_UNSUPPORTED_PS));
            return result;
        }
        int parametersCount = sqlStatement.getParameterCount();
parametersCount is 5 after parsing

Steps to reproduce the behavior, such as: SQL to execute, sharding rule configuration, when exception occur etc.

Run sql via jdbc:

jdbcUrl:
jdbc:mysql://127.0.0.1:3307/sharding_db?serverTimezone=UTC&useSSL=false&useServerPrepStmts=true&cachePrepStmts=true

try (PreparedStatement statement = connection.prepareStatement(
        "insert into t_order (order_id, user_id, status) values (?, ?, ?) ON DUPLICATE KEY UPDATE status = ?")) {
	statement.setInt(1, orderId);
	statement.setInt(2, userId);
	statement.setString(3, status);
	statement.setString(4, "DUPLICATED");
	statement.executeUpdate();
}

Example codes for reproduce this issue (such as a github link).

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (5 by maintainers)

github_iconTop GitHub Comments

2reactions
strongduanmucommented, Aug 20, 2020

@sandynz Thank you for the example, and I have reproduced this exception. The reason for this problem is that the value in the on duplicate key statement is parsed twice, therefore the parametersCount is greater than the actual value by 1.

@Override
public ASTNode visitOnDuplicateKeyClause(final OnDuplicateKeyClauseContext ctx) {
    Collection<AssignmentSegment> columns = new LinkedList<>();
    for (AssignmentContext each : ctx.assignment()) {
        columns.add((AssignmentSegment) visit(each));
        visit(each.assignmentValue());
    }
    return new OnDuplicateKeyColumnsSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), columns);
}

I will fix this problem as soon as possible.

0reactions
sandynzcommented, Jun 29, 2022

Hi @beitengda , looks it’s fixed on 5.0.0-alpha. If you’re sure there’s still a problem on 5.1.0, then welcome to submit a new issue.

Read more comments on GitHub >

github_iconTop Results From Across the Web

13.2.7.2 INSERT ... ON DUPLICATE KEY UPDATE Statement
With ON DUPLICATE KEY UPDATE , the affected-rows value per row is 1 if the row is inserted as a new row, 2...
Read more >
ON DUPLICATE KEY UPDATE Sub-Clause paramter dropped
It figures that, the args in update sub-clause loosed/dropped, even if the same arg is used at insert sub-clause. This usage without sharding ......
Read more >
On Duplicate Key Update same as insert - Stack Overflow
The UPDATE statement is given so that older fields can be updated to new value. If your older values are the same as...
Read more >
INSERT... ON DUPLICATE KEY UPDATE not working as I ...
The value that will not be repeated is set in the db in the indexes. Behind the sentence: ON DUPLICATE KEY UPDATE, here...
Read more >
Database Engine events and errors - SQL Server
ls' of the INSERT statement cannot be on either side of a (primary key, foreign key) relationship when the FROM clause contains a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found