Skip to content

Commit

Permalink
bugfix: mysql insert on update duplicate sensitive case not matched (a…
Browse files Browse the repository at this point in the history
  • Loading branch information
funky-eyes committed Sep 6, 2022
1 parent b5ddb71 commit de7d04f
Show file tree
Hide file tree
Showing 6 changed files with 31 additions and 21 deletions.
2 changes: 2 additions & 0 deletions changes/en-us/develop.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ Add changes here for all PR submitted to the develop branch.
- [[#4817](https://github.com/seata/seata/pull/4817)] fix in high version springboot property not Standard
- [[#4838](https://github.com/seata/seata/pull/4838)] fix when use Statement.executeBatch() can not generate undo log
- [[#4779](https://github.com/seata/seata/pull/4779)] fix and support Apache Dubbo 3
- [[#4912](https://github.com/seata/seata/pull/4912)] fix mysql InsertOnDuplicateUpdate column case is different and cannot be matched
- [[#4543](https://github.com/seata/seata/pull/4543)] fix support Oracle nclob types


### optimize:
- [[#4774](https://github.com/seata/seata/pull/4774)] optimize mysql8 dependencies for seataio/seata-server image
- [[#4790](https://github.com/seata/seata/pull/4790)] Add a github action to publish Seata to OSSRH
Expand Down
1 change: 1 addition & 0 deletions changes/zh-cn/develop.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
- [[#4817](https://github.com/seata/seata/pull/4817)] 修复高版本springboot配置不标准的问题
- [[#4838](https://github.com/seata/seata/pull/4838)] 修复使用 Statement.executeBatch() 时无法生成undo log 的问题
- [[#4779](https://github.com/seata/seata/pull/4779)] 修复支持 Apache Dubbo 3 版本
- [[#4912](https://github.com/seata/seata/pull/4912)] 修复mysql InsertOnDuplicateUpdate 列名大小写不一致无法正确匹配
- [[#4543](https://github.com/seata/seata/pull/4543)] 修复对 Oracle 数据类型nclob的支持

### optimize:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
*/
package io.seata.common.util;

import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.Collection;
import java.util.Objects;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;

public class LowerCaseLinkHashMap<V> implements Map<String, V> {

Expand Down Expand Up @@ -110,7 +110,7 @@ public void clear() {

@Override
public Set<String> keySet() {
return lowerKeyToOriginMap.values().stream().collect(Collectors.toSet());
return new HashSet<>(lowerKeyToOriginMap.values());
}

@Override
Expand Down Expand Up @@ -204,4 +204,10 @@ public boolean equals(Object o) {
public int hashCode() {
return Objects.hash(targetMap);
}

@Override
public String toString() {
return targetMap.toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import io.seata.core.context.RootContext;
import io.seata.core.model.BranchType;
import io.seata.rm.datasource.StatementProxy;
import io.seata.rm.datasource.exec.mysql.MySQLInsertOrUpdateExecutor;
import io.seata.rm.datasource.exec.mysql.MySQLInsertOnDuplicateUpdateExecutor;
import io.seata.rm.datasource.sql.SQLVisitorFactory;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.util.JdbcConstants;
Expand Down Expand Up @@ -107,7 +107,7 @@ public static <T, S extends Statement> T execute(List<SQLRecognizer> sqlRecogniz
case JdbcConstants.MYSQL:
case JdbcConstants.MARIADB:
executor =
new MySQLInsertOrUpdateExecutor(statementProxy, statementCallback, sqlRecognizer);
new MySQLInsertOnDuplicateUpdateExecutor(statementProxy, statementCallback, sqlRecognizer);
break;
default:
throw new NotSupportYetException(dbType + " not support to INSERT_ON_DUPLICATE_UPDATE");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@
import java.util.Collections;
import java.util.StringJoiner;


import com.google.common.base.Joiner;
import io.seata.common.exception.NotSupportYetException;
import io.seata.common.exception.ShouldNeverHappenException;
import io.seata.common.loader.LoadLevel;
import io.seata.common.loader.Scope;
import io.seata.common.util.CollectionUtils;
import io.seata.common.util.IOUtil;
import io.seata.common.util.LowerCaseLinkHashMap;
import io.seata.common.util.StringUtils;
import io.seata.rm.datasource.ConnectionProxy;
import io.seata.rm.datasource.PreparedStatementProxy;
Expand All @@ -52,10 +52,10 @@
import io.seata.sqlparser.util.JdbcConstants;

/**
* @author: yangyicong
* @author yangyicong
*/
@LoadLevel(name = JdbcConstants.MYSQL, scope = Scope.PROTOTYPE)
public class MySQLInsertOrUpdateExecutor extends MySQLInsertExecutor implements Defaultable {
public class MySQLInsertOnDuplicateUpdateExecutor extends MySQLInsertExecutor implements Defaultable {


private static final String COLUMN_SEPARATOR = "|";
Expand Down Expand Up @@ -83,7 +83,7 @@ public ArrayList<List<Object>> getParamAppenderList() {
*/
private ArrayList<List<Object>> paramAppenderList;

public MySQLInsertOrUpdateExecutor(StatementProxy statementProxy, StatementCallback statementCallback, SQLRecognizer sqlRecognizer) {
public MySQLInsertOnDuplicateUpdateExecutor(StatementProxy statementProxy, StatementCallback statementCallback, SQLRecognizer sqlRecognizer) {
super(statementProxy, statementCallback, sqlRecognizer);
}

Expand Down Expand Up @@ -255,7 +255,8 @@ public TableRecords beforeImage() throws SQLException {
*/
public TableRecords buildTableRecords2(TableMeta tableMeta, String selectSQL, ArrayList<List<Object>> paramAppenderList, List<Object> primaryKeys) throws SQLException {
ResultSet rs = null;
try (PreparedStatement ps = statementProxy.getConnection().prepareStatement(selectSQL + " FOR UPDATE")) {
try (PreparedStatement ps = statementProxy.getConnection()
.prepareStatement(primaryKeys.isEmpty() ? selectSQL + " FOR UPDATE" : selectSQL)) {
int ts = CollectionUtils.isEmpty(paramAppenderList) ? 0 : paramAppenderList.size();
int ds = ts == 0 ? 0 : paramAppenderList.get(0).size();
for (int i = 0; i < ts; i++) {
Expand Down Expand Up @@ -300,12 +301,13 @@ public String buildImageSQL(TableMeta tableMeta) {
List<String> uniqueList = new ArrayList<>();
for (ColumnMeta m : v.getValues()) {
String columnName = m.getColumnName();
if (imageParameterMap.get(columnName) == null && m.getColumnDef() != null) {
List<Object> imageParameters = imageParameterMap.get(columnName);
if (imageParameters == null && m.getColumnDef() != null) {
uniqueList.add(columnName + " = DEFAULT(" + columnName + ") ");
columnIsNull = false;
continue;
}
if ((imageParameterMap.get(columnName) == null && m.getColumnDef() == null) || imageParameterMap.get(columnName).get(finalI) == null || imageParameterMap.get(columnName).get(finalI) instanceof Null) {
if ((imageParameters == null && m.getColumnDef() == null) || imageParameters.get(finalI) == null || imageParameters.get(finalI) instanceof Null) {
if (!"PRIMARY".equalsIgnoreCase(k)) {
columnIsNull = false;
uniqueList.add(columnName + " is ? ");
Expand All @@ -316,7 +318,7 @@ public String buildImageSQL(TableMeta tableMeta) {
}
columnIsNull = false;
uniqueList.add(columnName + " = ? ");
paramAppenderTempList.add(imageParameterMap.get(columnName).get(finalI));
paramAppenderTempList.add(imageParameters.get(finalI));
}
if (!columnIsNull) {
if (isContainWhere[0]) {
Expand Down Expand Up @@ -354,7 +356,7 @@ public Map<String, ArrayList<Object>> buildImageParameters(SQLInsertRecognizer r
}
});
}
Map<String, ArrayList<Object>> imageParameterMap = new HashMap<>();
Map<String, ArrayList<Object>> imageParameterMap = new LowerCaseLinkHashMap<>();
Map<Integer, ArrayList<Object>> parameters = ((PreparedStatementProxy) statementProxy).getParameters();
// VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
List<String> insertParamsList = recognizer.getInsertParamsValue();
Expand All @@ -370,15 +372,13 @@ public Map<String, ArrayList<Object>> buildImageParameters(SQLInsertRecognizer r
ArrayList<Object> objects = parameters.get(paramsindex);
imageListTemp.addAll(objects);
paramsindex++;
} else if (params instanceof String) {
} else {
// params is character string constant
if ((params.trim().startsWith("'") && params.trim().endsWith("'")) || params.trim().startsWith("\"") && params.trim().endsWith("\"")) {
params = params.trim();
params = params.substring(1, params.length() - 1);
}
imageListTemp.add(params);
} else {
imageListTemp.add(params);
}
imageParameterMap.put(m, imageListTemp);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Collections;
Expand All @@ -27,7 +28,7 @@
import io.seata.rm.datasource.ConnectionProxy;
import io.seata.rm.datasource.PreparedStatementProxy;
import io.seata.rm.datasource.StatementProxy;
import io.seata.rm.datasource.exec.mysql.MySQLInsertOrUpdateExecutor;
import io.seata.rm.datasource.exec.mysql.MySQLInsertOnDuplicateUpdateExecutor;
import io.seata.rm.datasource.sql.struct.ColumnMeta;
import io.seata.rm.datasource.sql.struct.IndexMeta;
import io.seata.rm.datasource.sql.struct.IndexType;
Expand All @@ -48,7 +49,7 @@
/**
* @author: yangyicong
*/
public class MySQLInsertOrUpdateExecutorTest {
public class MySQLInsertOnDuplicateUpdateExecutorTest {

private static final String ID_COLUMN = "id";
private static final String USER_ID_COLUMN = "user_id";
Expand All @@ -62,7 +63,7 @@ public class MySQLInsertOrUpdateExecutorTest {

private TableMeta tableMeta;

private MySQLInsertOrUpdateExecutor insertOrUpdateExecutor;
private MySQLInsertOnDuplicateUpdateExecutor insertOrUpdateExecutor;

private final int pkIndex = 0;
private HashMap<String,Integer> pkIndexMap;
Expand All @@ -78,7 +79,7 @@ public void init() {
StatementCallback statementCallback = mock(StatementCallback.class);
sqlInsertRecognizer = mock(SQLInsertRecognizer.class);
tableMeta = mock(TableMeta.class);
insertOrUpdateExecutor = Mockito.spy(new MySQLInsertOrUpdateExecutor(statementProxy, statementCallback, sqlInsertRecognizer));
insertOrUpdateExecutor = Mockito.spy(new MySQLInsertOnDuplicateUpdateExecutor(statementProxy, statementCallback, sqlInsertRecognizer));

pkIndexMap = new HashMap<String,Integer>(){
{
Expand Down Expand Up @@ -242,7 +243,7 @@ private void mockImageParameterMap_contain_constant() {
}

private Map<String, ArrayList<Object>> mockImageParameterMap(){
Map<String, ArrayList<Object>> imageParameterMap = new HashMap<>();
Map<String, ArrayList<Object>> imageParameterMap = new LinkedHashMap<>();
ArrayList<Object> idList = new ArrayList<>();
idList.add("100");
idList.add("101");
Expand Down

0 comments on commit de7d04f

Please sign in to comment.