From e2685b895d30d78897fcd3c07ceb2e72283703dc Mon Sep 17 00:00:00 2001 From: caohdgege <1170050364@qq.com> Date: Mon, 2 Nov 2020 13:55:25 +0800 Subject: [PATCH] bugfix: fix the exception when limit condition contains VariantRefExpr (#3246) --- .../rm/datasource/exec/DeleteExecutor.java | 4 +++- .../rm/datasource/exec/UpdateExecutor.java | 4 +++- .../io/seata/sqlparser/WhereRecognizer.java | 2 +- .../druid/mysql/BaseMySQLRecognizer.java | 23 +++++++++++++++---- .../druid/mysql/MySQLDeleteRecognizer.java | 4 ++-- .../druid/mysql/MySQLUpdateRecognizer.java | 4 ++-- .../druid/MySQLDeleteRecognizerTest.java | 13 ++++++++--- 7 files changed, 39 insertions(+), 15 deletions(-) diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/DeleteExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/DeleteExecutor.java index 4f67d1e40..e48e86589 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/DeleteExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/DeleteExecutor.java @@ -26,6 +26,7 @@ import io.seata.rm.datasource.ColumnUtils; import io.seata.rm.datasource.StatementProxy; import io.seata.rm.datasource.sql.struct.TableMeta; import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.sqlparser.ParametersHolder; import io.seata.sqlparser.SQLDeleteRecognizer; import io.seata.sqlparser.SQLRecognizer; @@ -70,7 +71,8 @@ public class DeleteExecutor<T, S extends Statement> extends AbstractDMLBaseExecu if (StringUtils.isNotBlank(orderBy)) { suffix.append(orderBy); } - String limit = visitor.getLimit(); + ParametersHolder parametersHolder = statementProxy instanceof ParametersHolder ? (ParametersHolder)statementProxy : null; + String limit = visitor.getLimit(parametersHolder, paramAppenderList); if (StringUtils.isNotBlank(limit)) { suffix.append(limit); } diff --git a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/UpdateExecutor.java b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/UpdateExecutor.java index b899aa74e..e2b39b3cf 100644 --- a/rm-datasource/src/main/java/io/seata/rm/datasource/exec/UpdateExecutor.java +++ b/rm-datasource/src/main/java/io/seata/rm/datasource/exec/UpdateExecutor.java @@ -34,6 +34,7 @@ import io.seata.rm.datasource.SqlGenerateUtils; import io.seata.rm.datasource.StatementProxy; import io.seata.rm.datasource.sql.struct.TableMeta; import io.seata.rm.datasource.sql.struct.TableRecords; +import io.seata.sqlparser.ParametersHolder; import io.seata.sqlparser.SQLRecognizer; import io.seata.sqlparser.SQLUpdateRecognizer; @@ -85,7 +86,8 @@ public class UpdateExecutor<T, S extends Statement> extends AbstractDMLBaseExecu if (StringUtils.isNotBlank(orderBy)) { suffix.append(orderBy); } - String limit = recognizer.getLimit(); + ParametersHolder parametersHolder = statementProxy instanceof ParametersHolder ? (ParametersHolder)statementProxy : null; + String limit = recognizer.getLimit(parametersHolder, paramAppenderList); if (StringUtils.isNotBlank(limit)) { suffix.append(limit); } diff --git a/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/WhereRecognizer.java b/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/WhereRecognizer.java index a010f644b..28f2b4db5 100644 --- a/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/WhereRecognizer.java +++ b/sqlparser/seata-sqlparser-core/src/main/java/io/seata/sqlparser/WhereRecognizer.java @@ -46,7 +46,7 @@ public interface WhereRecognizer extends SQLRecognizer { * * @return The limit SQL. */ - default String getLimit() { + default String getLimit(ParametersHolder parametersHolder, ArrayList<List<Object>> paramAppenderList) { return null; } diff --git a/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mysql/BaseMySQLRecognizer.java b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mysql/BaseMySQLRecognizer.java index 58ebe6cfa..43c94b7e7 100644 --- a/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mysql/BaseMySQLRecognizer.java +++ b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mysql/BaseMySQLRecognizer.java @@ -17,6 +17,7 @@ package io.seata.sqlparser.druid.mysql; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; import com.alibaba.druid.sql.ast.SQLExpr; @@ -96,7 +97,7 @@ public abstract class BaseMySQLRecognizer extends BaseRecognizer { return sb.toString(); } - protected String getLimit(SQLStatement sqlStatement, SQLType sqlType) { + protected String getLimit(SQLStatement sqlStatement, SQLType sqlType, ParametersHolder parametersHolder, ArrayList<List<Object>> paramAppenderList) { SQLLimit limit = null; if (SQLType.UPDATE == sqlType) { limit = ((MySqlUpdateStatement)sqlStatement).getLimit(); @@ -107,12 +108,24 @@ public abstract class BaseMySQLRecognizer extends BaseRecognizer { StringBuilder builder = new StringBuilder(" LIMIT "); SQLIntegerExpr expr; if (limit.getOffset() != null) { - expr = (SQLIntegerExpr)limit.getOffset(); - builder.append(expr.getNumber()).append(","); + if (limit.getOffset() instanceof SQLVariantRefExpr) { + builder.append("?,"); + Map<Integer, ArrayList<Object>> parameters = parametersHolder.getParameters(); + paramAppenderList.add(parameters.get(parameters.size() - 1)); + } else { + expr = (SQLIntegerExpr)limit.getOffset(); + builder.append(expr.getNumber()).append(","); + } } if (limit.getRowCount() != null) { - expr = (SQLIntegerExpr)limit.getRowCount(); - builder.append(expr.getNumber()); + if (limit.getRowCount() instanceof SQLVariantRefExpr) { + builder.append("?"); + Map<Integer, ArrayList<Object>> parameters = parametersHolder.getParameters(); + paramAppenderList.add(parameters.get(parameters.size())); + } else { + expr = (SQLIntegerExpr)limit.getRowCount(); + builder.append(expr.getNumber()); + } } return builder.toString(); } diff --git a/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mysql/MySQLDeleteRecognizer.java b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mysql/MySQLDeleteRecognizer.java index 62c3a099f..6dcf19870 100644 --- a/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mysql/MySQLDeleteRecognizer.java +++ b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mysql/MySQLDeleteRecognizer.java @@ -94,8 +94,8 @@ public class MySQLDeleteRecognizer extends BaseMySQLRecognizer implements SQLDel } @Override - public String getLimit() { - return super.getLimit(ast, getSQLType()); + public String getLimit(ParametersHolder parametersHolder, ArrayList<List<Object>> paramAppenderList) { + return super.getLimit(ast, getSQLType(), parametersHolder, paramAppenderList); } @Override diff --git a/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mysql/MySQLUpdateRecognizer.java b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mysql/MySQLUpdateRecognizer.java index 6eac619a7..5f01571da 100644 --- a/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mysql/MySQLUpdateRecognizer.java +++ b/sqlparser/seata-sqlparser-druid/src/main/java/io/seata/sqlparser/druid/mysql/MySQLUpdateRecognizer.java @@ -132,8 +132,8 @@ public class MySQLUpdateRecognizer extends BaseMySQLRecognizer implements SQLUpd } @Override - public String getLimit() { - return super.getLimit(ast, getSQLType()); + public String getLimit(ParametersHolder parametersHolder, ArrayList<List<Object>> paramAppenderList) { + return super.getLimit(ast, getSQLType(), parametersHolder, paramAppenderList); } @Override diff --git a/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MySQLDeleteRecognizerTest.java b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MySQLDeleteRecognizerTest.java index f5bbb3783..dc19801b9 100644 --- a/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MySQLDeleteRecognizerTest.java +++ b/sqlparser/seata-sqlparser-druid/src/test/java/io/seata/sqlparser/druid/MySQLDeleteRecognizerTest.java @@ -49,10 +49,17 @@ public class MySQLDeleteRecognizerTest extends AbstractRecognizerTest { */ @Test public void deleteRecognizerTest_0() { + ParametersHolder parametersHolder = new ParametersHolder() { + @Override + public Map<Integer,ArrayList<Object>> getParameters() { + return Collections.EMPTY_MAP; + } + }; String sql = "DELETE FROM t1 WHERE id = 'id1' order by id asc,name desc limit 1,2"; SQLStatement statement = getSQLStatement(sql); + ArrayList<List<Object>> paramAppenderList = new ArrayList<>(); MySQLDeleteRecognizer mySQLDeleteRecognizer = new MySQLDeleteRecognizer(sql, statement); String orderBy = mySQLDeleteRecognizer.getOrderBy(); @@ -60,18 +67,18 @@ public class MySQLDeleteRecognizerTest extends AbstractRecognizerTest { Assertions.assertEquals(sql, mySQLDeleteRecognizer.getOriginalSQL()); Assertions.assertEquals("t1", mySQLDeleteRecognizer.getTableName()); Assertions.assertEquals("id = 'id1'", mySQLDeleteRecognizer.getWhereCondition()); - String limit = mySQLDeleteRecognizer.getLimit(); + String limit = mySQLDeleteRecognizer.getLimit(parametersHolder, paramAppenderList); Assertions.assertEquals(" LIMIT 1,2", limit); sql = "DELETE FROM t1 WHERE id > 1 order by id ,name desc limit 1"; statement = getSQLStatement(sql); mySQLDeleteRecognizer = new MySQLDeleteRecognizer(sql, statement); orderBy = mySQLDeleteRecognizer.getOrderBy(); Assertions.assertTrue(orderBy.equalsIgnoreCase(" order by id,name desc")); - Assertions.assertEquals(" LIMIT 1", mySQLDeleteRecognizer.getLimit()); + Assertions.assertEquals(" LIMIT 1", mySQLDeleteRecognizer.getLimit(parametersHolder, paramAppenderList)); sql = "DELETE FROM t1 WHERE id > 1"; statement = getSQLStatement(sql); mySQLDeleteRecognizer = new MySQLDeleteRecognizer(sql, statement); - Assertions.assertEquals(null, mySQLDeleteRecognizer.getLimit()); + Assertions.assertEquals(null, mySQLDeleteRecognizer.getLimit(parametersHolder, paramAppenderList)); orderBy = mySQLDeleteRecognizer.getOrderBy(); Assertions.assertEquals(null, mySQLDeleteRecognizer.getOrderBy()); -- GitLab